Repository: CTFd/CTFd

Issue:
Setup flow should always use the core theme
This just simplifies theme development. I think would be easier to do after CTFd.js but being optimistic. 


Discussion:
Thinking about this I don't think this is as big a deal as I used to think it is. With theme fallback this shouldn't be as big an issue as it was at one point. 

Resolving patch:
diff --git a/CTFd/forms/setup.py b/CTFd/forms/setup.py
--- a/CTFd/forms/setup.py
+++ b/CTFd/forms/setup.py
@@ -2,6 +2,7 @@
 from wtforms import (
     FileField,
     HiddenField,
+    IntegerField,
     PasswordField,
     RadioField,
     SelectField,
@@ -10,7 +11,14 @@
 )
 from wtforms.fields.html5 import EmailField
 from wtforms.validators import InputRequired
+from wtforms.widgets.html5 import NumberInput
 
+from CTFd.constants.config import (
+    AccountVisibilityTypes,
+    ChallengeVisibilityTypes,
+    RegistrationVisibilityTypes,
+    ScoreVisibilityTypes,
+)
 from CTFd.forms import BaseForm
 from CTFd.forms.fields import SubmitField
 from CTFd.utils.config import get_themes
@@ -79,6 +87,58 @@ class SetupForm(BaseForm):
         ),
     )
 
+    verify_emails = SelectField(
+        _l("Verify Emails"),
+        description="Control whether users must confirm their email addresses before participating",
+        choices=[("true", "Enabled"), ("false", "Disabled")],
+        default="false",
+    )
+    team_size = IntegerField(
+        widget=NumberInput(min=0),
+        description="Amount of users per team (Teams mode only) Optional.",
+    )
+    challenge_visibility = SelectField(
+        "Challenge Visibility",
+        description="Control whether users must be logged in to see challenges",
+        choices=[
+            (ChallengeVisibilityTypes.PUBLIC, "Public"),
+            (ChallengeVisibilityTypes.PRIVATE, "Private"),
+            (ChallengeVisibilityTypes.ADMINS, "Admins Only"),
+        ],
+        default=ChallengeVisibilityTypes.PRIVATE,
+    )
+    account_visibility = SelectField(
+        "Account Visibility",
+        description="Control whether accounts (users & teams) are shown to everyone, only to authenticated users, or only to admins",
+        choices=[
+            (AccountVisibilityTypes.PUBLIC, "Public"),
+            (AccountVisibilityTypes.PRIVATE, "Private"),
+            (AccountVisibilityTypes.ADMINS, "Admins Only"),
+        ],
+        default=AccountVisibilityTypes.PUBLIC,
+    )
+    score_visibility = SelectField(
+        "Score Visibility",
+        description="Control whether solves/score are shown to the public, to logged in users, hidden to all non-admins, or only shown to admins",
+        choices=[
+            (ScoreVisibilityTypes.PUBLIC, "Public"),
+            (ScoreVisibilityTypes.PRIVATE, "Private"),
+            (ScoreVisibilityTypes.HIDDEN, "Hidden"),
+            (ScoreVisibilityTypes.ADMINS, "Admins Only"),
+        ],
+        default=AccountVisibilityTypes.PUBLIC,
+    )
+    registration_visibility = SelectField(
+        "Registration Visibility",
+        description="Control whether registration is enabled for everyone or disabled",
+        choices=[
+            (RegistrationVisibilityTypes.PUBLIC, "Public"),
+            (RegistrationVisibilityTypes.PRIVATE, "Private"),
+            (RegistrationVisibilityTypes.MLC, "MajorLeagueCyber Only"),
+        ],
+        default=RegistrationVisibilityTypes.PUBLIC,
+    )
+
     start = StringField(
         _l("Start Time"),
         description=_l("Time when your CTF is scheduled to start. Optional."),
diff --git a/CTFd/views.py b/CTFd/views.py
--- a/CTFd/views.py
+++ b/CTFd/views.py
@@ -85,6 +85,31 @@ def setup():
             set_config("ctf_description", ctf_description)
             set_config("user_mode", user_mode)
 
+            # Settings
+            challenge_visibility = ChallengeVisibilityTypes(
+                request.form.get(
+                    "challenge_visibility", default=ChallengeVisibilityTypes.PRIVATE
+                )
+            )
+            account_visibility = AccountVisibilityTypes(
+                request.form.get(
+                    "account_visibility", default=AccountVisibilityTypes.PUBLIC
+                )
+            )
+            score_visibility = ScoreVisibilityTypes(
+                request.form.get(
+                    "score_visibility", default=ScoreVisibilityTypes.PUBLIC
+                )
+            )
+            registration_visibility = RegistrationVisibilityTypes(
+                request.form.get(
+                    "registration_visibility",
+                    default=RegistrationVisibilityTypes.PUBLIC,
+                )
+            )
+            verify_emails = request.form.get("verify_emails")
+            team_size = request.form.get("team_size")
+
             # Style
             ctf_logo = request.files.get("ctf_logo")
             if ctf_logo:
@@ -198,17 +223,16 @@ def setup():
             page.content = index
 
             # Visibility
-            set_config(
-                ConfigTypes.CHALLENGE_VISIBILITY, ChallengeVisibilityTypes.PRIVATE
-            )
-            set_config(
-                ConfigTypes.REGISTRATION_VISIBILITY, RegistrationVisibilityTypes.PUBLIC
-            )
-            set_config(ConfigTypes.SCORE_VISIBILITY, ScoreVisibilityTypes.PUBLIC)
-            set_config(ConfigTypes.ACCOUNT_VISIBILITY, AccountVisibilityTypes.PUBLIC)
+            set_config(ConfigTypes.CHALLENGE_VISIBILITY, challenge_visibility)
+            set_config(ConfigTypes.REGISTRATION_VISIBILITY, registration_visibility)
+            set_config(ConfigTypes.SCORE_VISIBILITY, score_visibility)
+            set_config(ConfigTypes.ACCOUNT_VISIBILITY, account_visibility)
 
             # Verify emails
-            set_config("verify_emails", None)
+            set_config("verify_emails", verify_emails)
+
+            # Team Size
+            set_config("team_size", team_size)
 
             set_config("mail_server", None)
             set_config("mail_port", None)
@@ -273,6 +297,8 @@ def setup():
 
             return redirect(url_for("views.static_html"))
         try:
+            if bool(get_config("ctf_theme")) is False:
+                set_config("ctf_theme", "core-beta")
             return render_template("setup.html", state=serialize(generate_nonce()))
         except TemplateNotFound:
             # Set theme to default and try again


Test patch: