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()

```

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()

{"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"}]}