Repository: CTFd/CTFd

Issue:
Users cant solve challenge after changing to user mode
**Environment**:

- CTFd Version/Commit: 3.7.0
- Operating System: Ubuntu 22.04.3 LTS
- Web Browser and Version: Bug is occurs in Newest Chrome, Chromium and Firefox. Not tested more.

**What happened?**
Some of our users was not able to submit correct flag to solve the challenge. This occurred for after we swapped to user mode for one of our events, our ctfd instance is usually in Team mode. We narrowed it down to being because the teams still exist, making some users unable to get a solve because they are in a "hidden" team where one of their team members already had solved the challenge. 

**What did you expect to happen?**
Expected to be able to swap to user mode, and be able to have all users solve all challenges, so we dont have to create new teams and users every time we would like to swap mode.

**How to reproduce your issue**
Create a few users in the same team. 
Swap to user mode.
Have one of the users solve a challenge.
Try to solve the same challenge with one of the other users.

**Any associated stack traces or error logs**
n/a



Discussion:
Hmm I thought that when switching user mode via the Admin Panel it would remove users from their teams but it appears maybe not. 

How did you switch user mode? Via the Admin Panel? 
I see that in the original commit this just deleted submissions https://github.com/CTFd/CTFd/pull/1956/files. This would work in moving from users to teams but it doesn't work the other way around. When we switch teams to users we need to remove all users from teams. 
> How did you switch user mode? Via the Admin Panel?

Switched user mode via the admin panel, yes.

> When we switch teams to users we need to remove all users from teams.

So it is an issue with the way the teams and users are set up in relation to eachother, if im understanding this correctly? 

Resolving patch:
diff --git a/CTFd/admin/__init__.py b/CTFd/admin/__init__.py
--- a/CTFd/admin/__init__.py
+++ b/CTFd/admin/__init__.py
@@ -28,6 +28,8 @@
 from CTFd.admin import users  # noqa: F401,I001
 from CTFd.cache import (
     cache,
+    clear_all_team_sessions,
+    clear_all_user_sessions,
     clear_challenges,
     clear_config,
     clear_pages,
@@ -241,6 +243,13 @@ def reset():
             Unlocks.query.delete()
             Tracking.query.delete()
 
+        if data.get("user_mode") == "users":
+            db.session.query(Users).update({Users.team_id: None})
+            Teams.query.delete()
+
+            clear_all_user_sessions()
+            clear_all_team_sessions()
+
         if require_setup:
             set_config("setup", False)
             cache.clear()


Test patch:
diff --git a/tests/api/v1/test_config.py b/tests/api/v1/test_config.py
--- a/tests/api/v1/test_config.py
+++ b/tests/api/v1/test_config.py
@@ -1,8 +1,8 @@
 #!/usr/bin/env python
 # -*- coding: utf-8 -*-
-
+from CTFd.models import Teams, Users
 from CTFd.utils import get_config
-from tests.helpers import create_ctfd, destroy_ctfd, login_as_user
+from tests.helpers import create_ctfd, destroy_ctfd, gen_team, login_as_user
 
 
 def test_api_configs_get_non_admin():
@@ -176,3 +176,38 @@ def test_config_value_types():
             assert r.status_code == 200
             assert get_config("mail_username") == "testusername"
     destroy_ctfd(app)
+
+
+def test_teams_are_removed_after_migrating_from_team_mode_to_user_mode():
+    """Are teams, and user.team relations removed when migrating from team mode to user mode"""
+    app = create_ctfd()
+    with app.app_context():
+        with login_as_user(app, "admin") as admin:
+            r = admin.patch("/api/v1/configs", json={"user_mode": "teams"})
+            assert r.status_code == 200
+            assert get_config("user_mode") == "teams"
+
+            gen_team(app.db)
+
+            assert Users.query.count() == 5
+            assert Teams.query.count() == 1
+
+            r = admin.patch("/api/v1/configs", json={"user_mode": "users"})
+            assert r.status_code == 200
+            assert get_config("user_mode") == "users"
+
+            with admin.session_transaction() as sess:
+                data = {
+                    "user_mode": "users",
+                    "submissions": "true",
+                    "nonce": sess.get("nonce"),
+                }
+            r = admin.post("/admin/reset", data=data)
+            assert r.status_code == 302
+
+            assert Users.query.count() == 5
+            assert Teams.query.count() == 0
+
+            for user in Users.query.all():
+                assert user.team is None
+    destroy_ctfd(app)