Exemple #1
0
class FieldList(Resource):
    @admins_only
    @validate_args(
        {
            "type": (str, None),
            "q": (str, None),
            "field":
            (RawEnum("FieldFields", {"description": "description"}), None),
        },
        location="query",
    )
    def get(self, query_args):
        q = query_args.pop("q", None)
        field = str(query_args.pop("field", None))
        filters = build_model_filters(model=Fields, query=q, field=field)

        fields = Fields.query.filter_by(**query_args).filter(*filters).all()
        schema = FieldSchema(many=True)

        response = schema.dump(fields)

        if response.errors:
            return {"success": False, "errors": response.errors}, 400

        return {"success": True, "data": response.data}

    @admins_only
    def post(self):
        req = request.get_json()
        schema = FieldSchema()
        response = schema.load(req, session=db.session)

        if response.errors:
            return {"success": False, "errors": response.errors}, 400

        db.session.add(response.data)
        db.session.commit()

        response = schema.dump(response.data)
        db.session.close()

        return {"success": True, "data": response.data}
Exemple #2
0
class ChallengeList(Resource):
    @check_challenge_visibility
    @during_ctf_time_only
    @require_verified_emails
    @challenges_namespace.doc(
        description="Endpoint to get Challenge objects in bulk",
        responses={
            200: ("Success", "ChallengeListSuccessResponse"),
            400: (
                "An error occured processing the provided or stored data",
                "APISimpleErrorResponse",
            ),
        },
    )
    @validate_args(
        {
            "name": (str, None),
            "max_attempts": (int, None),
            "value": (int, None),
            "category": (str, None),
            "type": (str, None),
            "state": (str, None),
            "q": (str, None),
            "field": (
                RawEnum(
                    "ChallengeFields",
                    {
                        "name": "name",
                        "description": "description",
                        "category": "category",
                        "type": "type",
                        "state": "state",
                    },
                ),
                None,
            ),
        },
        location="query",
    )
    def get(self, query_args):
        # Build filtering queries
        q = query_args.pop("q", None)
        field = str(query_args.pop("field", None))
        filters = build_model_filters(model=Challenges, query=q, field=field)

        # This can return None (unauth) if visibility is set to public
        user = get_current_user()

        # Admins can request to see everything
        if is_admin() and request.args.get("view") == "admin":
            challenges = (Challenges.query.filter_by(**query_args).filter(
                *filters).order_by(Challenges.value).all())
            solve_ids = set([challenge.id for challenge in challenges])
        else:
            challenges = (Challenges.query.filter(
                and_(Challenges.state != "hidden",
                     Challenges.state != "locked")).filter_by(
                         **query_args).filter(*filters).order_by(
                             Challenges.value).all())

            if user:
                solve_ids = (Solves.query.with_entities(
                    Solves.challenge_id).filter_by(
                        account_id=user.account_id).order_by(
                            Solves.challenge_id.asc()).all())
                solve_ids = set([value for value, in solve_ids])

                # TODO: Convert this into a re-useable decorator
                if is_admin():
                    pass
                else:
                    if config.is_teams_mode() and get_current_team() is None:
                        abort(403)
            else:
                solve_ids = set()

        response = []
        tag_schema = TagSchema(view="user", many=True)
        for challenge in challenges:
            if challenge.requirements:
                requirements = challenge.requirements.get("prerequisites", [])
                anonymize = challenge.requirements.get("anonymize")
                prereqs = set(requirements)
                if solve_ids >= prereqs:
                    pass
                else:
                    if anonymize:
                        response.append({
                            "id": challenge.id,
                            "type": "hidden",
                            "name": "???",
                            "value": 0,
                            "category": "???",
                            "tags": [],
                            "template": "",
                            "script": "",
                        })
                    # Fallthrough to continue
                    continue

            try:
                challenge_type = get_chal_class(challenge.type)
            except KeyError:
                # Challenge type does not exist. Fall through to next challenge.
                continue

            # Challenge passes all checks, add it to response
            response.append({
                "id": challenge.id,
                "type": challenge_type.name,
                "name": challenge.name,
                "value": challenge.value,
                "category": challenge.category,
                "tags": tag_schema.dump(challenge.tags).data,
                "template": challenge_type.templates["view"],
                "script": challenge_type.scripts["view"],
            })

        db.session.close()
        return {"success": True, "data": response}

    @admins_only
    @challenges_namespace.doc(
        description="Endpoint to create a Challenge object",
        responses={
            200: ("Success", "ChallengeDetailedSuccessResponse"),
            400: (
                "An error occured processing the provided or stored data",
                "APISimpleErrorResponse",
            ),
        },
    )
    def post(self):
        data = request.form or request.get_json()
        challenge_type = data["type"]
        challenge_class = get_chal_class(challenge_type)
        challenge = challenge_class.create(request)
        response = challenge_class.read(challenge)
        return {"success": True, "data": response}
Exemple #3
0
class FilesList(Resource):
    @admins_only
    @files_namespace.doc(
        description="Endpoint to get file objects in bulk",
        responses={
            200: ("Success", "FileListSuccessResponse"),
            400: (
                "An error occured processing the provided or stored data",
                "APISimpleErrorResponse",
            ),
        },
    )
    @validate_args(
        {
            "type": (str, None),
            "location": (str, None),
            "q": (str, None),
            "field": (
                RawEnum("FileFields", {
                    "type": "type",
                    "location": "location"
                }),
                None,
            ),
        },
        location="query",
    )
    def get(self, query_args):
        q = query_args.pop("q", None)
        field = str(query_args.pop("field", None))
        filters = build_model_filters(model=Files, query=q, field=field)

        files = Files.query.filter_by(**query_args).filter(*filters).all()
        schema = FileSchema(many=True)
        response = schema.dump(files)

        if response.errors:
            return {"success": False, "errors": response.errors}, 400

        return {"success": True, "data": response.data}

    @admins_only
    @files_namespace.doc(
        description="Endpoint to get file objects in bulk",
        responses={
            200: ("Success", "FileDetailedSuccessResponse"),
            400: (
                "An error occured processing the provided or stored data",
                "APISimpleErrorResponse",
            ),
        },
    )
    def post(self):
        files = request.files.getlist("file")
        # challenge_id
        # page_id

        objs = []
        for f in files:
            # uploads.upload_file(file=f, chalid=req.get('challenge'))
            obj = uploads.upload_file(file=f, **request.form.to_dict())
            objs.append(obj)

        schema = FileSchema(many=True)
        response = schema.dump(objs)

        if response.errors:
            return {"success": False, "errors": response.errorss}, 400

        return {"success": True, "data": response.data}
