from flask import session, request, abort
from flask_restplus import Namespace, Resource
from CTFd.models import (
    db,
    Users,
    Solves,
    Awards,
    Tracking,
    Unlocks,
    Submissions,
    Notifications,
)
from CTFd.utils.decorators import authed_only, admins_only, ratelimit
from CTFd.cache import clear_standings
from CTFd.utils.user import get_current_user, is_admin
from CTFd.utils.decorators.visibility import (
    check_account_visibility,
    check_score_visibility,
)

from CTFd.schemas.submissions import SubmissionSchema
from CTFd.schemas.awards import AwardSchema
from CTFd.schemas.users import UserSchema


users_namespace = Namespace("users", description="Endpoint to retrieve Users")


@users_namespace.route("")
class UserList(Resource):
    @check_account_visibility
    def get(self):
        users = Users.query.filter_by(banned=False, hidden=False)
        response = UserSchema(view="user", many=True).dump(users)

        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 = 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
            password = req.get("password")

        clear_standings()

        response = schema.dump(response.data)

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


@users_namespace.route("/<int:user_id>")
@users_namespace.param("user_id", "User ID")
class UserPublic(Resource):
    @check_account_visibility
    def get(self, user_id):
        user = Users.query.filter_by(id=user_id).first_or_404()

        if (user.banned or user.hidden) and is_admin() is False:
            abort(404)

        response = UserSchema(view=session.get("type", "user")).dump(user)

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

        response.data["place"] = user.place
        response.data["score"] = user.score

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

    @admins_only
    def patch(self, user_id):
        user = Users.query.filter_by(id=user_id).first_or_404()
        data = request.get_json()
        data["id"] = user_id
        schema = UserSchema(view="admin", instance=user, partial=True)
        response = schema.load(data)
        if response.errors:
            return {"success": False, "errors": response.errors}, 400

        db.session.commit()

        response = schema.dump(response.data)

        db.session.close()

        clear_standings()

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

    @admins_only
    def delete(self, user_id):
        Notifications.query.filter_by(user_id=user_id).delete()
        Awards.query.filter_by(user_id=user_id).delete()
        Unlocks.query.filter_by(user_id=user_id).delete()
        Submissions.query.filter_by(user_id=user_id).delete()
        Solves.query.filter_by(user_id=user_id).delete()
        Tracking.query.filter_by(user_id=user_id).delete()
        Users.query.filter_by(id=user_id).delete()
        db.session.commit()
        db.session.close()

        clear_standings()

        return {"success": True}


@users_namespace.route("/me")
class UserPrivate(Resource):
    @authed_only
    def get(self):
        user = get_current_user()
        response = UserSchema("self").dump(user).data
        response["place"] = user.place
        response["score"] = user.score
        return {"success": True, "data": response}

    @authed_only
    def patch(self):
        user = get_current_user()
        data = request.get_json()
        schema = UserSchema(view="self", instance=user, partial=True)
        response = schema.load(data)
        if response.errors:
            return {"success": False, "errors": response.errors}, 400

        db.session.commit()

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

        clear_standings()

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


@users_namespace.route("/me/solves")
class UserPrivateSolves(Resource):
    @authed_only
    def get(self):
        user = get_current_user()
        solves = user.get_solves(admin=True)

        view = "user" if not is_admin() else "admin"
        response = SubmissionSchema(view=view, many=True).dump(solves)

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

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


@users_namespace.route("/me/fails")
class UserPrivateFails(Resource):
    @authed_only
    def get(self):
        user = get_current_user()
        fails = user.get_fails(admin=True)

        view = "user" if not is_admin() else "admin"
        response = SubmissionSchema(view=view, many=True).dump(fails)
        if response.errors:
            return {"success": False, "errors": response.errors}, 400

        if is_admin():
            data = response.data
        else:
            data = []
        count = len(response.data)

        return {"success": True, "data": data, "meta": {"count": count}}


@users_namespace.route("/me/awards")
@users_namespace.param("user_id", "User ID")
class UserPrivateAwards(Resource):
    @authed_only
    def get(self):
        user = get_current_user()
        awards = user.get_awards(admin=True)

        view = "user" if not is_admin() else "admin"
        response = AwardSchema(view=view, many=True).dump(awards)

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

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


