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}

[((26, 18, 26, 78), 'flask_restplus.Namespace', 'Namespace', (), '', False, 'from flask_restplus import Namespace, Resource\n'), ((33, 16, 33, 65), 'CTFd.models.Users.query.filter_by', 'Users.query.filter_by', (), '', False, 'from CTFd.models import db, Users, Solves, Awards, Tracking, Unlocks, Submissions, Notifications\n'), ((43, 14, 43, 32), 'flask.request.get_json', 'request.get_json', ({}, {}), '()', False, 'from flask import session, request, abort\n'), ((44, 17, 44, 36), 'CTFd.schemas.users.UserSchema', 'UserSchema', ({(44, 28, 44, 35): '"""admin"""'}, {}), "('admin')", False, 'from CTFd.schemas.users import UserSchema\n'), ((50, 8, 50, 37), 'CTFd.models.db.session.add', 'db.session.add', ({(50, 23, 50, 36): 'response.data'}, {}), '(response.data)', False, 'from CTFd.models import db, Users, Solves, Awards, Tracking, Unlocks, Submissions, Notifications\n'), ((51, 8, 51, 27), 'CTFd.models.db.session.commit', 'db.session.commit', ({}, {}), '()', False, 'from CTFd.models import db, Users, Solves, Awards, Tracking, Unlocks, Submissions, Notifications\n'), ((53, 11, 53, 37), 'flask.request.args.get', 'request.args.get', ({(53, 28, 53, 36): '"""notify"""'}, {}), "('notify')", False, 'from flask import session, request, abort\n'), ((57, 8, 57, 25), 'CTFd.cache.clear_standings', 'clear_standings', ({}, {}), '()', False, 'from CTFd.cache import clear_standings\n'), ((87, 15, 87, 33), 'flask.request.get_json', 'request.get_json', ({}, {}), '()', False, 'from flask import session, request, abort\n'), ((89, 17, 89, 70), 'CTFd.schemas.users.UserSchema', 'UserSchema', (), '', False, 'from CTFd.schemas.users import UserSchema\n'), ((94, 8, 94, 27), 'CTFd.models.db.session.commit', 'db.session.commit', ({}, {}), '()', False, 'from CTFd.models import db, Users, Solves, Awards, Tracking, Unlocks, Submissions, Notifications\n'), ((98, 8, 98, 26), 'CTFd.models.db.session.close', 'db.session.close', ({}, {}), '()', False, 'from CTFd.models import db, Users, Solves, Awards, Tracking, Unlocks, Submissions, Notifications\n'), ((100, 8, 100, 25), 'CTFd.cache.clear_standings', 'clear_standings', ({}, {}), '()', False, 'from CTFd.cache import clear_standings\n'), ((113, 8, 113, 27), 'CTFd.models.db.session.commit', 'db.session.commit', ({}, {}), '()', False, 'from CTFd.models import db, Users, Solves, Awards, Tracking, Unlocks, Submissions, Notifications\n'), ((114, 8, 114, 26), 'CTFd.models.db.session.close', 'db.session.close', ({}, {}), '()', False, 'from CTFd.models import db, Users, Solves, Awards, Tracking, Unlocks, Submissions, Notifications\n'), ((116, 8, 116, 25), 'CTFd.cache.clear_standings', 'clear_standings', ({}, {}), '()', False, 'from CTFd.cache import clear_standings\n'), ((125, 15, 125, 33), 'CTFd.utils.user.get_current_user', 'get_current_user', ({}, {}), '()', False, 'from CTFd.utils.user import get_current_user, is_admin\n'), ((133, 15, 133, 33), 'CTFd.utils.user.get_current_user', 'get_current_user', ({}, {}), '()', False, 'from CTFd.utils.user import get_current_user, is_admin\n'), ((134, 15, 134, 33), 'flask.request.get_json', 'request.get_json', ({}, {}), '()', False, 'from flask import session, request, abort\n'), ((135, 17, 135, 69), 'CTFd.schemas.users.UserSchema', 'UserSchema', (), '', False, 'from CTFd.schemas.users import UserSchema\n'), ((140, 8, 140, 27), 'CTFd.models.db.session.commit', 'db.session.commit', ({}, {}), '()', False, 'from CTFd.models import db, Users, Solves, Awards, Tracking, Unlocks, Submissions, Notifications\n'), ((143, 8, 143, 26), 'CTFd.models.db.session.close', 'db.session.close', ({}, {}), '()', False, 'from CTFd.models import db, Users, Solves, Awards, Tracking, Unlocks, Submissions, Notifications\n'), ((145, 8, 145, 25), 'CTFd.cache.clear_standings', 'clear_standings', ({}, {}), '()', False, 'from CTFd.cache import clear_standings\n'), ((154, 15, 154, 33), 'CTFd.utils.user.get_current_user', 'get_current_user', ({}, {}), '()', False, 'from CTFd.utils.user import get_current_user, is_admin\n'), ((170, 15, 170, 33), 'CTFd.utils.user.get_current_user', 'get_current_user', ({}, {}), '()', False, 'from CTFd.utils.user import get_current_user, is_admin\n'), ((178, 11, 178, 21), 'CTFd.utils.user.is_admin', 'is_admin', ({}, {}), '()', False, 'from CTFd.utils.user import get_current_user, is_admin\n'), ((192, 15, 192, 33), 'CTFd.utils.user.get_current_user', 'get_current_user', ({}, {}), '()', False, 'from CTFd.utils.user import get_current_user, is_admin\n'), ((244, 11, 244, 21), 'CTFd.utils.user.is_admin', 'is_admin', ({}, {}), '()', False, 'from CTFd.utils.user import get_current_user, is_admin\n'), ((72, 12, 72, 22), 'flask.abort', 'abort', ({(72, 18, 72, 21): '(404)'}, {}), '(404)', False, 'from flask import session, request, abort\n'), ((213, 12, 213, 22), 'flask.abort', 'abort', ({(213, 18, 213, 21): '(404)'}, {}), '(404)', False, 'from flask import session, request, abort\n'), ((236, 12, 236, 22), 'flask.abort', 'abort', ({(236, 18, 236, 21): '(404)'}, {}), '(404)', False, 'from flask import session, request, abort\n'), ((263, 12, 263, 22), 'flask.abort', 'abort', ({(263, 18, 263, 21): '(404)'}, {}), '(404)', False, 'from flask import session, request, abort\n'), ((34, 19, 34, 53), 'CTFd.schemas.users.UserSchema', 'UserSchema', (), '', False, 'from CTFd.schemas.users import UserSchema\n'), ((69, 15, 69, 48), 'CTFd.models.Users.query.filter_by', 'Users.query.filter_by', (), '', False, 'from CTFd.models import db, Users, Solves, Awards, Tracking, Unlocks, Submissions, Notifications\n'), ((71, 44, 71, 54), 'CTFd.utils.user.is_admin', 'is_admin', ({}, {}), '()', False, 'from CTFd.utils.user import get_current_user, is_admin\n'), ((86, 15, 86, 48), 'CTFd.models.Users.query.filter_by', 'Users.query.filter_by', (), '', False, 'from CTFd.models import db, Users, Solves, Awards, Tracking, Unlocks, Submissions, Notifications\n'), ((106, 8, 106, 54), 'CTFd.models.Notifications.query.filter_by', 'Notifications.query.filter_by', (), '', False, 'from CTFd.models import db, Users, Solves, Awards, Tracking, Unlocks, Submissions, Notifications\n'), ((107, 8, 107, 47), 'CTFd.models.Awards.query.filter_by', 'Awards.query.filter_by', (), '', False, 'from CTFd.models import db, Users, Solves, Awards, Tracking, Unlocks, Submissions, Notifications\n'), ((108, 8, 108, 48), 'CTFd.models.Unlocks.query.filter_by', 'Unlocks.query.filter_by', (), '', False, 'from CTFd.models import db, Users, Solves, Awards, Tracking, Unlocks, Submissions, Notifications\n'), ((109, 8, 109, 52), 'CTFd.models.Submissions.query.filter_by', 'Submissions.query.filter_by', (), '', False, 'from CTFd.models import db, Users, Solves, Awards, Tracking, Unlocks, Submissions, Notifications\n'), ((110, 8, 110, 47), 'CTFd.models.Solves.query.filter_by', 'Solves.query.filter_by', (), '', False, 'from CTFd.models import db, Users, Solves, Awards, Tracking, Unlocks, Submissions, Notifications\n'), ((111, 8, 111, 49), 'CTFd.models.Tracking.query.filter_by', 'Tracking.query.filter_by', (), '', False, 'from CTFd.models import db, Users, Solves, Awards, Tracking, Unlocks, Submissions, Notifications\n'), ((112, 8, 112, 41), 'CTFd.models.Users.query.filter_by', 'Users.query.filter_by', (), '', False, 'from CTFd.models import db, Users, Solves, Awards, Tracking, Unlocks, Submissions, Notifications\n'), ((157, 29, 157, 39), 'CTFd.utils.user.is_admin', 'is_admin', ({}, {}), '()', False, 'from CTFd.utils.user import get_current_user, is_admin\n'), ((158, 19, 158, 57), 'CTFd.schemas.submissions.SubmissionSchema', 'SubmissionSchema', (), '', False, 'from CTFd.schemas.submissions import SubmissionSchema\n'), ((173, 29, 173, 39), 'CTFd.utils.user.is_admin', 'is_admin', ({}, {}), '()', False, 'from CTFd.utils.user import get_current_user, is_admin\n'), ((174, 19, 174, 57), 'CTFd.schemas.submissions.SubmissionSchema', 'SubmissionSchema', (), '', False, 'from CTFd.schemas.submissions import SubmissionSchema\n'), ((195, 29, 195, 39), 'CTFd.utils.user.is_admin', 'is_admin', ({}, {}), '()', False, 'from CTFd.utils.user import get_current_user, is_admin\n'), ((196, 19, 196, 52), 'CTFd.schemas.awards.AwardSchema', 'AwardSchema', (), '', False, 'from CTFd.schemas.awards import AwardSchema\n'), ((210, 15, 210, 48), 'CTFd.models.Users.query.filter_by', 'Users.query.filter_by', (), '', False, 'from CTFd.models import db, Users, Solves, Awards, Tracking, Unlocks, Submissions, Notifications\n'), ((212, 44, 212, 54), 'CTFd.utils.user.is_admin', 'is_admin', ({}, {}), '()', False, 'from CTFd.utils.user import get_current_user, is_admin\n'), ((215, 39, 215, 49), 'CTFd.utils.user.is_admin', 'is_admin', ({}, {}), '()', False, 'from CTFd.utils.user import get_current_user, is_admin\n'), ((217, 29, 217, 39), 'CTFd.utils.user.is_admin', 'is_admin', ({}, {}), '()', False, 'from CTFd.utils.user import get_current_user, is_admin\n'), ((218, 19, 218, 57), 'CTFd.schemas.submissions.SubmissionSchema', 'SubmissionSchema', (), '', False, 'from CTFd.schemas.submissions import SubmissionSchema\n'), ((233, 15, 233, 48), 'CTFd.models.Users.query.filter_by', 'Users.query.filter_by', (), '', False, 'from CTFd.models import db, Users, Solves, Awards, Tracking, Unlocks, Submissions, Notifications\n'), ((235, 44, 235, 54), 'CTFd.utils.user.is_admin', 'is_admin', ({}, {}), '()', False, 'from CTFd.utils.user import get_current_user, is_admin\n'), ((237, 37, 237, 47), 'CTFd.utils.user.is_admin', 'is_admin', ({}, {}), '()', False, 'from CTFd.utils.user import get_current_user, is_admin\n'), ((239, 29, 239, 39), 'CTFd.utils.user.is_admin', 'is_admin', ({}, {}), '()', False, 'from CTFd.utils.user import get_current_user, is_admin\n'), ((240, 19, 240, 57), 'CTFd.schemas.submissions.SubmissionSchema', 'SubmissionSchema', (), '', False, 'from CTFd.schemas.submissions import SubmissionSchema\n'), ((260, 15, 260, 48), 'CTFd.models.Users.query.filter_by', 'Users.query.filter_by', (), '', False, 'from CTFd.models import db, Users, Solves, Awards, Tracking, Unlocks, Submissions, Notifications\n'), ((262, 44, 262, 54), 'CTFd.utils.user.is_admin', 'is_admin', ({}, {}), '()', False, 'from CTFd.utils.user import get_current_user, is_admin\n'), ((264, 39, 264, 49), 'CTFd.utils.user.is_admin', 'is_admin', ({}, {}), '()', False, 'from CTFd.utils.user import get_current_user, is_admin\n'), ((266, 29, 266, 39), 'CTFd.utils.user.is_admin', 'is_admin', ({}, {}), '()', False, 'from CTFd.utils.user import get_current_user, is_admin\n'), ((267, 19, 267, 52), 'CTFd.schemas.awards.AwardSchema', 'AwardSchema', (), '', False, 'from CTFd.schemas.awards import AwardSchema\n'), ((126, 19, 126, 37), 'CTFd.schemas.users.UserSchema', 'UserSchema', ({(126, 30, 126, 36): '"""self"""'}, {}), "('self')", False, 'from CTFd.schemas.users import UserSchema\n'), ((74, 35, 74, 62), 'flask.session.get', 'session.get', ({(74, 47, 74, 53): '"""type"""', (74, 55, 74, 61): '"""user"""'}, {}), "('type', 'user')", False, 'from flask import session, request, abort\n')]