prompt: 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()
  
  ```
  
golden_diff: 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'])
  
verification_info: {"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"}]}