We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
API crashes when a non-valid date is entered
E.g. `http://rsr.akvo.org/rest/v1/project_update_extra/?created_at__gt=2015-07`


--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `akvo/rest/views/project_update.py`
Content:
```
1 # -*- coding: utf-8 -*-
2 """Akvo RSR is covered by the GNU Affero General Public License.
3 
4 See more details in the license.txt file located at the root folder of the Akvo RSR module.
5 For additional details on the GNU license please see < http://www.gnu.org/licenses/agpl.html >.
6 """
7 
8 from akvo.rsr.models import ProjectUpdate
9 
10 from ..serializers import ProjectUpdateSerializer, ProjectUpdateExtraSerializer
11 from ..viewsets import PublicProjectViewSet
12 
13 from rest_framework.decorators import api_view, permission_classes
14 from rest_framework.permissions import IsAuthenticated
15 from rest_framework.response import Response
16 from rest_framework.exceptions import ParseError
17 from re import match
18 
19 
20 class ProjectUpdateViewSet(PublicProjectViewSet):
21 
22     """."""
23     queryset = ProjectUpdate.objects.select_related('project',
24                                                     'user').prefetch_related('locations')
25     serializer_class = ProjectUpdateSerializer
26 
27     paginate_by_param = 'limit'
28     max_paginate_by = 1000
29 
30     def get_queryset(self):
31         """
32         Allow simple filtering on selected fields.
33         We don't use the default filter_fields, because Up filters on
34         datetime for last_modified_at, and they only support a date, not datetime.
35         """
36         created_at__gt = validate_date(self.request.QUERY_PARAMS.get('created_at__gt', None))
37         if created_at__gt is not None:
38             self.queryset = self.queryset.filter(created_at__gt=created_at__gt)
39         created_at__lt = validate_date(self.request.QUERY_PARAMS.get('created_at__lt', None))
40         if created_at__lt is not None:
41             self.queryset = self.queryset.filter(created_at__lt=created_at__lt)
42         last_modified_at__gt = validate_date(self.request.QUERY_PARAMS.get('last_modified_at__gt', None))
43         if last_modified_at__gt is not None:
44             self.queryset = self.queryset.filter(last_modified_at__gt=last_modified_at__gt)
45         last_modified_at__lt = validate_date(self.request.QUERY_PARAMS.get('last_modified_at__lt', None))
46         if last_modified_at__lt is not None:
47             self.queryset = self.queryset.filter(last_modified_at__lt=last_modified_at__lt)
48         # Get updates per organisation
49         project__partners = self.request.QUERY_PARAMS.get('project__partners', None)
50         if project__partners:
51             self.queryset = self.queryset.filter(project__partners=project__partners)
52         user__organisations = self.request.QUERY_PARAMS.get('user__organisations', None)
53         if user__organisations:
54             self.queryset = self.queryset.filter(user__organisations=user__organisations)
55         return super(ProjectUpdateViewSet, self).get_queryset()
56 
57 
58 class ProjectUpdateExtraViewSet(PublicProjectViewSet):
59 
60     """Project update extra resource."""
61 
62     max_paginate_by = 30
63     paginate_by = 10
64 
65     queryset = ProjectUpdate.objects.select_related(
66         'primary_location',
67         'primary_location__location_target',
68         'primary_location__location_target__project',
69         'primary_location__location_target__user',
70         'primary_location__location_target__primary_location',
71         'primary_location__location_target__country',
72         'project',
73         'user',
74         'user__organisation',
75         'user__organisation__primary_location',
76         'user__organisation__primary_location__country',
77         'user__organisation__primary_location__location_target',
78         'user__organisation__primary_location__location_target__internal_org_ids',
79 
80     ).prefetch_related(
81         'user__organisations',
82         'user__organisations__primary_location',
83         'user__organisations__primary_location__country',
84         'user__organisations__primary_location__location_target')
85     serializer_class = ProjectUpdateExtraSerializer
86 
87     def get_queryset(self):
88         """
89         Allow simple filtering on selected fields.
90         We don't use the default filter_fields, because Up filters on
91         datetime for last_modified_at, and they only support a date, not datetime.
92         """
93         created_at__gt = validate_date(self.request.QUERY_PARAMS.get('created_at__gt', None))
94         if created_at__gt is not None:
95             self.queryset = self.queryset.filter(created_at__gt=created_at__gt)
96         created_at__lt = validate_date(self.request.QUERY_PARAMS.get('created_at__lt', None))
97         if created_at__lt is not None:
98             self.queryset = self.queryset.filter(created_at__lt=created_at__lt)
99         last_modified_at__gt = validate_date(self.request.QUERY_PARAMS.get('last_modified_at__gt', None))
100         if last_modified_at__gt is not None:
101             self.queryset = self.queryset.filter(last_modified_at__gt=last_modified_at__gt)
102         last_modified_at__lt = validate_date(self.request.QUERY_PARAMS.get('last_modified_at__lt', None))
103         if last_modified_at__lt is not None:
104             self.queryset = self.queryset.filter(last_modified_at__lt=last_modified_at__lt)
105         # Get updates per organisation
106         project__partners = self.request.QUERY_PARAMS.get('project__partners', None)
107         if project__partners:
108             self.queryset = self.queryset.filter(project__partners=project__partners)
109         user__organisations = self.request.QUERY_PARAMS.get('user__organisations', None)
110         if user__organisations:
111             self.queryset = self.queryset.filter(user__organisations=user__organisations)
112         return super(ProjectUpdateExtraViewSet, self).get_queryset()
113 
114 
115 # validate date strings from URL
116 def validate_date(date):
117 
118     if date is None:
119         return None
120     # if yyyy-mm-dd
121     elif match('^\d{4}\-(0?[1-9]|1[012])\-(0?[1-9]|[12][0-9]|3[01])$', date) is not None:
122         return date
123     # if yyyy-mm
124     elif match('^\d{4}\-(0?[1-9]|1[012])$', date) is not None:
125         return date + '-01'
126     else:
127         raise ParseError('created_at and last_modified_at dates must be in format: yyyy-mm-dd')
128 
129 
130 @api_view(['POST'])
131 @permission_classes((IsAuthenticated, ))
132 def upload_indicator_update_photo(request, pk=None):
133     update = ProjectUpdate.objects.get(pk=pk)
134     user = request.user
135 
136     # TODO: permissions
137 
138     files = request.FILES
139 
140     if 'photo' in files.keys():
141         update.photo = files['photo']
142         update.save(update_fields=['photo'])
143 
144     return Response(ProjectUpdateExtraSerializer(update).data)
145
```
--- END FILES ---