Exemple #4
0
class ChallengeList(Resource):
    @check_challenge_visibility
    @during_ctf_time_only
    @require_verified_emails
    @challenges_namespace.doc(
        description="Endpoint to get Challenge objects in bulk",
        responses={
            200: ("Success", "ChallengeListSuccessResponse"),
            400: (
                "An error occured processing the provided or stored data",
                "APISimpleErrorResponse",
            ),
        },
    )
    @validate_args(
        {
            "name": (str, None),
            "max_attempts": (int, None),
            "value": (int, None),
            "category": (str, None),
            "type": (str, None),
            "state": (str, None),
            "q": (str, None),
            "field": (
                RawEnum(
                    "ChallengeFields",
                    {
                        "name": "name",
                        "description": "description",
                        "category": "category",
                        "type": "type",
                        "state": "state",
                    },
                ),
                None,
            ),
        },
        location="query",
    )
    def get(self, query_args):
        # Require a team if in teams mode
        # TODO: Convert this into a re-useable decorator
        # TODO: The require_team decorator doesnt work because of no admin passthru
        if get_current_user_attrs():
            if is_admin():
                pass
            else:
                if config.is_teams_mode() and get_current_team_attrs() is None:
                    abort(403)

        # Build filtering queries
        q = query_args.pop("q", None)
        field = str(query_args.pop("field", None))
        filters = build_model_filters(model=Challenges, query=q, field=field)

        # Admins get a shortcut to see all challenges despite pre-requisites
        admin_view = is_admin() and request.args.get("view") == "admin"

        solve_counts = {}
        # Build a query for to show challenge solve information. We only
        # give an admin view if the request argument has been provided.
        #
        # NOTE: This is different behaviour to the challenge detail
        # endpoint which only needs the current user to be an admin rather
        # than also also having to provide `view=admin` as a query arg.
        solves_q, user_solves = _build_solves_query(admin_view=admin_view)
        # Aggregate the query results into the hashes defined at the top of
        # this block for later use
        for chal_id, solve_count in solves_q:
            solve_counts[chal_id] = solve_count
        if scores_visible() and accounts_visible():
            solve_count_dfl = 0
        else:
            # Empty out the solves_count if we're hiding scores/accounts
            solve_counts = {}
            # This is necessary to match the challenge detail API which returns
            # `None` for the solve count if visiblity checks fail
            solve_count_dfl = None

        # Build the query for the challenges which may be listed
        chal_q = Challenges.query
        # Admins can see hidden and locked challenges in the admin view
        if admin_view is False:
            chal_q = chal_q.filter(
                and_(Challenges.state != "hidden",
                     Challenges.state != "locked"))
        chal_q = (chal_q.filter_by(**query_args).filter(*filters).order_by(
            Challenges.value, Challenges.id))

        # Iterate through the list of challenges, adding to the object which
        # will be JSONified back to the client
        response = []
        tag_schema = TagSchema(view="user", many=True)

        # Gather all challenge IDs so that we can determine invalid challenge prereqs
        all_challenge_ids = {
            c.id
            for c in Challenges.query.with_entities(Challenges.id).all()
        }
        for challenge in chal_q:
            if challenge.requirements:
                requirements = challenge.requirements.get("prerequisites", [])
                anonymize = challenge.requirements.get("anonymize")
                prereqs = set(requirements).intersection(all_challenge_ids)
                if user_solves >= prereqs or admin_view:
                    pass
                else:
                    if anonymize:
                        response.append({
                            "id": challenge.id,
                            "type": "hidden",
                            "name": "???",
                            "value": 0,
                            "solves": None,
                            "solved_by_me": False,
                            "category": "???",
                            "tags": [],
                            "template": "",
                            "script": "",
                        })
                    # Fallthrough to continue
                    continue

            try:
                challenge_type = get_chal_class(challenge.type)
            except KeyError:
                # Challenge type does not exist. Fall through to next challenge.
                continue

            # Challenge passes all checks, add it to response
            response.append({
                "id":
                challenge.id,
                "type":
                challenge_type.name,
                "name":
                challenge.name,
                "value":
                challenge.value,
                "solves":
                solve_counts.get(challenge.id, solve_count_dfl),
                "solved_by_me":
                challenge.id in user_solves,
                "category":
                challenge.category,
                "tags":
                tag_schema.dump(challenge.tags).data,
                "template":
                challenge_type.templates["view"],
                "script":
                challenge_type.scripts["view"],
            })

        db.session.close()
        return {"success": True, "data": response}

    @admins_only
    @challenges_namespace.doc(
        description="Endpoint to create a Challenge object",
        responses={
            200: ("Success", "ChallengeDetailedSuccessResponse"),
            400: (
                "An error occured processing the provided or stored data",
                "APISimpleErrorResponse",
            ),
        },
    )
    def post(self):
        data = request.form or request.get_json()

        # Load data through schema for validation but not for insertion
        schema = ChallengeSchema()
        response = schema.load(data)
        if response.errors:
            return {"success": False, "errors": response.errors}, 400

        challenge_type = data["type"]
        challenge_class = get_chal_class(challenge_type)
        challenge = challenge_class.create(request)
        response = challenge_class.read(challenge)
        return {"success": True, "data": response}
Exemple #5
0
class NotificantionList(Resource):
    @notifications_namespace.doc(
        description="Endpoint to get notification objects in bulk",
        responses={
            200: ("Success", "NotificationListSuccessResponse"),
            400: (
                "An error occured processing the provided or stored data",
                "APISimpleErrorResponse",
            ),
        },
    )
    @validate_args(
        {
            "title": (str, None),
            "content": (str, None),
            "user_id": (int, None),
            "team_id": (int, None),
            "q": (str, None),
            "field": (
                RawEnum("NotificationFields", {
                    "title": "title",
                    "content": "content"
                }),
                None,
            ),
        },
        location="query",
    )
    def get(self, query_args):
        q = query_args.pop("q", None)
        field = str(query_args.pop("field", None))
        filters = build_model_filters(model=Notifications,
                                      query=q,
                                      field=field)

        notifications = (Notifications.query.filter_by(**query_args).filter(
            *filters).all())
        schema = NotificationSchema(many=True)
        result = schema.dump(notifications)
        if result.errors:
            return {"success": False, "errors": result.errors}, 400
        return {"success": True, "data": result.data}

    @admins_only
    @notifications_namespace.doc(
        description="Endpoint to create a notification object",
        responses={
            200: ("Success", "NotificationDetailedSuccessResponse"),
            400: (
                "An error occured processing the provided or stored data",
                "APISimpleErrorResponse",
            ),
        },
    )
    def post(self):
        req = request.get_json()

        schema = NotificationSchema()
        result = schema.load(req)

        if result.errors:
            return {"success": False, "errors": result.errors}, 400

        db.session.add(result.data)
        db.session.commit()

        response = schema.dump(result.data)

        # Grab additional settings
        notif_type = req.get("type", "alert")
        notif_sound = req.get("sound", True)
        response.data["type"] = notif_type
        response.data["sound"] = notif_sound

        current_app.events_manager.publish(data=response.data,
                                           type="notification")

        return {"success": True, "data": response.data}
