prompt: You will be provided with a partial code base and an issue statement explaining a problem to resolve.
  <issue>
  Mandatory mB topic selection on bet.in ( US #1775)
  All projects need a topic on bet.in now, even existing ones. Can we remove that requirement? We haven't yet thought about how to implement topics on bet.in and there are not shown anywhere, so it would probably be confusing for initiators.
  
  </issue>
  <code>
  [start of liqd_product/apps/projects/dashboard.py]
  1 from django.urls import reverse
  2 from django.utils.translation import ugettext_lazy as _
  3 
  4 from adhocracy4.dashboard import DashboardComponent
  5 from adhocracy4.dashboard import ProjectFormComponent
  6 from adhocracy4.dashboard import components
  7 
  8 from . import forms
  9 from . import views
  10 
  11 
  12 class ParticipantsComponent(DashboardComponent):
  13     identifier = 'participants'
  14     weight = 30
  15     label = _('Participants')
  16 
  17     def is_effective(self, project):
  18         return not project.is_draft and project.is_private
  19 
  20     def get_base_url(self, project):
  21         return reverse('a4dashboard:dashboard-participants-edit', kwargs={
  22             'project_slug': project.slug
  23         })
  24 
  25     def get_urls(self):
  26         return [(
  27             r'^projects/(?P<project_slug>[-\w_]+)/participants/$',
  28             views.DashboardProjectParticipantsView.as_view(component=self),
  29             'dashboard-participants-edit'
  30         )]
  31 
  32 
  33 class ModeratorsComponent(DashboardComponent):
  34     identifier = 'moderators'
  35     weight = 32
  36     label = _('Moderators')
  37 
  38     def is_effective(self, project):
  39         return True
  40 
  41     def get_base_url(self, project):
  42         return reverse('a4dashboard:dashboard-moderators-edit', kwargs={
  43             'project_slug': project.slug
  44         })
  45 
  46     def get_urls(self):
  47         return [(
  48             r'^projects/(?P<project_slug>[-\w_]+)/moderators/$',
  49             views.DashboardProjectModeratorsView.as_view(component=self),
  50             'dashboard-moderators-edit'
  51         )]
  52 
  53 
  54 class TopicComponent(ProjectFormComponent):
  55     identifier = 'topics'
  56     weight = 33
  57     label = _('Topics')
  58 
  59     form_title = _('Edit topics')
  60     form_class = forms.TopicForm
  61     form_template_name = 'liqd_product_projects/project_topics.html'
  62 
  63 
  64 components.register_project(ModeratorsComponent())
  65 components.register_project(ParticipantsComponent())
  66 components.register_project(TopicComponent())
  67
  [end of liqd_product/apps/projects/dashboard.py]
  [start of liqd_product/apps/projects/forms.py]
  1 from django import forms
  2 from django.contrib.auth import get_user_model
  3 from django.core.exceptions import ValidationError
  4 from django.utils.translation import ugettext_lazy as _
  5 
  6 from adhocracy4.dashboard.forms import ProjectDashboardForm
  7 from adhocracy4.projects.models import Project
  8 from liqd_product.apps.users import fields as user_fields
  9 
  10 from .models import ModeratorInvite
  11 from .models import ParticipantInvite
  12 
  13 User = get_user_model()
  14 
  15 
  16 class InviteForm(forms.ModelForm):
  17     accept = forms.CharField(required=False)
  18     reject = forms.CharField(required=False)
  19 
  20     def clean(self):
  21         data = self.data
  22         if 'accept' not in data and 'reject' not in data:
  23             raise ValidationError('Reject or accept')
  24         return data
  25 
  26     def is_accepted(self):
  27         data = self.data
  28         return 'accept' in data and 'reject' not in data
  29 
  30 
  31 class ParticipantInviteForm(InviteForm):
  32 
  33     class Meta:
  34         model = ParticipantInvite
  35         fields = ['accept', 'reject']
  36 
  37 
  38 class ModeratorInviteForm(InviteForm):
  39 
  40     class Meta:
  41         model = ModeratorInvite
  42         fields = ['accept', 'reject']
  43 
  44 
  45 class InviteUsersFromEmailForm(forms.Form):
  46     add_users = user_fields.CommaSeparatedEmailField(
  47         required=False,
  48         label=_('Invite users via email')
  49     )
  50 
  51     add_users_upload = user_fields.EmailFileField(
  52         required=False,
  53         label=_('Invite users via file upload'),
  54         help_text=_('Upload a csv file containing email addresses.')
  55     )
  56 
  57     def __init__(self, *args, **kwargs):
  58         labels = kwargs.pop('labels', None)
  59         super().__init__(*args, **kwargs)
  60 
  61         if labels:
  62             self.fields['add_users'].label = labels[0]
  63             self.fields['add_users_upload'].label = labels[1]
  64 
  65     def clean(self):
  66         cleaned_data = super().clean()
  67         add_users = self.data.get('add_users')
  68         add_users_upload = self.files.get('add_users_upload')
  69         if not self.errors and not add_users and not add_users_upload:
  70             raise ValidationError(
  71                 _('Please enter email addresses or upload a file'))
  72         return cleaned_data
  73 
  74 
  75 class TopicForm(ProjectDashboardForm):
  76 
  77     class Meta:
  78         model = Project
  79         fields = ['topics']
  80         required_for_project_publish = ['topics']
  81
  [end of liqd_product/apps/projects/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/liqd_product/apps/projects/dashboard.py b/liqd_product/apps/projects/dashboard.py
  --- a/liqd_product/apps/projects/dashboard.py
  +++ b/liqd_product/apps/projects/dashboard.py
  @@ -2,10 +2,8 @@
   from django.utils.translation import ugettext_lazy as _
   
   from adhocracy4.dashboard import DashboardComponent
  -from adhocracy4.dashboard import ProjectFormComponent
   from adhocracy4.dashboard import components
   
  -from . import forms
   from . import views
   
   
  @@ -51,16 +49,5 @@
           )]
   
   
  -class TopicComponent(ProjectFormComponent):
  -    identifier = 'topics'
  -    weight = 33
  -    label = _('Topics')
  -
  -    form_title = _('Edit topics')
  -    form_class = forms.TopicForm
  -    form_template_name = 'liqd_product_projects/project_topics.html'
  -
  -
   components.register_project(ModeratorsComponent())
   components.register_project(ParticipantsComponent())
  -components.register_project(TopicComponent())
  diff --git a/liqd_product/apps/projects/forms.py b/liqd_product/apps/projects/forms.py
  --- a/liqd_product/apps/projects/forms.py
  +++ b/liqd_product/apps/projects/forms.py
  @@ -3,8 +3,6 @@
   from django.core.exceptions import ValidationError
   from django.utils.translation import ugettext_lazy as _
   
  -from adhocracy4.dashboard.forms import ProjectDashboardForm
  -from adhocracy4.projects.models import Project
   from liqd_product.apps.users import fields as user_fields
   
   from .models import ModeratorInvite
  @@ -70,11 +68,3 @@
               raise ValidationError(
                   _('Please enter email addresses or upload a file'))
           return cleaned_data
  -
  -
  -class TopicForm(ProjectDashboardForm):
  -
  -    class Meta:
  -        model = Project
  -        fields = ['topics']
  -        required_for_project_publish = ['topics']
  