Please first localize the bug based on the issue statement, and then generate a patch according to the `git diff` format fenced by three backticks.

Here is an example:

```diff
diff --git a/examples/server_async.py b/examples/server_async.py
--- a/examples/server_async.py
+++ b/examples/server_async.py
@@ -313,4 +313,4 @@
 
 
 if __name__ == "__main__":
-    asyncio.run(run_async_server("."), debug=True)
+    asyncio.run(run_async_server(), debug=True)
diff --git a/examples/server_sync.py b/examples/server_sync.py
--- a/examples/server_sync.py
+++ b/examples/server_sync.py
@@ -313,5 +313,5 @@
 
 
 if __name__ == "__main__":
-    server = run_sync_server(".")
+    server = run_sync_server()
     server.shutdown()

```

diff --git a/akvo/rest/views/project_update.py b/akvo/rest/views/project_update.py
--- a/akvo/rest/views/project_update.py
+++ b/akvo/rest/views/project_update.py
@@ -117,6 +117,11 @@
 
     if date is None:
         return None
+    # if yyyy-mm-ddThh:mm:ss
+    elif match(
+            '^\d{4}\-(0?[1-9]|1[012])\-(0?[1-9]|[12][0-9]|3[01])T[0-2]\d{1}:[0-5]\d{1}:[0-5]\d{1}$',
+            date) is not None:
+        return date
     # if yyyy-mm-dd
     elif match('^\d{4}\-(0?[1-9]|1[012])\-(0?[1-9]|[12][0-9]|3[01])$', date) is not None:
         return date