Exemple #6
0
class UnlockList(Resource):
    @admins_only
    @unlocks_namespace.doc(
        description="Endpoint to get unlock objects in bulk",
        responses={
            200: ("Success", "UnlockListSuccessResponse"),
            400: (
                "An error occured processing the provided or stored data",
                "APISimpleErrorResponse",
            ),
        },
    )
    @validate_args(
        {
            "user_id": (int, None),
            "team_id": (int, None),
            "target": (int, None),
            "type": (str, None),
            "q": (str, None),
            "field": (
                RawEnum("UnlockFields", {
                    "target": "target",
                    "type": "type"
                }),
                None,
            ),
        },
        location="query",
    )
    def get(self, query_args):
        q = query_args.pop("q", None)
        field = str(query_args.pop("field", None))
        filters = build_model_filters(model=Unlocks, query=q, field=field)

        unlocks = Unlocks.query.filter_by(**query_args).filter(*filters).all()
        schema = UnlockSchema()
        response = schema.dump(unlocks)

        if response.errors:
            return {"success": False, "errors": response.errors}, 400

        return {"success": True, "data": response.data}

    @during_ctf_time_only
    @require_verified_emails
    @authed_only
    @unlocks_namespace.doc(
        description=
        "Endpoint to create an unlock object. Used to unlock hints.",
        responses={
            200: ("Success", "UnlockDetailedSuccessResponse"),
            400: (
                "An error occured processing the provided or stored data",
                "APISimpleErrorResponse",
            ),
        },
    )
    def post(self):
        req = request.get_json()
        user = get_current_user()

        req["user_id"] = user.id
        req["team_id"] = user.team_id

        Model = get_class_by_tablename(req["type"])
        target = Model.query.filter_by(id=req["target"]).first_or_404()

        if target.cost > user.score:
            return (
                {
                    "success": False,
                    "errors": {
                        "score":
                        "У вас недостаточно очков, чтобы разблокировать эту подсказку"
                    },
                },
                400,
            )

        schema = UnlockSchema()
        response = schema.load(req, session=db.session)

        if response.errors:
            return {"success": False, "errors": response.errors}, 400

        existing = Unlocks.query.filter_by(**req).first()
        if existing:
            return (
                {
                    "success": False,
                    "errors": {
                        "target": "Вы уже разблокировали это"
                    },
                },
                400,
            )

        db.session.add(response.data)

        award_schema = AwardSchema()
        award = {
            "user_id": user.id,
            "team_id": user.team_id,
            "name": target.name,
            "description": target.description,
            "value": (-target.cost),
            "category": target.category,
        }

        award = award_schema.load(award)
        db.session.add(award.data)
        db.session.commit()
        clear_standings()

        response = schema.dump(response.data)

        return {"success": True, "data": response.data}
Exemple #7
0
class UserList(Resource):
    @check_account_visibility
    @users_namespace.doc(
        description="Endpoint to get User objects in bulk",
        responses={
            200: ("Success", "UserListSuccessResponse"),
            400: (
                "An error occured processing the provided or stored data",
                "APISimpleErrorResponse",
            ),
        },
    )
    @validate_args(
        {
            "affiliation": (str, None),
            "country": (str, None),
            "bracket": (str, None),
            "q": (str, None),
            "field": (
                RawEnum(
                    "UserFields",
                    {
                        "name": "name",
                        "website": "website",
                        "country": "country",
                        "bracket": "bracket",
                        "affiliation": "affiliation",
                    },
                ),
                None,
            ),
        },
        location="query",
    )
    def get(self, query_args):
        q = query_args.pop("q", None)
        field = str(query_args.pop("field", None))
        filters = build_model_filters(model=Users, query=q, field=field)

        if is_admin() and request.args.get("view") == "admin":
            users = (Users.query.filter_by(**query_args).filter(
                *filters).paginate(per_page=50, max_per_page=100))
        else:
            users = (Users.query.filter_by(
                banned=False, hidden=False,
                **query_args).filter(*filters).paginate(per_page=50,
                                                        max_per_page=100))

        response = UserSchema(view="user", many=True).dump(users.items)

        if response.errors:
            return {"success": False, "errors": response.errors}, 400

        return {
            "meta": {
                "pagination": {
                    "page": users.page,
                    "next": users.next_num,
                    "prev": users.prev_num,
                    "pages": users.pages,
                    "per_page": users.per_page,
                    "total": users.total,
                }
            },
            "success": True,
            "data": response.data,
        }

    @admins_only
    @users_namespace.doc(
        description="Endpoint to create a User object",
        responses={
            200: ("Success", "UserDetailedSuccessResponse"),
            400: (
                "An error occured processing the provided or stored data",
                "APISimpleErrorResponse",
            ),
        },
        params={
            "notify":
            "Whether to send the created user an email with their credentials"
        },
    )
    def post(self):
        req = request.get_json()
        schema = UserSchema("admin")
        response = schema.load(req)

        if response.errors:
            return {"success": False, "errors": response.errors}, 400

        db.session.add(response.data)
        db.session.commit()

        if request.args.get("notify"):
            name = response.data.name
            email = response.data.email
            password = req.get("password")

            user_created_notification(addr=email, name=name, password=password)

        clear_standings()

        response = schema.dump(response.data)

        return {"success": True, "data": response.data}
Exemple #8
0
class TagList(Resource):
    @admins_only
    @tags_namespace.doc(
        description="Endpoint to list Tag objects in bulk",
        responses={
            200: ("Success", "TagListSuccessResponse"),
            400: (
                "An error occured processing the provided or stored data",
                "APISimpleErrorResponse",
            ),
        },
    )
    @validate_args(
        {
            "challenge_id": (int, None),
            "value": (str, None),
            "q": (str, None),
            "field": (
                RawEnum("TagFields", {
                    "challenge_id": "challenge_id",
                    "value": "value"
                }),
                None,
            ),
        },
        location="query",
    )
    def get(self, query_args):
        q = query_args.pop("q", None)
        field = str(query_args.pop("field", None))
        filters = build_model_filters(model=Tags, query=q, field=field)

        tags = Tags.query.filter_by(**query_args).filter(*filters).all()
        schema = TagSchema(many=True)
        response = schema.dump(tags)

        if response.errors:
            return {"success": False, "errors": response.errors}, 400

        return {"success": True, "data": response.data}

    @admins_only
    @tags_namespace.doc(
        description="Endpoint to create a Tag object",
        responses={
            200: ("Success", "TagDetailedSuccessResponse"),
            400: (
                "An error occured processing the provided or stored data",
                "APISimpleErrorResponse",
            ),
        },
    )
    def post(self):
        req = request.get_json()
        schema = TagSchema()
        response = schema.load(req, session=db.session)

        if response.errors:
            return {"success": False, "errors": response.errors}, 400

        db.session.add(response.data)
        db.session.commit()

        response = schema.dump(response.data)
        db.session.close()

        return {"success": True, "data": response.data}
