diff options
Diffstat (limited to 'alphabetlearning/resources/forms.py')
-rw-r--r-- | alphabetlearning/resources/forms.py | 274 |
1 files changed, 274 insertions, 0 deletions
diff --git a/alphabetlearning/resources/forms.py b/alphabetlearning/resources/forms.py new file mode 100644 index 0000000..35632bd --- /dev/null +++ b/alphabetlearning/resources/forms.py @@ -0,0 +1,274 @@ +import logging + +import magic +from crispy_forms.bootstrap import FormActions +from crispy_forms.helper import FormHelper +from crispy_forms.layout import Button +from crispy_forms.layout import Field +from crispy_forms.layout import Layout +from crispy_forms.layout import Submit +from django import forms + +from alphabetlearning.resources.models import Resource +from alphabetlearning.resources.models import ResourceCategory +from alphabetlearning.resources.models import ResourceSubcategory +from alphabetlearning.resources.models import ResourceType + +from .models import AGE_RANGE_CHOICES +from .models import CURRICULUM_CHOICES + +logger = logging.getLogger(__name__) + +ALLOWED_THUMBNAILS = 5 +ALLOWED_PDFS = 20 + + +def _create_choices_tuple() -> list[tuple[str, str]]: + """Returns a list of tuples containing resource subcategory names.""" + vals = sorted(ResourceSubcategory.objects.values_list("name", flat=True), key=str) + out = tuple((x, x) for x in vals) + return out + + +class ResourceCreateForm(forms.Form): + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + self.helper = FormHelper(self) + self.helper.add_input(Submit("submit", "Submit")) + self.fields["subcategories"].choices = _create_choices_tuple() + pass + + error_css_class = "error" + required_css_class = "required" + + name = forms.CharField( + max_length=255, + help_text="Concisely describe what the resource is, aiming for" + " in 35-45 characters. " + "eg: 'Fractions KS2 Worksheet and Answers.'", + ) + description = forms.CharField( + max_length=5000, + widget=forms.Textarea, + help_text=" You can (and should) use <strong>Markdown</strong> here. " + "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.", + ) + card_description = forms.CharField( + max_length=1000, + widget=forms.Textarea, + help_text=( + "If you enter text here, it will be used in the 'card' description " + "box on the home page. Max 1000 characters." + ), + ) + resource_type = forms.ModelChoiceField(queryset=ResourceType.objects.all()) + age_range = forms.ChoiceField( + choices=AGE_RANGE_CHOICES, + 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=CURRICULUM_CHOICES, + required=False, + ) + 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.", + ) + subcategories = forms.MultipleChoiceField( + required=False, + ) + + pdf_files = forms.FileField( + widget=forms.TextInput( + attrs={ + "multiple": True, + "type": "File", + "required": True, + }, + ), + required=False, + help_text="You can multi-select up to 20 .pdf files here.", + label="PDF files", + ) + thumbnail_files = forms.FileField( + widget=forms.TextInput( + attrs={ + "multiple": True, + "type": "File", + "required": True, + }, + ), + 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.", + ) + pdf_files.widget.attrs.update({"class": "file_upload", "accept": ".pdf"}) + thumbnail_files.widget.attrs.update({"class": "file_upload", "accept": ".png,.jpg"}) + feature_slot = forms.IntegerField( + min_value=1, + max_value=3, + required=False, + help_text=( + "Please enter either 1, 2 or 3 here. This will dictate where on the page " + "this resource will feature on the main list page." + ), + ) + + def clean_thumbnail_files(self): + thumbnail_files = self.files.getlist("thumbnail_files") + if not thumbnail_files: + raise forms.ValidationError("Please select at least one thumbnail file.") + acceptable = ["image/png", "image/jpeg"] + for f in thumbnail_files: + content_type = magic.from_buffer(f.file.read(), mime=True) + f.file.seek(0) + if content_type not in acceptable: + raise forms.ValidationError("Please select only PNG or JPG files.") + if len(thumbnail_files) > ALLOWED_THUMBNAILS: + raise forms.ValidationError("Please select up to 5 files.") + return thumbnail_files + + def clean_pdf_files(self): + pdf_files = self.files.getlist("pdf_files") + if not pdf_files: + raise forms.ValidationError("Please select at least one PDF file.") + acceptable = ["application/pdf"] + for f in pdf_files: + content_type = magic.from_buffer(f.file.read(), mime=True) + f.file.seek(0) + if content_type not in acceptable: + raise forms.ValidationError("Please select only PDF files.") + if len(pdf_files) > ALLOWED_PDFS: + raise forms.ValidationError("Please select up to 20 PDF files.") + return pdf_files + + +class ResourceUpdateMetadataForm(forms.ModelForm): + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + self.helper = FormHelper(self) + self.helper.add_input(Submit("submit", "Submit")) + self.fields["subcategories"].queryset = ResourceSubcategory.objects.all().order_by("name") + + error_css_class = "error" + required_css_class = "required" + + class Meta: + model = Resource + fields = [ + "name", + "description", + "card_description", + "resource_type", + "age_range", + "curriculum", + "main_resource_category", + "subcategories", + "feature_slot", + ] + + +class ResourceUpdatePDFsForm(forms.Form): + def __init__(self, cancel_url: str, *args, **kwargs): + try: + self.resource = kwargs.pop("resource") + except KeyError: + pass + super().__init__(*args, **kwargs) + self.helper = FormHelper(self) + self.helper.layout = Layout( + Field("pdf_files"), + FormActions( + Submit("submit", "Submit", css_class="btn btn-primary"), + Button("cancel", "Cancel", css_class="btn btn-danger", onclick="location.href=''"), + ), + ) + + pdf_files = forms.FileField( + widget=forms.TextInput( + attrs={ + "multiple": True, + "type": "File", + "required": True, + }, + ), + required=False, + help_text="You can multi-select up to 20 .pdf files here.", + label="PDF files", + ) + + pdf_files.widget.attrs.update({"class": "file_upload", "accept": ".pdf"}) + + def clean_pdf_files(self): + pdf_files = self.files.getlist("pdf_files") + if not pdf_files: + raise forms.ValidationError("Please select at least one PDF file.") + acceptable = ["application/pdf"] + for f in pdf_files: + content_type = magic.from_buffer(f.file.read(), mime=True) + f.file.seek(0) + if content_type not in acceptable: + raise forms.ValidationError("Please select only PDF files.") + if len(pdf_files) > ALLOWED_PDFS: + raise forms.ValidationError("Please select up to 20 PDF files.") + return pdf_files + + +class ResourceUpdateThumbnailsForm(forms.Form): + def __init__(self, *args, **kwargs): + try: + self.resource = kwargs.pop("resource") + except KeyError: + pass + super().__init__(*args, **kwargs) + self.helper = FormHelper(self) + self.helper.add_input(Submit("submit", "Submit")) + + thumbnail_files = forms.FileField( + widget=forms.TextInput( + attrs={ + "multiple": True, + "type": "File", + "required": True, + }, + ), + required=False, + label="Thumbnail files", + help_text="You can upload 5 files.", + ) + thumbnail_files.widget.attrs.update({"class": "file_upload", "accept": ".png,.jpg"}) + + def clean_thumbnail_files(self): + thumbnail_files = self.files.getlist("thumbnail_files") + if not thumbnail_files: + raise forms.ValidationError("Please select at least one thumbnail file.") + acceptable = ["image/png", "image/jpeg"] + for f in thumbnail_files: + content_type = magic.from_buffer(f.file.read(), mime=True) + f.file.seek(0) + if content_type not in acceptable: + raise forms.ValidationError("Please select only PNG or JPG files.") + if len(thumbnail_files) > ALLOWED_THUMBNAILS: + raise forms.ValidationError("Please select up to 5 files.") + return thumbnail_files |