diff --git a/django_psdb_engine/base.py b/django_psdb_engine/base.py index feb7a62..ddd6d1f 100644 --- a/django_psdb_engine/base.py +++ b/django_psdb_engine/base.py @@ -3,5 +3,5 @@ class DatabaseWrapper(MysqlDatabaseWrapper): - vendor = 'planetscale' - features_class = DatabaseFeatures \ No newline at end of file + vendor = "planetscale" + features_class = DatabaseFeatures diff --git a/django_psdb_engine/features.py b/django_psdb_engine/features.py index 6f4ac3c..d2d3373 100644 --- a/django_psdb_engine/features.py +++ b/django_psdb_engine/features.py @@ -1,4 +1,7 @@ -from django.db.backends.mysql.features import DatabaseFeatures as MysqlBaseDatabaseFeatures +from django.db.backends.mysql.features import ( + DatabaseFeatures as MysqlBaseDatabaseFeatures, +) + class DatabaseFeatures(MysqlBaseDatabaseFeatures): - supports_foreign_keys = False \ No newline at end of file + supports_foreign_keys = False diff --git a/manage.py b/manage.py index dfbc1a0..717b530 100755 --- a/manage.py +++ b/manage.py @@ -6,7 +6,7 @@ def main(): """Run administrative tasks.""" - os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'pasteme.settings') + os.environ.setdefault("DJANGO_SETTINGS_MODULE", "pasteme.settings") try: from django.core.management import execute_from_command_line except ImportError as exc: @@ -18,5 +18,5 @@ def main(): execute_from_command_line(sys.argv) -if __name__ == '__main__': +if __name__ == "__main__": main() diff --git a/pasteme/asgi.py b/pasteme/asgi.py index c8e37b1..2704364 100644 --- a/pasteme/asgi.py +++ b/pasteme/asgi.py @@ -11,6 +11,6 @@ from django.core.asgi import get_asgi_application -os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'pasteme.settings') +os.environ.setdefault("DJANGO_SETTINGS_MODULE", "pasteme.settings") application = get_asgi_application() diff --git a/pasteme/settings.py b/pasteme/settings.py index b800c83..9c5c5ff 100644 --- a/pasteme/settings.py +++ b/pasteme/settings.py @@ -22,27 +22,25 @@ # See https://docs.djangoproject.com/en/4.0/howto/deployment/checklist/ # SECURITY WARNING: keep the secret key used in production secret! -SECRET_KEY = config('SECRET_KEY') +SECRET_KEY = config("SECRET_KEY") # SECURITY WARNING: don't run with debug turned on in production! DEBUG = False -ALLOWED_HOSTS = ['*'] +ALLOWED_HOSTS = ["*"] # Application definition INSTALLED_APPS = [ - 'django.contrib.admin', - 'django.contrib.auth', - 'django.contrib.contenttypes', - 'django.contrib.sessions', - 'django.contrib.messages', - 'django.contrib.staticfiles', - + "django.contrib.admin", + "django.contrib.auth", + "django.contrib.contenttypes", + "django.contrib.sessions", + "django.contrib.messages", + "django.contrib.staticfiles", # 3rd parties - 'rest_framework', - 'drf_yasg', - + "rest_framework", + "drf_yasg", # apps 'snippet', 'blog', @@ -50,42 +48,42 @@ ] MIDDLEWARE = [ - 'django.middleware.security.SecurityMiddleware', - 'django.contrib.sessions.middleware.SessionMiddleware', - 'django.middleware.common.CommonMiddleware', - 'django.middleware.csrf.CsrfViewMiddleware', - 'django.contrib.auth.middleware.AuthenticationMiddleware', - 'django.contrib.messages.middleware.MessageMiddleware', - 'django.middleware.clickjacking.XFrameOptionsMiddleware', + "django.middleware.security.SecurityMiddleware", + "django.contrib.sessions.middleware.SessionMiddleware", + "django.middleware.common.CommonMiddleware", + "django.middleware.csrf.CsrfViewMiddleware", + "django.contrib.auth.middleware.AuthenticationMiddleware", + "django.contrib.messages.middleware.MessageMiddleware", + "django.middleware.clickjacking.XFrameOptionsMiddleware", ] -ROOT_URLCONF = 'pasteme.urls' +ROOT_URLCONF = "pasteme.urls" TEMPLATES = [ { - 'BACKEND': 'django.template.backends.django.DjangoTemplates', - 'DIRS': [str(BASE_DIR.joinpath('templates'))], - 'APP_DIRS': True, - 'OPTIONS': { - 'context_processors': [ - 'django.template.context_processors.debug', - 'django.template.context_processors.request', - 'django.contrib.auth.context_processors.auth', - 'django.contrib.messages.context_processors.messages', + "BACKEND": "django.template.backends.django.DjangoTemplates", + "DIRS": [str(BASE_DIR.joinpath("templates"))], + "APP_DIRS": True, + "OPTIONS": { + "context_processors": [ + "django.template.context_processors.debug", + "django.template.context_processors.request", + "django.contrib.auth.context_processors.auth", + "django.contrib.messages.context_processors.messages", ], }, }, ] -WSGI_APPLICATION = 'pasteme.wsgi.application' +WSGI_APPLICATION = "pasteme.wsgi.application" # Database # https://docs.djangoproject.com/en/4.0/ref/settings/#databases DATABASES = { - 'default': { - 'ENGINE': 'django.db.backends.sqlite3', - 'NAME': BASE_DIR / 'db.sqlite3', + "default": { + "ENGINE": "django.db.backends.sqlite3", + "NAME": BASE_DIR / "db.sqlite3", } } @@ -94,16 +92,16 @@ AUTH_PASSWORD_VALIDATORS = [ { - 'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator', + "NAME": "django.contrib.auth.password_validation.UserAttributeSimilarityValidator", }, { - 'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator', + "NAME": "django.contrib.auth.password_validation.MinimumLengthValidator", }, { - 'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator', + "NAME": "django.contrib.auth.password_validation.CommonPasswordValidator", }, { - 'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator', + "NAME": "django.contrib.auth.password_validation.NumericPasswordValidator", }, ] @@ -111,9 +109,9 @@ # Internationalization # https://docs.djangoproject.com/en/4.0/topics/i18n/ -LANGUAGE_CODE = 'en-us' +LANGUAGE_CODE = "en-us" -TIME_ZONE = 'UTC' +TIME_ZONE = "UTC" USE_I18N = True @@ -123,21 +121,22 @@ # Static files (CSS, JavaScript, Images) # https://docs.djangoproject.com/en/4.0/howto/static-files/ -STATIC_URL = '/static/' -STATIC_ROOT = 'static/' +STATIC_URL = "/static/" +STATIC_ROOT = "static/" -MEDIA_URL = '/media/' -MEDIA_ROOT = 'media/' +MEDIA_URL = "/media/" +MEDIA_ROOT = "media/" # Default primary key field type # https://docs.djangoproject.com/en/4.0/ref/settings/#default-auto-field -DEFAULT_AUTO_FIELD = 'django.db.models.BigAutoField' +DEFAULT_AUTO_FIELD = "django.db.models.BigAutoField" -DOMAIN_URL = 'https://pasteme.pythonanywhere.com/' +DOMAIN_URL = "https://pasteme.pythonanywhere.com/" # Import local settings try: from .local_settings import * -except ImportError: pass \ No newline at end of file +except ImportError: + pass diff --git a/pasteme/urls.py b/pasteme/urls.py index e22a7c6..5198c19 100644 --- a/pasteme/urls.py +++ b/pasteme/urls.py @@ -5,16 +5,16 @@ from rest_framework import permissions schema_view = get_schema_view( - openapi.Info( - title="PasteMe API Documentation", - default_version='v1', - description="API endpoints for PasteMe RESTful service.", - contact=openapi.Contact(email="lnxpylnxpy@gmail.com"), - license=openapi.License(name="MIT License"), - ), - public=True, - permission_classes=[permissions.AllowAny], - authentication_classes=None, + openapi.Info( + title="PasteMe API Documentation", + default_version="v1", + description="API endpoints for PasteMe RESTful service.", + contact=openapi.Contact(email="lnxpylnxpy@gmail.com"), + license=openapi.License(name="MIT License"), + ), + public=True, + permission_classes=[permissions.AllowAny], + authentication_classes=None, ) urlpatterns = [ diff --git a/pasteme/wsgi.py b/pasteme/wsgi.py index d337d9f..f1a2a55 100644 --- a/pasteme/wsgi.py +++ b/pasteme/wsgi.py @@ -11,6 +11,6 @@ from django.core.wsgi import get_wsgi_application -os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'pasteme.settings') +os.environ.setdefault("DJANGO_SETTINGS_MODULE", "pasteme.settings") application = get_wsgi_application() diff --git a/pypi/admin.py b/pypi/admin.py index a23ff81..694323f 100644 --- a/pypi/admin.py +++ b/pypi/admin.py @@ -1 +1 @@ -from django.contrib import admin \ No newline at end of file +from django.contrib import admin diff --git a/pypi/apps.py b/pypi/apps.py index 4ab525a..ec463ea 100644 --- a/pypi/apps.py +++ b/pypi/apps.py @@ -2,5 +2,5 @@ class PypiConfig(AppConfig): - default_auto_field = 'django.db.models.BigAutoField' - name = 'pypi' + default_auto_field = "django.db.models.BigAutoField" + name = "pypi" diff --git a/pypi/management/commands/collectstatistics.py b/pypi/management/commands/collectstatistics.py index 94ce1bc..f56844f 100644 --- a/pypi/management/commands/collectstatistics.py +++ b/pypi/management/commands/collectstatistics.py @@ -8,23 +8,35 @@ class Command(BaseCommand): - help = 'Collects stats of pasteme-cli package using pypistats SDK' + help = "Collects stats of pasteme-cli package using pypistats SDK" def handle(self, *args, **options): - pasteme_totlal_stars = int(requests.get('https://api.github.com/repos/collove/pasteme').json()['stargazers_count']) - pastemecli_totlal_stars = int(requests.get('https://api.github.com/repos/collove/pasteme-cli').json()['stargazers_count']) - daily_payload = json.loads(pypistats.recent("pasteme-cli", format="json"))['data'] - overall_downloads = json.loads(pypistats.overall('pasteme-cli', format='json'))['data'][0]['downloads'] - + pasteme_totlal_stars = int( + requests.get("https://api.github.com/repos/collove/pasteme").json()[ + "stargazers_count" + ] + ) + pastemecli_totlal_stars = int( + requests.get("https://api.github.com/repos/collove/pasteme-cli").json()[ + "stargazers_count" + ] + ) + daily_payload = json.loads(pypistats.recent("pasteme-cli", format="json"))[ + "data" + ] + overall_downloads = json.loads(pypistats.overall("pasteme-cli", format="json"))[ + "data" + ][0]["downloads"] + obj = Statistic( - last_day_downloads=daily_payload['last_day'], - last_week_downloads=daily_payload['last_week'], - last_month_downloads=daily_payload['last_month'], + last_day_downloads=daily_payload["last_day"], + last_week_downloads=daily_payload["last_week"], + last_month_downloads=daily_payload["last_month"], total_downloads=overall_downloads, total_service_stars=pasteme_totlal_stars, total_package_stars=pastemecli_totlal_stars, ) - + obj.save() - - self.stdout.write(f'Statistics {obj} object created!') \ No newline at end of file + + self.stdout.write(f"Statistics {obj} object created!") diff --git a/pypi/migrations/0001_initial.py b/pypi/migrations/0001_initial.py index c4dff33..822c944 100644 --- a/pypi/migrations/0001_initial.py +++ b/pypi/migrations/0001_initial.py @@ -7,21 +7,28 @@ class Migration(migrations.Migration): initial = True - dependencies = [ - ] + dependencies = [] operations = [ migrations.CreateModel( - name='Statistic', + name="Statistic", fields=[ - ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), - ('last_day_downloads', models.PositiveIntegerField()), - ('last_week_downloads', models.PositiveIntegerField()), - ('last_month_downloads', models.PositiveIntegerField()), - ('total_downloads', models.PositiveIntegerField()), - ('total_service_stars', models.PositiveIntegerField()), - ('total_package_stars', models.PositiveIntegerField()), - ('date', models.DateTimeField(auto_now=True)), + ( + "id", + models.BigAutoField( + auto_created=True, + primary_key=True, + serialize=False, + verbose_name="ID", + ), + ), + ("last_day_downloads", models.PositiveIntegerField()), + ("last_week_downloads", models.PositiveIntegerField()), + ("last_month_downloads", models.PositiveIntegerField()), + ("total_downloads", models.PositiveIntegerField()), + ("total_service_stars", models.PositiveIntegerField()), + ("total_package_stars", models.PositiveIntegerField()), + ("date", models.DateTimeField(auto_now=True)), ], ), ] diff --git a/pypi/models.py b/pypi/models.py index 08a4d93..285ea45 100644 --- a/pypi/models.py +++ b/pypi/models.py @@ -9,5 +9,6 @@ class Statistic(models.Model): total_service_stars = models.PositiveIntegerField() total_package_stars = models.PositiveIntegerField() date = models.DateTimeField(auto_now=True) - - def __str__(self): return f'{self.id} at {self.date}' \ No newline at end of file + + def __str__(self): + return f"{self.id} at {self.date}" diff --git a/snippet/apps.py b/snippet/apps.py index 989fd5d..1a15f93 100644 --- a/snippet/apps.py +++ b/snippet/apps.py @@ -2,5 +2,5 @@ class SnippetConfig(AppConfig): - default_auto_field = 'django.db.models.BigAutoField' - name = 'snippet' + default_auto_field = "django.db.models.BigAutoField" + name = "snippet" diff --git a/snippet/constants.py b/snippet/constants.py index 0a2559a..2be8229 100644 --- a/snippet/constants.py +++ b/snippet/constants.py @@ -1,31 +1,35 @@ # Language choices - LANGUAGES = ( - ('bash', 'Bash'), - ('c', 'C'), - ('cpp', 'C++'), - ('csharp', 'C#'), - ('css', 'CSS'), - ('go', 'Go'), - ('html', 'HTML'), - ('java', 'Java'), - ('js', 'JavaScript'), - ('json', 'JSON'), - ('lua', 'Lua'), - ('md', 'MarkDown'), - ('php', 'PHP'), - ('plaintext', 'PlainText'), - ('python', 'Python'), - ('rb', 'Ruby'), + ("bash", "Bash"), + ("c", "C"), + ("cpp", "C++"), + ("csharp", "C#"), + ("css", "CSS"), + ("go", "Go"), + ("html", "HTML"), + ("java", "Java"), + ("js", "JavaScript"), + ("json", "JSON"), + ("lua", "Lua"), + ("md", "MarkDown"), + ("php", "PHP"), + ("plaintext", "PlainText"), + ("python", "Python"), + ("rb", "Ruby"), ) # Themes - THEMES = ( - ('default', 'Default Light'), - ('dark', 'Default Dark'), - ('atom-one-light', 'Atom One Light'), - ('atom-one-dark', 'Atom One Dark'), - ('github', 'Github Light'), - ('github-dark', 'Github Dark'), -) \ No newline at end of file + ("default", "Default Light"), + ("dark", "Default Dark"), + ("atom-one-light", "Atom One Light"), + ("atom-one-dark", "Atom One Dark"), + ("github", "Github Light"), + ("github-dark", "Github Dark"), +) + +EXPIRY_OPTIONS = ( + (1, "One Day"), + (7, "One Week"), + (30, "One Month"), +) diff --git a/snippet/management/__init__.py b/snippet/management/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/snippet/management/commands/__init__.py b/snippet/management/commands/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/snippet/management/commands/delete_expired_snippets.py b/snippet/management/commands/delete_expired_snippets.py new file mode 100644 index 0000000..039d640 --- /dev/null +++ b/snippet/management/commands/delete_expired_snippets.py @@ -0,0 +1,21 @@ +from django.core.management.base import BaseCommand +from django.utils import timezone +from django.db.models import F + +from snippet.models import Snippet + + +class Command(BaseCommand): + help = "Delete Expired Snippets" + + def handle(self, *args, **options): + expired_snippets = Snippet.objects.filter( + expires_in__lt=timezone.now().date() - F("created_at__date"), + ) + expired_snippets_count = expired_snippets.count() + expired_snippets.delete() + self.stdout.write( + self.style.SUCCESS( + f"{expired_snippets_count} snippet(s) deleted successfully" + ) + ) diff --git a/snippet/migrations/0001_initial.py b/snippet/migrations/0001_initial.py index 18188f4..844168b 100644 --- a/snippet/migrations/0001_initial.py +++ b/snippet/migrations/0001_initial.py @@ -8,19 +8,69 @@ class Migration(migrations.Migration): initial = True - dependencies = [ - ] + dependencies = [] operations = [ migrations.CreateModel( - name='Snippet', + name="Snippet", fields=[ - ('id', shortuuid.django_fields.ShortUUIDField(alphabet='abcdefg12345', length=5, max_length=40, prefix='', primary_key=True, serialize=False)), - ('title', models.CharField(default='Untitled', max_length=120)), - ('body', models.TextField()), - ('language', models.CharField(choices=[('bash', 'Bash'), ('c', 'C'), ('cpp', 'C++'), ('csharp', 'C#'), ('css', 'CSS'), ('go', 'Go'), ('html', 'HTML'), ('java', 'Java'), ('js', 'JavaScript'), ('json', 'JSON'), ('lua', 'Lua'), ('md', 'MarkDown'), ('php', 'PHP'), ('plaintext', 'PlainText'), ('python', 'Python'), ('rb', 'Ruby')], default='plaintext', max_length=120)), - ('theme', models.CharField(choices=[('default', 'Default Light'), ('dark', 'Default Dark'), ('atom-one-light', 'Atom One Light'), ('atom-one-dark', 'Atom One Dark'), ('github', 'Github Light'), ('github-dark', 'Github Dark')], default='default', max_length=120)), - ('created_at', models.DateTimeField(auto_now=True, verbose_name='Created at')), + ( + "id", + shortuuid.django_fields.ShortUUIDField( + alphabet="abcdefg12345", + length=5, + max_length=40, + prefix="", + primary_key=True, + serialize=False, + ), + ), + ("title", models.CharField(default="Untitled", max_length=120)), + ("body", models.TextField()), + ( + "language", + models.CharField( + choices=[ + ("bash", "Bash"), + ("c", "C"), + ("cpp", "C++"), + ("csharp", "C#"), + ("css", "CSS"), + ("go", "Go"), + ("html", "HTML"), + ("java", "Java"), + ("js", "JavaScript"), + ("json", "JSON"), + ("lua", "Lua"), + ("md", "MarkDown"), + ("php", "PHP"), + ("plaintext", "PlainText"), + ("python", "Python"), + ("rb", "Ruby"), + ], + default="plaintext", + max_length=120, + ), + ), + ( + "theme", + models.CharField( + choices=[ + ("default", "Default Light"), + ("dark", "Default Dark"), + ("atom-one-light", "Atom One Light"), + ("atom-one-dark", "Atom One Dark"), + ("github", "Github Light"), + ("github-dark", "Github Dark"), + ], + default="default", + max_length=120, + ), + ), + ( + "created_at", + models.DateTimeField(auto_now=True, verbose_name="Created at"), + ), ], ), ] diff --git a/snippet/migrations/0002_snippet_expires_in.py b/snippet/migrations/0002_snippet_expires_in.py new file mode 100644 index 0000000..98e1fd7 --- /dev/null +++ b/snippet/migrations/0002_snippet_expires_in.py @@ -0,0 +1,22 @@ +# Generated by Django 4.0.6 on 2022-07-31 20:49 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ("snippet", "0001_initial"), + ] + + operations = [ + migrations.AddField( + model_name="snippet", + name="expires_in", + field=models.SmallIntegerField( + choices=[(1, "One Day"), (7, "One Week"), (30, "One Month")], + default=1, + verbose_name="Expires in", + ), + ), + ] diff --git a/snippet/models.py b/snippet/models.py index b2bdc5b..a96e05c 100644 --- a/snippet/models.py +++ b/snippet/models.py @@ -1,7 +1,8 @@ -from django.db import models from shortuuid.django_fields import ShortUUIDField +from django.db import models -from .constants import LANGUAGES, THEMES + +from .constants import LANGUAGES, THEMES, EXPIRY_OPTIONS class Snippet(models.Model): @@ -13,23 +14,29 @@ class Snippet(models.Model): ) title = models.CharField( max_length=120, - default='Untitled', + default="Untitled", ) body = models.TextField() language = models.CharField( max_length=120, choices=LANGUAGES, - default='plaintext', + default="plaintext", ) theme = models.CharField( max_length=120, - default='default', + default="default", choices=THEMES, ) created_at = models.DateTimeField( - verbose_name='Created at', + verbose_name="Created at", auto_now=True, editable=False, ) + expires_in = models.SmallIntegerField( + verbose_name="Expires in", + choices=EXPIRY_OPTIONS, + default=1, + ) - def __str__(self): return f'{self.title} at {self.created_at.date()}' \ No newline at end of file + def __str__(self): + return f"{self.title} at {self.created_at.date()}" diff --git a/snippet/serializers.py b/snippet/serializers.py index 971a72e..eafc4a9 100644 --- a/snippet/serializers.py +++ b/snippet/serializers.py @@ -7,14 +7,14 @@ class SnippetSerializer(ModelSerializer): - def to_representation(self, instance): data = super().to_representation(instance) - data['url'] = path.join(settings.DOMAIN_URL, 'paste', data['id']) - data['theme'] = instance.get_theme_display() + data["theme"] = instance.get_theme_display() + data["expires_in"] = instance.get_expires_in_display() + data["url"] = path.join(settings.DOMAIN_URL, "paste", data["id"]) return data class Meta: model = Snippet - fields = ['id', 'title', 'body', 'language', 'theme'] - read_only_fields = ['id'] \ No newline at end of file + fields = ["id", "title", "body", "language", "theme", "expires_in"] + read_only_fields = ["id"] diff --git a/snippet/templates/snippet.html b/snippet/templates/snippet.html index 8c7adb7..87d1f01 100644 --- a/snippet/templates/snippet.html +++ b/snippet/templates/snippet.html @@ -1,47 +1,49 @@ {% extends '_base.html' %} {% load static %} - -{% block title %}{{snippet.title}} ({{snippet.get_language_display}}){% endblock %} - +{% block title %}{{ snippet.title }} ({{ snippet.get_language_display }}){% endblock %} {% block metas %} - + - - + - - + {% endblock %} {% block addon_link %} {% endblock %} - {% block addon_script %} - - - + + + {% endblock %} - {% block content %} -
-
-