Exemple #9
0
class SubmissionsList(Resource):
    @admins_only
    @submissions_namespace.doc(
        description="Endpoint to get submission objects in bulk",
        responses={
            200: ("Success", "SubmissionListSuccessResponse"),
            400: (
                "An error occured processing the provided or stored data",
                "APISimpleErrorResponse",
            ),
        },
    )
    @validate_args(
        {
            "challenge_id": (int, None),
            "user_id": (int, None),
            "team_id": (int, None),
            "ip": (str, None),
            "provided": (str, None),
            "type": (str, None),
            "q": (str, None),
            "field": (
                RawEnum(
                    "SubmissionFields",
                    {
                        "challenge_id": "challenge_id",
                        "user_id": "user_id",
                        "team_id": "team_id",
                        "ip": "ip",
                        "provided": "provided",
                        "type": "type",
                    },
                ),
                None,
            ),
        },
        location="query",
    )
    def get(self, query_args):
        q = query_args.pop("q", None)
        field = str(query_args.pop("field", None))
        filters = build_model_filters(model=Submissions, query=q, field=field)

        args = query_args
        schema = SubmissionSchema(many=True)

        submissions = (Submissions.query.filter_by(**args).filter(
            *filters).paginate(max_per_page=100))

        response = schema.dump(submissions.items)

        if response.errors:
            return {"success": False, "errors": response.errors}, 400

        return {
            "meta": {
                "pagination": {
                    "page": submissions.page,
                    "next": submissions.next_num,
                    "prev": submissions.prev_num,
                    "pages": submissions.pages,
                    "per_page": submissions.per_page,
                    "total": submissions.total,
                }
            },
            "success": True,
            "data": response.data,
        }

    @admins_only
    @submissions_namespace.doc(
        description=
        "Endpoint to create a submission object. Users should interact with the attempt endpoint to submit flags.",
        responses={
            200: ("Success", "SubmissionListSuccessResponse"),
            400: (
                "An error occured processing the provided or stored data",
                "APISimpleErrorResponse",
            ),
        },
    )
    @validate_args(TransientSubmissionModel, location="json")
    def post(self, json_args):
        req = json_args
        Model = Submissions.get_child(type=req.get("type"))
        schema = SubmissionSchema(instance=Model())
        response = schema.load(req)
        if response.errors:
            return {"success": False, "errors": response.errors}, 400

        db.session.add(response.data)
        db.session.commit()

        response = schema.dump(response.data)
        db.session.close()

        # Delete standings cache
        clear_standings()

        return {"success": True, "data": response.data}
Exemple #10
0
class AwardList(Resource):
    @admins_only
    @awards_namespace.doc(
        description="Endpoint to list Award objects in bulk",
        responses={
            200: ("Success", "AwardListSuccessResponse"),
            400: (
                "An error occured processing the provided or stored data",
                "APISimpleErrorResponse",
            ),
        },
    )
    @validate_args(
        {
            "user_id": (int, None),
            "team_id": (int, None),
            "type": (str, None),
            "value": (int, None),
            "category": (int, None),
            "icon": (int, None),
            "q": (str, None),
            "field": (
                RawEnum(
                    "AwardFields",
                    {
                        "name": "name",
                        "description": "description",
                        "category": "category",
                        "icon": "icon",
                    },
                ),
                None,
            ),
        },
        location="query",
    )
    def get(self, query_args):
        q = query_args.pop("q", None)
        field = str(query_args.pop("field", None))
        filters = build_model_filters(model=Awards, query=q, field=field)

        awards = Awards.query.filter_by(**query_args).filter(*filters).all()
        schema = AwardSchema(many=True)
        response = schema.dump(awards)

        if response.errors:
            return {"success": False, "errors": response.errors}, 400

        return {"success": True, "data": response.data}

    @admins_only
    @awards_namespace.doc(
        description="Endpoint to create an Award object",
        responses={
            200: ("Success", "AwardListSuccessResponse"),
            400: (
                "An error occured processing the provided or stored data",
                "APISimpleErrorResponse",
            ),
        },
    )
    def post(self):
        req = request.get_json()

        # Force a team_id if in team mode and unspecified
        if is_teams_mode():
            team_id = req.get("team_id")
            if team_id is None:
                user = Users.query.filter_by(id=req["user_id"]).first()
                if user.team_id is None:
                    return (
                        {
                            "success": False,
                            "errors": {
                                "team_id": [
                                    "User doesn't have a team to associate award with"
                                ]
                            },
                        },
                        400,
                    )
                req["team_id"] = user.team_id

        schema = AwardSchema()

        response = schema.load(req, session=db.session)
        if response.errors:
            return {"success": False, "errors": response.errors}, 400

        db.session.add(response.data)
        db.session.commit()

        response = schema.dump(response.data)
        db.session.close()

        # Delete standings cache because awards can change scores
        clear_standings()

        return {"success": True, "data": response.data}
Exemple #11
0
class UnlockList(Resource):
    @admins_only
    @unlocks_namespace.doc(
        description="Endpoint to get unlock objects in bulk",
        responses={
            200: ("Success", "UnlockListSuccessResponse"),
            400: (
                "An error occured processing the provided or stored data",
                "APISimpleErrorResponse",
            ),
        },
    )
    @validate_args(
        {
            "user_id": (int, None),
            "team_id": (int, None),
            "target": (int, None),
            "type": (str, None),
            "q": (str, None),
            "field": (
                RawEnum("UnlockFields", {"target": "target", "type": "type"}),
                None,
            ),
        },
        location="query",
    )
    def get(self, query_args):
        q = query_args.pop("q", None)
        field = str(query_args.pop("field", None))
        filters = build_model_filters(model=Unlocks, query=q, field=field)

        unlocks = Unlocks.query.filter_by(**query_args).filter(*filters).all()
        schema = UnlockSchema()
        response = schema.dump(unlocks)

        if response.errors:
            return {"success": False, "errors": response.errors}, 400

        return {"success": True, "data": response.data}

    @during_ctf_time_only
    @require_verified_emails
    @authed_only
    @unlocks_namespace.doc(
        description="Endpoint to create an unlock object. Used to unlock hints.",
        responses={
            200: ("Success", "UnlockDetailedSuccessResponse"),
            400: (
                "An error occured processing the provided or stored data",
                "APISimpleErrorResponse",
            ),
        },
    )
    def post(self):
        req = request.get_json()
        user = get_current_user()

        req["user_id"] = user.id
        req["team_id"] = user.team_id

        Model = get_class_by_tablename(req["type"])
        target = Model.query.filter_by(id=req["target"]).first_or_404()

        # We should use the team's score if in teams mode
        if is_teams_mode():
            team = get_current_team()
            score = team.score
        else:
            score = user.score

        if target.cost > score:
            return (
                {
                    "success": False,
                    "errors": {
                        "score": "You do not have enough points to unlock this hint"
                    },
                },
                400,
            )

        schema = UnlockSchema()
        response = schema.load(req, session=db.session)

        if response.errors:
            return {"success": False, "errors": response.errors}, 400

        # Search for an existing unlock that matches the target and type
        # And matches either the requesting user id or the requesting team id
        existing = Unlocks.query.filter(
            Unlocks.target == req["target"],
            Unlocks.type == req["type"],
            (Unlocks.user_id == req["user_id"]) | (Unlocks.team_id == req["team_id"]),
        ).first()
        if existing:
            return (
                {
                    "success": False,
                    "errors": {"target": "You've already unlocked this this target"},
                },
                400,
            )

        db.session.add(response.data)

        award_schema = AwardSchema()
        award = {
            "user_id": user.id,
            "team_id": user.team_id,
            "name": target.name,
            "description": target.description,
            "value": (-target.cost),
            "category": target.category,
        }

        award = award_schema.load(award)
        db.session.add(award.data)
        db.session.commit()
        clear_standings()

        response = schema.dump(response.data)

        return {"success": True, "data": response.data}