verification_info: {"golden_diff": "diff --git a/liqd_product/apps/projects/dashboard.py b/liqd_product/apps/projects/dashboard.py\n--- a/liqd_product/apps/projects/dashboard.py\n+++ b/liqd_product/apps/projects/dashboard.py\n@@ -2,10 +2,8 @@\n from django.utils.translation import ugettext_lazy as _\n \n from adhocracy4.dashboard import DashboardComponent\n-from adhocracy4.dashboard import ProjectFormComponent\n from adhocracy4.dashboard import components\n \n-from . import forms\n from . import views\n \n \n@@ -51,16 +49,5 @@\n         )]\n \n \n-class TopicComponent(ProjectFormComponent):\n-    identifier = 'topics'\n-    weight = 33\n-    label = _('Topics')\n-\n-    form_title = _('Edit topics')\n-    form_class = forms.TopicForm\n-    form_template_name = 'liqd_product_projects/project_topics.html'\n-\n-\n components.register_project(ModeratorsComponent())\n components.register_project(ParticipantsComponent())\n-components.register_project(TopicComponent())\ndiff --git a/liqd_product/apps/projects/forms.py b/liqd_product/apps/projects/forms.py\n--- a/liqd_product/apps/projects/forms.py\n+++ b/liqd_product/apps/projects/forms.py\n@@ -3,8 +3,6 @@\n from django.core.exceptions import ValidationError\n from django.utils.translation import ugettext_lazy as _\n \n-from adhocracy4.dashboard.forms import ProjectDashboardForm\n-from adhocracy4.projects.models import Project\n from liqd_product.apps.users import fields as user_fields\n \n from .models import ModeratorInvite\n@@ -70,11 +68,3 @@\n             raise ValidationError(\n                 _('Please enter email addresses or upload a file'))\n         return cleaned_data\n-\n-\n-class TopicForm(ProjectDashboardForm):\n-\n-    class Meta:\n-        model = Project\n-        fields = ['topics']\n-        required_for_project_publish = ['topics']\n", "issue": "Mandatory mB topic selection on bet.in ( US #1775)\nAll projects need a topic on bet.in now, even existing ones. Can we remove that requirement? We haven't yet thought about how to implement topics on bet.in and there are not shown anywhere, so it would probably be confusing for initiators.\n", "before_files": [{"content": "from django.urls import reverse\nfrom django.utils.translation import ugettext_lazy as _\n\nfrom adhocracy4.dashboard import DashboardComponent\nfrom adhocracy4.dashboard import ProjectFormComponent\nfrom adhocracy4.dashboard import components\n\nfrom . import forms\nfrom . import views\n\n\nclass ParticipantsComponent(DashboardComponent):\n    identifier = 'participants'\n    weight = 30\n    label = _('Participants')\n\n    def is_effective(self, project):\n        return not project.is_draft and project.is_private\n\n    def get_base_url(self, project):\n        return reverse('a4dashboard:dashboard-participants-edit', kwargs={\n            'project_slug': project.slug\n        })\n\n    def get_urls(self):\n        return [(\n            r'^projects/(?P<project_slug>[-\\w_]+)/participants/$',\n            views.DashboardProjectParticipantsView.as_view(component=self),\n            'dashboard-participants-edit'\n        )]\n\n\nclass ModeratorsComponent(DashboardComponent):\n    identifier = 'moderators'\n    weight = 32\n    label = _('Moderators')\n\n    def is_effective(self, project):\n        return True\n\n    def get_base_url(self, project):\n        return reverse('a4dashboard:dashboard-moderators-edit', kwargs={\n            'project_slug': project.slug\n        })\n\n    def get_urls(self):\n        return [(\n            r'^projects/(?P<project_slug>[-\\w_]+)/moderators/$',\n            views.DashboardProjectModeratorsView.as_view(component=self),\n            'dashboard-moderators-edit'\n        )]\n\n\nclass TopicComponent(ProjectFormComponent):\n    identifier = 'topics'\n    weight = 33\n    label = _('Topics')\n\n    form_title = _('Edit topics')\n    form_class = forms.TopicForm\n    form_template_name = 'liqd_product_projects/project_topics.html'\n\n\ncomponents.register_project(ModeratorsComponent())\ncomponents.register_project(ParticipantsComponent())\ncomponents.register_project(TopicComponent())\n", "path": "liqd_product/apps/projects/dashboard.py"}, {"content": "from django import forms\nfrom django.contrib.auth import get_user_model\nfrom django.core.exceptions import ValidationError\nfrom django.utils.translation import ugettext_lazy as _\n\nfrom adhocracy4.dashboard.forms import ProjectDashboardForm\nfrom adhocracy4.projects.models import Project\nfrom liqd_product.apps.users import fields as user_fields\n\nfrom .models import ModeratorInvite\nfrom .models import ParticipantInvite\n\nUser = get_user_model()\n\n\nclass InviteForm(forms.ModelForm):\n    accept = forms.CharField(required=False)\n    reject = forms.CharField(required=False)\n\n    def clean(self):\n        data = self.data\n        if 'accept' not in data and 'reject' not in data:\n            raise ValidationError('Reject or accept')\n        return data\n\n    def is_accepted(self):\n        data = self.data\n        return 'accept' in data and 'reject' not in data\n\n\nclass ParticipantInviteForm(InviteForm):\n\n    class Meta:\n        model = ParticipantInvite\n        fields = ['accept', 'reject']\n\n\nclass ModeratorInviteForm(InviteForm):\n\n    class Meta:\n        model = ModeratorInvite\n        fields = ['accept', 'reject']\n\n\nclass InviteUsersFromEmailForm(forms.Form):\n    add_users = user_fields.CommaSeparatedEmailField(\n        required=False,\n        label=_('Invite users via email')\n    )\n\n    add_users_upload = user_fields.EmailFileField(\n        required=False,\n        label=_('Invite users via file upload'),\n        help_text=_('Upload a csv file containing email addresses.')\n    )\n\n    def __init__(self, *args, **kwargs):\n        labels = kwargs.pop('labels', None)\n        super().__init__(*args, **kwargs)\n\n        if labels:\n            self.fields['add_users'].label = labels[0]\n            self.fields['add_users_upload'].label = labels[1]\n\n    def clean(self):\n        cleaned_data = super().clean()\n        add_users = self.data.get('add_users')\n        add_users_upload = self.files.get('add_users_upload')\n        if not self.errors and not add_users and not add_users_upload:\n            raise ValidationError(\n                _('Please enter email addresses or upload a file'))\n        return cleaned_data\n\n\nclass TopicForm(ProjectDashboardForm):\n\n    class Meta:\n        model = Project\n        fields = ['topics']\n        required_for_project_publish = ['topics']\n", "path": "liqd_product/apps/projects/forms.py"}]}