{{snippet.title}}

-

{{snippet.get_language_display}} {{snippet.get_theme_display}} Theme - {{snippet.created_at.date}}

-
-
{{snippet.body}}
+
+
+

{{ snippet.title }}

+

+ Created at {{ snippet.created_at.date }} + Expires in {{ snippet.get_expires_in_display }} + {{ snippet.get_language_display }} + {{ snippet.get_theme_display }} Theme +

+
+
{{snippet.body}}
+
-
-
-{% endblock %} \ No newline at end of file + +{% endblock %} diff --git a/snippet/tests/test_api_views.py b/snippet/tests/test_api_views.py index 9758614..f80906c 100644 --- a/snippet/tests/test_api_views.py +++ b/snippet/tests/test_api_views.py @@ -10,42 +10,38 @@ class SnippetAPITestCase(APITestCase): - def setUp(self): self.sample = { - 'title': 'sample title', - 'body': 'code snippet', - 'language': LANGUAGES[0][0], + "title": "sample title", + "body": "code snippet", + "language": LANGUAGES[0][0], } - + def test_create_snippet(self): - url = reverse('create-paste') + url = reverse("create-paste") response = self.client.post( - url, - json.dumps(self.sample), - content_type='application/json' + url, json.dumps(self.sample), content_type="application/json" ) - + self.assertEqual(response.status_code, status.HTTP_201_CREATED) self.assertEqual(Snippet.objects.count(), 1) - self.assertEqual(Snippet.objects.get().title, 'sample title') - + self.assertEqual(Snippet.objects.get().title, "sample title") + def test_if_object_exists(self): post_response = self.client.post( - reverse('create-paste'), + reverse("create-paste"), json.dumps(self.sample), - content_type='application/json' + content_type="application/json", ) - - id = post_response.json()['id'] + + id = post_response.json()["id"] get_response = self.client.get( - reverse('get-paste', args=[id]), - content_type='application/json' + reverse("get-paste", args=[id]), content_type="application/json" ) - + get_serialized = SnippetSerializer(get_response.json()).data - + self.assertEqual(post_response.status_code, status.HTTP_201_CREATED) self.assertEqual(get_response.status_code, status.HTTP_200_OK) - self.assertEqual(get_serialized, post_response.json()) \ No newline at end of file + self.assertEqual(get_serialized, post_response.json()) diff --git a/snippet/tests/test_models.py b/snippet/tests/test_models.py index 3b97f17..b448ab6 100644 --- a/snippet/tests/test_models.py +++ b/snippet/tests/test_models.py @@ -5,13 +5,12 @@ class SnippetTestCase(TestCase): - @classmethod def setUpTestData(cls) -> None: cls.sample = { - 'title': 'sample title', - 'body': 'code snippet', - 'language': LANGUAGES[0][1], + "title": "sample title", + "body": "code snippet", + "language": LANGUAGES[0][1], } def setUp(self) -> None: @@ -19,9 +18,9 @@ def setUp(self) -> None: def test_if_obj_returns_same_fields(self): fields = { - 'title': self.snippet.title, - 'body': self.snippet.body, - 'language': self.snippet.language, + "title": self.snippet.title, + "body": self.snippet.body, + "language": self.snippet.language, } self.assertEqual(fields, self.sample) @@ -29,4 +28,4 @@ def test_if_obj_is_retrievable(self): self.assertIsInstance(Snippet.objects.get(id=self.snippet.id), Snippet) def test_sid_length(self): - self.assertEqual(len(self.snippet.id), 5) \ No newline at end of file + self.assertEqual(len(self.snippet.id), 5) diff --git a/snippet/tests/test_template_views.py b/snippet/tests/test_template_views.py index 889a34a..174a647 100644 --- a/snippet/tests/test_template_views.py +++ b/snippet/tests/test_template_views.py @@ -3,10 +3,9 @@ class SnippetTemplateTestCase(TestCase): - def setUp(self) -> None: self.client = Client() - + def test_home_page(self): - response = self.client.get(reverse('home')) - self.assertEqual(response.status_code, 200) \ No newline at end of file + response = self.client.get(reverse("home")) + self.assertEqual(response.status_code, 200) diff --git a/snippet/urls.py b/snippet/urls.py index c61182d..8c67cb5 100644 --- a/snippet/urls.py +++ b/snippet/urls.py @@ -3,9 +3,8 @@ from .views import api, template urlpatterns = [ - path('', template.HomeView.as_view(), name='home'), - path('paste//', template.SnippetView.as_view(), name='view-paste'), - - path('api/v1/paste/', api.CreateSnippetAPI.as_view(), name='create-paste'), - path('api/v1/paste//', api.GetSnippetAPI.as_view(), name='get-paste'), -] \ No newline at end of file + path("", template.HomeView.as_view(), name="home"), + path("paste//", template.SnippetView.as_view(), name="view-paste"), + path("api/v1/paste/", api.CreateSnippetAPI.as_view(), name="create-paste"), + path("api/v1/paste//", api.GetSnippetAPI.as_view(), name="get-paste"), +] diff --git a/snippet/views/api.py b/snippet/views/api.py index 46467af..a357d75 100644 --- a/snippet/views/api.py +++ b/snippet/views/api.py @@ -11,6 +11,6 @@ class CreateSnippetAPI(CreateAPIView): class GetSnippetAPI(RetrieveAPIView): model = Snippet - lookup_field = 'pk' + lookup_field = "pk" serializer_class = SnippetSerializer - queryset = Snippet.objects.all() \ No newline at end of file + queryset = Snippet.objects.all() diff --git a/snippet/views/template.py b/snippet/views/template.py index 0fa4cc3..df351b2 100644 --- a/snippet/views/template.py +++ b/snippet/views/template.py @@ -5,7 +5,7 @@ class HomeView(TemplateView): - template_name = 'home.html' + template_name = "home.html" def get_context_data(self, **kwargs): context = super().get_context_data(**kwargs) @@ -15,5 +15,5 @@ def get_context_data(self, **kwargs): class SnippetView(DetailView): model = Snippet - template_name = 'snippet.html' - context_object_name = 'snippet' \ No newline at end of file + template_name = "snippet.html" + context_object_name = "snippet" diff --git a/templates/_base.html b/templates/_base.html index e110ae8..5a829e3 100644 --- a/templates/_base.html +++ b/templates/_base.html @@ -146,10 +146,7 @@ API Docs - Open Source on GitHub + Open Source on GitHub