Exemple #12
0
class PageList(Resource):
    @admins_only
    @pages_namespace.doc(
        description="Endpoint to get page objects in bulk",
        responses={
            200: ("Success", "PageListSuccessResponse"),
            400: (
                "An error occured processing the provided or stored data",
                "APISimpleErrorResponse",
            ),
        },
    )
    @validate_args(
        {
            "id": (int, None),
            "title": (str, None),
            "route": (str, None),
            "draft": (bool, None),
            "hidden": (bool, None),
            "auth_required": (bool, None),
            "q": (str, None),
            "field": (
                RawEnum(
                    "PageFields",
                    {
                        "title": "title",
                        "route": "route",
                        "content": "content"
                    },
                ),
                None,
            ),
        },
        location="query",
    )
    def get(self, query_args):
        q = query_args.pop("q", None)
        field = str(query_args.pop("field", None))
        filters = build_model_filters(model=Pages, query=q, field=field)

        pages = Pages.query.filter_by(**query_args).filter(*filters).all()
        schema = PageSchema(exclude=["content"], many=True)
        response = schema.dump(pages)
        if response.errors:
            return {"success": False, "errors": response.errors}, 400

        return {"success": True, "data": response.data}

    @admins_only
    @pages_namespace.doc(
        description="Endpoint to create a page object",
        responses={
            200: ("Success", "PageDetailedSuccessResponse"),
            400: (
                "An error occured processing the provided or stored data",
                "APISimpleErrorResponse",
            ),
        },
    )
    @validate_args(TransientPageModel, location="json")
    def post(self, json_args):
        req = json_args
        schema = PageSchema()
        response = schema.load(req)

        if response.errors:
            return {"success": False, "errors": response.errors}, 400

        db.session.add(response.data)
        db.session.commit()

        response = schema.dump(response.data)
        db.session.close()

        clear_pages()

        return {"success": True, "data": response.data}
Exemple #13
0
class CommentList(Resource):
    @admins_only
    @comments_namespace.doc(
        description="Endpoint to list Comment objects in bulk",
        responses={
            200: ("Success", "CommentListSuccessResponse"),
            400: (
                "An error occured processing the provided or stored data",
                "APISimpleErrorResponse",
            ),
        },
    )
    @validate_args(
        {
            "challenge_id": (int, None),
            "user_id": (int, None),
            "team_id": (int, None),
            "page_id": (int, None),
            "q": (str, None),
            "field": (RawEnum("CommentFields", {"content": "content"}), None),
        },
        location="query",
    )
    def get(self, query_args):
        q = query_args.pop("q", None)
        field = str(query_args.pop("field", None))
        CommentModel = get_comment_model(data=query_args)
        filters = build_model_filters(model=CommentModel, query=q, field=field)

        comments = (CommentModel.query.filter_by(**query_args).filter(
            *filters).order_by(
                CommentModel.id.desc()).paginate(max_per_page=100))
        schema = CommentSchema(many=True)
        response = schema.dump(comments.items)

        if response.errors:
            return {"success": False, "errors": response.errors}, 400

        return {
            "meta": {
                "pagination": {
                    "page": comments.page,
                    "next": comments.next_num,
                    "prev": comments.prev_num,
                    "pages": comments.pages,
                    "per_page": comments.per_page,
                    "total": comments.total,
                }
            },
            "success": True,
            "data": response.data,
        }

    @admins_only
    @comments_namespace.doc(
        description="Endpoint to create a Comment object",
        responses={
            200: ("Success", "CommentDetailedSuccessResponse"),
            400: (
                "An error occured processing the provided or stored data",
                "APISimpleErrorResponse",
            ),
        },
    )
    def post(self):
        req = request.get_json()
        # Always force author IDs to be the actual user
        req["author_id"] = session["id"]
        CommentModel = get_comment_model(data=req)

        m = CommentModel(**req)
        db.session.add(m)
        db.session.commit()

        schema = CommentSchema()

        response = schema.dump(m)
        db.session.close()

        return {"success": True, "data": response.data}
