prompt: You will be provided with a partial code base and an issue statement explaining a problem to resolve.
  <issue>
  Creating a task with the "Task Code" as a number doesn't work as expected.
  After creating a task with the task code as a number, and accepting the task, when users want to navigate to the task, it should ideally take us to a page which says "The task owner still needs to activate this task.", but in this case, we are shown the respective page for a millisecond, and taken back to the home page, which I think is unexpected behaviour.
  
  A demonstration is given in the following screen recording of the same issue.
  
  **Steps to reproduce**:
  - Create a task proposal with the "Task Code" field as a number
  - Accept the task as the admin user.
  - Now try to click on the respective task from your "Tasks" page. It should just take you back to the homepage.
  
  This seems to happen only for a purely numeric "Task Code" and not for an alphanumeric "Task Code"
  
  https://user-images.githubusercontent.com/48560219/135757335-d98f116f-b7d6-44dc-a1fd-0c8b6fac7c61.mov
  
  
  
  </issue>
  <code>
  [start of api/controllers/task_proposals.py]
  1 # Copyright (c) Facebook, Inc. and its affiliates.
  2 # This source code is licensed under the MIT license found in the
  3 # LICENSE file in the root directory of this source tree.
  4 
  5 import re
  6 
  7 import bottle
  8 
  9 import common.auth as _auth
  10 import common.helpers as util
  11 from common.logging import logger
  12 from models.base import DBSession as dbs
  13 from models.task import TaskModel
  14 from models.task_proposal import TaskProposal, TaskProposalModel
  15 from models.user import UserModel
  16 
  17 
  18 @bottle.get("/task_proposals/user/<page:int>/<limit:int>")
  19 @_auth.requires_auth
  20 def get_user_task_proposals(credentials, page, limit):
  21     tpm = TaskProposalModel()
  22     proposals = tpm.getByUid(credentials["id"])
  23     identifiers = []
  24     for proposal in proposals:
  25         identifiers.append(proposal.to_dict())
  26     return util.json_encode(
  27         {
  28             "data": identifiers[page * limit : page * limit + limit],
  29             "count": len(identifiers),
  30         }
  31     )
  32 
  33 
  34 @bottle.get("/task_proposals/all/<page:int>/<limit:int>")
  35 @_auth.requires_auth
  36 def get_all_task_proposals(credentials, page, limit):
  37     um = UserModel()
  38     user = um.get(credentials["id"])
  39     if not user.admin:
  40         bottle.abort(403, "Access denied")
  41 
  42     proposals = dbs.query(TaskProposal)
  43     identifiers = []
  44     for proposal in proposals:
  45         identifiers.append(proposal.to_dict())
  46     return util.json_encode(
  47         {
  48             "data": identifiers[page * limit : page * limit + limit],
  49             "count": len(identifiers),
  50         }
  51     )
  52 
  53 
  54 @bottle.post("/task_proposals/create")
  55 @_auth.requires_auth
  56 def create_task_proposal(credentials):
  57     data = bottle.request.json
  58 
  59     if not util.check_fields(data, ["task_code", "name", "desc", "longdesc"]):
  60         bottle.abort(400, "Missing data")
  61 
  62     tm = TaskModel()
  63     if tm.getByTaskCode(data["task_code"]):
  64         bottle.abort(400, "Invalid task code; this task code is already taken")
  65 
  66     if tm.getByName(data["name"]):
  67         bottle.abort(400, "Invalid name; this name is already taken")
  68 
  69     if not bool(re.search("^[a-zA-Z0-9_-]*$", data["task_code"])):
  70         bottle.abort(
  71             400,
  72             "Invalid task code (no special characters allowed besides underscores "
  73             + "and dashes)",
  74         )
  75 
  76     try:
  77         tp = TaskProposal(
  78             uid=credentials["id"],
  79             task_code=data["task_code"],
  80             name=data["name"],
  81             desc=data["desc"],
  82             longdesc=data["longdesc"],
  83         )
  84 
  85         tm.dbs.add(tp)
  86         tm.dbs.flush()
  87         tm.dbs.commit()
  88         logger.info("Added task proposal (%s)" % (tp.id))
  89 
  90     except Exception as error_message:
  91         logger.error("Could not create task proposal (%s)" % error_message)
  92         return False
  93 
  94     return util.json_encode({"success": "ok", "id": tp.id})
  95
  [end of api/controllers/task_proposals.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/api/controllers/task_proposals.py b/api/controllers/task_proposals.py
  --- a/api/controllers/task_proposals.py
  +++ b/api/controllers/task_proposals.py
  @@ -66,11 +66,13 @@
       if tm.getByName(data["name"]):
           bottle.abort(400, "Invalid name; this name is already taken")
   
  -    if not bool(re.search("^[a-zA-Z0-9_-]*$", data["task_code"])):
  +    if not bool(
  +        re.search("(?=^[a-zA-Z0-9_-]*$)(?=.*[a-zA-Z].*).*$", data["task_code"])
  +    ):
           bottle.abort(
               400,
               "Invalid task code (no special characters allowed besides underscores "
  -            + "and dashes)",
  +            + "and dashes. At least one letter required)",
           )
   
       try:
  
verification_info: {"golden_diff": "diff --git a/api/controllers/task_proposals.py b/api/controllers/task_proposals.py\n--- a/api/controllers/task_proposals.py\n+++ b/api/controllers/task_proposals.py\n@@ -66,11 +66,13 @@\n     if tm.getByName(data[\"name\"]):\n         bottle.abort(400, \"Invalid name; this name is already taken\")\n \n-    if not bool(re.search(\"^[a-zA-Z0-9_-]*$\", data[\"task_code\"])):\n+    if not bool(\n+        re.search(\"(?=^[a-zA-Z0-9_-]*$)(?=.*[a-zA-Z].*).*$\", data[\"task_code\"])\n+    ):\n         bottle.abort(\n             400,\n             \"Invalid task code (no special characters allowed besides underscores \"\n-            + \"and dashes)\",\n+            + \"and dashes. At least one letter required)\",\n         )\n \n     try:\n", "issue": "Creating a task with the \"Task Code\" as a number doesn't work as expected.\nAfter creating a task with the task code as a number, and accepting the task, when users want to navigate to the task, it should ideally take us to a page which says \"The task owner still needs to activate this task.\", but in this case, we are shown the respective page for a millisecond, and taken back to the home page, which I think is unexpected behaviour.\r\n\r\nA demonstration is given in the following screen recording of the same issue.\r\n\r\n**Steps to reproduce**:\r\n- Create a task proposal with the \"Task Code\" field as a number\r\n- Accept the task as the admin user.\r\n- Now try to click on the respective task from your \"Tasks\" page. It should just take you back to the homepage.\r\n\r\nThis seems to happen only for a purely numeric \"Task Code\" and not for an alphanumeric \"Task Code\"\r\n\r\nhttps://user-images.githubusercontent.com/48560219/135757335-d98f116f-b7d6-44dc-a1fd-0c8b6fac7c61.mov\r\n\r\n\n", "before_files": [{"content": "# Copyright (c) Facebook, Inc. and its affiliates.\n# This source code is licensed under the MIT license found in the\n# LICENSE file in the root directory of this source tree.\n\nimport re\n\nimport bottle\n\nimport common.auth as _auth\nimport common.helpers as util\nfrom common.logging import logger\nfrom models.base import DBSession as dbs\nfrom models.task import TaskModel\nfrom models.task_proposal import TaskProposal, TaskProposalModel\nfrom models.user import UserModel\n\n\n@bottle.get(\"/task_proposals/user/<page:int>/<limit:int>\")\n@_auth.requires_auth\ndef get_user_task_proposals(credentials, page, limit):\n    tpm = TaskProposalModel()\n    proposals = tpm.getByUid(credentials[\"id\"])\n    identifiers = []\n    for proposal in proposals:\n        identifiers.append(proposal.to_dict())\n    return util.json_encode(\n        {\n            \"data\": identifiers[page * limit : page * limit + limit],\n            \"count\": len(identifiers),\n        }\n    )\n\n\n@bottle.get(\"/task_proposals/all/<page:int>/<limit:int>\")\n@_auth.requires_auth\ndef get_all_task_proposals(credentials, page, limit):\n    um = UserModel()\n    user = um.get(credentials[\"id\"])\n    if not user.admin:\n        bottle.abort(403, \"Access denied\")\n\n    proposals = dbs.query(TaskProposal)\n    identifiers = []\n    for proposal in proposals:\n        identifiers.append(proposal.to_dict())\n    return util.json_encode(\n        {\n            \"data\": identifiers[page * limit : page * limit + limit],\n            \"count\": len(identifiers),\n        }\n    )\n\n\n@bottle.post(\"/task_proposals/create\")\n@_auth.requires_auth\ndef create_task_proposal(credentials):\n    data = bottle.request.json\n\n    if not util.check_fields(data, [\"task_code\", \"name\", \"desc\", \"longdesc\"]):\n        bottle.abort(400, \"Missing data\")\n\n    tm = TaskModel()\n    if tm.getByTaskCode(data[\"task_code\"]):\n        bottle.abort(400, \"Invalid task code; this task code is already taken\")\n\n    if tm.getByName(data[\"name\"]):\n        bottle.abort(400, \"Invalid name; this name is already taken\")\n\n    if not bool(re.search(\"^[a-zA-Z0-9_-]*$\", data[\"task_code\"])):\n        bottle.abort(\n            400,\n            \"Invalid task code (no special characters allowed besides underscores \"\n            + \"and dashes)\",\n        )\n\n    try:\n        tp = TaskProposal(\n            uid=credentials[\"id\"],\n            task_code=data[\"task_code\"],\n            name=data[\"name\"],\n            desc=data[\"desc\"],\n            longdesc=data[\"longdesc\"],\n        )\n\n        tm.dbs.add(tp)\n        tm.dbs.flush()\n        tm.dbs.commit()\n        logger.info(\"Added task proposal (%s)\" % (tp.id))\n\n    except Exception as error_message:\n        logger.error(\"Could not create task proposal (%s)\" % error_message)\n        return False\n\n    return util.json_encode({\"success\": \"ok\", \"id\": tp.id})\n", "path": "api/controllers/task_proposals.py"}]}