diff --git a/.eslintrc b/.eslintrc
new file mode 100644
index 0000000..516cec4
--- /dev/null
+++ b/.eslintrc
@@ -0,0 +1,51 @@
+{
+ "env": {
+ "browser": true,
+ "es6": true,
+ "jquery": true
+ },
+ "extends": [
+ "eslint:recommended"
+ ],
+ "ignorePatterns": ["dist/", "node_modules/"],
+ "rules": {
+ "block-scoped-var": "error",
+ "consistent-return": "error",
+ "curly": "error",
+ "default-case": "error",
+ "default-param-last": ["error"],
+ "dot-notation": "error",
+ "eqeqeq": "error",
+ "guard-for-in": "error",
+ "max-classes-per-file": "error",
+ "no-alert": "error",
+ "no-caller": "error",
+ "no-else-return": "error",
+ "no-empty-function": "error",
+ "no-floating-decimal": "error",
+ "no-implicit-coercion": "error",
+ "no-multi-spaces": "error",
+ "no-multi-str": "error",
+ "no-param-reassign": "error",
+ "no-return-assign": "error",
+ "no-return-await": "error",
+ "no-self-compare": "error",
+ "no-throw-literal": "error",
+ "no-useless-concat": "error",
+ "radix": ["error", "as-needed"],
+ "require-await": "error",
+ "yoda": "error",
+ "no-shadow": "off",
+ "prefer-destructuring": ["error", { "array": false, "object": true }],
+ "padding-line-between-statements": [
+ "error",
+ { "blankLine": "always", "prev": "import", "next": "export" },
+ { "blankLine": "always", "prev": "export", "next": "export" },
+ { "blankLine": "always", "prev": "*", "next": "return" }
+ ]
+ },
+ "parserOptions": {
+ "ecmaVersion": 6,
+ "sourceType": "module"
+ }
+}
diff --git a/.flake8 b/.flake8
index 944cb72..92201aa 100644
--- a/.flake8
+++ b/.flake8
@@ -6,3 +6,5 @@ ignore =
W503,
# class member shadows builtin
A003,
+max-complexity = 10
+format = %(path)s:%(row)d:%(col)d: %(code)s %(text)s https://lintlyci.github.io/Flake8Rules/rules/%(code)s.html
diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml
index 3f7432a..9eac4b6 100644
--- a/.pre-commit-config.yaml
+++ b/.pre-commit-config.yaml
@@ -1,4 +1,4 @@
-exclude: \.min\.(js|css)(\.map)?$
+exclude: (\.min\.(js|css)(\.map)?$|/vendor/)
repos:
- repo: https://github.com/pre-commit/pre-commit-hooks
rev: v4.0.1
@@ -34,6 +34,15 @@ repos:
- id: pyupgrade
args:
- --py310-plus
+ - repo: https://github.com/adamchainz/django-upgrade
+ rev: 1.4.0
+ hooks:
+ - id: django-upgrade
+ args: [--target-version, "4.0"]
+ - repo: https://github.com/rtts/djhtml
+ rev: v1.4.10
+ hooks:
+ - id: djhtml
- repo: https://github.com/pycqa/flake8
rev: 4.0.1
hooks:
@@ -44,3 +53,18 @@ repos:
- flake8-builtins
- flake8-comprehensions
- flake8-eradicate
+ - flake8-pytest-style
+ - repo: https://github.com/pre-commit/mirrors-prettier
+ rev: v2.5.1
+ hooks:
+ - id: prettier
+ types_or: [javascript, css]
+ - repo: https://github.com/pre-commit/mirrors-eslint
+ rev: v8.4.1
+ hooks:
+ - id: eslint
+ args: [--fix]
+ types_or: [javascript, css]
+ additional_dependencies:
+ - eslint@^7.29.0
+ - eslint-config-prettier@^8.3.0
diff --git a/.prettierrc b/.prettierrc
new file mode 100644
index 0000000..d6245f5
--- /dev/null
+++ b/.prettierrc
@@ -0,0 +1,5 @@
+{
+ "tabWidth": 4,
+ "printWidth": 120,
+ "endOfLine": "auto"
+}
diff --git a/src/articles/static/admin_articles.css b/src/articles/static/admin_articles.css
index a473ae4..b0a5aa2 100644
--- a/src/articles/static/admin_articles.css
+++ b/src/articles/static/admin_articles.css
@@ -1,4 +1,5 @@
-#id_content, #id_custom_css {
+#id_content,
+#id_custom_css {
font-family: "JetBrains Mono", monospace;
min-height: 30em;
resize: vertical;
@@ -9,6 +10,7 @@
height: 38em;
}
-label[for=id_content], label[for=id_custom_css] {
+label[for="id_content"],
+label[for="id_custom_css"] {
display: none;
}
diff --git a/src/articles/static/admonitions.css b/src/articles/static/admonitions.css
index 603e272..56a1a0f 100644
--- a/src/articles/static/admonitions.css
+++ b/src/articles/static/admonitions.css
@@ -9,7 +9,7 @@
--warning-text: #856404;
}
-@media(prefers-color-scheme: dark) {
+@media (prefers-color-scheme: dark) {
:root {
--info-background: #0c5460;
--info-text: #d1ecf1;
diff --git a/src/articles/static/authenticated.css b/src/articles/static/authenticated.css
index 179e3b8..23c5047 100644
--- a/src/articles/static/authenticated.css
+++ b/src/articles/static/authenticated.css
@@ -2,7 +2,7 @@
font-size: 60%;
background-color: var(--nc-tx-2);
color: var(--nc-bg-1);
- padding: .5ex 1ex;
+ padding: 0.5ex 1ex;
border-radius: 1ex;
vertical-align: 15%;
text-decoration: none;
diff --git a/src/articles/static/copy-code.js b/src/articles/static/copy-code.js
index 75f5767..e333507 100644
--- a/src/articles/static/copy-code.js
+++ b/src/articles/static/copy-code.js
@@ -2,8 +2,8 @@
function addCopyCode() {
const codeBlocks = document.querySelectorAll("pre");
- codeBlocks.forEach(pre => {
- pre.addEventListener("click", event => {
+ codeBlocks.forEach((pre) => {
+ pre.addEventListener("click", (event) => {
if (event.detail === 4) {
const selection = window.getSelection();
selection.setBaseAndExtent(
@@ -18,7 +18,6 @@ function addCopyCode() {
});
}
-
((readyState) => {
if (readyState === "interactive") {
addCopyCode();
diff --git a/src/articles/static/edit-keymap.js b/src/articles/static/edit-keymap.js
index 72ec61d..19cef49 100644
--- a/src/articles/static/edit-keymap.js
+++ b/src/articles/static/edit-keymap.js
@@ -1,4 +1,4 @@
-'use strict';
+"use strict";
function bindKey() {
const adminLinkElement = document.querySelector("a#admin-link");
@@ -10,7 +10,7 @@ function bindKey() {
if (event.code === "KeyE") {
window.location = adminLocation;
}
- })
+ });
}
((readyState) => {
diff --git a/src/articles/static/live-preview.js b/src/articles/static/live-preview.js
index 8e7c370..f58721b 100644
--- a/src/articles/static/live-preview.js
+++ b/src/articles/static/live-preview.js
@@ -1,6 +1,6 @@
let preview = null;
-function onLoad () {
+function onLoad() {
const previewButton = document.querySelector("input#_live_preview");
if (previewButton) {
previewButton.addEventListener("click", openPreviewPopup);
@@ -34,11 +34,11 @@ function openPreviewPopup(event) {
function loadPreview() {
const id = Number(window.location.pathname.match(/\d+/)[0]);
const body = prepareBody();
- fetch(`/api/render/${id}/`, {method: "POST", body: body})
- .then(response => {
+ fetch(`/api/render/${id}/`, { method: "POST", body: body })
+ .then((response) => {
return response.text();
})
- .then(value => {
+ .then((value) => {
preview.document.open("text/html", "replace");
preview.document.write(value);
preview.document.close();
@@ -79,8 +79,11 @@ function prepareBody() {
const element = document.querySelector(input.selector);
body.set(input.to, element[input.property]);
}
- const tagIds = Array.from(document.querySelector("#id_tags").selectedOptions).map(option => option.value).join();
+ const tagIds = Array.from(document.querySelector("#id_tags").selectedOptions)
+ .map((option) => option.value)
+ .join();
body.set("tag_ids", tagIds);
+
return body;
}
@@ -105,8 +108,10 @@ function setupLivePreview() {
*/
function debounce(func, wait) {
let timeout;
+
return function () {
- const context = this, args = arguments;
+ const context = this,
+ args = arguments;
const later = function () {
timeout = null;
func.apply(context, args);
diff --git a/src/articles/static/login.css b/src/articles/static/login.css
index d6c9db9..5c1600b 100644
--- a/src/articles/static/login.css
+++ b/src/articles/static/login.css
@@ -1,18 +1,22 @@
.d-none {
- display: none !important;
+ display: none !important;
}
.float-right {
- float: right;
+ float: right;
}
-td, th, tr, tbody, tr:nth-child(2n) {
- background-color: inherit;
- border: none;
- padding-left: 0;
- padding-right: 0;
+td,
+th,
+tr,
+tbody,
+tr:nth-child(2n) {
+ background-color: inherit;
+ border: none;
+ padding-left: 0;
+ padding-right: 0;
}
img {
- background-color: white;
+ background-color: white;
}
diff --git a/src/articles/static/public.css b/src/articles/static/public.css
index 396800d..d131159 100644
--- a/src/articles/static/public.css
+++ b/src/articles/static/public.css
@@ -3,7 +3,9 @@ body {
max-width: 750px;
}
-h1, h2, h3 {
+h1,
+h2,
+h3 {
border-bottom: unset;
}
@@ -20,8 +22,9 @@ footer > :first-child {
margin-top: 1em;
}
-nav a:not(:first-child):before, a.tag:not(:first-of-type):before {
- content: '\00B7';
+nav a:not(:first-child):before,
+a.tag:not(:first-of-type):before {
+ content: "\00B7";
margin: 0 5px;
color: var(--nc-tx-1);
text-decoration: none;
diff --git a/src/articles/templates/articles/base.html b/src/articles/templates/articles/base.html
index 1236728..b3bea09 100644
--- a/src/articles/templates/articles/base.html
+++ b/src/articles/templates/articles/base.html
@@ -1,42 +1,42 @@
{% load static %}
{% spaceless %}
-
-
-
-
-
-
-
-
-
- {% block title %}Home | {% endblock %}{{ blog_title }} by {{ blog_author }}
- {% block feed_link %}
-
- {% endblock %}
- {% include "articles/snippets/analytics_head.html" %}
- {% include "articles/snippets/page_metadata.html" %}
+
+
+
+
+
+
+
+
+
+ {% block title %}Home | {% endblock %}{{ blog_title }} by {{ blog_author }}
+ {% block feed_link %}
+
+ {% endblock %}
+ {% include "articles/snippets/analytics_head.html" %}
+ {% include "articles/snippets/page_metadata.html" %}
-
-
-
- {% if article and article.has_code %}
-
- {% endif %}
- {% if user.is_authenticated %}
-
- {% endif %}
+
+
+
+ {% if article and article.has_code %}
+
+ {% endif %}
+ {% if user.is_authenticated %}
+
+ {% endif %}
- {% block append_css %}
- {% endblock %}
+ {% block append_css %}
+ {% endblock %}
- {% include "articles/snippets/favicon.html" %}
-
-
-
- {{ blog_title }}
- {{ blog_description }}
- {% include "articles/snippets/navigation.html" %}
-
+ {% include "articles/snippets/favicon.html" %}
+
+
+
+ {{ blog_title }}
+ {{ blog_description }}
+ {% include "articles/snippets/navigation.html" %}
+
{% endspaceless %}
@@ -45,31 +45,31 @@
{% spaceless %}
-
+
-{% include "articles/snippets/analytics.html" %}
-{% if user.is_authenticated %}
-
-{% endif %}
-{% if article and article.has_code %}
-
-{% endif %}
+ {% include "articles/snippets/analytics.html" %}
+ {% if user.is_authenticated %}
+
+ {% endif %}
+ {% if article and article.has_code %}
+
+ {% endif %}
-
-
+
+
{% endspaceless %}
diff --git a/src/articles/templates/articles/snippets/analytics.html b/src/articles/templates/articles/snippets/analytics.html
index 179b18a..a7de6d3 100644
--- a/src/articles/templates/articles/snippets/analytics.html
+++ b/src/articles/templates/articles/snippets/analytics.html
@@ -2,9 +2,9 @@
{% if not user.is_authenticated and goatcounter_domain is not None %}
+ data-goatcounter="https://{{ goatcounter_domain }}/count">
{% endif %}
diff --git a/src/articles/templates/articles/snippets/metadata.html b/src/articles/templates/articles/snippets/metadata.html
index 248196b..c9c7626 100644
--- a/src/articles/templates/articles/snippets/metadata.html
+++ b/src/articles/templates/articles/snippets/metadata.html
@@ -3,6 +3,6 @@
· {{ article.get_read_time }} min read
{% include "articles/snippets/admin_link.html" %}
{% if tags %}
-
{% for tag in tags %}{{ tag.name }}{% endfor %}
+
{% for tag in tags %}{{ tag.name }}{% endfor %}
{% endif %}
diff --git a/src/articles/tests/conftest.py b/src/articles/tests/conftest.py
index b179ba3..7c0b1ef 100644
--- a/src/articles/tests/conftest.py
+++ b/src/articles/tests/conftest.py
@@ -8,19 +8,19 @@ from articles.models import Article, Tag, User
@pytest.fixture()
-@pytest.mark.django_db
+@pytest.mark.django_db()
def author() -> User:
return User.objects.create_user("gaugendre", is_staff=True, is_superuser=True)
@pytest.fixture()
-@pytest.mark.django_db
+@pytest.mark.django_db()
def tag() -> Tag:
return Tag.objects.create(name="This is a new tag", slug="this-new-tag")
@pytest.fixture()
-@pytest.mark.django_db
+@pytest.mark.django_db()
def published_article(author: User, tag: Tag) -> Article:
article = Article.objects.create(
title="Some interesting article title",
@@ -41,7 +41,7 @@ def published_article(author: User, tag: Tag) -> Article:
@pytest.fixture()
-@pytest.mark.django_db
+@pytest.mark.django_db()
def unpublished_article(author: User) -> Article:
return Article.objects.create(
title="Some interesting article title, but sorry it is not public yet",
@@ -55,5 +55,5 @@ def unpublished_article(author: User) -> Article:
@pytest.fixture(autouse=True, scope="session")
-def collect_static():
+def _collect_static():
call_command("collectstatic", "--no-input", "--clear")
diff --git a/src/articles/tests/test_admin.py b/src/articles/tests/test_admin.py
index 8882cec..af4ab79 100644
--- a/src/articles/tests/test_admin.py
+++ b/src/articles/tests/test_admin.py
@@ -5,7 +5,7 @@ from django.urls import reverse
from articles.models import User
-@pytest.mark.django_db
+@pytest.mark.django_db()
# @pytest.mark.skip("Fails for no apparent reason")
@pytest.mark.flaky(reruns=5, reruns_delay=3)
def test_can_access_add_article(client: Client, author: User):
diff --git a/src/articles/tests/test_api_views.py b/src/articles/tests/test_api_views.py
index 87c75dd..804d2f2 100644
--- a/src/articles/tests/test_api_views.py
+++ b/src/articles/tests/test_api_views.py
@@ -6,7 +6,7 @@ from articles.models import Article
from articles.utils import format_article_content
-@pytest.mark.django_db
+@pytest.mark.django_db()
def test_unauthenticated_render_redirects(published_article: Article, client: Client):
api_res = client.post(
reverse("api-render-article", kwargs={"article_pk": published_article.pk}),
@@ -15,7 +15,7 @@ def test_unauthenticated_render_redirects(published_article: Article, client: Cl
assert api_res.status_code == 302
-@pytest.mark.django_db
+@pytest.mark.django_db()
def test_render_article_same_content(published_article: Article, client: Client):
client.force_login(published_article.author)
api_res = post_article(client, published_article, published_article.content)
@@ -35,7 +35,7 @@ def test_render_article_same_content(published_article: Article, client: Client)
assert api_content == standard_content
-@pytest.mark.django_db
+@pytest.mark.django_db()
def test_render_article_change_content(published_article: Article, client: Client):
client.force_login(published_article.author)
preview_content = "This is a different content **with strong emphasis**"
@@ -46,7 +46,7 @@ def test_render_article_change_content(published_article: Article, client: Clien
assert html_preview_content in api_content
-@pytest.mark.django_db
+@pytest.mark.django_db()
def test_render_article_doesnt_save(published_article, client: Client):
client.force_login(published_article.author)
original_content = published_article.content
@@ -57,7 +57,7 @@ def test_render_article_doesnt_save(published_article, client: Client):
assert published_article.content == original_content
-@pytest.mark.django_db
+@pytest.mark.django_db()
def test_render_article_no_tags(published_article, client: Client):
client.force_login(published_article.author)
api_res = client.post(
diff --git a/src/articles/tests/test_feed_views.py b/src/articles/tests/test_feed_views.py
index 80bf257..1bb90b6 100644
--- a/src/articles/tests/test_feed_views.py
+++ b/src/articles/tests/test_feed_views.py
@@ -7,7 +7,7 @@ from articles.models import Article, User
from articles.views.feeds import CompleteFeed
-@pytest.mark.django_db
+@pytest.mark.django_db()
def test_can_access_feed(client: Client, published_article):
res = client.get(reverse("complete-feed"))
assert res.status_code == 200
@@ -16,7 +16,7 @@ def test_can_access_feed(client: Client, published_article):
assert published_article.title in content
-@pytest.mark.django_db
+@pytest.mark.django_db()
def test_feed_limits_number_of_articles(client: Client, author: User):
baker.make(Article, 100, status=Article.PUBLISHED, author=author)
res = client.get(reverse("complete-feed"))
diff --git a/src/articles/tests/test_html_views.py b/src/articles/tests/test_html_views.py
index 212a96e..d8a9f82 100644
--- a/src/articles/tests/test_html_views.py
+++ b/src/articles/tests/test_html_views.py
@@ -6,7 +6,7 @@ from model_bakery import baker
from articles.models import Article, User
-@pytest.mark.django_db
+@pytest.mark.django_db()
def test_can_access_list(client: Client, published_article: Article):
res = client.get(reverse("articles-list"))
assert res.status_code == 200
@@ -15,7 +15,7 @@ def test_can_access_list(client: Client, published_article: Article):
assert published_article.get_abstract() not in content
-@pytest.mark.django_db
+@pytest.mark.django_db()
def test_only_title_shown_on_list(client: Client, author: User):
title = "This is a very long title mouahahaha"
abstract = "Some abstract"
@@ -34,7 +34,7 @@ def test_only_title_shown_on_list(client: Client, author: User):
assert after not in content
-@pytest.mark.django_db
+@pytest.mark.django_db()
def test_access_article_by_slug(client: Client, published_article: Article):
_test_access_article_by_slug(client, published_article)
@@ -52,7 +52,7 @@ def _assert_article_is_rendered(item: Article, res):
assert html in content
-@pytest.mark.django_db
+@pytest.mark.django_db()
def test_anonymous_cant_access_draft_detail(
client: Client, unpublished_article: Article
):
@@ -62,7 +62,7 @@ def test_anonymous_cant_access_draft_detail(
assert res.status_code == 404
-@pytest.mark.django_db
+@pytest.mark.django_db()
def test_anonymous_can_access_draft_detail_with_key(
client: Client, unpublished_article: Article
):
@@ -73,7 +73,7 @@ def test_anonymous_can_access_draft_detail_with_key(
_assert_article_is_rendered(unpublished_article, res)
-@pytest.mark.django_db
+@pytest.mark.django_db()
def test_user_can_access_draft_detail(
client: Client, author: User, unpublished_article: Article
):
@@ -81,7 +81,7 @@ def test_user_can_access_draft_detail(
_test_access_article_by_slug(client, unpublished_article)
-@pytest.mark.django_db
+@pytest.mark.django_db()
def test_anonymous_cant_access_drafts_list(
client: Client, unpublished_article: Article
):
@@ -89,7 +89,7 @@ def test_anonymous_cant_access_drafts_list(
assert res.status_code == 302
-@pytest.mark.django_db
+@pytest.mark.django_db()
def test_user_can_access_drafts_list(
client: Client, author: User, unpublished_article: Article
):
@@ -100,7 +100,7 @@ def test_user_can_access_drafts_list(
assert unpublished_article.title in content
-@pytest.mark.django_db
+@pytest.mark.django_db()
def test_has_goatcounter_if_set(client: Client, settings):
settings.GOATCOUNTER_DOMAIN = "gc.gabnotes.org"
res = client.get(reverse("articles-list"))
@@ -109,7 +109,7 @@ def test_has_goatcounter_if_set(client: Client, settings):
assert f"{settings.GOATCOUNTER_DOMAIN}/count" in content
-@pytest.mark.django_db
+@pytest.mark.django_db()
def test_doesnt_have_goatcounter_if_unset(client: Client, settings):
settings.GOATCOUNTER_DOMAIN = None
res = client.get(reverse("articles-list"))
@@ -118,7 +118,7 @@ def test_doesnt_have_goatcounter_if_unset(client: Client, settings):
assert f"{settings.GOATCOUNTER_DOMAIN}/count" not in content
-@pytest.mark.django_db
+@pytest.mark.django_db()
def test_logged_in_user_doesnt_have_goatcounter(client: Client, author: User, settings):
client.force_login(author)
settings.GOATCOUNTER_DOMAIN = "gc.gabnotes.org"
@@ -128,7 +128,7 @@ def test_logged_in_user_doesnt_have_goatcounter(client: Client, author: User, se
assert f"{settings.GOATCOUNTER_DOMAIN}/count" not in content
-@pytest.mark.django_db
+@pytest.mark.django_db()
def test_image_is_lazy(client: Client, published_article: Article):
res = client.get(reverse("article-detail", kwargs={"slug": published_article.slug}))
assert res.status_code == 200
diff --git a/src/articles/tests/test_migrations.py b/src/articles/tests/test_migrations.py
index 907207b..0b79cd1 100644
--- a/src/articles/tests/test_migrations.py
+++ b/src/articles/tests/test_migrations.py
@@ -2,6 +2,6 @@ import pytest
from django.core.management import call_command
-@pytest.mark.django_db
+@pytest.mark.django_db()
def test_missing_migrations():
call_command("makemigrations", "--check")
diff --git a/src/articles/tests/test_models.py b/src/articles/tests/test_models.py
index 2bdd268..2a0f31b 100644
--- a/src/articles/tests/test_models.py
+++ b/src/articles/tests/test_models.py
@@ -3,7 +3,7 @@ import pytest
from articles.models import Article, User
-@pytest.mark.django_db
+@pytest.mark.django_db()
def test_publish_article(unpublished_article: Article):
assert unpublished_article.status == Article.DRAFT
assert unpublished_article.published_at is None
@@ -12,7 +12,7 @@ def test_publish_article(unpublished_article: Article):
assert published_article.published_at is not None
-@pytest.mark.django_db
+@pytest.mark.django_db()
def test_unpublish_article(published_article: Article):
assert published_article.status == Article.PUBLISHED
assert published_article.published_at is not None
@@ -21,7 +21,7 @@ def test_unpublish_article(published_article: Article):
assert unpublished_article.published_at is None
-@pytest.mark.django_db
+@pytest.mark.django_db()
def test_save_article_adds_missing_slug(author: User):
# Explicitly calling bulk_create with one article because it doesn't call save().
articles = Article.objects.bulk_create(
@@ -33,7 +33,7 @@ def test_save_article_adds_missing_slug(author: User):
assert article.slug != ""
-@pytest.mark.django_db
+@pytest.mark.django_db()
def test_save_article_doesnt_change_existing_slug(published_article: Article):
original_slug = published_article.slug
published_article.title = "This is a brand new title"
@@ -41,19 +41,19 @@ def test_save_article_doesnt_change_existing_slug(published_article: Article):
assert published_article.slug == original_slug
-@pytest.mark.django_db
+@pytest.mark.django_db()
def test_empty_custom_css_minified(published_article):
published_article.custom_css = ""
assert published_article.get_minified_custom_css == ""
-@pytest.mark.django_db
+@pytest.mark.django_db()
def test_simple_custom_css_minified(published_article):
published_article.custom_css = ".cls {\n background-color: red;\n}"
assert published_article.get_minified_custom_css == ".cls{background-color:red}"
-@pytest.mark.django_db
+@pytest.mark.django_db()
def test_larger_custom_css_minified(published_article):
published_article.custom_css = """\
.profile {
diff --git a/src/attachments/static/attachments/js/copy_url.js b/src/attachments/static/attachments/js/copy_url.js
index 22428c5..51c0c6e 100644
--- a/src/attachments/static/attachments/js/copy_url.js
+++ b/src/attachments/static/attachments/js/copy_url.js
@@ -2,10 +2,10 @@ function copy(event) {
const text = event.target.dataset.toCopy;
navigator.clipboard.writeText(text).then(() => {
console.log("Copied");
- })
+ });
}
-$(document).ready(function() {
+$(document).ready(function () {
const buttons = document.querySelectorAll(".copy-button");
for (const button of buttons) {
button.addEventListener("click", copy);
diff --git a/src/attachments/tests/test_models.py b/src/attachments/tests/test_models.py
index b6435ab..4024081 100644
--- a/src/attachments/tests/test_models.py
+++ b/src/attachments/tests/test_models.py
@@ -6,9 +6,9 @@ from django.core.files import File
from attachments.models import Attachment
-@pytest.mark.block_network
-@pytest.mark.vcr
-@pytest.mark.django_db
+@pytest.mark.block_network()
+@pytest.mark.vcr()
+@pytest.mark.django_db()
def test_attachment_is_processed_by_shortpixel():
# This path manipulation is required to make the test run from this directory
# or from upper in the hierarchy (e.g.: settings.BASE_DIR)
diff --git a/src/blog/templates/admin/base_site.html b/src/blog/templates/admin/base_site.html
index 5600d01..c2e6dd0 100644
--- a/src/blog/templates/admin/base_site.html
+++ b/src/blog/templates/admin/base_site.html
@@ -3,7 +3,7 @@
{% block title %}{{ title }} | {{ site_title|default:_('Django site admin') }}{% endblock %}
{% block branding %}
-
+
{% endblock %}
{% block extrahead %}