Exemple #14
0
class NotificantionList(Resource):
    @notifications_namespace.doc(
        description="Endpoint to get notification objects in bulk",
        responses={
            200: ("Success", "NotificationListSuccessResponse"),
            400: (
                "An error occured processing the provided or stored data",
                "APISimpleErrorResponse",
            ),
        },
    )
    @validate_args(
        {
            "title": (str, None),
            "content": (str, None),
            "user_id": (int, None),
            "team_id": (int, None),
            "q": (str, None),
            "field": (
                RawEnum("NotificationFields", {
                    "title": "title",
                    "content": "content"
                }),
                None,
            ),
        },
        location="query",
    )
    def get(self, query_args):
        q = query_args.pop("q", None)
        field = str(query_args.pop("field", None))
        filters = build_model_filters(model=Notifications,
                                      query=q,
                                      field=field)

        notifications = (Notifications.query.filter_by(**query_args).filter(
            *filters).all())
        schema = NotificationSchema(many=True)
        result = schema.dump(notifications)
        if result.errors:
            return {"success": False, "errors": result.errors}, 400
        return {"success": True, "data": result.data}

    @admins_only
    @notifications_namespace.doc(
        description="Endpoint to create a notification object",
        responses={
            200: ("Success", "NotificationDetailedSuccessResponse"),
            400: (
                "An error occured processing the provided or stored data",
                "APISimpleErrorResponse",
            ),
        },
    )
    def post(self):
        req = request.get_json()

        schema = NotificationSchema()
        result = schema.load(req)

        if result.errors:
            return {"success": False, "errors": result.errors}, 400

        response = schema.dump(result.data)
        print(response)

        # Custom LR
        bar = '================\n'
        if ";" in response.data['content']:
            split_data = response.data['content'].split(";")
            for i in range(len(split_data)):
                if "=" in split_data[i].lower():
                    print(
                        '\n{}WARNING! Usering Equal Sign instead of Colon!\n'.
                        format(bar))
                    split_data[i].replace('=', ':')
                if "id" in split_data[i].lower():
                    response.data['id'] = split_data[i].replace('id:', '')
                elif "user" in split_data[i].lower():
                    response.data['user'] = split_data[i].replace('user:'******'')
                elif "ip" in split_data[i].lower():
                    response.data['ip'] = split_data[i].replace('ip:', '')
                elif "password" in split_data[i].lower():
                    response.data['password'] = split_data[i].replace(
                        'password:'******'')

            # If ip is supplied, password does too run the add VMs with existing
            if 'ip' in response.data:
                new_assoc = Association(user_id=response.data['id'], \
                    name=response.data['user'],  ip=response.data['ip'], \
                    password=response.data['password'])
            else:
                new_assoc = Association(user_id=response.data['id'],
                                        name=response.data['user'])
            db.session.add(new_assoc)
            db.session.commit()
            return {"success": True}
        elif "#delete_association" in response.data['content'] or \
            "#da" in response.data['content']:
            if "=" in response.data['content']:
                response.data['content'] = response.data['content'].replace(
                    '=', ':')
            target_id = response.data['content']
            target_id = target_id.replace('#da:', '')
            print('Target: {} - '.format(target_id, type(target_id)))
            db.session.execute(
                'DELETE from association WHERE id={}'.format(target_id))
            db.session.commit()

            # publish mods
            response.data['content'] += f'{target_id} Deleted\n'
            db.session.add(response.data)
            db.session.commit()

            # Grab additional settings
            notif_type = req.get("type", "alert")
            notif_sound = req.get("sound", True)
            response.data["type"] = notif_type
            response.data["sound"] = notif_sound

            #current_app.events_manager.publish(data=response.data, type="notification")
            return {"success": True, "data": response.data}

        elif "#assign_association" in response.data['content'] or \
            "#aa" in response.data['content']:
            if "=" in response.data['content']:
                response.data['content'] = response.data['content'].replace(
                    '=', ':')
            target_id = response.data['content'].replace('#aa:', '')
            current_users = db.session.query(Users.id, Users.name,
                                             Users.email).all()
            can_continue = True
            for user in current_users:
                if target_id == user[2]:
                    print(f'({user[0]}), {user[1]}: {user[2]}')
                    #response.data['content'] += f'{user[0]},{user[1]}'
                    can_continue = True
                else:
                    can_continue = False

            # Get Current List of Assoc
            assoc_table = ''
            for current_ids in db.session.query(Association).all():
                print(current_ids.user_id)
                assoc_table += f'{current_ids.user_id}, '

            # Sift through current registered users if not in assoc_table add
            current_assoc = db.session.query(Association).all()
            if str(user[0]) not in assoc_table:

                # Check for available VMs
                for assoc in current_assoc:
                    if assoc.user_name == None and assoc.ip != None:
                        response.data[
                            'content'] += f' > {assoc.ip} : {assoc.password} \n'
                        #response.data['content'] += f'{user[1]},{user[0]} > {assoc.ip} : {assoc.password} \n'
                        db.session.query(Association).filter_by(
                            id=assoc.id).update({
                                'user_name': user[1],
                                'user_id': user[0],
                                'email': user[2]
                            })
                        db.session.commit()
                        break
            else:
                print('Already has a VM!')
                user_inf = db.session.query(Association).filter_by(
                    id=str(user[0]))
                for inf in user_inf:
                    print(f'user_inf: {inf.ip} {inf.password}')
                    response.data[
                        'content'] += f' > (Already has VM)\nhttps://{inf.ip}.logwars.logrhythm.com\nUsername: {inf.user_name}\nPassword: {inf.password} \n'
            db.session.add(result.data)
            db.session.commit()

            # Grab additional settings
            notif_type = req.get("type", "alert")
            notif_sound = req.get("sound", True)
            response.data["type"] = notif_type
            response.data["sound"] = notif_sound

            #current_app.events_manager.publish(data=response.data, type="notification")
            return {"success": True, "data": response.data}


        elif "#show_associations" in response.data['content'] or \
            "#sa" in response.data['content']:
            print("\nCurrent Associations\n{}".format(bar))
            print(f'response.data["content"] = {type(response.data)}')
            assoc_val = response.data['content']
            for assoc in db.session.query(Association).all():
                assoc_val = f'\nID: {assoc.id}, Name: {assoc.name}, Email: {assoc.email}, IP: {assoc.ip}, Password: {assoc.password}, UserId: {assoc.user_id}, UserName: {assoc.user_name}'
                response.data['content'] += f'{assoc_val}\n'
                #   assoc_val = "empty"
                print(assoc_val)
            #return {"success": True}

            db.session.add(result.data)
            db.session.commit()

            # Grab additional settings
            notif_type = req.get("type", "alert")
            notif_sound = req.get("sound", True)
            response.data["type"] = notif_type
            response.data["sound"] = notif_sound

            #current_app.events_manager.publish(data=response.data, type="notification")
            return {"success": True, "data": response.data}
        elif "#show_users" in response.data['content'] or \
            "#su" in response.data['content']:
            current_users = db.session.query(Users.id, Users.name).all()
            print('\nRegistered Users:\n{}'.format(bar))
            for user in current_users:
                print("({}) {}".format(user[0], user[1]))
                response.data['content'] += f'{user[0]},{user[1]}'

            # Grab additional settings
            notif_type = req.get("type", "alert")
            notif_sound = req.get("sound", True)
            response.data["type"] = notif_type
            response.data["sound"] = notif_sound

            #current_app.events_manager.publish(data=response.data, type="notification")
            return {"success": True, "data": response.data}
        elif "#showassociationcolumns" in response.data['content']:
            result = db.session.execute('SHOW COLUMNS FROM association;')
            for r in result:
                print('Column: {}'.format(r))

        elif "#ca" in response.data['content'] or \
            "#checkAssociation" in response.data['content']:
            print(' - Checking for new Registered Users')
            current_users = db.session.query(Users.id, Users.name).all()

            # Get Current List of Assoc
            assoc_table = ''
            for current_ids in db.session.query(Association).all():
                print(current_ids.user_id)
                assoc_table += f'{current_ids.user_id}, '

            # Sift through current registered users if not in assoc_table add
            current_assoc = db.session.query(Association).all()
            for user in current_users:
                if str(user[0]) not in assoc_table:

                    # Check for available VMs
                    for assoc in current_assoc:
                        if assoc.user_name == None and assoc.ip != None:
                            response.data[
                                'content'] += f'{user[1]},{user[0]} \n'
                            db.session.query(Association).filter_by(
                                id=assoc.id).update({
                                    'user_name': user[1],
                                    'user_id': user[0]
                                })
                            db.session.commit()
                            break
            db.session.add(result.data)
            db.session.commit()

            # Grab additional settings
            notif_type = req.get("type", "alert")
            notif_sound = req.get("sound", True)
            response.data["type"] = notif_type
            response.data["sound"] = notif_sound

            return {"success": True, "data": response.data}

        elif "#vm:" in response.data['content']:
            print(' - Uploading new VMs')
            existing_get_vms = False
            vm_list = response.data['content'].replace('#vm:', '').split("&")
            for current_vm in vm_list:
                print('Current VM: {}'.format(current_vm))

                # TODO : Time constraints this is ugly and needs recoding but works
                # Check for existing Users and assign first 20 users per VM
                vms_allowed = 11
                v_reset = vms_allowed
                print(f'allow : {vms_allowed}\nreset: {v_reset}')
                vm_used = 1
                current_name = str(vm_used)
                found_users = False
                current_assoc_table = db.session.query(Association).all()
                for assoc in current_assoc_table:
                    found_users = True
                    if vm_used >= vms_allowed:
                        print(
                            'Used up 10 VMs for registered users. ({})'.format(
                                str(vm_used)))

                    # Grab user if none register, update index for VM to stay 20 Range
                    if assoc.name is not None and assoc.ip is None:
                        print('assoc before: {}'.format(str(vm_used).zfill(2)))
                        user_id = 'User{}'.format(str(vm_used).zfill(2))
                        db.session.query(Association).filter_by(id=assoc.id).\
                            update({'ip':current_vm, 'password':'******'.format(user_id.capitalize().replace('User', 'U')), 'name':user_id})
                        #update({'ip':vm_list[vm], 'password':gen_pass})
                        db.session.commit()
                        vm_used += 1
                        print('assoc After: {}'.format(str(vm_used).zfill(2)))

                # If Used for registered users make available
                print('VMs Currently Used: {}'.format(str(vm_used).zfill(2)))
                if found_users:
                    vms_allowed = vms_allowed - vm_used
                    current_name = str(vms_allowed - 1).zfill(2)
                    print(
                        'After Assoc VMs Currently Used: {}\nAllowed: {}\ncurrent_name:{}'
                        .format(
                            str(vm_used).zfill(2), vms_allowed, current_name))
                else:
                    current_name = str(vms_allowed).zfill(2)
                for no_user in range(vms_allowed):
                    if vm_used < vms_allowed:
                        user_id = 'User{}'.format(str(vm_used).zfill(2))
                        db.session.add(
                            Association(ip=current_vm,
                                        password='******'.format(
                                            user_id.capitalize().replace(
                                                'User', 'U')),
                                        name=user_id))
                        db.session.commit()
                        vm_used += 1
                        current_name = int(current_name) + 1

                # reset values for next VM
                vms_allowed = v_reset
                vm_used = 1
                current_name = str(vm_used)

            db.session.add(result.data)
            db.session.commit()

            # Grab additional settings
            notif_type = req.get("type", "alert")
            notif_sound = req.get("sound", True)
            response.data["type"] = notif_type
            response.data["sound"] = notif_sound

            #current_app.events_manager.publish(data=response.data, type="notification")
            return {"success": True, "data": response.data}

        elif "#pa" in response.data['content']:
            print(
                ' - Updating Association Table > MariaDB Syntax will not work in Debug'
            )
            db.session.execute('DROP TABLE IF EXISTS association;')
            db.session.commit()
            new_table_qry = 'CREATE TABLE association (' \
                'id INTEGER NOT NULL AUTO_INCREMENT,user_id INTEGER,name VARCHAR(128),user_name VARCHAR(128),email VARCHAR(128),' \
                'ip VARCHAR(128),password VARCHAR(128),PRIMARY KEY (id),UNIQUE (id),UNIQUE (email))'
            db.session.execute(new_table_qry)
            db.session.commit()

            # Grab additional settings
            notif_type = req.get("type", "alert")
            notif_sound = req.get("sound", True)
            response.data["type"] = notif_type
            response.data["sound"] = notif_sound

            #current_app.events_manager.publish(data=response.data, type="notification")
            return {"success": True, "data": response.data}

        elif "#tp" in response.data['content']:
            print('Generated Password: {}'.format(self.gen_password()))
            # Grab additional settings
            notif_type = req.get("type", "alert")
            notif_sound = req.get("sound", True)
            response.data["type"] = notif_type
            response.data["sound"] = notif_sound

            #current_app.events_manager.publish(data=response.data, type="notification")
            return {"success": True, "data": response.data}

        elif "#testCreateUser:"******"type", "alert")
            notif_sound = req.get("sound", True)
            response.data["type"] = notif_type
            response.data["sound"] = notif_sound

            #current_app.events_manager.publish(data=response.data, type="notification")
            return {"success": True, "data": response.data}

        else:
            db.session.add(result.data)
            db.session.commit()

            response = schema.dump(result.data)

            # Grab additional settings
            notif_type = req.get("type", "alert")
            notif_sound = req.get("sound", True)
            response.data["type"] = notif_type
            response.data["sound"] = notif_sound

            current_app.events_manager.publish(data=response.data,
                                               type="notification")

            return {"success": True, "data": response.data}