@@ -124,7 +129,10 @@
     elif match('^\d{4}\-(0?[1-9]|1[012])$', date) is not None:
         return date + '-01'
     else:
-        raise ParseError('created_at and last_modified_at dates must be in format: yyyy-mm-dd')
+        raise ParseError(
+            'Invalid date: created_at and last_modified_at dates must be in one of the following '
+            'formats: yyyy-mm, yyyy-mm-dd or yyyy-mm-ddThh:mm:ss'
+        )
 
 
 @api_view(['POST'])

{"golden_diff": "diff --git a/akvo/rest/views/project_update.py b/akvo/rest/views/project_update.py\n--- a/akvo/rest/views/project_update.py\n+++ b/akvo/rest/views/project_update.py\n@@ -117,6 +117,11 @@\n \n     if date is None:\n         return None\n+    # if yyyy-mm-ddThh:mm:ss\n+    elif match(\n+            '^\\d{4}\\-(0?[1-9]|1[012])\\-(0?[1-9]|[12][0-9]|3[01])T[0-2]\\d{1}:[0-5]\\d{1}:[0-5]\\d{1}$',\n+            date) is not None:\n+        return date\n     # if yyyy-mm-dd\n     elif match('^\\d{4}\\-(0?[1-9]|1[012])\\-(0?[1-9]|[12][0-9]|3[01])$', date) is not None:\n         return date\n@@ -124,7 +129,10 @@\n     elif match('^\\d{4}\\-(0?[1-9]|1[012])$', date) is not None:\n         return date + '-01'\n     else:\n-        raise ParseError('created_at and last_modified_at dates must be in format: yyyy-mm-dd')\n+        raise ParseError(\n+            'Invalid date: created_at and last_modified_at dates must be in one of the following '\n+            'formats: yyyy-mm, yyyy-mm-dd or yyyy-mm-ddThh:mm:ss'\n+        )\n \n \n @api_view(['POST'])\n", "issue": "API crashes when a non-valid date is entered\nE.g. `http://rsr.akvo.org/rest/v1/project_update_extra/?created_at__gt=2015-07`\n\n", "before_files": [{"content": "# -*- coding: utf-8 -*-\n\"\"\"Akvo RSR is covered by the GNU Affero General Public License.\n\nSee more details in the license.txt file located at the root folder of the Akvo RSR module.\nFor additional details on the GNU license please see < http://www.gnu.org/licenses/agpl.html >.\n\"\"\"\n\nfrom akvo.rsr.models import ProjectUpdate\n\nfrom ..serializers import ProjectUpdateSerializer, ProjectUpdateExtraSerializer\nfrom ..viewsets import PublicProjectViewSet\n\nfrom rest_framework.decorators import api_view, permission_classes\nfrom rest_framework.permissions import IsAuthenticated\nfrom rest_framework.response import Response\nfrom rest_framework.exceptions import ParseError\nfrom re import match\n\n\nclass ProjectUpdateViewSet(PublicProjectViewSet):\n\n    \"\"\".\"\"\"\n    queryset = ProjectUpdate.objects.select_related('project',\n                                                    'user').prefetch_related('locations')\n    serializer_class = ProjectUpdateSerializer\n\n    paginate_by_param = 'limit'\n    max_paginate_by = 1000\n\n    def get_queryset(self):\n        \"\"\"\n        Allow simple filtering on selected fields.\n        We don't use the default filter_fields, because Up filters on\n        datetime for last_modified_at, and they only support a date, not datetime.\n        \"\"\"\n        created_at__gt = validate_date(self.request.QUERY_PARAMS.get('created_at__gt', None))\n        if created_at__gt is not None:\n            self.queryset = self.queryset.filter(created_at__gt=created_at__gt)\n        created_at__lt = validate_date(self.request.QUERY_PARAMS.get('created_at__lt', None))\n        if created_at__lt is not None:\n            self.queryset = self.queryset.filter(created_at__lt=created_at__lt)\n        last_modified_at__gt = validate_date(self.request.QUERY_PARAMS.get('last_modified_at__gt', None))\n        if last_modified_at__gt is not None:\n            self.queryset = self.queryset.filter(last_modified_at__gt=last_modified_at__gt)\n        last_modified_at__lt = validate_date(self.request.QUERY_PARAMS.get('last_modified_at__lt', None))\n        if last_modified_at__lt is not None:\n            self.queryset = self.queryset.filter(last_modified_at__lt=last_modified_at__lt)\n        # Get updates per organisation\n        project__partners = self.request.QUERY_PARAMS.get('project__partners', None)\n        if project__partners:\n            self.queryset = self.queryset.filter(project__partners=project__partners)\n        user__organisations = self.request.QUERY_PARAMS.get('user__organisations', None)\n        if user__organisations:\n            self.queryset = self.queryset.filter(user__organisations=user__organisations)\n        return super(ProjectUpdateViewSet, self).get_queryset()\n\n\nclass ProjectUpdateExtraViewSet(PublicProjectViewSet):\n\n    \"\"\"Project update extra resource.\"\"\"\n\n    max_paginate_by = 30\n    paginate_by = 10\n\n    queryset = ProjectUpdate.objects.select_related(\n        'primary_location',\n        'primary_location__location_target',\n        'primary_location__location_target__project',\n        'primary_location__location_target__user',\n        'primary_location__location_target__primary_location',\n        'primary_location__location_target__country',\n        'project',\n        'user',\n        'user__organisation',\n        'user__organisation__primary_location',\n        'user__organisation__primary_location__country',\n        'user__organisation__primary_location__location_target',\n        'user__organisation__primary_location__location_target__internal_org_ids',\n\n    ).prefetch_related(\n        'user__organisations',\n        'user__organisations__primary_location',\n        'user__organisations__primary_location__country',\n        'user__organisations__primary_location__location_target')\n    serializer_class = ProjectUpdateExtraSerializer\n\n    def get_queryset(self):\n        \"\"\"\n        Allow simple filtering on selected fields.\n        We don't use the default filter_fields, because Up filters on\n        datetime for last_modified_at, and they only support a date, not datetime.\n        \"\"\"\n        created_at__gt = validate_date(self.request.QUERY_PARAMS.get('created_at__gt', None))\n        if created_at__gt is not None:\n            self.queryset = self.queryset.filter(created_at__gt=created_at__gt)\n        created_at__lt = validate_date(self.request.QUERY_PARAMS.get('created_at__lt', None))\n        if created_at__lt is not None:\n            self.queryset = self.queryset.filter(created_at__lt=created_at__lt)\n        last_modified_at__gt = validate_date(self.request.QUERY_PARAMS.get('last_modified_at__gt', None))\n        if last_modified_at__gt is not None:\n            self.queryset = self.queryset.filter(last_modified_at__gt=last_modified_at__gt)\n        last_modified_at__lt = validate_date(self.request.QUERY_PARAMS.get('last_modified_at__lt', None))\n        if last_modified_at__lt is not None:\n            self.queryset = self.queryset.filter(last_modified_at__lt=last_modified_at__lt)\n        # Get updates per organisation\n        project__partners = self.request.QUERY_PARAMS.get('project__partners', None)\n        if project__partners:\n            self.queryset = self.queryset.filter(project__partners=project__partners)\n        user__organisations = self.request.QUERY_PARAMS.get('user__organisations', None)\n        if user__organisations:\n            self.queryset = self.queryset.filter(user__organisations=user__organisations)\n        return super(ProjectUpdateExtraViewSet, self).get_queryset()\n\n\n# validate date strings from URL\ndef validate_date(date):\n\n    if date is None:\n        return None\n    # if yyyy-mm-dd\n    elif match('^\\d{4}\\-(0?[1-9]|1[012])\\-(0?[1-9]|[12][0-9]|3[01])$', date) is not None:\n        return date\n    # if yyyy-mm\n    elif match('^\\d{4}\\-(0?[1-9]|1[012])$', date) is not None:\n        return date + '-01'\n    else:\n        raise ParseError('created_at and last_modified_at dates must be in format: yyyy-mm-dd')\n\n\n@api_view(['POST'])\n@permission_classes((IsAuthenticated, ))\ndef upload_indicator_update_photo(request, pk=None):\n    update = ProjectUpdate.objects.get(pk=pk)\n    user = request.user\n\n    # TODO: permissions\n\n    files = request.FILES\n\n    if 'photo' in files.keys():\n        update.photo = files['photo']\n        update.save(update_fields=['photo'])\n\n    return Response(ProjectUpdateExtraSerializer(update).data)\n", "path": "akvo/rest/views/project_update.py"}], "after_files": [{"content": "# -*- coding: utf-8 -*-\n\"\"\"Akvo RSR is covered by the GNU Affero General Public License.\n\nSee more details in the license.txt file located at the root folder of the Akvo RSR module.\nFor additional details on the GNU license please see < http://www.gnu.org/licenses/agpl.html >.\n\"\"\"\n\nfrom akvo.rsr.models import ProjectUpdate\n\nfrom ..serializers import ProjectUpdateSerializer, ProjectUpdateExtraSerializer\nfrom ..viewsets import PublicProjectViewSet\n\nfrom rest_framework.decorators import api_view, permission_classes\nfrom rest_framework.permissions import IsAuthenticated\nfrom rest_framework.response import Response\nfrom rest_framework.exceptions import ParseError\nfrom re import match\n\n\nclass ProjectUpdateViewSet(PublicProjectViewSet):\n\n    \"\"\".\"\"\"\n    queryset = ProjectUpdate.objects.select_related('project',\n                                                    'user').prefetch_related('locations')\n    serializer_class = ProjectUpdateSerializer\n\n    paginate_by_param = 'limit'\n    max_paginate_by = 1000\n\n    def get_queryset(self):\n        \"\"\"\n        Allow simple filtering on selected fields.\n        We don't use the default filter_fields, because Up filters on\n        datetime for last_modified_at, and they only support a date, not datetime.\n        \"\"\"\n        created_at__gt = validate_date(self.request.QUERY_PARAMS.get('created_at__gt', None))\n        if created_at__gt is not None:\n            self.queryset = self.queryset.filter(created_at__gt=created_at__gt)\n        created_at__lt = validate_date(self.request.QUERY_PARAMS.get('created_at__lt', None))\n        if created_at__lt is not None:\n            self.queryset = self.queryset.filter(created_at__lt=created_at__lt)\n        last_modified_at__gt = validate_date(self.request.QUERY_PARAMS.get('last_modified_at__gt', None))\n        if last_modified_at__gt is not None:\n            self.queryset = self.queryset.filter(last_modified_at__gt=last_modified_at__gt)\n        last_modified_at__lt = validate_date(self.request.QUERY_PARAMS.get('last_modified_at__lt', None))\n        if last_modified_at__lt is not None:\n            self.queryset = self.queryset.filter(last_modified_at__lt=last_modified_at__lt)\n        # Get updates per organisation\n        project__partners = self.request.QUERY_PARAMS.get('project__partners', None)\n        if project__partners:\n            self.queryset = self.queryset.filter(project__partners=project__partners)\n        user__organisations = self.request.QUERY_PARAMS.get('user__organisations', None)\n        if user__organisations:\n            self.queryset = self.queryset.filter(user__organisations=user__organisations)\n        return super(ProjectUpdateViewSet, self).get_queryset()\n\n\nclass ProjectUpdateExtraViewSet(PublicProjectViewSet):\n\n    \"\"\"Project update extra resource.\"\"\"\n\n    max_paginate_by = 30\n    paginate_by = 10\n\n    queryset = ProjectUpdate.objects.select_related(\n        'primary_location',\n        'primary_location__location_target',\n        'primary_location__location_target__project',\n        'primary_location__location_target__user',\n        'primary_location__location_target__primary_location',\n        'primary_location__location_target__country',\n        'project',\n        'user',\n        'user__organisation',\n        'user__organisation__primary_location',\n        'user__organisation__primary_location__country',\n        'user__organisation__primary_location__location_target',\n        'user__organisation__primary_location__location_target__internal_org_ids',\n\n    ).prefetch_related(\n        'user__organisations',\n        'user__organisations__primary_location',\n        'user__organisations__primary_location__country',\n        'user__organisations__primary_location__location_target')\n    serializer_class = ProjectUpdateExtraSerializer\n\n    def get_queryset(self):\n        \"\"\"\n        Allow simple filtering on selected fields.\n        We don't use the default filter_fields, because Up filters on\n        datetime for last_modified_at, and they only support a date, not datetime.\n        \"\"\"\n        created_at__gt = validate_date(self.request.QUERY_PARAMS.get('created_at__gt', None))\n        if created_at__gt is not None:\n            self.queryset = self.queryset.filter(created_at__gt=created_at__gt)\n        created_at__lt = validate_date(self.request.QUERY_PARAMS.get('created_at__lt', None))\n        if created_at__lt is not None:\n            self.queryset = self.queryset.filter(created_at__lt=created_at__lt)\n        last_modified_at__gt = validate_date(self.request.QUERY_PARAMS.get('last_modified_at__gt', None))\n        if last_modified_at__gt is not None:\n            self.queryset = self.queryset.filter(last_modified_at__gt=last_modified_at__gt)\n        last_modified_at__lt = validate_date(self.request.QUERY_PARAMS.get('last_modified_at__lt', None))\n        if last_modified_at__lt is not None:\n            self.queryset = self.queryset.filter(last_modified_at__lt=last_modified_at__lt)\n        # Get updates per organisation\n        project__partners = self.request.QUERY_PARAMS.get('project__partners', None)\n        if project__partners:\n            self.queryset = self.queryset.filter(project__partners=project__partners)\n        user__organisations = self.request.QUERY_PARAMS.get('user__organisations', None)\n        if user__organisations:\n            self.queryset = self.queryset.filter(user__organisations=user__organisations)\n        return super(ProjectUpdateExtraViewSet, self).get_queryset()\n\n\n# validate date strings from URL\ndef validate_date(date):\n\n    if date is None:\n        return None\n    # if yyyy-mm-ddThh:mm:ss\n    elif match(\n            '^\\d{4}\\-(0?[1-9]|1[012])\\-(0?[1-9]|[12][0-9]|3[01])T[0-2]\\d{1}:[0-5]\\d{1}:[0-5]\\d{1}$',\n            date) is not None:\n        return date\n    # if yyyy-mm-dd\n    elif match('^\\d{4}\\-(0?[1-9]|1[012])\\-(0?[1-9]|[12][0-9]|3[01])$', date) is not None:\n        return date\n    # if yyyy-mm\n    elif match('^\\d{4}\\-(0?[1-9]|1[012])$', date) is not None:\n        return date + '-01'\n    else:\n        raise ParseError(\n            'Invalid date: created_at and last_modified_at dates must be in one of the following '\n            'formats: yyyy-mm, yyyy-mm-dd or yyyy-mm-ddThh:mm:ss'\n        )\n\n\n@api_view(['POST'])\n@permission_classes((IsAuthenticated, ))\ndef upload_indicator_update_photo(request, pk=None):\n    update = ProjectUpdate.objects.get(pk=pk)\n    user = request.user\n\n    # TODO: permissions\n\n    files = request.FILES\n\n    if 'photo' in files.keys():\n        update.photo = files['photo']\n        update.save(update_fields=['photo'])\n\n    return Response(ProjectUpdateExtraSerializer(update).data)\n", "path": "akvo/rest/views/project_update.py"}]}