We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
Expose unix_time_to_utc to Jinja
I have a need for `unix_time_to_utc` in the Jinja template but it isn't currently exposed. Ultimately it's to convert between an Epoch timestamp to ISO 8601. 

--- 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/utils/initialization/__init__.py`
Content:
```
1 import datetime
2 import logging
3 import os
4 import sys
5 
6 from flask import abort, redirect, render_template, request, session, url_for
7 from sqlalchemy.exc import IntegrityError, InvalidRequestError
8 from werkzeug.middleware.dispatcher import DispatcherMiddleware
9 
10 from CTFd.cache import clear_user_recent_ips
11 from CTFd.exceptions import UserNotFoundException, UserTokenExpiredException
12 from CTFd.models import Tracking, db
13 from CTFd.utils import config, get_config, import_in_progress, markdown
14 from CTFd.utils.config import (
15     can_send_mail,
16     ctf_logo,
17     ctf_name,
18     ctf_theme,
19     integrations,
20     is_setup,
21 )
22 from CTFd.utils.config.pages import get_pages
23 from CTFd.utils.dates import isoformat, unix_time, unix_time_millis
24 from CTFd.utils.events import EventManager, RedisEventManager
25 from CTFd.utils.humanize.words import pluralize
26 from CTFd.utils.modes import generate_account_url, get_mode_as_word
27 from CTFd.utils.plugins import (
28     get_configurable_plugins,
29     get_registered_admin_scripts,
30     get_registered_admin_stylesheets,
31     get_registered_scripts,
32     get_registered_stylesheets,
33 )
34 from CTFd.utils.security.auth import login_user, logout_user, lookup_user_token
35 from CTFd.utils.security.csrf import generate_nonce
36 from CTFd.utils.user import (
37     authed,
38     get_current_team_attrs,
39     get_current_user_attrs,
40     get_current_user_recent_ips,
41     get_ip,
42     is_admin,
43 )
44 
45 
46 def init_cli(app):
47     from CTFd.cli import _cli
48 
49     app.register_blueprint(_cli, cli_group=None)
50 
51 
52 def init_template_filters(app):
53     app.jinja_env.filters["markdown"] = markdown
54     app.jinja_env.filters["unix_time"] = unix_time
55     app.jinja_env.filters["unix_time_millis"] = unix_time_millis
56     app.jinja_env.filters["isoformat"] = isoformat
57     app.jinja_env.filters["pluralize"] = pluralize
58 
59 
60 def init_template_globals(app):
61     from CTFd.constants import JINJA_ENUMS  # noqa: I001
62     from CTFd.constants.assets import Assets
63     from CTFd.constants.config import Configs
64     from CTFd.constants.plugins import Plugins
65     from CTFd.constants.sessions import Session
66     from CTFd.constants.static import Static
67     from CTFd.constants.users import User
68     from CTFd.constants.teams import Team
69     from CTFd.forms import Forms
70     from CTFd.utils.config.visibility import (
71         accounts_visible,
72         challenges_visible,
73         registration_visible,
74         scores_visible,
75     )
76     from CTFd.utils.countries import get_countries, lookup_country_code
77     from CTFd.utils.countries.geoip import lookup_ip_address, lookup_ip_address_city
78 
79     app.jinja_env.globals.update(config=config)
80     app.jinja_env.globals.update(get_pages=get_pages)
81     app.jinja_env.globals.update(can_send_mail=can_send_mail)
82     app.jinja_env.globals.update(get_ctf_name=ctf_name)
83     app.jinja_env.globals.update(get_ctf_logo=ctf_logo)
84     app.jinja_env.globals.update(get_ctf_theme=ctf_theme)
85     app.jinja_env.globals.update(get_configurable_plugins=get_configurable_plugins)
86     app.jinja_env.globals.update(get_registered_scripts=get_registered_scripts)
87     app.jinja_env.globals.update(get_registered_stylesheets=get_registered_stylesheets)
88     app.jinja_env.globals.update(
89         get_registered_admin_scripts=get_registered_admin_scripts
90     )
91     app.jinja_env.globals.update(
92         get_registered_admin_stylesheets=get_registered_admin_stylesheets
93     )
94     app.jinja_env.globals.update(get_config=get_config)
95     app.jinja_env.globals.update(generate_account_url=generate_account_url)
96     app.jinja_env.globals.update(get_countries=get_countries)
97     app.jinja_env.globals.update(lookup_country_code=lookup_country_code)
98     app.jinja_env.globals.update(lookup_ip_address=lookup_ip_address)
99     app.jinja_env.globals.update(lookup_ip_address_city=lookup_ip_address_city)
100     app.jinja_env.globals.update(accounts_visible=accounts_visible)
101     app.jinja_env.globals.update(challenges_visible=challenges_visible)
102     app.jinja_env.globals.update(registration_visible=registration_visible)
103     app.jinja_env.globals.update(scores_visible=scores_visible)
104     app.jinja_env.globals.update(get_mode_as_word=get_mode_as_word)
105     app.jinja_env.globals.update(integrations=integrations)
106     app.jinja_env.globals.update(authed=authed)
107     app.jinja_env.globals.update(is_admin=is_admin)
108     app.jinja_env.globals.update(get_current_user_attrs=get_current_user_attrs)
109     app.jinja_env.globals.update(get_current_team_attrs=get_current_team_attrs)
110     app.jinja_env.globals.update(get_ip=get_ip)
111     app.jinja_env.globals.update(Assets=Assets)
112     app.jinja_env.globals.update(Configs=Configs)
113     app.jinja_env.globals.update(Plugins=Plugins)
114     app.jinja_env.globals.update(Session=Session)
115     app.jinja_env.globals.update(Static=Static)
116     app.jinja_env.globals.update(Forms=Forms)
117     app.jinja_env.globals.update(User=User)
118     app.jinja_env.globals.update(Team=Team)
119 
120     # Add in JinjaEnums
121     # The reason this exists is that on double import, JinjaEnums are not reinitialized
122     # Thus, if you try to create two jinja envs (e.g. during testing), sometimes
123     # an Enum will not be available to Jinja.
124     # Instead we can just directly grab them from the persisted global dictionary.
125     for k, v in JINJA_ENUMS.items():
126         # .update() can't be used here because it would use the literal value k
127         app.jinja_env.globals[k] = v
128 
129 
130 def init_logs(app):
131     logger_submissions = logging.getLogger("submissions")
132     logger_logins = logging.getLogger("logins")
133     logger_registrations = logging.getLogger("registrations")
134 
135     logger_submissions.setLevel(logging.INFO)
136     logger_logins.setLevel(logging.INFO)
137     logger_registrations.setLevel(logging.INFO)
138 
139     log_dir = app.config["LOG_FOLDER"]
140     if not os.path.exists(log_dir):
141         os.makedirs(log_dir)
142 
143     logs = {
144         "submissions": os.path.join(log_dir, "submissions.log"),
145         "logins": os.path.join(log_dir, "logins.log"),
146         "registrations": os.path.join(log_dir, "registrations.log"),
147     }
148 
149     try:
150         for log in logs.values():
151             if not os.path.exists(log):
152                 open(log, "a").close()
153 
154         submission_log = logging.handlers.RotatingFileHandler(
155             logs["submissions"], maxBytes=10485760, backupCount=5
156         )
157         login_log = logging.handlers.RotatingFileHandler(
158             logs["logins"], maxBytes=10485760, backupCount=5
159         )
160         registration_log = logging.handlers.RotatingFileHandler(
161             logs["registrations"], maxBytes=10485760, backupCount=5
162         )
163 
164         logger_submissions.addHandler(submission_log)
165         logger_logins.addHandler(login_log)
166         logger_registrations.addHandler(registration_log)
167     except IOError:
168         pass
169 
170     stdout = logging.StreamHandler(stream=sys.stdout)
171 
172     logger_submissions.addHandler(stdout)
173     logger_logins.addHandler(stdout)
174     logger_registrations.addHandler(stdout)
175 
176     logger_submissions.propagate = 0
177     logger_logins.propagate = 0
178     logger_registrations.propagate = 0
179 
180 
181 def init_events(app):
182     if app.config.get("CACHE_TYPE") == "redis":
183         app.events_manager = RedisEventManager()
184     elif app.config.get("CACHE_TYPE") == "filesystem":
185         app.events_manager = EventManager()
186     else:
187         app.events_manager = EventManager()
188     app.events_manager.listen()
189 
190 
191 def init_request_processors(app):
192     @app.url_defaults
193     def inject_theme(endpoint, values):
194         if "theme" not in values and app.url_map.is_endpoint_expecting(
195             endpoint, "theme"
196         ):
197             values["theme"] = ctf_theme()
198 
199     @app.before_request
200     def needs_setup():
201         if import_in_progress():
202             if request.endpoint == "admin.import_ctf":
203                 return
204             else:
205                 return "Import currently in progress", 403
206         if is_setup() is False:
207             if request.endpoint in (
208                 "views.setup",
209                 "views.integrations",
210                 "views.themes",
211                 "views.files",
212                 "views.healthcheck",
213                 "views.robots",
214             ):
215                 return
216             else:
217                 return redirect(url_for("views.setup"))
218 
219     @app.before_request
220     def tracker():
221         if request.endpoint == "views.themes":
222             return
223 
224         if import_in_progress():
225             if request.endpoint == "admin.import_ctf":
226                 return
227             else:
228                 return "Import currently in progress", 403
229 
230         if authed():
231             user_ips = get_current_user_recent_ips()
232             ip = get_ip()
233 
234             track = None
235             if (ip not in user_ips) or (request.method != "GET"):
236                 track = Tracking.query.filter_by(
237                     ip=get_ip(), user_id=session["id"]
238                 ).first()
239 
240                 if track:
241                     track.date = datetime.datetime.utcnow()
242                 else:
243                     track = Tracking(ip=get_ip(), user_id=session["id"])
244                     db.session.add(track)
245 
246             if track:
247                 try:
248                     db.session.commit()
249                 except (InvalidRequestError, IntegrityError):
250                     db.session.rollback()
251                     db.session.close()
252                     logout_user()
253                 else:
254                     clear_user_recent_ips(user_id=session["id"])
255 
256     @app.before_request
257     def banned():
258         if request.endpoint == "views.themes":
259             return
260 
261         if authed():
262             user = get_current_user_attrs()
263             team = get_current_team_attrs()
264 
265             if user and user.banned:
266                 return (
267                     render_template(
268                         "errors/403.html", error="You have been banned from this CTF"
269                     ),
270                     403,
271                 )
272 
273             if team and team.banned:
274                 return (
275                     render_template(
276                         "errors/403.html",
277                         error="Your team has been banned from this CTF",
278                     ),
279                     403,
280                 )
281 
282     @app.before_request
283     def tokens():
284         token = request.headers.get("Authorization")
285         if token and (
286             request.mimetype == "application/json"
287             # Specially allow multipart/form-data for file uploads
288             or (
289                 request.endpoint == "api.files_files_list"
290                 and request.method == "POST"
291                 and request.mimetype == "multipart/form-data"
292             )
293         ):
294             try:
295                 token_type, token = token.split(" ", 1)
296                 user = lookup_user_token(token)
297             except UserNotFoundException:
298                 abort(401)
299             except UserTokenExpiredException:
300                 abort(401, description="Your access token has expired")
301             except Exception:
302                 abort(401)
303             else:
304                 login_user(user)
305 
306     @app.before_request
307     def csrf():
308         try:
309             func = app.view_functions[request.endpoint]
310         except KeyError:
311             abort(404)
312         if hasattr(func, "_bypass_csrf"):
313             return
314         if request.headers.get("Authorization"):
315             return
316         if not session.get("nonce"):
317             session["nonce"] = generate_nonce()
318         if request.method not in ("GET", "HEAD", "OPTIONS", "TRACE"):
319             if request.content_type == "application/json":
320                 if session["nonce"] != request.headers.get("CSRF-Token"):
321                     abort(403)
322             if request.content_type != "application/json":
323                 if session["nonce"] != request.form.get("nonce"):
324                     abort(403)
325 
326     application_root = app.config.get("APPLICATION_ROOT")
327     if application_root != "/":
328 
329         @app.before_request
330         def force_subdirectory_redirect():
331             if request.path.startswith(application_root) is False:
332                 return redirect(
333                     application_root + request.script_root + request.full_path
334                 )
335 
336         app.wsgi_app = DispatcherMiddleware(app.wsgi_app, {application_root: app})
337
```
--- 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/utils/initialization/__init__.py b/CTFd/utils/initialization/__init__.py
--- a/CTFd/utils/initialization/__init__.py
+++ b/CTFd/utils/initialization/__init__.py
@@ -20,7 +20,7 @@
     is_setup,
 )
 from CTFd.utils.config.pages import get_pages
-from CTFd.utils.dates import isoformat, unix_time, unix_time_millis
+from CTFd.utils.dates import isoformat, unix_time, unix_time_millis, unix_time_to_utc
 from CTFd.utils.events import EventManager, RedisEventManager
 from CTFd.utils.humanize.words import pluralize
 from CTFd.utils.modes import generate_account_url, get_mode_as_word
@@ -53,6 +53,7 @@
     app.jinja_env.filters["markdown"] = markdown
     app.jinja_env.filters["unix_time"] = unix_time
     app.jinja_env.filters["unix_time_millis"] = unix_time_millis
+    app.jinja_env.filters["unix_time_to_utc"] = unix_time_to_utc
     app.jinja_env.filters["isoformat"] = isoformat
     app.jinja_env.filters["pluralize"] = pluralize

{"golden_diff": "diff --git a/CTFd/utils/initialization/__init__.py b/CTFd/utils/initialization/__init__.py\n--- a/CTFd/utils/initialization/__init__.py\n+++ b/CTFd/utils/initialization/__init__.py\n@@ -20,7 +20,7 @@\n     is_setup,\n )\n from CTFd.utils.config.pages import get_pages\n-from CTFd.utils.dates import isoformat, unix_time, unix_time_millis\n+from CTFd.utils.dates import isoformat, unix_time, unix_time_millis, unix_time_to_utc\n from CTFd.utils.events import EventManager, RedisEventManager\n from CTFd.utils.humanize.words import pluralize\n from CTFd.utils.modes import generate_account_url, get_mode_as_word\n@@ -53,6 +53,7 @@\n     app.jinja_env.filters[\"markdown\"] = markdown\n     app.jinja_env.filters[\"unix_time\"] = unix_time\n     app.jinja_env.filters[\"unix_time_millis\"] = unix_time_millis\n+    app.jinja_env.filters[\"unix_time_to_utc\"] = unix_time_to_utc\n     app.jinja_env.filters[\"isoformat\"] = isoformat\n     app.jinja_env.filters[\"pluralize\"] = pluralize\n", "issue": "Expose unix_time_to_utc to Jinja\nI have a need for `unix_time_to_utc` in the Jinja template but it isn't currently exposed. Ultimately it's to convert between an Epoch timestamp to ISO 8601. \n", "before_files": [{"content": "import datetime\nimport logging\nimport os\nimport sys\n\nfrom flask import abort, redirect, render_template, request, session, url_for\nfrom sqlalchemy.exc import IntegrityError, InvalidRequestError\nfrom werkzeug.middleware.dispatcher import DispatcherMiddleware\n\nfrom CTFd.cache import clear_user_recent_ips\nfrom CTFd.exceptions import UserNotFoundException, UserTokenExpiredException\nfrom CTFd.models import Tracking, db\nfrom CTFd.utils import config, get_config, import_in_progress, markdown\nfrom CTFd.utils.config import (\n    can_send_mail,\n    ctf_logo,\n    ctf_name,\n    ctf_theme,\n    integrations,\n    is_setup,\n)\nfrom CTFd.utils.config.pages import get_pages\nfrom CTFd.utils.dates import isoformat, unix_time, unix_time_millis\nfrom CTFd.utils.events import EventManager, RedisEventManager\nfrom CTFd.utils.humanize.words import pluralize\nfrom CTFd.utils.modes import generate_account_url, get_mode_as_word\nfrom CTFd.utils.plugins import (\n    get_configurable_plugins,\n    get_registered_admin_scripts,\n    get_registered_admin_stylesheets,\n    get_registered_scripts,\n    get_registered_stylesheets,\n)\nfrom CTFd.utils.security.auth import login_user, logout_user, lookup_user_token\nfrom CTFd.utils.security.csrf import generate_nonce\nfrom CTFd.utils.user import (\n    authed,\n    get_current_team_attrs,\n    get_current_user_attrs,\n    get_current_user_recent_ips,\n    get_ip,\n    is_admin,\n)\n\n\ndef init_cli(app):\n    from CTFd.cli import _cli\n\n    app.register_blueprint(_cli, cli_group=None)\n\n\ndef init_template_filters(app):\n    app.jinja_env.filters[\"markdown\"] = markdown\n    app.jinja_env.filters[\"unix_time\"] = unix_time\n    app.jinja_env.filters[\"unix_time_millis\"] = unix_time_millis\n    app.jinja_env.filters[\"isoformat\"] = isoformat\n    app.jinja_env.filters[\"pluralize\"] = pluralize\n\n\ndef init_template_globals(app):\n    from CTFd.constants import JINJA_ENUMS  # noqa: I001\n    from CTFd.constants.assets import Assets\n    from CTFd.constants.config import Configs\n    from CTFd.constants.plugins import Plugins\n    from CTFd.constants.sessions import Session\n    from CTFd.constants.static import Static\n    from CTFd.constants.users import User\n    from CTFd.constants.teams import Team\n    from CTFd.forms import Forms\n    from CTFd.utils.config.visibility import (\n        accounts_visible,\n        challenges_visible,\n        registration_visible,\n        scores_visible,\n    )\n    from CTFd.utils.countries import get_countries, lookup_country_code\n    from CTFd.utils.countries.geoip import lookup_ip_address, lookup_ip_address_city\n\n    app.jinja_env.globals.update(config=config)\n    app.jinja_env.globals.update(get_pages=get_pages)\n    app.jinja_env.globals.update(can_send_mail=can_send_mail)\n    app.jinja_env.globals.update(get_ctf_name=ctf_name)\n    app.jinja_env.globals.update(get_ctf_logo=ctf_logo)\n    app.jinja_env.globals.update(get_ctf_theme=ctf_theme)\n    app.jinja_env.globals.update(get_configurable_plugins=get_configurable_plugins)\n    app.jinja_env.globals.update(get_registered_scripts=get_registered_scripts)\n    app.jinja_env.globals.update(get_registered_stylesheets=get_registered_stylesheets)\n    app.jinja_env.globals.update(\n        get_registered_admin_scripts=get_registered_admin_scripts\n    )\n    app.jinja_env.globals.update(\n        get_registered_admin_stylesheets=get_registered_admin_stylesheets\n    )\n    app.jinja_env.globals.update(get_config=get_config)\n    app.jinja_env.globals.update(generate_account_url=generate_account_url)\n    app.jinja_env.globals.update(get_countries=get_countries)\n    app.jinja_env.globals.update(lookup_country_code=lookup_country_code)\n    app.jinja_env.globals.update(lookup_ip_address=lookup_ip_address)\n    app.jinja_env.globals.update(lookup_ip_address_city=lookup_ip_address_city)\n    app.jinja_env.globals.update(accounts_visible=accounts_visible)\n    app.jinja_env.globals.update(challenges_visible=challenges_visible)\n    app.jinja_env.globals.update(registration_visible=registration_visible)\n    app.jinja_env.globals.update(scores_visible=scores_visible)\n    app.jinja_env.globals.update(get_mode_as_word=get_mode_as_word)\n    app.jinja_env.globals.update(integrations=integrations)\n    app.jinja_env.globals.update(authed=authed)\n    app.jinja_env.globals.update(is_admin=is_admin)\n    app.jinja_env.globals.update(get_current_user_attrs=get_current_user_attrs)\n    app.jinja_env.globals.update(get_current_team_attrs=get_current_team_attrs)\n    app.jinja_env.globals.update(get_ip=get_ip)\n    app.jinja_env.globals.update(Assets=Assets)\n    app.jinja_env.globals.update(Configs=Configs)\n    app.jinja_env.globals.update(Plugins=Plugins)\n    app.jinja_env.globals.update(Session=Session)\n    app.jinja_env.globals.update(Static=Static)\n    app.jinja_env.globals.update(Forms=Forms)\n    app.jinja_env.globals.update(User=User)\n    app.jinja_env.globals.update(Team=Team)\n\n    # Add in JinjaEnums\n    # The reason this exists is that on double import, JinjaEnums are not reinitialized\n    # Thus, if you try to create two jinja envs (e.g. during testing), sometimes\n    # an Enum will not be available to Jinja.\n    # Instead we can just directly grab them from the persisted global dictionary.\n    for k, v in JINJA_ENUMS.items():\n        # .update() can't be used here because it would use the literal value k\n        app.jinja_env.globals[k] = v\n\n\ndef init_logs(app):\n    logger_submissions = logging.getLogger(\"submissions\")\n    logger_logins = logging.getLogger(\"logins\")\n    logger_registrations = logging.getLogger(\"registrations\")\n\n    logger_submissions.setLevel(logging.INFO)\n    logger_logins.setLevel(logging.INFO)\n    logger_registrations.setLevel(logging.INFO)\n\n    log_dir = app.config[\"LOG_FOLDER\"]\n    if not os.path.exists(log_dir):\n        os.makedirs(log_dir)\n\n    logs = {\n        \"submissions\": os.path.join(log_dir, \"submissions.log\"),\n        \"logins\": os.path.join(log_dir, \"logins.log\"),\n        \"registrations\": os.path.join(log_dir, \"registrations.log\"),\n    }\n\n    try:\n        for log in logs.values():\n            if not os.path.exists(log):\n                open(log, \"a\").close()\n\n        submission_log = logging.handlers.RotatingFileHandler(\n            logs[\"submissions\"], maxBytes=10485760, backupCount=5\n        )\n        login_log = logging.handlers.RotatingFileHandler(\n            logs[\"logins\"], maxBytes=10485760, backupCount=5\n        )\n        registration_log = logging.handlers.RotatingFileHandler(\n            logs[\"registrations\"], maxBytes=10485760, backupCount=5\n        )\n\n        logger_submissions.addHandler(submission_log)\n        logger_logins.addHandler(login_log)\n        logger_registrations.addHandler(registration_log)\n    except IOError:\n        pass\n\n    stdout = logging.StreamHandler(stream=sys.stdout)\n\n    logger_submissions.addHandler(stdout)\n    logger_logins.addHandler(stdout)\n    logger_registrations.addHandler(stdout)\n\n    logger_submissions.propagate = 0\n    logger_logins.propagate = 0\n    logger_registrations.propagate = 0\n\n\ndef init_events(app):\n    if app.config.get(\"CACHE_TYPE\") == \"redis\":\n        app.events_manager = RedisEventManager()\n    elif app.config.get(\"CACHE_TYPE\") == \"filesystem\":\n        app.events_manager = EventManager()\n    else:\n        app.events_manager = EventManager()\n    app.events_manager.listen()\n\n\ndef init_request_processors(app):\n    @app.url_defaults\n    def inject_theme(endpoint, values):\n        if \"theme\" not in values and app.url_map.is_endpoint_expecting(\n            endpoint, \"theme\"\n        ):\n            values[\"theme\"] = ctf_theme()\n\n    @app.before_request\n    def needs_setup():\n        if import_in_progress():\n            if request.endpoint == \"admin.import_ctf\":\n                return\n            else:\n                return \"Import currently in progress\", 403\n        if is_setup() is False:\n            if request.endpoint in (\n                \"views.setup\",\n                \"views.integrations\",\n                \"views.themes\",\n                \"views.files\",\n                \"views.healthcheck\",\n                \"views.robots\",\n            ):\n                return\n            else:\n                return redirect(url_for(\"views.setup\"))\n\n    @app.before_request\n    def tracker():\n        if request.endpoint == \"views.themes\":\n            return\n\n        if import_in_progress():\n            if request.endpoint == \"admin.import_ctf\":\n                return\n            else:\n                return \"Import currently in progress\", 403\n\n        if authed():\n            user_ips = get_current_user_recent_ips()\n            ip = get_ip()\n\n            track = None\n            if (ip not in user_ips) or (request.method != \"GET\"):\n                track = Tracking.query.filter_by(\n                    ip=get_ip(), user_id=session[\"id\"]\n                ).first()\n\n                if track:\n                    track.date = datetime.datetime.utcnow()\n                else:\n                    track = Tracking(ip=get_ip(), user_id=session[\"id\"])\n                    db.session.add(track)\n\n            if track:\n                try:\n                    db.session.commit()\n                except (InvalidRequestError, IntegrityError):\n                    db.session.rollback()\n                    db.session.close()\n                    logout_user()\n                else:\n                    clear_user_recent_ips(user_id=session[\"id\"])\n\n    @app.before_request\n    def banned():\n        if request.endpoint == \"views.themes\":\n            return\n\n        if authed():\n            user = get_current_user_attrs()\n            team = get_current_team_attrs()\n\n            if user and user.banned:\n                return (\n                    render_template(\n                        \"errors/403.html\", error=\"You have been banned from this CTF\"\n                    ),\n                    403,\n                )\n\n            if team and team.banned:\n                return (\n                    render_template(\n                        \"errors/403.html\",\n                        error=\"Your team has been banned from this CTF\",\n                    ),\n                    403,\n                )\n\n    @app.before_request\n    def tokens():\n        token = request.headers.get(\"Authorization\")\n        if token and (\n            request.mimetype == \"application/json\"\n            # Specially allow multipart/form-data for file uploads\n            or (\n                request.endpoint == \"api.files_files_list\"\n                and request.method == \"POST\"\n                and request.mimetype == \"multipart/form-data\"\n            )\n        ):\n            try:\n                token_type, token = token.split(\" \", 1)\n                user = lookup_user_token(token)\n            except UserNotFoundException:\n                abort(401)\n            except UserTokenExpiredException:\n                abort(401, description=\"Your access token has expired\")\n            except Exception:\n                abort(401)\n            else:\n                login_user(user)\n\n    @app.before_request\n    def csrf():\n        try:\n            func = app.view_functions[request.endpoint]\n        except KeyError:\n            abort(404)\n        if hasattr(func, \"_bypass_csrf\"):\n            return\n        if request.headers.get(\"Authorization\"):\n            return\n        if not session.get(\"nonce\"):\n            session[\"nonce\"] = generate_nonce()\n        if request.method not in (\"GET\", \"HEAD\", \"OPTIONS\", \"TRACE\"):\n            if request.content_type == \"application/json\":\n                if session[\"nonce\"] != request.headers.get(\"CSRF-Token\"):\n                    abort(403)\n            if request.content_type != \"application/json\":\n                if session[\"nonce\"] != request.form.get(\"nonce\"):\n                    abort(403)\n\n    application_root = app.config.get(\"APPLICATION_ROOT\")\n    if application_root != \"/\":\n\n        @app.before_request\n        def force_subdirectory_redirect():\n            if request.path.startswith(application_root) is False:\n                return redirect(\n                    application_root + request.script_root + request.full_path\n                )\n\n        app.wsgi_app = DispatcherMiddleware(app.wsgi_app, {application_root: app})\n", "path": "CTFd/utils/initialization/__init__.py"}], "after_files": [{"content": "import datetime\nimport logging\nimport os\nimport sys\n\nfrom flask import abort, redirect, render_template, request, session, url_for\nfrom sqlalchemy.exc import IntegrityError, InvalidRequestError\nfrom werkzeug.middleware.dispatcher import DispatcherMiddleware\n\nfrom CTFd.cache import clear_user_recent_ips\nfrom CTFd.exceptions import UserNotFoundException, UserTokenExpiredException\nfrom CTFd.models import Tracking, db\nfrom CTFd.utils import config, get_config, import_in_progress, markdown\nfrom CTFd.utils.config import (\n    can_send_mail,\n    ctf_logo,\n    ctf_name,\n    ctf_theme,\n    integrations,\n    is_setup,\n)\nfrom CTFd.utils.config.pages import get_pages\nfrom CTFd.utils.dates import isoformat, unix_time, unix_time_millis, unix_time_to_utc\nfrom CTFd.utils.events import EventManager, RedisEventManager\nfrom CTFd.utils.humanize.words import pluralize\nfrom CTFd.utils.modes import generate_account_url, get_mode_as_word\nfrom CTFd.utils.plugins import (\n    get_configurable_plugins,\n    get_registered_admin_scripts,\n    get_registered_admin_stylesheets,\n    get_registered_scripts,\n    get_registered_stylesheets,\n)\nfrom CTFd.utils.security.auth import login_user, logout_user, lookup_user_token\nfrom CTFd.utils.security.csrf import generate_nonce\nfrom CTFd.utils.user import (\n    authed,\n    get_current_team_attrs,\n    get_current_user_attrs,\n    get_current_user_recent_ips,\n    get_ip,\n    is_admin,\n)\n\n\ndef init_cli(app):\n    from CTFd.cli import _cli\n\n    app.register_blueprint(_cli, cli_group=None)\n\n\ndef init_template_filters(app):\n    app.jinja_env.filters[\"markdown\"] = markdown\n    app.jinja_env.filters[\"unix_time\"] = unix_time\n    app.jinja_env.filters[\"unix_time_millis\"] = unix_time_millis\n    app.jinja_env.filters[\"unix_time_to_utc\"] = unix_time_to_utc\n    app.jinja_env.filters[\"isoformat\"] = isoformat\n    app.jinja_env.filters[\"pluralize\"] = pluralize\n\n\ndef init_template_globals(app):\n    from CTFd.constants import JINJA_ENUMS  # noqa: I001\n    from CTFd.constants.assets import Assets\n    from CTFd.constants.config import Configs\n    from CTFd.constants.plugins import Plugins\n    from CTFd.constants.sessions import Session\n    from CTFd.constants.static import Static\n    from CTFd.constants.users import User\n    from CTFd.constants.teams import Team\n    from CTFd.forms import Forms\n    from CTFd.utils.config.visibility import (\n        accounts_visible,\n        challenges_visible,\n        registration_visible,\n        scores_visible,\n    )\n    from CTFd.utils.countries import get_countries, lookup_country_code\n    from CTFd.utils.countries.geoip import lookup_ip_address, lookup_ip_address_city\n\n    app.jinja_env.globals.update(config=config)\n    app.jinja_env.globals.update(get_pages=get_pages)\n    app.jinja_env.globals.update(can_send_mail=can_send_mail)\n    app.jinja_env.globals.update(get_ctf_name=ctf_name)\n    app.jinja_env.globals.update(get_ctf_logo=ctf_logo)\n    app.jinja_env.globals.update(get_ctf_theme=ctf_theme)\n    app.jinja_env.globals.update(get_configurable_plugins=get_configurable_plugins)\n    app.jinja_env.globals.update(get_registered_scripts=get_registered_scripts)\n    app.jinja_env.globals.update(get_registered_stylesheets=get_registered_stylesheets)\n    app.jinja_env.globals.update(\n        get_registered_admin_scripts=get_registered_admin_scripts\n    )\n    app.jinja_env.globals.update(\n        get_registered_admin_stylesheets=get_registered_admin_stylesheets\n    )\n    app.jinja_env.globals.update(get_config=get_config)\n    app.jinja_env.globals.update(generate_account_url=generate_account_url)\n    app.jinja_env.globals.update(get_countries=get_countries)\n    app.jinja_env.globals.update(lookup_country_code=lookup_country_code)\n    app.jinja_env.globals.update(lookup_ip_address=lookup_ip_address)\n    app.jinja_env.globals.update(lookup_ip_address_city=lookup_ip_address_city)\n    app.jinja_env.globals.update(accounts_visible=accounts_visible)\n    app.jinja_env.globals.update(challenges_visible=challenges_visible)\n    app.jinja_env.globals.update(registration_visible=registration_visible)\n    app.jinja_env.globals.update(scores_visible=scores_visible)\n    app.jinja_env.globals.update(get_mode_as_word=get_mode_as_word)\n    app.jinja_env.globals.update(integrations=integrations)\n    app.jinja_env.globals.update(authed=authed)\n    app.jinja_env.globals.update(is_admin=is_admin)\n    app.jinja_env.globals.update(get_current_user_attrs=get_current_user_attrs)\n    app.jinja_env.globals.update(get_current_team_attrs=get_current_team_attrs)\n    app.jinja_env.globals.update(get_ip=get_ip)\n    app.jinja_env.globals.update(Assets=Assets)\n    app.jinja_env.globals.update(Configs=Configs)\n    app.jinja_env.globals.update(Plugins=Plugins)\n    app.jinja_env.globals.update(Session=Session)\n    app.jinja_env.globals.update(Static=Static)\n    app.jinja_env.globals.update(Forms=Forms)\n    app.jinja_env.globals.update(User=User)\n    app.jinja_env.globals.update(Team=Team)\n\n    # Add in JinjaEnums\n    # The reason this exists is that on double import, JinjaEnums are not reinitialized\n    # Thus, if you try to create two jinja envs (e.g. during testing), sometimes\n    # an Enum will not be available to Jinja.\n    # Instead we can just directly grab them from the persisted global dictionary.\n    for k, v in JINJA_ENUMS.items():\n        # .update() can't be used here because it would use the literal value k\n        app.jinja_env.globals[k] = v\n\n\ndef init_logs(app):\n    logger_submissions = logging.getLogger(\"submissions\")\n    logger_logins = logging.getLogger(\"logins\")\n    logger_registrations = logging.getLogger(\"registrations\")\n\n    logger_submissions.setLevel(logging.INFO)\n    logger_logins.setLevel(logging.INFO)\n    logger_registrations.setLevel(logging.INFO)\n\n    log_dir = app.config[\"LOG_FOLDER\"]\n    if not os.path.exists(log_dir):\n        os.makedirs(log_dir)\n\n    logs = {\n        \"submissions\": os.path.join(log_dir, \"submissions.log\"),\n        \"logins\": os.path.join(log_dir, \"logins.log\"),\n        \"registrations\": os.path.join(log_dir, \"registrations.log\"),\n    }\n\n    try:\n        for log in logs.values():\n            if not os.path.exists(log):\n                open(log, \"a\").close()\n\n        submission_log = logging.handlers.RotatingFileHandler(\n            logs[\"submissions\"], maxBytes=10485760, backupCount=5\n        )\n        login_log = logging.handlers.RotatingFileHandler(\n            logs[\"logins\"], maxBytes=10485760, backupCount=5\n        )\n        registration_log = logging.handlers.RotatingFileHandler(\n            logs[\"registrations\"], maxBytes=10485760, backupCount=5\n        )\n\n        logger_submissions.addHandler(submission_log)\n        logger_logins.addHandler(login_log)\n        logger_registrations.addHandler(registration_log)\n    except IOError:\n        pass\n\n    stdout = logging.StreamHandler(stream=sys.stdout)\n\n    logger_submissions.addHandler(stdout)\n    logger_logins.addHandler(stdout)\n    logger_registrations.addHandler(stdout)\n\n    logger_submissions.propagate = 0\n    logger_logins.propagate = 0\n    logger_registrations.propagate = 0\n\n\ndef init_events(app):\n    if app.config.get(\"CACHE_TYPE\") == \"redis\":\n        app.events_manager = RedisEventManager()\n    elif app.config.get(\"CACHE_TYPE\") == \"filesystem\":\n        app.events_manager = EventManager()\n    else:\n        app.events_manager = EventManager()\n    app.events_manager.listen()\n\n\ndef init_request_processors(app):\n    @app.url_defaults\n    def inject_theme(endpoint, values):\n        if \"theme\" not in values and app.url_map.is_endpoint_expecting(\n            endpoint, \"theme\"\n        ):\n            values[\"theme\"] = ctf_theme()\n\n    @app.before_request\n    def needs_setup():\n        if import_in_progress():\n            if request.endpoint == \"admin.import_ctf\":\n                return\n            else:\n                return \"Import currently in progress\", 403\n        if is_setup() is False:\n            if request.endpoint in (\n                \"views.setup\",\n                \"views.integrations\",\n                \"views.themes\",\n                \"views.files\",\n                \"views.healthcheck\",\n                \"views.robots\",\n            ):\n                return\n            else:\n                return redirect(url_for(\"views.setup\"))\n\n    @app.before_request\n    def tracker():\n        if request.endpoint == \"views.themes\":\n            return\n\n        if import_in_progress():\n            if request.endpoint == \"admin.import_ctf\":\n                return\n            else:\n                return \"Import currently in progress\", 403\n\n        if authed():\n            user_ips = get_current_user_recent_ips()\n            ip = get_ip()\n\n            track = None\n            if (ip not in user_ips) or (request.method != \"GET\"):\n                track = Tracking.query.filter_by(\n                    ip=get_ip(), user_id=session[\"id\"]\n                ).first()\n\n                if track:\n                    track.date = datetime.datetime.utcnow()\n                else:\n                    track = Tracking(ip=get_ip(), user_id=session[\"id\"])\n                    db.session.add(track)\n\n            if track:\n                try:\n                    db.session.commit()\n                except (InvalidRequestError, IntegrityError):\n                    db.session.rollback()\n                    db.session.close()\n                    logout_user()\n                else:\n                    clear_user_recent_ips(user_id=session[\"id\"])\n\n    @app.before_request\n    def banned():\n        if request.endpoint == \"views.themes\":\n            return\n\n        if authed():\n            user = get_current_user_attrs()\n            team = get_current_team_attrs()\n\n            if user and user.banned:\n                return (\n                    render_template(\n                        \"errors/403.html\", error=\"You have been banned from this CTF\"\n                    ),\n                    403,\n                )\n\n            if team and team.banned:\n                return (\n                    render_template(\n                        \"errors/403.html\",\n                        error=\"Your team has been banned from this CTF\",\n                    ),\n                    403,\n                )\n\n    @app.before_request\n    def tokens():\n        token = request.headers.get(\"Authorization\")\n        if token and (\n            request.mimetype == \"application/json\"\n            # Specially allow multipart/form-data for file uploads\n            or (\n                request.endpoint == \"api.files_files_list\"\n                and request.method == \"POST\"\n                and request.mimetype == \"multipart/form-data\"\n            )\n        ):\n            try:\n                token_type, token = token.split(\" \", 1)\n                user = lookup_user_token(token)\n            except UserNotFoundException:\n                abort(401)\n            except UserTokenExpiredException:\n                abort(401, description=\"Your access token has expired\")\n            except Exception:\n                abort(401)\n            else:\n                login_user(user)\n\n    @app.before_request\n    def csrf():\n        try:\n            func = app.view_functions[request.endpoint]\n        except KeyError:\n            abort(404)\n        if hasattr(func, \"_bypass_csrf\"):\n            return\n        if request.headers.get(\"Authorization\"):\n            return\n        if not session.get(\"nonce\"):\n            session[\"nonce\"] = generate_nonce()\n        if request.method not in (\"GET\", \"HEAD\", \"OPTIONS\", \"TRACE\"):\n            if request.content_type == \"application/json\":\n                if session[\"nonce\"] != request.headers.get(\"CSRF-Token\"):\n                    abort(403)\n            if request.content_type != \"application/json\":\n                if session[\"nonce\"] != request.form.get(\"nonce\"):\n                    abort(403)\n\n    application_root = app.config.get(\"APPLICATION_ROOT\")\n    if application_root != \"/\":\n\n        @app.before_request\n        def force_subdirectory_redirect():\n            if request.path.startswith(application_root) is False:\n                return redirect(\n                    application_root + request.script_root + request.full_path\n                )\n\n        app.wsgi_app = DispatcherMiddleware(app.wsgi_app, {application_root: app})\n", "path": "CTFd/utils/initialization/__init__.py"}]}