Exemple #15
0
class HintList(Resource):
    @admins_only
    @hints_namespace.doc(
        description="Endpoint to list Hint objects in bulk",
        responses={
            200: ("Success", "HintListSuccessResponse"),
            400: (
                "An error occured processing the provided or stored data",
                "APISimpleErrorResponse",
            ),
        },
    )
    @validate_args(
        {
            "type": (str, None),
            "challenge_id": (int, None),
            "content": (str, None),
            "cost": (int, None),
            "q": (str, None),
            "field": (
                RawEnum("HintFields", {
                    "type": "type",
                    "content": "content"
                }),
                None,
            ),
        },
        location="query",
    )
    def get(self, query_args):
        q = query_args.pop("q", None)
        field = str(query_args.pop("field", None))
        filters = build_model_filters(model=Hints, query=q, field=field)

        hints = Hints.query.filter_by(**query_args).filter(*filters).all()
        response = HintSchema(many=True, view="locked").dump(hints)

        if response.errors:
            return {"success": False, "errors": response.errors}, 400

        return {"success": True, "data": response.data}

    @admins_only
    @hints_namespace.doc(
        description="Endpoint to create a Hint object",
        responses={
            200: ("Success", "HintDetailedSuccessResponse"),
            400: (
                "An error occured processing the provided or stored data",
                "APISimpleErrorResponse",
            ),
        },
    )
    def post(self):
        req = request.get_json()
        schema = HintSchema(view="admin")
        response = schema.load(req, session=db.session)

        if response.errors:
            return {"success": False, "errors": response.errors}, 400

        db.session.add(response.data)
        db.session.commit()

        response = schema.dump(response.data)

        return {"success": True, "data": response.data}
