prompt: We are currently solving the following issue within our repository. Here is the issue text:
  --- BEGIN ISSUE ---
  Getting dynamic challenges by ID does not return decay function
  When getting a dynamic challenge from `GET /api/v1/challenges/<challenge-id>`, the challenge does not return its decay function.
  
  This seems to be caused by [this](https://github.com/CTFd/CTFd/blob/master/CTFd/plugins/dynamic_challenges/__init__.py#L60-L90) function which does not include `challenge.function`.
  
  This seems be have been missed out when implementing different decay functions for dynamic challenges. This does not have any impact on normal usage of CTFd, but I see no reason not to include the function in the response.
  
  
  --- END ISSUE ---
  
  Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
  --- BEGIN FILES ---
  Path: `CTFd/plugins/dynamic_challenges/__init__.py`
  Content:
  ```
  1 from flask import Blueprint
  2 
  3 from CTFd.models import Challenges, db
  4 from CTFd.plugins import register_plugin_assets_directory
  5 from CTFd.plugins.challenges import CHALLENGE_CLASSES, BaseChallenge
  6 from CTFd.plugins.dynamic_challenges.decay import DECAY_FUNCTIONS, logarithmic
  7 from CTFd.plugins.migrations import upgrade
  8 
  9 
  10 class DynamicChallenge(Challenges):
  11     __mapper_args__ = {"polymorphic_identity": "dynamic"}
  12     id = db.Column(
  13         db.Integer, db.ForeignKey("challenges.id", ondelete="CASCADE"), primary_key=True
  14     )
  15     initial = db.Column(db.Integer, default=0)
  16     minimum = db.Column(db.Integer, default=0)
  17     decay = db.Column(db.Integer, default=0)
  18     function = db.Column(db.String(32), default="logarithmic")
  19 
  20     def __init__(self, *args, **kwargs):
  21         super(DynamicChallenge, self).__init__(**kwargs)
  22         self.value = kwargs["initial"]
  23 
  24 
  25 class DynamicValueChallenge(BaseChallenge):
  26     id = "dynamic"  # Unique identifier used to register challenges
  27     name = "dynamic"  # Name of a challenge type
  28     templates = (
  29         {  # Handlebars templates used for each aspect of challenge editing & viewing
  30             "create": "/plugins/dynamic_challenges/assets/create.html",
  31             "update": "/plugins/dynamic_challenges/assets/update.html",
  32             "view": "/plugins/dynamic_challenges/assets/view.html",
  33         }
  34     )
  35     scripts = {  # Scripts that are loaded when a template is loaded
  36         "create": "/plugins/dynamic_challenges/assets/create.js",
  37         "update": "/plugins/dynamic_challenges/assets/update.js",
  38         "view": "/plugins/dynamic_challenges/assets/view.js",
  39     }
  40     # Route at which files are accessible. This must be registered using register_plugin_assets_directory()
  41     route = "/plugins/dynamic_challenges/assets/"
  42     # Blueprint used to access the static_folder directory.
  43     blueprint = Blueprint(
  44         "dynamic_challenges",
  45         __name__,
  46         template_folder="templates",
  47         static_folder="assets",
  48     )
  49     challenge_model = DynamicChallenge
  50 
  51     @classmethod
  52     def calculate_value(cls, challenge):
  53         f = DECAY_FUNCTIONS.get(challenge.function, logarithmic)
  54         value = f(challenge)
  55 
  56         challenge.value = value
  57         db.session.commit()
  58         return challenge
  59 
  60     @classmethod
  61     def read(cls, challenge):
  62         """
  63         This method is in used to access the data of a challenge in a format processable by the front end.
  64 
  65         :param challenge:
  66         :return: Challenge object, data dictionary to be returned to the user
  67         """
  68         challenge = DynamicChallenge.query.filter_by(id=challenge.id).first()
  69         data = {
  70             "id": challenge.id,
  71             "name": challenge.name,
  72             "value": challenge.value,
  73             "initial": challenge.initial,
  74             "decay": challenge.decay,
  75             "minimum": challenge.minimum,
  76             "description": challenge.description,
  77             "connection_info": challenge.connection_info,
  78             "next_id": challenge.next_id,
  79             "category": challenge.category,
  80             "state": challenge.state,
  81             "max_attempts": challenge.max_attempts,
  82             "type": challenge.type,
  83             "type_data": {
  84                 "id": cls.id,
  85                 "name": cls.name,
  86                 "templates": cls.templates,
  87                 "scripts": cls.scripts,
  88             },
  89         }
  90         return data
  91 
  92     @classmethod
  93     def update(cls, challenge, request):
  94         """
  95         This method is used to update the information associated with a challenge. This should be kept strictly to the
  96         Challenges table and any child tables.
  97 
  98         :param challenge:
  99         :param request:
  100         :return:
  101         """
  102         data = request.form or request.get_json()
  103 
  104         for attr, value in data.items():
  105             # We need to set these to floats so that the next operations don't operate on strings
  106             if attr in ("initial", "minimum", "decay"):
  107                 value = float(value)
  108             setattr(challenge, attr, value)
  109 
  110         return DynamicValueChallenge.calculate_value(challenge)
  111 
  112     @classmethod
  113     def solve(cls, user, team, challenge, request):
  114         super().solve(user, team, challenge, request)
  115 
  116         DynamicValueChallenge.calculate_value(challenge)
  117 
  118 
  119 def load(app):
  120     upgrade(plugin_name="dynamic_challenges")
  121     CHALLENGE_CLASSES["dynamic"] = DynamicValueChallenge
  122     register_plugin_assets_directory(
  123         app, base_path="/plugins/dynamic_challenges/assets/"
  124     )
  125
  ```
  --- 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/CTFd/plugins/dynamic_challenges/__init__.py b/CTFd/plugins/dynamic_challenges/__init__.py
  --- a/CTFd/plugins/dynamic_challenges/__init__.py
  +++ b/CTFd/plugins/dynamic_challenges/__init__.py
  @@ -73,6 +73,7 @@
               "initial": challenge.initial,
               "decay": challenge.decay,
               "minimum": challenge.minimum,
  +            "function": challenge.function,
               "description": challenge.description,
               "connection_info": challenge.connection_info,
               "next_id": challenge.next_id,
  
verification_info: {"golden_diff": "diff --git a/CTFd/plugins/dynamic_challenges/__init__.py b/CTFd/plugins/dynamic_challenges/__init__.py\n--- a/CTFd/plugins/dynamic_challenges/__init__.py\n+++ b/CTFd/plugins/dynamic_challenges/__init__.py\n@@ -73,6 +73,7 @@\n             \"initial\": challenge.initial,\n             \"decay\": challenge.decay,\n             \"minimum\": challenge.minimum,\n+            \"function\": challenge.function,\n             \"description\": challenge.description,\n             \"connection_info\": challenge.connection_info,\n             \"next_id\": challenge.next_id,\n", "issue": "Getting dynamic challenges by ID does not return decay function\nWhen getting a dynamic challenge from `GET /api/v1/challenges/<challenge-id>`, the challenge does not return its decay function.\r\n\r\nThis seems to be caused by [this](https://github.com/CTFd/CTFd/blob/master/CTFd/plugins/dynamic_challenges/__init__.py#L60-L90) function which does not include `challenge.function`.\r\n\r\nThis seems be have been missed out when implementing different decay functions for dynamic challenges. This does not have any impact on normal usage of CTFd, but I see no reason not to include the function in the response.\r\n\n", "before_files": [{"content": "from flask import Blueprint\n\nfrom CTFd.models import Challenges, db\nfrom CTFd.plugins import register_plugin_assets_directory\nfrom CTFd.plugins.challenges import CHALLENGE_CLASSES, BaseChallenge\nfrom CTFd.plugins.dynamic_challenges.decay import DECAY_FUNCTIONS, logarithmic\nfrom CTFd.plugins.migrations import upgrade\n\n\nclass DynamicChallenge(Challenges):\n    __mapper_args__ = {\"polymorphic_identity\": \"dynamic\"}\n    id = db.Column(\n        db.Integer, db.ForeignKey(\"challenges.id\", ondelete=\"CASCADE\"), primary_key=True\n    )\n    initial = db.Column(db.Integer, default=0)\n    minimum = db.Column(db.Integer, default=0)\n    decay = db.Column(db.Integer, default=0)\n    function = db.Column(db.String(32), default=\"logarithmic\")\n\n    def __init__(self, *args, **kwargs):\n        super(DynamicChallenge, self).__init__(**kwargs)\n        self.value = kwargs[\"initial\"]\n\n\nclass DynamicValueChallenge(BaseChallenge):\n    id = \"dynamic\"  # Unique identifier used to register challenges\n    name = \"dynamic\"  # Name of a challenge type\n    templates = (\n        {  # Handlebars templates used for each aspect of challenge editing & viewing\n            \"create\": \"/plugins/dynamic_challenges/assets/create.html\",\n            \"update\": \"/plugins/dynamic_challenges/assets/update.html\",\n            \"view\": \"/plugins/dynamic_challenges/assets/view.html\",\n        }\n    )\n    scripts = {  # Scripts that are loaded when a template is loaded\n        \"create\": \"/plugins/dynamic_challenges/assets/create.js\",\n        \"update\": \"/plugins/dynamic_challenges/assets/update.js\",\n        \"view\": \"/plugins/dynamic_challenges/assets/view.js\",\n    }\n    # Route at which files are accessible. This must be registered using register_plugin_assets_directory()\n    route = \"/plugins/dynamic_challenges/assets/\"\n    # Blueprint used to access the static_folder directory.\n    blueprint = Blueprint(\n        \"dynamic_challenges\",\n        __name__,\n        template_folder=\"templates\",\n        static_folder=\"assets\",\n    )\n    challenge_model = DynamicChallenge\n\n    @classmethod\n    def calculate_value(cls, challenge):\n        f = DECAY_FUNCTIONS.get(challenge.function, logarithmic)\n        value = f(challenge)\n\n        challenge.value = value\n        db.session.commit()\n        return challenge\n\n    @classmethod\n    def read(cls, challenge):\n        \"\"\"\n        This method is in used to access the data of a challenge in a format processable by the front end.\n\n        :param challenge:\n        :return: Challenge object, data dictionary to be returned to the user\n        \"\"\"\n        challenge = DynamicChallenge.query.filter_by(id=challenge.id).first()\n        data = {\n            \"id\": challenge.id,\n            \"name\": challenge.name,\n            \"value\": challenge.value,\n            \"initial\": challenge.initial,\n            \"decay\": challenge.decay,\n            \"minimum\": challenge.minimum,\n            \"description\": challenge.description,\n            \"connection_info\": challenge.connection_info,\n            \"next_id\": challenge.next_id,\n            \"category\": challenge.category,\n            \"state\": challenge.state,\n            \"max_attempts\": challenge.max_attempts,\n            \"type\": challenge.type,\n            \"type_data\": {\n                \"id\": cls.id,\n                \"name\": cls.name,\n                \"templates\": cls.templates,\n                \"scripts\": cls.scripts,\n            },\n        }\n        return data\n\n    @classmethod\n    def update(cls, challenge, request):\n        \"\"\"\n        This method is used to update the information associated with a challenge. This should be kept strictly to the\n        Challenges table and any child tables.\n\n        :param challenge:\n        :param request:\n        :return:\n        \"\"\"\n        data = request.form or request.get_json()\n\n        for attr, value in data.items():\n            # We need to set these to floats so that the next operations don't operate on strings\n            if attr in (\"initial\", \"minimum\", \"decay\"):\n                value = float(value)\n            setattr(challenge, attr, value)\n\n        return DynamicValueChallenge.calculate_value(challenge)\n\n    @classmethod\n    def solve(cls, user, team, challenge, request):\n        super().solve(user, team, challenge, request)\n\n        DynamicValueChallenge.calculate_value(challenge)\n\n\ndef load(app):\n    upgrade(plugin_name=\"dynamic_challenges\")\n    CHALLENGE_CLASSES[\"dynamic\"] = DynamicValueChallenge\n    register_plugin_assets_directory(\n        app, base_path=\"/plugins/dynamic_challenges/assets/\"\n    )\n", "path": "CTFd/plugins/dynamic_challenges/__init__.py"}], "after_files": [{"content": "from flask import Blueprint\n\nfrom CTFd.models import Challenges, db\nfrom CTFd.plugins import register_plugin_assets_directory\nfrom CTFd.plugins.challenges import CHALLENGE_CLASSES, BaseChallenge\nfrom CTFd.plugins.dynamic_challenges.decay import DECAY_FUNCTIONS, logarithmic\nfrom CTFd.plugins.migrations import upgrade\n\n\nclass DynamicChallenge(Challenges):\n    __mapper_args__ = {\"polymorphic_identity\": \"dynamic\"}\n    id = db.Column(\n        db.Integer, db.ForeignKey(\"challenges.id\", ondelete=\"CASCADE\"), primary_key=True\n    )\n    initial = db.Column(db.Integer, default=0)\n    minimum = db.Column(db.Integer, default=0)\n    decay = db.Column(db.Integer, default=0)\n    function = db.Column(db.String(32), default=\"logarithmic\")\n\n    def __init__(self, *args, **kwargs):\n        super(DynamicChallenge, self).__init__(**kwargs)\n        self.value = kwargs[\"initial\"]\n\n\nclass DynamicValueChallenge(BaseChallenge):\n    id = \"dynamic\"  # Unique identifier used to register challenges\n    name = \"dynamic\"  # Name of a challenge type\n    templates = (\n        {  # Handlebars templates used for each aspect of challenge editing & viewing\n            \"create\": \"/plugins/dynamic_challenges/assets/create.html\",\n            \"update\": \"/plugins/dynamic_challenges/assets/update.html\",\n            \"view\": \"/plugins/dynamic_challenges/assets/view.html\",\n        }\n    )\n    scripts = {  # Scripts that are loaded when a template is loaded\n        \"create\": \"/plugins/dynamic_challenges/assets/create.js\",\n        \"update\": \"/plugins/dynamic_challenges/assets/update.js\",\n        \"view\": \"/plugins/dynamic_challenges/assets/view.js\",\n    }\n    # Route at which files are accessible. This must be registered using register_plugin_assets_directory()\n    route = \"/plugins/dynamic_challenges/assets/\"\n    # Blueprint used to access the static_folder directory.\n    blueprint = Blueprint(\n        \"dynamic_challenges\",\n        __name__,\n        template_folder=\"templates\",\n        static_folder=\"assets\",\n    )\n    challenge_model = DynamicChallenge\n\n    @classmethod\n    def calculate_value(cls, challenge):\n        f = DECAY_FUNCTIONS.get(challenge.function, logarithmic)\n        value = f(challenge)\n\n        challenge.value = value\n        db.session.commit()\n        return challenge\n\n    @classmethod\n    def read(cls, challenge):\n        \"\"\"\n        This method is in used to access the data of a challenge in a format processable by the front end.\n\n        :param challenge:\n        :return: Challenge object, data dictionary to be returned to the user\n        \"\"\"\n        challenge = DynamicChallenge.query.filter_by(id=challenge.id).first()\n        data = {\n            \"id\": challenge.id,\n            \"name\": challenge.name,\n            \"value\": challenge.value,\n            \"initial\": challenge.initial,\n            \"decay\": challenge.decay,\n            \"minimum\": challenge.minimum,\n            \"function\": challenge.function,\n            \"description\": challenge.description,\n            \"connection_info\": challenge.connection_info,\n            \"next_id\": challenge.next_id,\n            \"category\": challenge.category,\n            \"state\": challenge.state,\n            \"max_attempts\": challenge.max_attempts,\n            \"type\": challenge.type,\n            \"type_data\": {\n                \"id\": cls.id,\n                \"name\": cls.name,\n                \"templates\": cls.templates,\n                \"scripts\": cls.scripts,\n            },\n        }\n        return data\n\n    @classmethod\n    def update(cls, challenge, request):\n        \"\"\"\n        This method is used to update the information associated with a challenge. This should be kept strictly to the\n        Challenges table and any child tables.\n\n        :param challenge:\n        :param request:\n        :return:\n        \"\"\"\n        data = request.form or request.get_json()\n\n        for attr, value in data.items():\n            # We need to set these to floats so that the next operations don't operate on strings\n            if attr in (\"initial\", \"minimum\", \"decay\"):\n                value = float(value)\n            setattr(challenge, attr, value)\n\n        return DynamicValueChallenge.calculate_value(challenge)\n\n    @classmethod\n    def solve(cls, user, team, challenge, request):\n        super().solve(user, team, challenge, request)\n\n        DynamicValueChallenge.calculate_value(challenge)\n\n\ndef load(app):\n    upgrade(plugin_name=\"dynamic_challenges\")\n    CHALLENGE_CLASSES[\"dynamic\"] = DynamicValueChallenge\n    register_plugin_assets_directory(\n        app, base_path=\"/plugins/dynamic_challenges/assets/\"\n    )\n", "path": "CTFd/plugins/dynamic_challenges/__init__.py"}]}