import django.forms as forms from django.forms import ModelForm from django.forms.models import modelformset_factory from troggle.core.models.caves import Cave, CaveAndEntrance, Entrance from troggle.core.views.editor_helpers import HTMLarea from django.core.exceptions import ValidationError # from tinymce.widgets import TinyMCE import re """These are all the class-based Forms used by troggle. There are other, simpler, upload forms in view/uploads.py class-based forms are quicker to set up (for Django experts) but are more difficult to maintain by non-Django experts. """ todo = """ """ class CaveForm(ModelForm): """Only those fields for which we want to override defaults are listed here the other fields are present on the form, but use the default presentation style """ official_name = forms.CharField(required=False, widget=forms.TextInput(attrs={"size": "45"})) underground_description = forms.CharField( required=False, widget=HTMLarea(attrs={"height": "80%", "rows": 20, "placeholder": "Enter page content (using HTML)"}), ) explorers = forms.CharField( required=False, widget=HTMLarea(attrs={"height": "80%", "rows": 20, "placeholder": "Enter page content (using HTML)"}), ) equipment = forms.CharField( required=False, widget=HTMLarea(attrs={"height": "80%", "rows": 20, "placeholder": "Enter page content (using HTML)"}), ) survey = forms.CharField( required=False, widget=HTMLarea(attrs={"height": "80%", "rows": 20, "placeholder": "Enter page content (using HTML)"}), ) # survey = forms.CharField(required = False, widget=TinyMCE(attrs={'cols': 80, 'rows': 10})) kataster_status = forms.CharField(required=False) underground_centre_line = forms.CharField( required=False, widget=HTMLarea(attrs={"height": "80%", "rows": 20, "placeholder": "Enter page content (using HTML)"}), ) notes = forms.CharField( required=False, widget=HTMLarea(attrs={"height": "80%", "rows": 20, "placeholder": "Enter page content (using HTML)"}), ) references = forms.CharField( required=False, widget=HTMLarea(attrs={"height": "80%", "rows": 20, "placeholder": "Enter page content (using HTML)"}), ) description_file = forms.CharField(required=False, label="Path of top-level description file for this cave, when a separate file is used. Otherwise blank.", widget=forms.TextInput(attrs={"size": "45"}), help_text="") survex_file = forms.CharField( required=False, label="Survex file eg. caves-1623/000/000.svx", widget=forms.TextInput(attrs={"size": "45"}) ) #url = forms.CharField(required=True, label="URL eg. 1623/000/000 (no .html)", widget=forms.TextInput(attrs={"size": "45"})) length = forms.CharField(required=False, label="Length (m)") depth = forms.CharField(required=False, label="Depth (m)") extent = forms.CharField(required=False, label="Extent (m)") #cave_slug = forms.CharField() class Meta: model = Cave exclude = ("filename",) field_order = ['area', 'unofficial_number', 'kataster_number', 'official_name', 'underground_description', 'explorers', 'equipment', 'survey', 'kataster_status', 'underground_centre_line', 'notes', 'references', 'description_file', 'survex_file', 'url', 'length', 'depth', 'extent'] def get_area(self): for a in self.cleaned_data["area"]: if a.kat_area(): return a.kat_area() def clean_cave_slug(self): if self.cleaned_data["cave_slug"] == "": myArea = "" for a in self.cleaned_data["area"]: if a.kat_area(): myArea = a.kat_area() if self.data["kataster_number"]: cave_slug = f"{myArea}-{self.cleaned_data['kataster_number']}" else: cave_slug = f"{myArea}-{self.cleaned_data['unofficial_number']}" else: cave_slug = self.cleaned_data["cave_slug"] # Converting a PENDING cave to a real cave by saving this form print("EEE", cave_slug.replace("-PENDING-", "-")) return cave_slug.replace("-PENDING-", "-") # def clean_url(self): # data = self.cleaned_data["url"] # if not re.match("\d\d\d\d/.", data): # raise ValidationError("URL must start with a four digit Kataster area.") # return data def clean(self): cleaned_data = super(CaveForm, self).clean() if self.data.get("kataster_number") == "" and self.data.get("unofficial_number") == "": self._errors["unofficial_number"] = self.error_class( ["Either the kataster or unoffical number is required."] ) # if self.cleaned_data.get("kataster_number") != "" and self.cleaned_data.get("official_name") == "": # self._errors["official_name"] = self.error_class(["This field is required when there is a kataster number."]) if cleaned_data.get("area") == []: self._errors["area"] = self.error_class(["This field is required."]) if cleaned_data.get("url") and cleaned_data.get("url").startswith("/"): self._errors["url"] = self.error_class(["This field cannot start with a /."]) return cleaned_data class EntranceForm(ModelForm): """Only those fields for which we want to override defaults are listed here the other fields are present on the form, but use the default presentation style """ name = forms.CharField(required=False, widget=forms.TextInput(attrs={"size": "45"})) entrance_description = forms.CharField( required=False, widget=HTMLarea(attrs={"height": "80%", "rows": 20, "placeholder": "Enter text (using HTML)"}), ) explorers = forms.CharField(required=False, widget=forms.TextInput(attrs={"size": "45"})) # explorers = forms.CharField(required = False, widget=TinyMCE(attrs={'cols': 80, 'rows': 10})) map_description = forms.CharField( required=False, widget=HTMLarea(attrs={"height": "80%", "rows": 20, "placeholder": "Enter text (using HTML)"}), ) location_description = forms.CharField( required=False, widget=HTMLarea(attrs={"height": "80%", "rows": 20, "placeholder": "Enter text (using HTML)"}), ) lastvisit = forms.CharField( required=False, widget=forms.TextInput(attrs={"size": "10"}), label="Date of last visit, e.g. 2023-07-11" ) approach = forms.CharField( required=False, widget=HTMLarea(attrs={"height": "80%", "rows": 20, "placeholder": "Enter text (using HTML)"}), ) underground_description = forms.CharField( required=False, widget=HTMLarea(attrs={"height": "80%", "rows": 20, "placeholder": "Enter text (using HTML)"}), ) photo = forms.CharField( required=False, widget=HTMLarea(attrs={"height": "80%", "rows": 20, "placeholder": "Enter text (using HTML)"}), ) marking_comment = forms.CharField( required=False, widget=HTMLarea(attrs={"height": "80%", "rows": 20, "placeholder": "Enter text (using HTML)"}), ) findability_description = forms.CharField( required=False, widget=HTMLarea(attrs={"height": "80%", "rows": 20, "placeholder": "Enter text (using HTML)"}), ) other_description = forms.CharField( required=False, widget=HTMLarea(attrs={"height": "80%", "rows": 20, "placeholder": "Enter text (using HTML)"}), ) bearings = forms.CharField( required=False, widget=HTMLarea(attrs={"height": "80%", "rows": 20, "placeholder": "Enter text (using HTML)"}), ) tag_station = forms.CharField( required=False, widget=forms.TextInput(attrs={"size": "50"}), label="Tag station: Survex station id, e.g. 1623.p2023-xx-01" ) exact_station = forms.CharField( required=False, widget=forms.TextInput(attrs={"size": "50"}), label="Exact station: Survex station id, e.g. 1623.2023-xx-01.2" ) other_station = forms.CharField( required=False, widget=forms.TextInput(attrs={"size": "50"}), label="Other station: Survex station id, e.g. 1623.2023-xx-01.33" ) northing = forms.CharField(required=False) easting = forms.CharField(required=False) lat_wgs84 = forms.CharField( required=False, widget=forms.TextInput(attrs={"size": "10"}), label="Latitude (WSG84) - if no other location" ) long_wgs84 = forms.CharField( required=False, widget=forms.TextInput(attrs={"size": "10"}), label="Longitude (WSG84) - if no other location" ) alt = forms.CharField(required=False, label="Altitude (m)") url = forms.CharField(required=False, label="URL [usually blank]", widget=forms.TextInput(attrs={"size": "45"})) field_order = ['name', 'entrance_description', 'explorers', 'map_description', 'location_description', 'lastvisit', 'approach', 'underground_description', 'photo', 'marking_comment', 'findability_description', 'other_description', 'bearings', 'tag_station', 'exact_station', 'other_station', 'northing', 'easting', 'lat_wgs84', 'long_wgs84', 'alt', 'url'] class Meta: model = Entrance exclude = ( "cached_primary_slug", "filename", ) def clean(self): if self.cleaned_data.get("url").startswith("/"): self._errors["url"] = self.error_class(["This field cannot start with a /."]) return self.cleaned_data # This next line is called from the templates/edit_cave.html template. # This is sufficient to create an entire entry for for the cave fields automatically # http://localhost:8000/cave/new/ # using django built-in Deep Magic. https://docs.djangoproject.com/en/dev/topics/forms/modelforms/ # for forms which map directly onto a Django Model CaveAndEntranceFormSet = modelformset_factory(CaveAndEntrance, exclude=("cave",)) # This is used only in edit_entrance() in views/caves.py class EntranceLetterForm(ModelForm): """Form to link entrances to caves, along with an entrance number. Nb. The relationship between caves and entrances has historically been a many to many relationship. With entrances gaining new caves and letters when caves are joined. """ class Meta: model = CaveAndEntrance exclude = ("cave", "entrance") def full_clean(self): super(EntranceLetterForm, self).full_clean() try: self.instance.validate_unique() except forms.ValidationError as e: self._update_errors(e)