prompt: You will be provided with a partial code base and an issue statement explaining a problem to resolve.
  <issue>
  Community Roles: Date range validation
  Currently, an end date earlier than start date is allowed.  
  
  </issue>
  <code>
  [start of amy/communityroles/forms.py]
  1 from collections import defaultdict
  2 from typing import Any, Optional
  3 
  4 from django import forms
  5 from django.core.exceptions import ObjectDoesNotExist, ValidationError
  6 
  7 from workshops.fields import HeavySelect2Widget, ModelSelect2Widget
  8 from workshops.forms import SELECT2_SIDEBAR, BootstrapHelper, WidgetOverrideMixin
  9 
  10 from .models import CommunityRole, CommunityRoleConfig
  11 
  12 
  13 class CommunityRoleForm(WidgetOverrideMixin, forms.ModelForm):
  14     class Meta:
  15         model = CommunityRole
  16         fields = (
  17             "config",
  18             "person",
  19             "award",
  20             "start",
  21             "end",
  22             "inactivation",
  23             "membership",
  24             "url",
  25             "generic_relation_content_type",
  26             "generic_relation_pk",
  27         )
  28         widgets = {
  29             "config": HeavySelect2Widget(
  30                 data_view="api:communityroleconfig-list", attrs=SELECT2_SIDEBAR
  31             ),
  32             "person": ModelSelect2Widget(
  33                 data_view="person-lookup", attrs=SELECT2_SIDEBAR
  34             ),
  35             "award": ModelSelect2Widget(
  36                 data_view="award-lookup", attrs=SELECT2_SIDEBAR
  37             ),
  38             "membership": ModelSelect2Widget(
  39                 data_view="membership-lookup", attrs=SELECT2_SIDEBAR
  40             ),
  41             "generic_relation_content_type": forms.Select(
  42                 # "disabled" means the browsers will not send the field during POST.
  43                 # See how it's handled in `clean()` method below.
  44                 attrs={"disabled": ""},
  45             ),
  46             "generic_relation_pk": HeavySelect2Widget(
  47                 data_view="generic-object-lookup", attrs=SELECT2_SIDEBAR
  48             ),
  49         }
  50         labels = {
  51             "generic_relation_content_type": "Generic relation object type",
  52             "generic_relation_pk": "Generic relation object",
  53         }
  54 
  55     class Media:
  56         js = ("communityrole_form.js",)
  57 
  58     def __init__(self, *args, **kwargs):
  59         form_tag = kwargs.pop("form_tag", True)
  60         super().__init__(*args, **kwargs)
  61         bootstrap_kwargs = {
  62             "add_cancel_button": False,
  63             "form_tag": form_tag,
  64         }
  65         self.helper = BootstrapHelper(**bootstrap_kwargs)
  66 
  67     def clean(self) -> dict[str, Any]:
  68         """Validate form according to rules set up in related Community Role
  69         configuration."""
  70         cleaned_data = super().clean()
  71         errors: defaultdict[str, list[ValidationError]] = defaultdict(list)
  72         config: Optional[CommunityRoleConfig] = cleaned_data.get("config")
  73 
  74         # Config is required, but field validation for 'config' should raise
  75         # validation error first.
  76         if not config:
  77             return cleaned_data
  78 
  79         # Award required?
  80         if config.link_to_award and not cleaned_data.get("award"):
  81             errors["award"].append(
  82                 ValidationError(f"Award is required with community role {config}")
  83             )
  84 
  85         # Specific award badge required?
  86         if (badge := config.award_badge_limit) and (award := cleaned_data.get("award")):
  87             if award.badge != badge:
  88                 errors["award"].append(
  89                     ValidationError(
  90                         f"Award badge must be {badge} for community role {config}"
  91                     )
  92                 )
  93 
  94         # Membership required?
  95         if config.link_to_membership and not cleaned_data.get("membership"):
  96             errors["membership"].append(
  97                 ValidationError(f"Membership is required with community role {config}")
  98             )
  99 
  100         # Additional URL supported?
  101         if not config.additional_url and cleaned_data.get("url"):
  102             errors["url"].append(
  103                 ValidationError(f"URL is not supported for community role {config}")
  104             )
  105 
  106         # Widget for `generic_relation_content_type` is disabled in HTML, which
  107         # makes browsers not send it. The code below sets the default value to
  108         # the same value as in related config.
  109         generic_relation_content_type = config.generic_relation_content_type
  110 
  111         # Generic relation object must exist
  112         if config.generic_relation_content_type and generic_relation_content_type:
  113             model_class = generic_relation_content_type.model_class()
  114             try:
  115                 model_class._base_manager.get(
  116                     pk=cleaned_data.get("generic_relation_pk")
  117                 )
  118             except ObjectDoesNotExist:
  119                 errors["generic_relation_pk"].append(
  120                     ValidationError(
  121                         f"Generic relation object of model {model_class.__name__} "
  122                         "doesn't exist"
  123                     )
  124                 )
  125 
  126         if errors:
  127             raise ValidationError(errors)
  128 
  129         return cleaned_data
  130
  [end of amy/communityroles/forms.py]
  </code>
  
  I need you to solve this issue by generating a single patch file that I can apply directly to this repository using git apply. Please respond with a single patch file in the following format.
  <patch>
  diff --git a/file.py b/file.py
  --- a/file.py
  +++ b/file.py
  @@ -1,27 +1,35 @@
   def euclidean(a, b):
  -    while b:
  -        a, b = b, a % b
  -    return a
  +    if b == 0:
  +        return a
  +    return euclidean(b, a % b)
   
   
   def bresenham(x0, y0, x1, y1):
       points = []
       dx = abs(x1 - x0)
       dy = abs(y1 - y0)
  -    sx = 1 if x0 < x1 else -1
  -    sy = 1 if y0 < y1 else -1
  -    err = dx - dy
  +    x, y = x0, y0
  +    sx = -1 if x0 > x1 else 1
  +    sy = -1 if y0 > y1 else 1
   
  -    while True:
  -        points.append((x0, y0))
  -        if x0 == x1 and y0 == y1:
  -            break
  -        e2 = 2 * err
  -        if e2 > -dy:
  -            err -= dy
  -            x0 += sx
  -        if e2 < dx:
  -            err += dx
  -            y0 += sy
  +    if dx > dy:
  +        err = dx / 2.0
  +        while x != x1:
  +            points.append((x, y))
  +            err -= dy
  +            if err < 0:
  +                y += sy
  +                err += dx
  +            x += sx
  +    else:
  +        err = dy / 2.0
  +        while y != y1:
  +            points.append((x, y))
  +            err -= dx
  +            if err < 0:
  +                x += sx
  +                err += dy
  +            y += sy
  +
  +    points.append((x, y))
       return points
  
  </patch>
