def login():
    trust = DontTrust(email=Schema().email().required(),
                      password=Schema().string().min(8).max(256).required())

    try:
        data = trust.validate(request.json)
    except ValidationError as e:
        raise HTTPException(
            e.message, dict(field=e.field, value=request.json.get(e.field)))

    email = data["email"]
    password = data["password"]

    user = User.query.filter_by(email=email).first()
    if user is None:
        raise HTTPException(f"User with email {email} was not found.",
                            dict(field="email", value=email))

    if user.is_deleted:
        raise HTTPException("This account belongs to a deleted user",
                            dict(field="email", value=email))

    if user.is_blocked:
        raise HTTPException("This account is banned from this website",
                            dict(field="email", value=email))

    if not checkpw(password.encode(), user.password.encode()):
        raise HTTPException("Invalid password",
                            dict(field="password", value=password))

    token = jwt.create_token(user)

    return response("Logged in",
                    dict(token=token, user=user.no_relations_dict()))
def register():
    trust = DontTrust(
        email=Schema().email().required(),
        password=Schema().string().min(8).max(256).required(),
        username=Schema().string().min(4).max(32).regex(r"[\w_]+").flags(re.I))

    try:
        data = trust.validate(request.json)
    except ValidationError as e:
        raise HTTPException(
            e.message, dict(field=e.field, value=request.json.get(e.field)))

    email = data["email"]
    password = data["password"]
    username = data["username"]

    user = User.query.filter_by(email=email).first()
    if user is not None:
        raise HTTPException(f"Email already registered",
                            dict(field="email", value=email))

    user = User.query.filter_by(username=username).first()
    if user is not None:
        raise HTTPException(f"Username taken",
                            dict(field="username", value=username))

    user = User(email=email,
                username=username,
                password=hashpw(password.encode(), gensalt(12)).decode())
    user.save()
    token = jwt.create_token(user)

    return response("Registered",
                    dict(token=token, user=user.no_relations_dict()))
def create_post():
    user = g.user
    trust = DontTrust(content=Schema().string().required())

    try:
        data = trust.validate(request.json)
    except ValidationError as e:
        raise HTTPException(
            e.message, dict(field=e.field, value=request.json.get(e.field)))

    content = data["content"]

    post = Post(content=content, user_id=user.id)
    post.save()

    return response("Created new post", dict(post=post.dict()))
def add_comment(post_id: str):
    post = Post.query.get_or_404(post_id, "Post not found")
    user = g.user
    trust = DontTrust(content=Schema().string().required())

    try:
        data = trust.validate(request.json)
    except ValidationError as e:
        raise HTTPException(e.message, dict(field=e.field, value=request.json.get(e.field)))

    content = data["content"]

    comment = Comment(content=content, user_id=user.id, post_id=post.id)
    comment.save()

    return response("Comment created", dict(comment=comment.dict()))
def update(id_: str):
    post = Post.query.get_or_404(id_, "Post not found")
    user = g.user
    if post.user.id != user.id:
        raise HTTPException("You don't have permission to do that", status=403)

    trust = DontTrust(content=Schema().string().required())

    try:
        data = trust.validate(request.json)
    except ValidationError as e:
        raise HTTPException(
            e.message, dict(field=e.field, value=request.json.get(e.field)))

    content = data["content"]
    post.content = content
    post.save()

    return response("Post updated", dict(post=post.dict()))
def update_comment(comment_id: int):
    comment = Comment.query.get_or_404(comment_id, "Comment not found")
    user = g.user

    if comment.user.id != user.id:
        raise HTTPException("You don't have permission to do that!", status=403)

    trust = DontTrust(content=Schema().string().required())

    try:
        data = trust.validate(request.json)
    except ValidationError as e:
        raise HTTPException(e.message, dict(field=e.field, value=request.json.get(e.field)))

    content = data["content"]

    comment.content = content
    comment.save()

    return response("Comment updated", dict(comment=comment.dict()))
def modify_user_account(mode: str):
    if mode == "email":
        trust = DontTrust(
            email=Schema().email().required(),
            password=Schema().string().min(8).max(256).required())
        try:
            data = trust.validate(request.json)
        except ValidationError as e:
            raise HTTPException(
                e.message, dict(field=e.field,
                                value=request.json.get(e.field)))

        email = data.get("email")
        password = data.get("password")

        user = g.user
        if not bcrypt.checkpw(password.encode(), user.password.encode()):
            raise HTTPException("Invalid password", status=401)

        user.email = email
        user.save()

        return response("Email changed", dict(user=user.dict()))
    if mode == "password":
        trust = DontTrust(
            password=Schema().string().required(),
            new_password=Schema().string().required().min(8).max(256),
            confirm_password=Schema().string().required().min(8).max(256))

        try:
            data = trust.validate(request.json)
        except ValidationError as e:
            raise HTTPException(
                e.message, dict(field=e.field,
                                value=request.form.get(e.field)))

        p = data["password"]
        n = data["new_password"]
        c = data["confirm_password"]

        if n != c:
            raise HTTPException("Passwords don't match")

        user = g.user

        if not bcrypt.checkpw(p.encode(), user.password.encode()):
            raise HTTPException("Invalid password", status=401)

        user.password = bcrypt.hashpw(n.encode(), bcrypt.gensalt(12)).decode()
        user.save()

        return response("Password changed", dict(user=user.dict()))
    else:
        raise HTTPException("Page not found", status=404)