@users_namespace.route("/<user_id>/solves")
@users_namespace.param("user_id", "User ID")
class UserPublicSolves(Resource):
    @check_account_visibility
    @check_score_visibility
    def get(self, user_id):
        user = Users.query.filter_by(id=user_id).first_or_404()

        if (user.banned or user.hidden) and is_admin() is False:
            abort(404)

        solves = user.get_solves(admin=is_admin())

        view = "user" if not is_admin() else "admin"
        response = SubmissionSchema(view=view, many=True).dump(solves)

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

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


@users_namespace.route("/<user_id>/fails")
@users_namespace.param("user_id", "User ID")
class UserPublicFails(Resource):
    @check_account_visibility
    @check_score_visibility
    def get(self, user_id):
        user = Users.query.filter_by(id=user_id).first_or_404()

        if (user.banned or user.hidden) and is_admin() is False:
            abort(404)
        fails = user.get_fails(admin=is_admin())

        view = "user" if not is_admin() else "admin"
        response = SubmissionSchema(view=view, many=True).dump(fails)
        if response.errors:
            return {"success": False, "errors": response.errors}, 400

        if is_admin():
            data = response.data
        else:
            data = []
        count = len(response.data)

        #  return {"success": True, "data": data, "meta": {"count": count}}
        return {"success": True, "data": None, "meta": {"count": None}}


@users_namespace.route("/<user_id>/awards")
@users_namespace.param("user_id", "User ID or 'me'")
class UserPublicAwards(Resource):
    @check_account_visibility
    @check_score_visibility
    def get(self, user_id):
        user = Users.query.filter_by(id=user_id).first_or_404()

        if (user.banned or user.hidden) and is_admin() is False:
            abort(404)
        awards = user.get_awards(admin=is_admin())

        view = "user" if not is_admin() else "admin"
        response = AwardSchema(view=view, many=True).dump(awards)

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

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

