Repository: CTFd/CTFd

Issue:
Standardize theme interface
Themes should have a static set of requirements that all themes should have. This really just means we need to provide more guidance on designing themes. 


Discussion:
Looking at some of this code there are some constructs that can be standardized. 

For example, CTFd configuration values (name, user mode, script_root, start, end, etc) can be abstracted out into a specific class. 

For example `{{ Config.name }}` could return the current CTF name. I think this jives well with the rest of the push towards static strings/enums. 

Similarly this idea can be applied to plugin constructs and the current user. 

I see so far the following classes:

- Config
- User
- Team
- Plugins
- Session
I suspect that we could also move certain repeated functionality into a macros file. The macro would still be dependent on the underlying CSS/JS framework but this gives people a single area to implement behavior. 
I think another goal here is to cut out as much logic from the user themes as possible. 
This is still missing the User, Team objects. 

Resolving patch:
diff --git a/CTFd/constants/teams.py b/CTFd/constants/teams.py
--- a/CTFd/constants/teams.py
+++ b/CTFd/constants/teams.py
@@ -18,3 +18,32 @@
         "created",
     ],
 )
+
+
+class _TeamAttrsWrapper:
+    def __getattr__(self, attr):
+        from CTFd.utils.user import get_current_team_attrs
+
+        attrs = get_current_team_attrs()
+        return getattr(attrs, attr, None)
+
+    @property
+    def place(self):
+        from CTFd.utils.user import get_current_team
+
+        team = get_current_team()
+        if team:
+            return team.place
+        return None
+
+    @property
+    def score(self):
+        from CTFd.utils.user import get_current_team
+
+        team = get_current_team()
+        if team:
+            return team.score
+        return None
+
+
+Team = _TeamAttrsWrapper()
diff --git a/CTFd/constants/users.py b/CTFd/constants/users.py
--- a/CTFd/constants/users.py
+++ b/CTFd/constants/users.py
@@ -20,3 +20,32 @@
         "created",
     ],
 )
+
+
+class _UserAttrsWrapper:
+    def __getattr__(self, attr):
+        from CTFd.utils.user import get_current_user_attrs
+
+        attrs = get_current_user_attrs()
+        return getattr(attrs, attr, None)
+
+    @property
+    def place(self):
+        from CTFd.utils.user import get_current_user
+
+        user = get_current_user()
+        if user:
+            return user.place
+        return None
+
+    @property
+    def score(self):
+        from CTFd.utils.user import get_current_user
+
+        user = get_current_user()
+        if user:
+            return user.score
+        return None
+
+
+User = _UserAttrsWrapper()
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
@@ -56,6 +56,8 @@ def init_template_globals(app):
     from CTFd.constants.config import Configs
     from CTFd.constants.plugins import Plugins
     from CTFd.constants.sessions import Session
+    from CTFd.constants.users import User
+    from CTFd.constants.teams import Team
     from CTFd.forms import Forms
     from CTFd.utils.config.visibility import (
         accounts_visible,
@@ -98,6 +100,8 @@ def init_template_globals(app):
     app.jinja_env.globals.update(Plugins=Plugins)
     app.jinja_env.globals.update(Session=Session)
     app.jinja_env.globals.update(Forms=Forms)
+    app.jinja_env.globals.update(User=User)
+    app.jinja_env.globals.update(Team=Team)
 
 
 def init_logs(app):


Test patch: