diff --git a/CTFd/admin/submissions.py b/CTFd/admin/submissions.py index 5a2a5d1d..805dd122 100644 --- a/CTFd/admin/submissions.py +++ b/CTFd/admin/submissions.py @@ -3,6 +3,7 @@ from flask import render_template, request, url_for from CTFd.admin import admin from CTFd.models import Challenges, Submissions from CTFd.utils.decorators import admins_only +from CTFd.utils.helpers.models import build_model_filters from CTFd.utils.modes import get_model @@ -19,12 +20,15 @@ def submissions_listing(submission_type): field = request.args.get("field") page = abs(request.args.get("page", 1, type=int)) - if q: - submissions = [] - if Submissions.__mapper__.has_property( - field - ): # The field exists as an exposed column - filters.append(getattr(Submissions, field).like("%{}%".format(q))) + filters = build_model_filters( + model=Submissions, + query=q, + field=field, + extra_columns={ + "challenge_name": Challenges.name, + "account_id": Submissions.account_id, + }, + ) Model = get_model() @@ -37,7 +41,7 @@ def submissions_listing(submission_type): Submissions.account_id, Submissions.date, Challenges.name.label("challenge_name"), - Model.name.label("team_name"), + Model.name.label("account_name"), ) .filter_by(**filters_by) .filter(*filters) diff --git a/CTFd/api/v1/awards.py b/CTFd/api/v1/awards.py index cc151338..1ecf80f5 100644 --- a/CTFd/api/v1/awards.py +++ b/CTFd/api/v1/awards.py @@ -3,7 +3,6 @@ from typing import List from flask import request from flask_restx import Namespace, Resource -from CTFd.api.v1.helpers.models import build_model_filters from CTFd.api.v1.helpers.request import validate_args from CTFd.api.v1.helpers.schemas import sqlalchemy_to_pydantic from CTFd.api.v1.schemas import APIDetailedSuccessResponse, APIListSuccessResponse @@ -13,6 +12,7 @@ from CTFd.models import Awards, Users, db from CTFd.schemas.awards import AwardSchema from CTFd.utils.config import is_teams_mode from CTFd.utils.decorators import admins_only +from CTFd.utils.helpers.models import build_model_filters awards_namespace = Namespace("awards", description="Endpoint to retrieve Awards") diff --git a/CTFd/api/v1/challenges.py b/CTFd/api/v1/challenges.py index 38db09d7..f24e38d0 100644 --- a/CTFd/api/v1/challenges.py +++ b/CTFd/api/v1/challenges.py @@ -5,7 +5,6 @@ from flask import abort, render_template, request, url_for from flask_restx import Namespace, Resource from sqlalchemy.sql import and_ -from CTFd.api.v1.helpers.models import build_model_filters from CTFd.api.v1.helpers.request import validate_args from CTFd.api.v1.helpers.schemas import sqlalchemy_to_pydantic from CTFd.api.v1.schemas import APIDetailedSuccessResponse, APIListSuccessResponse @@ -44,6 +43,7 @@ from CTFd.utils.decorators.visibility import ( check_challenge_visibility, check_score_visibility, ) +from CTFd.utils.helpers.models import build_model_filters from CTFd.utils.logging import log from CTFd.utils.modes import generate_account_url, get_model from CTFd.utils.security.signing import serialize diff --git a/CTFd/api/v1/config.py b/CTFd/api/v1/config.py index 3b13c10c..f4472982 100644 --- a/CTFd/api/v1/config.py +++ b/CTFd/api/v1/config.py @@ -3,7 +3,6 @@ from typing import List from flask import request from flask_restx import Namespace, Resource -from CTFd.api.v1.helpers.models import build_model_filters from CTFd.api.v1.helpers.request import validate_args from CTFd.api.v1.helpers.schemas import sqlalchemy_to_pydantic from CTFd.api.v1.schemas import APIDetailedSuccessResponse, APIListSuccessResponse @@ -13,6 +12,7 @@ from CTFd.models import Configs, db from CTFd.schemas.config import ConfigSchema from CTFd.utils import set_config from CTFd.utils.decorators import admins_only +from CTFd.utils.helpers.models import build_model_filters configs_namespace = Namespace("configs", description="Endpoint to retrieve Configs") diff --git a/CTFd/api/v1/files.py b/CTFd/api/v1/files.py index 46f8ef1d..d1ad5ebb 100644 --- a/CTFd/api/v1/files.py +++ b/CTFd/api/v1/files.py @@ -3,7 +3,6 @@ from typing import List from flask import request from flask_restx import Namespace, Resource -from CTFd.api.v1.helpers.models import build_model_filters from CTFd.api.v1.helpers.request import validate_args from CTFd.api.v1.helpers.schemas import sqlalchemy_to_pydantic from CTFd.api.v1.schemas import APIDetailedSuccessResponse, APIListSuccessResponse @@ -12,6 +11,7 @@ from CTFd.models import Files, db from CTFd.schemas.files import FileSchema from CTFd.utils import uploads from CTFd.utils.decorators import admins_only +from CTFd.utils.helpers.models import build_model_filters files_namespace = Namespace("files", description="Endpoint to retrieve Files") diff --git a/CTFd/api/v1/flags.py b/CTFd/api/v1/flags.py index 8be4f67f..e8b4aa9e 100644 --- a/CTFd/api/v1/flags.py +++ b/CTFd/api/v1/flags.py @@ -3,7 +3,6 @@ from typing import List from flask import request from flask_restx import Namespace, Resource -from CTFd.api.v1.helpers.models import build_model_filters from CTFd.api.v1.helpers.request import validate_args from CTFd.api.v1.helpers.schemas import sqlalchemy_to_pydantic from CTFd.api.v1.schemas import APIDetailedSuccessResponse, APIListSuccessResponse @@ -12,6 +11,7 @@ from CTFd.models import Flags, db from CTFd.plugins.flags import FLAG_CLASSES, get_flag_class from CTFd.schemas.flags import FlagSchema from CTFd.utils.decorators import admins_only +from CTFd.utils.helpers.models import build_model_filters flags_namespace = Namespace("flags", description="Endpoint to retrieve Flags") diff --git a/CTFd/api/v1/helpers/models.py b/CTFd/api/v1/helpers/models.py index 0bc8f6fe..db36439d 100644 --- a/CTFd/api/v1/helpers/models.py +++ b/CTFd/api/v1/helpers/models.py @@ -1,7 +1,12 @@ +# This file is no longer used. If you're importing the function from here please update your imports + +from CTFd.utils.helpers.models import build_model_filters as _build_model_filters + + def build_model_filters(model, query, field): - filters = [] - if query: - # The field exists as an exposed column - if model.__mapper__.has_property(field): - filters.append(getattr(model, field).like("%{}%".format(query))) - return filters + print("CTFd.api.v1.helpers.models.build_model_filters has been deprecated.") + print("Please switch to using CTFd.utils.helpers.models.build_model_filters") + print( + "This function will raise an exception in a future minor release of CTFd and then be removed in a major release." + ) + return _build_model_filters(model, query, field) diff --git a/CTFd/api/v1/hints.py b/CTFd/api/v1/hints.py index 921eb46a..3a876316 100644 --- a/CTFd/api/v1/hints.py +++ b/CTFd/api/v1/hints.py @@ -3,7 +3,6 @@ from typing import List from flask import request from flask_restx import Namespace, Resource -from CTFd.api.v1.helpers.models import build_model_filters from CTFd.api.v1.helpers.request import validate_args from CTFd.api.v1.helpers.schemas import sqlalchemy_to_pydantic from CTFd.api.v1.schemas import APIDetailedSuccessResponse, APIListSuccessResponse @@ -11,6 +10,7 @@ from CTFd.constants import RawEnum from CTFd.models import Hints, HintUnlocks, db from CTFd.schemas.hints import HintSchema from CTFd.utils.decorators import admins_only, authed_only, during_ctf_time_only +from CTFd.utils.helpers.models import build_model_filters from CTFd.utils.user import get_current_user, is_admin hints_namespace = Namespace("hints", description="Endpoint to retrieve Hints") diff --git a/CTFd/api/v1/notifications.py b/CTFd/api/v1/notifications.py index c10eea50..70143367 100644 --- a/CTFd/api/v1/notifications.py +++ b/CTFd/api/v1/notifications.py @@ -3,7 +3,6 @@ from typing import List from flask import current_app, request from flask_restx import Namespace, Resource -from CTFd.api.v1.helpers.models import build_model_filters from CTFd.api.v1.helpers.request import validate_args from CTFd.api.v1.helpers.schemas import sqlalchemy_to_pydantic from CTFd.api.v1.schemas import APIDetailedSuccessResponse, APIListSuccessResponse @@ -11,6 +10,7 @@ from CTFd.constants import RawEnum from CTFd.models import Notifications, db from CTFd.schemas.notifications import NotificationSchema from CTFd.utils.decorators import admins_only +from CTFd.utils.helpers.models import build_model_filters notifications_namespace = Namespace( "notifications", description="Endpoint to retrieve Notifications" diff --git a/CTFd/api/v1/pages.py b/CTFd/api/v1/pages.py index 62c19bbf..2c2ed505 100644 --- a/CTFd/api/v1/pages.py +++ b/CTFd/api/v1/pages.py @@ -3,7 +3,6 @@ from typing import List from flask import request from flask_restx import Namespace, Resource -from CTFd.api.v1.helpers.models import build_model_filters from CTFd.api.v1.helpers.request import validate_args from CTFd.api.v1.helpers.schemas import sqlalchemy_to_pydantic from CTFd.api.v1.schemas import APIDetailedSuccessResponse, APIListSuccessResponse @@ -12,6 +11,7 @@ from CTFd.constants import RawEnum from CTFd.models import Pages, db from CTFd.schemas.pages import PageSchema from CTFd.utils.decorators import admins_only +from CTFd.utils.helpers.models import build_model_filters pages_namespace = Namespace("pages", description="Endpoint to retrieve Pages") diff --git a/CTFd/api/v1/submissions.py b/CTFd/api/v1/submissions.py index 299d6112..d2b9b051 100644 --- a/CTFd/api/v1/submissions.py +++ b/CTFd/api/v1/submissions.py @@ -2,7 +2,6 @@ from typing import List from flask_restx import Namespace, Resource -from CTFd.api.v1.helpers.models import build_model_filters from CTFd.api.v1.helpers.request import validate_args from CTFd.api.v1.helpers.schemas import sqlalchemy_to_pydantic from CTFd.api.v1.schemas import ( @@ -14,6 +13,7 @@ from CTFd.constants import RawEnum from CTFd.models import Submissions, db from CTFd.schemas.submissions import SubmissionSchema from CTFd.utils.decorators import admins_only +from CTFd.utils.helpers.models import build_model_filters submissions_namespace = Namespace( "submissions", description="Endpoint to retrieve Submission" diff --git a/CTFd/api/v1/tags.py b/CTFd/api/v1/tags.py index a7849f91..84ae9228 100644 --- a/CTFd/api/v1/tags.py +++ b/CTFd/api/v1/tags.py @@ -3,7 +3,6 @@ from typing import List from flask import request from flask_restx import Namespace, Resource -from CTFd.api.v1.helpers.models import build_model_filters from CTFd.api.v1.helpers.request import validate_args from CTFd.api.v1.helpers.schemas import sqlalchemy_to_pydantic from CTFd.api.v1.schemas import APIDetailedSuccessResponse, APIListSuccessResponse @@ -11,6 +10,7 @@ from CTFd.constants import RawEnum from CTFd.models import Tags, db from CTFd.schemas.tags import TagSchema from CTFd.utils.decorators import admins_only +from CTFd.utils.helpers.models import build_model_filters tags_namespace = Namespace("tags", description="Endpoint to retrieve Tags") diff --git a/CTFd/api/v1/teams.py b/CTFd/api/v1/teams.py index dde077f7..243dde6e 100644 --- a/CTFd/api/v1/teams.py +++ b/CTFd/api/v1/teams.py @@ -4,7 +4,6 @@ from typing import List from flask import abort, request, session from flask_restx import Namespace, Resource -from CTFd.api.v1.helpers.models import build_model_filters from CTFd.api.v1.helpers.request import validate_args from CTFd.api.v1.helpers.schemas import sqlalchemy_to_pydantic from CTFd.api.v1.schemas import ( @@ -22,6 +21,7 @@ from CTFd.utils.decorators.visibility import ( check_account_visibility, check_score_visibility, ) +from CTFd.utils.helpers.models import build_model_filters from CTFd.utils.user import get_current_team, get_current_user_type, is_admin teams_namespace = Namespace("teams", description="Endpoint to retrieve Teams") diff --git a/CTFd/api/v1/unlocks.py b/CTFd/api/v1/unlocks.py index b3ca5d49..5a130f34 100644 --- a/CTFd/api/v1/unlocks.py +++ b/CTFd/api/v1/unlocks.py @@ -3,7 +3,6 @@ from typing import List from flask import request from flask_restx import Namespace, Resource -from CTFd.api.v1.helpers.models import build_model_filters from CTFd.api.v1.helpers.request import validate_args from CTFd.api.v1.helpers.schemas import sqlalchemy_to_pydantic from CTFd.api.v1.schemas import APIDetailedSuccessResponse, APIListSuccessResponse @@ -18,6 +17,7 @@ from CTFd.utils.decorators import ( during_ctf_time_only, require_verified_emails, ) +from CTFd.utils.helpers.models import build_model_filters from CTFd.utils.user import get_current_user unlocks_namespace = Namespace("unlocks", description="Endpoint to retrieve Unlocks") diff --git a/CTFd/api/v1/users.py b/CTFd/api/v1/users.py index 9d857e92..09b564be 100644 --- a/CTFd/api/v1/users.py +++ b/CTFd/api/v1/users.py @@ -3,7 +3,6 @@ from typing import List from flask import abort, request, session from flask_restx import Namespace, Resource -from CTFd.api.v1.helpers.models import build_model_filters from CTFd.api.v1.helpers.request import validate_args from CTFd.api.v1.helpers.schemas import sqlalchemy_to_pydantic from CTFd.api.v1.schemas import ( @@ -32,6 +31,7 @@ from CTFd.utils.decorators.visibility import ( check_score_visibility, ) from CTFd.utils.email import sendmail, user_created_notification +from CTFd.utils.helpers.models import build_model_filters from CTFd.utils.security.auth import update_user from CTFd.utils.user import get_current_user, get_current_user_type, is_admin diff --git a/CTFd/forms/submissions.py b/CTFd/forms/submissions.py index 0457b5cc..5b8faebb 100644 --- a/CTFd/forms/submissions.py +++ b/CTFd/forms/submissions.py @@ -8,7 +8,13 @@ from CTFd.forms.fields import SubmitField class SubmissionSearchForm(BaseForm): field = SelectField( "Search Field", - choices=[("provided", "Provided"), ("id", "ID")], + choices=[ + ("provided", "Provided"), + ("id", "ID"), + ("account_id", "Account ID"), + ("challenge_id", "Challenge ID"), + ("challenge_name", "Challenge Name"), + ], default="provided", validators=[InputRequired()], ) diff --git a/CTFd/models/__init__.py b/CTFd/models/__init__.py index cfaabe5e..b58aa7e0 100644 --- a/CTFd/models/__init__.py +++ b/CTFd/models/__init__.py @@ -617,9 +617,7 @@ class Submissions(db.Model): return child_classes[type] def __repr__(self): - return "".format( - self.team_id, self.challenge_id, self.ip, self.provided - ) + return f"" class Solves(Submissions): diff --git a/CTFd/themes/admin/templates/challenges/challenge.html b/CTFd/themes/admin/templates/challenges/challenge.html index 58531bf5..f23aacd2 100644 --- a/CTFd/themes/admin/templates/challenges/challenge.html +++ b/CTFd/themes/admin/templates/challenges/challenge.html @@ -29,6 +29,10 @@ + + + diff --git a/CTFd/themes/admin/templates/submissions.html b/CTFd/themes/admin/templates/submissions.html index 8c3f9429..03708a66 100644 --- a/CTFd/themes/admin/templates/submissions.html +++ b/CTFd/themes/admin/templates/submissions.html @@ -26,7 +26,7 @@ {% with form = Forms.submissions.SubmissionSearchForm(field=field, q=q) %}
-