aboutsummaryrefslogblamecommitdiffstats
path: root/alphabetlearning/resources/forms.py
blob: b0f7d767a51a7a56e7ccd9adc6caf24c583d7d8b (plain) (tree)
1
2
3
4
5
6
7
8
9


              
                                              
                                          



                                      

                        



                                                                 
 

                                      


                                    


                      
 
                                                     
                                                                         


                                                                                      

 
                                     



                                                         
                                                                      
            
 




                                   
                                                                       

                                                     

                                  
                        
                              



                                                                       
     


                                       



                                                                                
     

                                                                               
                                  
                                                                                         
                                                                                   

                                   
                                   
                       


                                                    
                                                                                      

                                                                                
     
                                              

                       
 





















                                                                   
                                                                                    



                                                                         


                                                                                        



                                      



                                                                                      
     










                                                                                     
                                                     












                                                                               
                                         

                                                                            


                                                  



                                                         
                                                                                                  



                                   




                          
                               



                                     
                            
                           
         

 
                                         
                                                         





                                                  



                                                                        
                                                                                                   

              






























                                                                               

                                               



                                                  












                                                         
                                
                                            
     














                                                                                        
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=(" Use <strong>markdown</strong> here. "
                   "This is the main (long) description so go for it. "
                   "5000 characters at your disposal."
                   ),
    )
    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