Exemple #16
0
class TeamList(Resource):
    @check_account_visibility
    @teams_namespace.doc(
        description="Endpoint to get Team objects in bulk",
        responses={
            200: ("Success", "TeamListSuccessResponse"),
            400: (
                "An error occured processing the provided or stored data",
                "APISimpleErrorResponse",
            ),
        },
    )
    @validate_args(
        {
            "affiliation": (str, None),
            "country": (str, None),
            "bracket": (str, None),
            "q": (str, None),
            "field": (
                RawEnum(
                    "TeamFields",
                    {
                        "name": "name",
                        "website": "website",
                        "country": "country",
                        "bracket": "bracket",
                        "affiliation": "affiliation",
                    },
                ),
                None,
            ),
        },
        location="query",
    )
    def get(self, query_args):
        q = query_args.pop("q", None)
        field = str(query_args.pop("field", None))
        filters = build_model_filters(model=Teams, query=q, field=field)

        if is_admin() and request.args.get("view") == "admin":
            teams = (
                Teams.query.filter_by(**query_args)
                .filter(*filters)
                .paginate(per_page=50, max_per_page=100)
            )
        else:
            teams = (
                Teams.query.filter_by(hidden=False, banned=False, **query_args)
                .filter(*filters)
                .paginate(per_page=50, max_per_page=100)
            )

        user_type = get_current_user_type(fallback="user")
        view = copy.deepcopy(TeamSchema.views.get(user_type))
        view.remove("members")
        response = TeamSchema(view=view, many=True).dump(teams.items)

        if response.errors:
            return {"success": False, "errors": response.errors}, 400

        return {
            "meta": {
                "pagination": {
                    "page": teams.page,
                    "next": teams.next_num,
                    "prev": teams.prev_num,
                    "pages": teams.pages,
                    "per_page": teams.per_page,
                    "total": teams.total,
                }
            },
            "success": True,
            "data": response.data,
        }

    @admins_only
    @teams_namespace.doc(
        description="Endpoint to create a Team object",
        responses={
            200: ("Success", "TeamDetailedSuccessResponse"),
            400: (
                "An error occured processing the provided or stored data",
                "APISimpleErrorResponse",
            ),
        },
    )
    def post(self):
        req = request.get_json()
        user_type = get_current_user_type()
        view = TeamSchema.views.get(user_type)
        schema = TeamSchema(view=view)
        response = schema.load(req)

        if response.errors:
            return {"success": False, "errors": response.errors}, 400

        db.session.add(response.data)
        db.session.commit()

        response = schema.dump(response.data)
        db.session.close()

        clear_standings()

        return {"success": True, "data": response.data}
class ConfigList(Resource):
    @admins_only
    @configs_namespace.doc(
        description="Endpoint to get Config objects in bulk",
        responses={
            200: ("Success", "ConfigListSuccessResponse"),
            400: (
                "An error occured processing the provided or stored data",
                "APISimpleErrorResponse",
            ),
        },
    )
    @validate_args(
        {
            "key": (str, None),
            "value": (str, None),
            "q": (str, None),
            "field": (RawEnum("ConfigFields", {
                "key": "key",
                "value": "value"
            }), None),
        },
        location="query",
    )
    def get(self, query_args):
        q = query_args.pop("q", None)
        field = str(query_args.pop("field", None))
        filters = build_model_filters(model=Configs, query=q, field=field)

        configs = Configs.query.filter_by(**query_args).filter(*filters).all()
        schema = ConfigSchema(many=True)
        response = schema.dump(configs)
        if response.errors:
            return {"success": False, "errors": response.errors}, 400

        return {"success": True, "data": response.data}

    @admins_only
    @configs_namespace.doc(
        description="Endpoint to get create a Config object",
        responses={
            200: ("Success", "ConfigDetailedSuccessResponse"),
            400: (
                "An error occured processing the provided or stored data",
                "APISimpleErrorResponse",
            ),
        },
    )
    def post(self):
        req = request.get_json()
        schema = ConfigSchema()
        response = schema.load(req)

        if response.errors:
            return {"success": False, "errors": response.errors}, 400

        db.session.add(response.data)
        db.session.commit()

        response = schema.dump(response.data)
        db.session.close()

        clear_config()
        clear_standings()

        return {"success": True, "data": response.data}

    @admins_only
    @configs_namespace.doc(
        description="Endpoint to get patch Config objects in bulk",
        responses={200: ("Success", "APISimpleSuccessResponse")},
    )
    def patch(self):
        req = request.get_json()

        for key, value in req.items():
            set_config(key=key, value=value)

        clear_config()
        clear_standings()

        return {"success": True}
Exemple #18
0
class TopicList(Resource):
    @admins_only
    @topics_namespace.doc(
        description="Endpoint to list Topic objects in bulk",
        responses={
            200: ("Success", "TopicListSuccessResponse"),
            400: (
                "An error occured processing the provided or stored data",
                "APISimpleErrorResponse",
            ),
        },
    )
    @validate_args(
        {
            "value": (str, None),
            "q": (str, None),
            "field": (
                RawEnum("TopicFields", {"value": "value"}),
                None,
            ),
        },
        location="query",
    )
    def get(self, query_args):
        q = query_args.pop("q", None)
        field = str(query_args.pop("field", None))
        filters = build_model_filters(model=Topics, query=q, field=field)

        topics = Topics.query.filter_by(**query_args).filter(*filters).all()
        schema = TopicSchema(many=True)
        response = schema.dump(topics)

        if response.errors:
            return {"success": False, "errors": response.errors}, 400

        return {"success": True, "data": response.data}

    @admins_only
    @topics_namespace.doc(
        description="Endpoint to create a Topic object",
        responses={
            200: ("Success", "TopicDetailedSuccessResponse"),
            400: (
                "An error occured processing the provided or stored data",
                "APISimpleErrorResponse",
            ),
        },
    )
    def post(self):
        req = request.get_json()
        value = req.get("value")

        if value:
            topic = Topics.query.filter_by(value=value).first()
            if topic is None:
                schema = TopicSchema()
                response = schema.load(req, session=db.session)

                if response.errors:
                    return {"success": False, "errors": response.errors}, 400

                topic = response.data
                db.session.add(topic)
                db.session.commit()
        else:
            topic_id = req.get("topic_id")
            topic = Topics.query.filter_by(id=topic_id).first_or_404()

        req["topic_id"] = topic.id
        topic_type = req.get("type")
        if topic_type == "challenge":
            schema = ChallengeTopicSchema()
            response = schema.load(req, session=db.session)
        else:
            return {"success": False}, 400

        db.session.add(response.data)
        db.session.commit()

        response = schema.dump(response.data)
        db.session.close()

        return {"success": True, "data": response.data}

    @admins_only
    @topics_namespace.doc(
        description=
        "Endpoint to delete a specific Topic object of a specific type",
        responses={200: ("Success", "APISimpleSuccessResponse")},
    )
    @validate_args(
        {
            "type": (str, None),
            "target_id": (int, 0)
        },
        location="query",
    )
    def delete(self, query_args):
        topic_type = query_args.get("type")
        target_id = int(query_args.get("target_id", 0))

        if topic_type == "challenge":
            Model = ChallengeTopics
        else:
            return {"success": False}, 400

        topic = Model.query.filter_by(id=target_id).first_or_404()
        db.session.delete(topic)
        db.session.commit()
        db.session.close()

        return {"success": True}