[((655, 715), 'flask_restplus.Namespace', 'Namespace', (['"""users"""'], {'description': '"""Endpoint to retrieve Users"""'}), "('users', description='Endpoint to retrieve Users')\n", (664, 715), False, 'from flask_restplus import Namespace, Resource\n'), ((836, 885), 'CTFd.models.Users.query.filter_by', 'Users.query.filter_by', ([], {'banned': '(False)', 'hidden': '(False)'}), '(banned=False, hidden=False)\n', (857, 885), False, 'from CTFd.models import db, Users, Solves, Awards, Tracking, Unlocks, Submissions, Notifications\n'), ((1160, 1178), 'flask.request.get_json', 'request.get_json', ([], {}), '()\n', (1176, 1178), False, 'from flask import session, request, abort\n'), ((1196, 1215), 'CTFd.schemas.users.UserSchema', 'UserSchema', (['"""admin"""'], {}), "('admin')\n", (1206, 1215), False, 'from CTFd.schemas.users import UserSchema\n'), ((1360, 1389), 'CTFd.models.db.session.add', 'db.session.add', (['response.data'], {}), '(response.data)\n', (1374, 1389), False, 'from CTFd.models import db, Users, Solves, Awards, Tracking, Unlocks, Submissions, Notifications\n'), ((1398, 1417), 'CTFd.models.db.session.commit', 'db.session.commit', ([], {}), '()\n', (1415, 1417), False, 'from CTFd.models import db, Users, Solves, Awards, Tracking, Unlocks, Submissions, Notifications\n'), ((1430, 1456), 'flask.request.args.get', 'request.args.get', (['"""notify"""'], {}), "('notify')\n", (1446, 1456), False, 'from flask import session, request, abort\n'), ((1548, 1565), 'CTFd.cache.clear_standings', 'clear_standings', ([], {}), '()\n', (1563, 1565), False, 'from CTFd.cache import clear_standings\n'), ((2445, 2463), 'flask.request.get_json', 'request.get_json', ([], {}), '()\n', (2461, 2463), False, 'from flask import session, request, abort\n'), ((2510, 2563), 'CTFd.schemas.users.UserSchema', 'UserSchema', ([], {'view': '"""admin"""', 'instance': 'user', 'partial': '(True)'}), "(view='admin', instance=user, partial=True)\n", (2520, 2563), False, 'from CTFd.schemas.users import UserSchema\n'), ((2708, 2727), 'CTFd.models.db.session.commit', 'db.session.commit', ([], {}), '()\n', (2725, 2727), False, 'from CTFd.models import db, Users, Solves, Awards, Tracking, Unlocks, Submissions, Notifications\n'), ((2784, 2802), 'CTFd.models.db.session.close', 'db.session.close', ([], {}), '()\n', (2800, 2802), False, 'from CTFd.models import db, Users, Solves, Awards, Tracking, Unlocks, Submissions, Notifications\n'), ((2812, 2829), 'CTFd.cache.clear_standings', 'clear_standings', ([], {}), '()\n', (2827, 2829), False, 'from CTFd.cache import clear_standings\n'), ((3347, 3366), 'CTFd.models.db.session.commit', 'db.session.commit', ([], {}), '()\n', (3364, 3366), False, 'from CTFd.models import db, Users, Solves, Awards, Tracking, Unlocks, Submissions, Notifications\n'), ((3375, 3393), 'CTFd.models.db.session.close', 'db.session.close', ([], {}), '()\n', (3391, 3393), False, 'from CTFd.models import db, Users, Solves, Awards, Tracking, Unlocks, Submissions, Notifications\n'), ((3403, 3420), 'CTFd.cache.clear_standings', 'clear_standings', ([], {}), '()\n', (3418, 3420), False, 'from CTFd.cache import clear_standings\n'), ((3567, 3585), 'CTFd.utils.user.get_current_user', 'get_current_user', ([], {}), '()\n', (3583, 3585), False, 'from CTFd.utils.user import get_current_user, is_admin\n'), ((3823, 3841), 'CTFd.utils.user.get_current_user', 'get_current_user', ([], {}), '()\n', (3839, 3841), False, 'from CTFd.utils.user import get_current_user, is_admin\n'), ((3857, 3875), 'flask.request.get_json', 'request.get_json', ([], {}), '()\n', (3873, 3875), False, 'from flask import session, request, abort\n'), ((3893, 3945), 'CTFd.schemas.users.UserSchema', 'UserSchema', ([], {'view': '"""self"""', 'instance': 'user', 'partial': '(True)'}), "(view='self', instance=user, partial=True)\n", (3903, 3945), False, 'from CTFd.schemas.users import UserSchema\n'), ((4090, 4109), 'CTFd.models.db.session.commit', 'db.session.commit', ([], {}), '()\n', (4107, 4109), False, 'from CTFd.models import db, Users, Solves, Awards, Tracking, Unlocks, Submissions, Notifications\n'), ((4165, 4183), 'CTFd.models.db.session.close', 'db.session.close', ([], {}), '()\n', (4181, 4183), False, 'from CTFd.models import db, Users, Solves, Awards, Tracking, Unlocks, Submissions, Notifications\n'), ((4193, 4210), 'CTFd.cache.clear_standings', 'clear_standings', ([], {}), '()\n', (4208, 4210), False, 'from CTFd.cache import clear_standings\n'), ((4393, 4411), 'CTFd.utils.user.get_current_user', 'get_current_user', ([], {}), '()\n', (4409, 4411), False, 'from CTFd.utils.user import get_current_user, is_admin\n'), ((4861, 4879), 'CTFd.utils.user.get_current_user', 'get_current_user', ([], {}), '()\n', (4877, 4879), False, 'from CTFd.utils.user import get_current_user, is_admin\n'), ((5157, 5167), 'CTFd.utils.user.is_admin', 'is_admin', ([], {}), '()\n', (5165, 5167), False, 'from CTFd.utils.user import get_current_user, is_admin\n'), ((5517, 5535), 'CTFd.utils.user.get_current_user', 'get_current_user', ([], {}), '()\n', (5533, 5535), False, 'from CTFd.utils.user import get_current_user, is_admin\n'), ((7249, 7259), 'CTFd.utils.user.is_admin', 'is_admin', ([], {}), '()\n', (7257, 7259), False, 'from CTFd.utils.user import get_current_user, is_admin\n'), ((1986, 1996), 'flask.abort', 'abort', (['(404)'], {}), '(404)\n', (1991, 1996), False, 'from flask import session, request, abort\n'), ((6210, 6220), 'flask.abort', 'abort', (['(404)'], {}), '(404)\n', (6215, 6220), False, 'from flask import session, request, abort\n'), ((6955, 6965), 'flask.abort', 'abort', (['(404)'], {}), '(404)\n', (6960, 6965), False, 'from flask import session, request, abort\n'), ((7875, 7885), 'flask.abort', 'abort', (['(404)'], {}), '(404)\n', (7880, 7885), False, 'from flask import session, request, abort\n'), ((905, 939), 'CTFd.schemas.users.UserSchema', 'UserSchema', ([], {'view': '"""user"""', 'many': '(True)'}), "(view='user', many=True)\n", (915, 939), False, 'from CTFd.schemas.users import UserSchema\n'), ((1859, 1892), 'CTFd.models.Users.query.filter_by', 'Users.query.filter_by', ([], {'id': 'user_id'}), '(id=user_id)\n', (1880, 1892), False, 'from CTFd.models import db, Users, Solves, Awards, Tracking, Unlocks, Submissions, Notifications\n'), ((1953, 1963), 'CTFd.utils.user.is_admin', 'is_admin', ([], {}), '()\n', (1961, 1963), False, 'from CTFd.utils.user import get_current_user, is_admin\n'), ((2381, 2414), 'CTFd.models.Users.query.filter_by', 'Users.query.filter_by', ([], {'id': 'user_id'}), '(id=user_id)\n', (2402, 2414), False, 'from CTFd.models import db, Users, Solves, Awards, Tracking, Unlocks, Submissions, Notifications\n'), ((2939, 2985), 'CTFd.models.Notifications.query.filter_by', 'Notifications.query.filter_by', ([], {'user_id': 'user_id'}), '(user_id=user_id)\n', (2968, 2985), False, 'from CTFd.models import db, Users, Solves, Awards, Tracking, Unlocks, Submissions, Notifications\n'), ((3003, 3042), 'CTFd.models.Awards.query.filter_by', 'Awards.query.filter_by', ([], {'user_id': 'user_id'}), '(user_id=user_id)\n', (3025, 3042), False, 'from CTFd.models import db, Users, Solves, Awards, Tracking, Unlocks, Submissions, Notifications\n'), ((3060, 3100), 'CTFd.models.Unlocks.query.filter_by', 'Unlocks.query.filter_by', ([], {'user_id': 'user_id'}), '(user_id=user_id)\n', (3083, 3100), False, 'from CTFd.models import db, Users, Solves, Awards, Tracking, Unlocks, Submissions, Notifications\n'), ((3118, 3162), 'CTFd.models.Submissions.query.filter_by', 'Submissions.query.filter_by', ([], {'user_id': 'user_id'}), '(user_id=user_id)\n', (3145, 3162), False, 'from CTFd.models import db, Users, Solves, Awards, Tracking, Unlocks, Submissions, Notifications\n'), ((3180, 3219), 'CTFd.models.Solves.query.filter_by', 'Solves.query.filter_by', ([], {'user_id': 'user_id'}), '(user_id=user_id)\n', (3202, 3219), False, 'from CTFd.models import db, Users, Solves, Awards, Tracking, Unlocks, Submissions, Notifications\n'), ((3237, 3278), 'CTFd.models.Tracking.query.filter_by', 'Tracking.query.filter_by', ([], {'user_id': 'user_id'}), '(user_id=user_id)\n', (3261, 3278), False, 'from CTFd.models import db, Users, Solves, Awards, Tracking, Unlocks, Submissions, Notifications\n'), ((3296, 3329), 'CTFd.models.Users.query.filter_by', 'Users.query.filter_by', ([], {'id': 'user_id'}), '(id=user_id)\n', (3317, 3329), False, 'from CTFd.models import db, Users, Solves, Awards, Tracking, Unlocks, Submissions, Notifications\n'), ((4487, 4497), 'CTFd.utils.user.is_admin', 'is_admin', ([], {}), '()\n', (4495, 4497), False, 'from CTFd.utils.user import get_current_user, is_admin\n'), ((4530, 4568), 'CTFd.schemas.submissions.SubmissionSchema', 'SubmissionSchema', ([], {'view': 'view', 'many': '(True)'}), '(view=view, many=True)\n', (4546, 4568), False, 'from CTFd.schemas.submissions import SubmissionSchema\n'), ((4953, 4963), 'CTFd.utils.user.is_admin', 'is_admin', ([], {}), '()\n', (4961, 4963), False, 'from CTFd.utils.user import get_current_user, is_admin\n'), ((4996, 5034), 'CTFd.schemas.submissions.SubmissionSchema', 'SubmissionSchema', ([], {'view': 'view', 'many': '(True)'}), '(view=view, many=True)\n', (5012, 5034), False, 'from CTFd.schemas.submissions import SubmissionSchema\n'), ((5611, 5621), 'CTFd.utils.user.is_admin', 'is_admin', ([], {}), '()\n', (5619, 5621), False, 'from CTFd.utils.user import get_current_user, is_admin\n'), ((5654, 5687), 'CTFd.schemas.awards.AwardSchema', 'AwardSchema', ([], {'view': 'view', 'many': '(True)'}), '(view=view, many=True)\n', (5665, 5687), False, 'from CTFd.schemas.awards import AwardSchema\n'), ((6083, 6116), 'CTFd.models.Users.query.filter_by', 'Users.query.filter_by', ([], {'id': 'user_id'}), '(id=user_id)\n', (6104, 6116), False, 'from CTFd.models import db, Users, Solves, Awards, Tracking, Unlocks, Submissions, Notifications\n'), ((6177, 6187), 'CTFd.utils.user.is_admin', 'is_admin', ([], {}), '()\n', (6185, 6187), False, 'from CTFd.utils.user import get_current_user, is_admin\n'), ((6261, 6271), 'CTFd.utils.user.is_admin', 'is_admin', ([], {}), '()\n', (6269, 6271), False, 'from CTFd.utils.user import get_current_user, is_admin\n'), ((6303, 6313), 'CTFd.utils.user.is_admin', 'is_admin', ([], {}), '()\n', (6311, 6313), False, 'from CTFd.utils.user import get_current_user, is_admin\n'), ((6346, 6384), 'CTFd.schemas.submissions.SubmissionSchema', 'SubmissionSchema', ([], {'view': 'view', 'many': '(True)'}), '(view=view, many=True)\n', (6362, 6384), False, 'from CTFd.schemas.submissions import SubmissionSchema\n'), ((6828, 6861), 'CTFd.models.Users.query.filter_by', 'Users.query.filter_by', ([], {'id': 'user_id'}), '(id=user_id)\n', (6849, 6861), False, 'from CTFd.models import db, Users, Solves, Awards, Tracking, Unlocks, Submissions, Notifications\n'), ((6922, 6932), 'CTFd.utils.user.is_admin', 'is_admin', ([], {}), '()\n', (6930, 6932), False, 'from CTFd.utils.user import get_current_user, is_admin\n'), ((7003, 7013), 'CTFd.utils.user.is_admin', 'is_admin', ([], {}), '()\n', (7011, 7013), False, 'from CTFd.utils.user import get_current_user, is_admin\n'), ((7045, 7055), 'CTFd.utils.user.is_admin', 'is_admin', ([], {}), '()\n', (7053, 7055), False, 'from CTFd.utils.user import get_current_user, is_admin\n'), ((7088, 7126), 'CTFd.schemas.submissions.SubmissionSchema', 'SubmissionSchema', ([], {'view': 'view', 'many': '(True)'}), '(view=view, many=True)\n', (7104, 7126), False, 'from CTFd.schemas.submissions import SubmissionSchema\n'), ((7748, 7781), 'CTFd.models.Users.query.filter_by', 'Users.query.filter_by', ([], {'id': 'user_id'}), '(id=user_id)\n', (7769, 7781), False, 'from CTFd.models import db, Users, Solves, Awards, Tracking, Unlocks, Submissions, Notifications\n'), ((7842, 7852), 'CTFd.utils.user.is_admin', 'is_admin', ([], {}), '()\n', (7850, 7852), False, 'from CTFd.utils.user import get_current_user, is_admin\n'), ((7925, 7935), 'CTFd.utils.user.is_admin', 'is_admin', ([], {}), '()\n', (7933, 7935), False, 'from CTFd.utils.user import get_current_user, is_admin\n'), ((7967, 7977), 'CTFd.utils.user.is_admin', 'is_admin', ([], {}), '()\n', (7975, 7977), False, 'from CTFd.utils.user import get_current_user, is_admin\n'), ((8010, 8043), 'CTFd.schemas.awards.AwardSchema', 'AwardSchema', ([], {'view': 'view', 'many': '(True)'}), '(view=view, many=True)\n', (8021, 8043), False, 'from CTFd.schemas.awards import AwardSchema\n'), ((3605, 3623), 'CTFd.schemas.users.UserSchema', 'UserSchema', (['"""self"""'], {}), "('self')\n", (3615, 3623), False, 'from CTFd.schemas.users import UserSchema\n'), ((2033, 2060), 'flask.session.get', 'session.get', (['"""type"""', '"""user"""'], {}), "('type', 'user')\n", (2044, 2060), False, 'from flask import session, request, abort\n')]