aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMatthew Lemon <y@yulqen.org>2024-05-14 13:59:52 +0100
committerMatthew Lemon <y@yulqen.org>2024-05-14 13:59:52 +0100
commitced16ee9dc3bf1790c0345e874dc7861e27c99ca (patch)
tree17cc73c5232b1043d241736c4728904b0fb8f9ed
parent46f11648d902b22a177b878e35d6049a7a127ce7 (diff)
Adds crispy forms helper
-rw-r--r--pyblackbird_cc/resources/forms.py47
-rw-r--r--pyblackbird_cc/templates/resources/resource_create.html21
-rw-r--r--pyblackbird_cc/templates/resources/resource_detail.html40
-rw-r--r--pyproject.toml127
4 files changed, 137 insertions, 98 deletions
diff --git a/pyblackbird_cc/resources/forms.py b/pyblackbird_cc/resources/forms.py
index c3b938d..9645a82 100644
--- a/pyblackbird_cc/resources/forms.py
+++ b/pyblackbird_cc/resources/forms.py
@@ -1,6 +1,8 @@
import logging
import magic
+from crispy_forms.helper import FormHelper
+from crispy_forms.layout import Submit
from django import forms
from .models import ResourceCategory
@@ -8,19 +10,43 @@ from .models import ResourceType
logger = logging.getLogger(__name__)
+ALLOWED_THUMBNAILS = 5
+ALLOWED_PDFS = 20
+
class ResourceCreateForm(forms.Form):
+ def __init__(self, *args, **kwargs):
+ super().__init__(*args, **kwargs)
+ self.helper = FormHelper(self)
+ self.helper.add_input(Submit("submit", "Submit"))
+
error_css_class = "error"
required_css_class = "required"
name = forms.CharField(
max_length=255,
- help_text="Concisely describe what the resource is, aiming for 35-45 characters. eg: ‘Fractions KS2 Worksheet and Answers.'",
+ help_text="Concisely describe what the resource is, aiming for"
+ "35-45 characters. "
+ "eg: 'Fractions KS2 Worksheet and Answers.'",
)
description = forms.CharField(
max_length=1000,
widget=forms.Textarea,
- help_text="This is your opportunity to clearly explain what your resource is all about! It’s worth remembering that you are using the space to communicate to two different audiences. Firstly, think about what fellow teachers would like to know, such as exactly what the resource contains and how it could be used in the classroom. Secondly, the words you include on this page are also talking to internal and external search engines. External search engines, like Google, show the first 155 characters of the resource description, so make sure you take advantage of these characters by using lots of relevant keywords as part of an enticing pitch.",
+ help_text="This is your opportunity to clearly explain what your resource "
+ "is all "
+ "about! It’s worth remembering that you are using the space to "
+ "communicate to two "
+ "different audiences. Firstly, think about what fellow teachers "
+ "would like "
+ "to know, such as exactly what the resource contains and how it "
+ "could be used in the classroom. Secondly, the words you include "
+ "on this page are also talking to internal and external search "
+ "engines."
+ " External search engines, like Google, show the first 155 characters "
+ "of the resource description, so make sure you take advantage "
+ "of these "
+ "characters by using lots of relevant keywords as part of an "
+ "enticing pitch.",
)
resource_type = forms.ModelChoiceField(queryset=ResourceType.objects.all())
age_range = forms.ChoiceField(
@@ -33,7 +59,8 @@ class ResourceCreateForm(forms.Form):
("16+", "16+"),
("Age not applicable", "Age not applicable"),
],
- help_text="Try to be accurate in your choice of age range so that your resource shows up in the correct searches. (Although we don't have searches yet!)",
+ help_text="Try to be accurate in your choice of age range so that your resource "
+ "shows up in the correct searches. (Although we don't have searches yet!)",
)
curriculum = forms.ChoiceField(
choices=[
@@ -44,7 +71,9 @@ class ResourceCreateForm(forms.Form):
)
main_resource_category = forms.ModelChoiceField(
queryset=ResourceCategory.objects.all(),
- help_text="Categorise your resource by subject so it shows up in the correct searches. It's a good idea to limit the number of subjects you select to one or two to make your resource easier to find.",
+ help_text="Categorise your resource by subject so it shows up in the correct "
+ "searches. It's a good idea to limit the number of subjects you select "
+ "to one or two to make your resource easier to find.",
)
additional_resource_category = forms.ModelChoiceField(
queryset=ResourceCategory.objects.all(),
@@ -72,7 +101,11 @@ class ResourceCreateForm(forms.Form):
),
required=False,
label="Cover images",
- help_text="Your cover image will be displayed in the search results and as the first image on your resource page in the preview function. It is important to add an eye catching cover image that gives other teachers an idea about what your resource contains. You can multi-select up to 5 .png or .jpg files here.",
+ help_text="Your cover image will be displayed in the search results and as "
+ "the first image on your resource page in the preview function. "
+ "It is important to add an eye catching cover image that gives "
+ "other teachers an idea about what your resource contains. "
+ "You can multi-select up to 5 .png or .jpg files here.",
)
pdf_files.widget.attrs.update({"class": "file_upload", "accept": ".pdf"})
thumbnail_files.widget.attrs.update({"class": "file_upload", "accept": ".png,.jpg"})
@@ -87,7 +120,7 @@ class ResourceCreateForm(forms.Form):
f.file.seek(0)
if content_type not in acceptable:
raise forms.ValidationError("Please select only PNG or JPG files.")
- if len(thumbnail_files) > 5:
+ if len(thumbnail_files) > ALLOWED_THUMBNAILS:
raise forms.ValidationError("Please select up to 5 files.")
return thumbnail_files
@@ -101,6 +134,6 @@ class ResourceCreateForm(forms.Form):
f.file.seek(0)
if content_type not in acceptable:
raise forms.ValidationError("Please select only PDF files.")
- if len(pdf_files) > 20:
+ if len(pdf_files) > ALLOWED_PDFS:
raise forms.ValidationError("Please select up to 20 PDF files.")
return pdf_files
diff --git a/pyblackbird_cc/templates/resources/resource_create.html b/pyblackbird_cc/templates/resources/resource_create.html
index 03a192a..c10e7b8 100644
--- a/pyblackbird_cc/templates/resources/resource_create.html
+++ b/pyblackbird_cc/templates/resources/resource_create.html
@@ -8,14 +8,17 @@
{# {% endblock %}#}
{% block content %}
<div class="container">
- <h2>Upload a new resource</h2>
- <p>{% lorem %}</p>
- <form action="{% url 'resources:create_resource' %}"
- method="post"
- enctype="multipart/form-data">
- {% csrf_token %}
- {{ form|crispy }}
- <input type="submit" class="btn btn-primary" value="Upload" />
- </form>
+ <div class="row d-flex justify-content-center">
+ <div class="col-md-10 bg-light mt-lg-4">
+ <h2>Upload a new resource</h2>
+ <p>{% lorem %}</p>
+ <form action="{% url 'resources:create_resource' %}"
+ method="post"
+ enctype="multipart/form-data">
+ {% csrf_token %}
+ {% crispy form form.helper %}
+ </form>
+ </div>
+ </div>
</div>
{% endblock content %}
diff --git a/pyblackbird_cc/templates/resources/resource_detail.html b/pyblackbird_cc/templates/resources/resource_detail.html
index 61d9265..a52c2c6 100644
--- a/pyblackbird_cc/templates/resources/resource_detail.html
+++ b/pyblackbird_cc/templates/resources/resource_detail.html
@@ -23,28 +23,28 @@
<h4>{{ snapshot_filename }}</h4>
</div>
<div>
- {% for snapshot_url in snapshot_urls %}<img src="{{ snapshot_url }}" alt="{{ snapshot_filename }}"{% endfor %} </div />
- {% endfor %}
- </div>
- <div class="resource-description-panel">
- <h3>What's included?</h3>
- <div>{{ resource.description }}</div>
- <h3>What's it for?</h3>
- <div>{% lorem %}</div>
- <h3>Resource Details</h3>
- <div>{% lorem %}</div>
- </div>
- <div class="resource-download-panel">
- <h4>Download the resource</h4>
- <div>
- Click
- <button hx-get="/hx-download-btn?rn={{ resource.pdf_filename }}"
- hx-target="next #download-reveal">here</button>
- to download the resource
+ {% for snapshot_url in snapshot_urls %}<img src="{{ snapshot_url }}" alt="{{ snapshot_filename }}" />{% endfor %}
+ <div class="resource-description-panel">
+ <h3>What's included?</h3>
+ <div>{{ resource.description }}</div>
+ <h3>What's it for?</h3>
+ <div>{% lorem %}</div>
+ <h3>Resource Details</h3>
+ <div>{% lorem %}</div>
+ </div>
+ <div class="resource-download-panel">
+ <h4>Download the resource</h4>
+ <div>
+ Click
+ <button hx-get="/hx-download-btn?rn={{ resource.pdf_filename }}"
+ hx-target="next #download-reveal">here</button>
+ to download the resource
+ </div>
+ <div id="download-reveal"></div>
</div>
- <div id="download-reveal"></div>
</div>
</div>
- </div>
+ {% endfor %}
<div>Logged in as {{ request.user.username }}</div>
{% endblock content %}
+</div>
diff --git a/pyproject.toml b/pyproject.toml
index eba190f..258cdbb 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -80,75 +80,78 @@ exclude = [
"staticfiles/*"
]
# Same as Django: https://github.com/cookiecutter/cookiecutter-django/issues/4792.
-line-length = 88
+line-length = 98
indent-width = 4
target-version = "py312"
[tool.ruff.lint]
select = [
- "F",
- "E",
- "W",
- "C90",
- "I",
- "N",
- "UP",
- "YTT",
- # "ANN", # flake8-annotations: we should support this in the future but 100+ errors atm
- "ASYNC",
- "S",
- "BLE",
- "FBT",
- "B",
- "A",
- "COM",
- "C4",
- "DTZ",
- "T10",
- "DJ",
- "EM",
- "EXE",
- "FA",
- 'ISC',
- "ICN",
- "G",
- 'INP',
- 'PIE',
- "T20",
- 'PYI',
- 'PT',
- "Q",
- "RSE",
- "RET",
- "SLF",
- "SLOT",
- "SIM",
- "TID",
- "TCH",
- "INT",
- # "ARG", # Unused function argument
- "PTH",
- "ERA",
- "PD",
- "PGH",
- "PL",
- "TRY",
- "FLY",
- # "NPY",
- # "AIR",
- "PERF",
- # "FURB",
- # "LOG",
- "RUF"
+ "F",
+ "E",
+ "W",
+ "C90",
+ "I",
+ "N",
+ "UP",
+ "YTT",
+ # "ANN", # flake8-annotations: we should support this in the future but 100+ errors atm
+ "ASYNC",
+ "S",
+ "BLE",
+ "FBT",
+ "B",
+ "A",
+ "COM",
+ "C4",
+ "DTZ",
+ "T10",
+ "DJ",
+ "EM",
+ "EXE",
+ "FA",
+ 'ISC',
+ "ICN",
+ "G",
+ 'INP',
+ 'PIE',
+ "T20",
+ 'PYI',
+ 'PT',
+ "Q",
+ "RSE",
+ "RET",
+ "SLF",
+ "SLOT",
+ "SIM",
+ "TID",
+ "TCH",
+ "INT",
+ # "ARG", # Unused function argument
+ "PTH",
+ "ERA",
+ "PD",
+ "PGH",
+ "PL",
+ "TRY",
+ "FLY",
+ # "NPY",
+ # "AIR",
+ "PERF",
+ # "FURB",
+ # "LOG",
+ "RUF"
]
ignore = [
- "S101", # Use of assert detected https://docs.astral.sh/ruff/rules/assert/
- "RUF012", # Mutable class attributes should be annotated with `typing.ClassVar`
- "SIM102", # sometimes it's better to nest
- "UP038" # Checks for uses of isinstance/issubclass that take a tuple
- # of types for comparison.
- # Deactivated because it can make the code slow:
- # https://github.com/astral-sh/ruff/issues/7871
+ "TRY003",
+ "RUF001",
+ "EM101",
+ "S101", # Use of assert detected https://docs.astral.sh/ruff/rules/assert/
+ "RUF012", # Mutable class attributes should be annotated with `typing.ClassVar`
+ "SIM102", # sometimes it's better to nest
+ "UP038" # Checks for uses of isinstance/issubclass that take a tuple
+ # of types for comparison.
+ # Deactivated because it can make the code slow:
+ # https://github.com/astral-sh/ruff/issues/7871
]
# Allow fix for all enabled rules (when `--fix`) is provided.
fixable = ["ALL"]