golden_diff: diff --git a/amy/communityroles/forms.py b/amy/communityroles/forms.py
  --- a/amy/communityroles/forms.py
  +++ b/amy/communityroles/forms.py
  @@ -127,3 +127,11 @@
               raise ValidationError(errors)
   
           return cleaned_data
  +
  +    def clean_end(self):
  +        """Validate that end >= start"""
  +        start = self.cleaned_data.get("start")
  +        end = self.cleaned_data.get("end")
  +        if start and end and end < start:
  +            raise ValidationError("Must not be earlier than start date.")
  +        return end
  
verification_info: {"golden_diff": "diff --git a/amy/communityroles/forms.py b/amy/communityroles/forms.py\n--- a/amy/communityroles/forms.py\n+++ b/amy/communityroles/forms.py\n@@ -127,3 +127,11 @@\n             raise ValidationError(errors)\n \n         return cleaned_data\n+\n+    def clean_end(self):\n+        \"\"\"Validate that end >= start\"\"\"\n+        start = self.cleaned_data.get(\"start\")\n+        end = self.cleaned_data.get(\"end\")\n+        if start and end and end < start:\n+            raise ValidationError(\"Must not be earlier than start date.\")\n+        return end\n", "issue": "Community Roles: Date range validation\nCurrently, an end date earlier than start date is allowed.  \n", "before_files": [{"content": "from collections import defaultdict\nfrom typing import Any, Optional\n\nfrom django import forms\nfrom django.core.exceptions import ObjectDoesNotExist, ValidationError\n\nfrom workshops.fields import HeavySelect2Widget, ModelSelect2Widget\nfrom workshops.forms import SELECT2_SIDEBAR, BootstrapHelper, WidgetOverrideMixin\n\nfrom .models import CommunityRole, CommunityRoleConfig\n\n\nclass CommunityRoleForm(WidgetOverrideMixin, forms.ModelForm):\n    class Meta:\n        model = CommunityRole\n        fields = (\n            \"config\",\n            \"person\",\n            \"award\",\n            \"start\",\n            \"end\",\n            \"inactivation\",\n            \"membership\",\n            \"url\",\n            \"generic_relation_content_type\",\n            \"generic_relation_pk\",\n        )\n        widgets = {\n            \"config\": HeavySelect2Widget(\n                data_view=\"api:communityroleconfig-list\", attrs=SELECT2_SIDEBAR\n            ),\n            \"person\": ModelSelect2Widget(\n                data_view=\"person-lookup\", attrs=SELECT2_SIDEBAR\n            ),\n            \"award\": ModelSelect2Widget(\n                data_view=\"award-lookup\", attrs=SELECT2_SIDEBAR\n            ),\n            \"membership\": ModelSelect2Widget(\n                data_view=\"membership-lookup\", attrs=SELECT2_SIDEBAR\n            ),\n            \"generic_relation_content_type\": forms.Select(\n                # \"disabled\" means the browsers will not send the field during POST.\n                # See how it's handled in `clean()` method below.\n                attrs={\"disabled\": \"\"},\n            ),\n            \"generic_relation_pk\": HeavySelect2Widget(\n                data_view=\"generic-object-lookup\", attrs=SELECT2_SIDEBAR\n            ),\n        }\n        labels = {\n            \"generic_relation_content_type\": \"Generic relation object type\",\n            \"generic_relation_pk\": \"Generic relation object\",\n        }\n\n    class Media:\n        js = (\"communityrole_form.js\",)\n\n    def __init__(self, *args, **kwargs):\n        form_tag = kwargs.pop(\"form_tag\", True)\n        super().__init__(*args, **kwargs)\n        bootstrap_kwargs = {\n            \"add_cancel_button\": False,\n            \"form_tag\": form_tag,\n        }\n        self.helper = BootstrapHelper(**bootstrap_kwargs)\n\n    def clean(self) -> dict[str, Any]:\n        \"\"\"Validate form according to rules set up in related Community Role\n        configuration.\"\"\"\n        cleaned_data = super().clean()\n        errors: defaultdict[str, list[ValidationError]] = defaultdict(list)\n        config: Optional[CommunityRoleConfig] = cleaned_data.get(\"config\")\n\n        # Config is required, but field validation for 'config' should raise\n        # validation error first.\n        if not config:\n            return cleaned_data\n\n        # Award required?\n        if config.link_to_award and not cleaned_data.get(\"award\"):\n            errors[\"award\"].append(\n                ValidationError(f\"Award is required with community role {config}\")\n            )\n\n        # Specific award badge required?\n        if (badge := config.award_badge_limit) and (award := cleaned_data.get(\"award\")):\n            if award.badge != badge:\n                errors[\"award\"].append(\n                    ValidationError(\n                        f\"Award badge must be {badge} for community role {config}\"\n                    )\n                )\n\n        # Membership required?\n        if config.link_to_membership and not cleaned_data.get(\"membership\"):\n            errors[\"membership\"].append(\n                ValidationError(f\"Membership is required with community role {config}\")\n            )\n\n        # Additional URL supported?\n        if not config.additional_url and cleaned_data.get(\"url\"):\n            errors[\"url\"].append(\n                ValidationError(f\"URL is not supported for community role {config}\")\n            )\n\n        # Widget for `generic_relation_content_type` is disabled in HTML, which\n        # makes browsers not send it. The code below sets the default value to\n        # the same value as in related config.\n        generic_relation_content_type = config.generic_relation_content_type\n\n        # Generic relation object must exist\n        if config.generic_relation_content_type and generic_relation_content_type:\n            model_class = generic_relation_content_type.model_class()\n            try:\n                model_class._base_manager.get(\n                    pk=cleaned_data.get(\"generic_relation_pk\")\n                )\n            except ObjectDoesNotExist:\n                errors[\"generic_relation_pk\"].append(\n                    ValidationError(\n                        f\"Generic relation object of model {model_class.__name__} \"\n                        \"doesn't exist\"\n                    )\n                )\n\n        if errors:\n            raise ValidationError(errors)\n\n        return cleaned_data\n", "path": "amy/communityroles/forms.py"}]}