prompt: We are currently solving the following issue within our repository. Here is the issue text:
  --- BEGIN ISSUE ---
  unlocks api does not check already unlocked hints 
  There is not check in the unlocks api for already unlocked hints in the file [unlocks.py](https://github.com/CTFd/CTFd/blob/master/CTFd/api/v1/unlocks.py)
  
  It is possible to unlock multiple times the same hint by just calling the api.
  
  --- 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/api/v1/unlocks.py`
  Content:
  ```
  1 from flask import request
  2 from flask_restplus import Namespace, Resource
  3 
  4 from CTFd.cache import clear_standings
  5 from CTFd.models import Unlocks, db, get_class_by_tablename
  6 from CTFd.schemas.awards import AwardSchema
  7 from CTFd.schemas.unlocks import UnlockSchema
  8 from CTFd.utils.decorators import (
  9     admins_only,
  10     authed_only,
  11     during_ctf_time_only,
  12     require_verified_emails,
  13 )
  14 from CTFd.utils.user import get_current_user
  15 
  16 unlocks_namespace = Namespace("unlocks", description="Endpoint to retrieve Unlocks")
  17 
  18 
  19 @unlocks_namespace.route("")
  20 class UnlockList(Resource):
  21     @admins_only
  22     def get(self):
  23         hints = Unlocks.query.all()
  24         schema = UnlockSchema()
  25         response = schema.dump(hints)
  26 
  27         if response.errors:
  28             return {"success": False, "errors": response.errors}, 400
  29 
  30         return {"success": True, "data": response.data}
  31 
  32     @during_ctf_time_only
  33     @require_verified_emails
  34     @authed_only
  35     def post(self):
  36         req = request.get_json()
  37         user = get_current_user()
  38 
  39         req["user_id"] = user.id
  40         req["team_id"] = user.team_id
  41 
  42         Model = get_class_by_tablename(req["type"])
  43         target = Model.query.filter_by(id=req["target"]).first_or_404()
  44 
  45         if target.cost > user.score:
  46             return (
  47                 {
  48                     "success": False,
  49                     "errors": {
  50                         "score": "You do not have enough points to unlock this hint"
  51                     },
  52                 },
  53                 400,
  54             )
  55 
  56         schema = UnlockSchema()
  57         response = schema.load(req, session=db.session)
  58 
  59         if response.errors:
  60             return {"success": False, "errors": response.errors}, 400
  61 
  62         db.session.add(response.data)
  63 
  64         award_schema = AwardSchema()
  65         award = {
  66             "user_id": user.id,
  67             "team_id": user.team_id,
  68             "name": target.name,
  69             "description": target.description,
  70             "value": (-target.cost),
  71             "category": target.category,
  72         }
  73 
  74         award = award_schema.load(award)
  75         db.session.add(award.data)
  76         db.session.commit()
  77         clear_standings()
  78 
  79         response = schema.dump(response.data)
  80 
  81         return {"success": True, "data": response.data}
  82
  ```
  --- 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/api/v1/unlocks.py b/CTFd/api/v1/unlocks.py
  --- a/CTFd/api/v1/unlocks.py
  +++ b/CTFd/api/v1/unlocks.py
  @@ -59,6 +59,16 @@
           if response.errors:
               return {"success": False, "errors": response.errors}, 400
   
  +        existing = Unlocks.query.filter_by(**req).first()
  +        if existing:
  +            return (
  +                {
  +                    "success": False,
  +                    "errors": {"target": "You've already unlocked this this target"},
  +                },
  +                400,
  +            )
  +
           db.session.add(response.data)
   
           award_schema = AwardSchema()
  
verification_info: {"golden_diff": "diff --git a/CTFd/api/v1/unlocks.py b/CTFd/api/v1/unlocks.py\n--- a/CTFd/api/v1/unlocks.py\n+++ b/CTFd/api/v1/unlocks.py\n@@ -59,6 +59,16 @@\n         if response.errors:\n             return {\"success\": False, \"errors\": response.errors}, 400\n \n+        existing = Unlocks.query.filter_by(**req).first()\n+        if existing:\n+            return (\n+                {\n+                    \"success\": False,\n+                    \"errors\": {\"target\": \"You've already unlocked this this target\"},\n+                },\n+                400,\n+            )\n+\n         db.session.add(response.data)\n \n         award_schema = AwardSchema()\n", "issue": "unlocks api does not check already unlocked hints \nThere is not check in the unlocks api for already unlocked hints in the file [unlocks.py](https://github.com/CTFd/CTFd/blob/master/CTFd/api/v1/unlocks.py)\r\n\r\nIt is possible to unlock multiple times the same hint by just calling the api.\n", "before_files": [{"content": "from flask import request\nfrom flask_restplus import Namespace, Resource\n\nfrom CTFd.cache import clear_standings\nfrom CTFd.models import Unlocks, db, get_class_by_tablename\nfrom CTFd.schemas.awards import AwardSchema\nfrom CTFd.schemas.unlocks import UnlockSchema\nfrom CTFd.utils.decorators import (\n    admins_only,\n    authed_only,\n    during_ctf_time_only,\n    require_verified_emails,\n)\nfrom CTFd.utils.user import get_current_user\n\nunlocks_namespace = Namespace(\"unlocks\", description=\"Endpoint to retrieve Unlocks\")\n\n\n@unlocks_namespace.route(\"\")\nclass UnlockList(Resource):\n    @admins_only\n    def get(self):\n        hints = Unlocks.query.all()\n        schema = UnlockSchema()\n        response = schema.dump(hints)\n\n        if response.errors:\n            return {\"success\": False, \"errors\": response.errors}, 400\n\n        return {\"success\": True, \"data\": response.data}\n\n    @during_ctf_time_only\n    @require_verified_emails\n    @authed_only\n    def post(self):\n        req = request.get_json()\n        user = get_current_user()\n\n        req[\"user_id\"] = user.id\n        req[\"team_id\"] = user.team_id\n\n        Model = get_class_by_tablename(req[\"type\"])\n        target = Model.query.filter_by(id=req[\"target\"]).first_or_404()\n\n        if target.cost > user.score:\n            return (\n                {\n                    \"success\": False,\n                    \"errors\": {\n                        \"score\": \"You do not have enough points to unlock this hint\"\n                    },\n                },\n                400,\n            )\n\n        schema = UnlockSchema()\n        response = schema.load(req, session=db.session)\n\n        if response.errors:\n            return {\"success\": False, \"errors\": response.errors}, 400\n\n        db.session.add(response.data)\n\n        award_schema = AwardSchema()\n        award = {\n            \"user_id\": user.id,\n            \"team_id\": user.team_id,\n            \"name\": target.name,\n            \"description\": target.description,\n            \"value\": (-target.cost),\n            \"category\": target.category,\n        }\n\n        award = award_schema.load(award)\n        db.session.add(award.data)\n        db.session.commit()\n        clear_standings()\n\n        response = schema.dump(response.data)\n\n        return {\"success\": True, \"data\": response.data}\n", "path": "CTFd/api/v1/unlocks.py"}], "after_files": [{"content": "from flask import request\nfrom flask_restplus import Namespace, Resource\n\nfrom CTFd.cache import clear_standings\nfrom CTFd.models import Unlocks, db, get_class_by_tablename\nfrom CTFd.schemas.awards import AwardSchema\nfrom CTFd.schemas.unlocks import UnlockSchema\nfrom CTFd.utils.decorators import (\n    admins_only,\n    authed_only,\n    during_ctf_time_only,\n    require_verified_emails,\n)\nfrom CTFd.utils.user import get_current_user\n\nunlocks_namespace = Namespace(\"unlocks\", description=\"Endpoint to retrieve Unlocks\")\n\n\n@unlocks_namespace.route(\"\")\nclass UnlockList(Resource):\n    @admins_only\n    def get(self):\n        hints = Unlocks.query.all()\n        schema = UnlockSchema()\n        response = schema.dump(hints)\n\n        if response.errors:\n            return {\"success\": False, \"errors\": response.errors}, 400\n\n        return {\"success\": True, \"data\": response.data}\n\n    @during_ctf_time_only\n    @require_verified_emails\n    @authed_only\n    def post(self):\n        req = request.get_json()\n        user = get_current_user()\n\n        req[\"user_id\"] = user.id\n        req[\"team_id\"] = user.team_id\n\n        Model = get_class_by_tablename(req[\"type\"])\n        target = Model.query.filter_by(id=req[\"target\"]).first_or_404()\n\n        if target.cost > user.score:\n            return (\n                {\n                    \"success\": False,\n                    \"errors\": {\n                        \"score\": \"You do not have enough points to unlock this hint\"\n                    },\n                },\n                400,\n            )\n\n        schema = UnlockSchema()\n        response = schema.load(req, session=db.session)\n\n        if response.errors:\n            return {\"success\": False, \"errors\": response.errors}, 400\n\n        existing = Unlocks.query.filter_by(**req).first()\n        if existing:\n            return (\n                {\n                    \"success\": False,\n                    \"errors\": {\"target\": \"You've already unlocked this this target\"},\n                },\n                400,\n            )\n\n        db.session.add(response.data)\n\n        award_schema = AwardSchema()\n        award = {\n            \"user_id\": user.id,\n            \"team_id\": user.team_id,\n            \"name\": target.name,\n            \"description\": target.description,\n            \"value\": (-target.cost),\n            \"category\": target.category,\n        }\n\n        award = award_schema.load(award)\n        db.session.add(award.data)\n        db.session.commit()\n        clear_standings()\n\n        response = schema.dump(response.data)\n\n        return {\"success\": True, \"data\": response.data}\n", "path": "CTFd/api/v1/unlocks.py"}]}