Example #1
0
    def signup():
        encoding = get_header_encoding(request)
        email = str(request.data.get("email", ""))
        signup_token = str(request.data.get("signup_token", ""))
        user = User.query.filter_by(_user_email=email).first()

        if user:
            response = compose_response(
                {
                    "code": 10,
                    "msg": "already signed up with that email"
                },
                encoding=encoding)
            response.status_code = 400
            return response

        user = User(email=email, signup_token=signup_token)
        user.save()
        response = compose_response(
            {
                "user": {
                    "id": str(user._user_auth_token),
                    "email": str(user._user_email)
                }
            },
            encoding=encoding)
        response.status_code = 200
        return response
Example #2
0
    def propagation(access_token):
        encoding = get_header_encoding(request)
        ppgn = get_ppgn_by_token(access_token)
        result = {}

        if ppgn:
            # BFS to find all child propagations
            queue = [(ppgn, access_token)]

            while queue:
                ppgn, ppgn_token = queue.pop(0)
                for child in filter_ppgn_by_parent_id(ppgn.ppgn_id):
                    queue.append((child, child._ppgn_token))

                    user = User.query.filter_by(
                        user_id=child.ppgn_user_id).first()
                    result[user._user_email] = {
                        "access-token": str(child._ppgn_token),
                        "parent-access-token": str(ppgn_token)
                    }

        response = compose_response({"propagations": result},
                                    encoding=encoding)
        response.status_code = 200
        return response
Example #3
0
    def view_tost(access_token):
        encoding = get_header_encoding(request)
        email, auth_token = get_header_auth(request)
        user = User.query.filter_by(_user_auth_token=auth_token).first()
        case, ppgn_token = review_access_token(access_token, user.user_id)

        if request.method == "GET":
            # case 1: propagation invalid
            if case == 1:
                response = compose_response(
                    {
                        "code": 40,
                        "msg": "tost not found"
                    }, encoding=encoding)
                response.status_code = 404
                return response

            # case 2: user visits resource for the first time
            # case 4: user propagation is of lower priority than propagation in URL
            # case 5: user propagation is of higher priority than propagation in URL
            if case in [2, 4, 5]:
                return redirect(url_for("view_tost", access_token=ppgn_token))

            # case 3: user is creator of tost that propagation points to
            tost = get_tost_by_token(ppgn_token)

            response = create_tost_summary(ppgn_token, tost, tost._tost_body,
                                           encoding)
            response.status_code = 200
            return response
Example #4
0
    def tost():
        encoding = get_header_encoding(request)
        email, auth_token = get_header_auth(request)
        user = User.query.filter_by(_user_auth_token=auth_token).first()

        if request.method == "GET":
            ppgns = filter_ppgn_by_user_id(user.user_id)

            result = {}
            for ppgn in ppgns:
                tost = Tost.query.filter_by(tost_id=ppgn.ppgn_tost_id).first()
                result[str(ppgn._ppgn_token)] = str(tost._tost_body[:32])

            response = compose_response(result, encoding=encoding)
            response.status_code = 200
            return response

        elif request.method == "POST":
            body = str(request.data.get("body", ""))
            creation_token = str(request.data.get("creation_token", ""))

            if not body:
                response = compose_response(
                    {
                        "code": 30,
                        "msg": "invalid",
                        "field": {
                            "tost": {
                                "body": "must not be blank"
                            }
                        }
                    },
                    encoding=encoding)
                response.status_code = 400
                return response

            tost = Tost(body, user.user_id, creation_token)
            tost.save()

            ppgn = Propagation(tost.tost_id, user.user_id)
            ppgn.save()

            response = create_tost_summary(ppgn._ppgn_token, tost, body,
                                           encoding)
            response.status_code = 200
            return response
Example #5
0
    def upgrade_propagation(access_token):
        encoding = get_header_encoding(request)
        src_access_token = str(request.data.get("src-access-token", ""))
        src_ppgn = get_ppgn_by_token(src_access_token)
        ppgn = get_ppgn_by_token(access_token)

        # return 400 if user propagation not descendant of propagation in URL
        if not (src_ppgn and ppgn
                and src_ppgn.ppgn_tost_id == ppgn.ppgn_tost_id
                and src_ppgn._ppgn_rank >= ppgn._ppgn_rank + 1):
            response = compose_response(
                {
                    "code": 60,
                    "msg": "destination not ancestor"
                },
                encoding=encoding)
            response.status_code = 400
            return response

        # upgrade if user propagation not direct descendant to propagation in URL
        if src_ppgn._ppgn_rank > ppgn._ppgn_rank + 1:
            src_ppgn._ppgn_parent_id = ppgn.ppgn_id
            src_ppgn._ppgn_rank = ppgn._ppgn_rank + 1

            # BFS to find all child propagations, then upgrade ranks
            queue = [(src_ppgn, ppgn._ppgn_rank + 1)]

            while queue:
                ppgn, rank = queue.pop(0)
                for child in filter_ppgn_by_parent_id(ppgn.ppgn_id):
                    queue.append((child, rank + 1))
                    child._ppgn_rank = rank + 1

            src_ppgn.save()

        response = compose_response(
            {
                "access-token": str(src_access_token),
                "parent-access-token": str(access_token)
            },
            encoding=encoding)
        response.status_code = 200
        return response
Example #6
0
    def disable_propagation(access_token):
        encoding = get_header_encoding(request)
        src_access_token = str(request.data.get("src-access-token", ""))
        src_ppgn = get_ppgn_by_token(src_access_token)
        ppgn = get_ppgn_by_token(access_token)

        # return 400 if user propagation not descendant of propagation in URL
        if not (src_ppgn and ppgn
                and src_ppgn.ppgn_tost_id == ppgn.ppgn_tost_id
                and src_ppgn._ppgn_rank >= ppgn._ppgn_rank + 1):
            response = compose_response(
                {
                    "code": 70,
                    "msg": "target not descendant of " + str(access_token)
                },
                encoding=encoding)
            response.status_code = 400
            return response

        src_ppgn._ppgn_disabled = True

        # BFS to find all child propagations, then toggle ancestor flag
        queue = [src_ppgn]

        while queue:
            ppgn = queue.pop(0)
            for child in filter_ppgn_by_parent_id(ppgn.ppgn_id):
                queue.append(child)
                child._ppgn_ancestor_disabled = True

        src_ppgn.save()

        response = compose_response(
            {
                "access-token": str(src_access_token),
                "parent-access-token": str(access_token)
            },
            encoding=encoding)
        response.status_code = 200
        return response
Example #7
0
 def create_tost_summary(ppgn_token, tost, body, encoding=None):
     return compose_response(
         {
             "tost": {
                 "access-token": str(ppgn_token),
                 "creator-id": str(tost.tost_creator_user_id),
                 "created-at": str(tost.tost_create_timestamp),
                 "updator-id": str(tost._tost_updator_user_id),
                 "updated-at": str(tost._tost_update_timestamp),
                 "body": str(body)
             }
         },
         encoding=encoding)
Example #8
0
    def login():
        encoding = get_header_encoding(request)
        auth_token = str(request.data.get("auth_token", ""))
        user = User.query.filter_by(_user_auth_token=auth_token).first()

        if not (user and user._user_auth_token == auth_token):
            response = compose_response({
                "code": 20,
                "msg": "invalid token"
            },
                                        encoding=encoding)
            response.status_code = 400
            return response

        response = compose_response(
            {
                "user": {
                    "id": str(user._user_auth_token),
                    "email": str(user._user_email)
                }
            },
            encoding=encoding)
        response.status_code = 200
        return response
Example #9
0
def create_app(config_name):
    from models import db, User, Tost, Propagation

    app = FlaskAPI(__name__)
    app.config.from_object(app_config[config_name])

    db.init_app(app)
    with app.app_context():
        db.create_all()
        db.session.commit()

    auth = HTTPBasicAuth()

    @app.route("/signup", methods=["POST"])
    def signup():
        encoding = get_header_encoding(request)
        email = str(request.data.get("email", ""))
        signup_token = str(request.data.get("signup_token", ""))
        user = User.query.filter_by(_user_email=email).first()

        if user:
            response = compose_response(
                {
                    "code": 10,
                    "msg": "already signed up with that email"
                },
                encoding=encoding)
            response.status_code = 400
            return response

        user = User(email=email, signup_token=signup_token)
        user.save()
        response = compose_response(
            {
                "user": {
                    "id": str(user._user_auth_token),
                    "email": str(user._user_email)
                }
            },
            encoding=encoding)
        response.status_code = 200
        return response

    @app.route("/login", methods=["POST"])
    def login():
        encoding = get_header_encoding(request)
        auth_token = str(request.data.get("auth_token", ""))
        user = User.query.filter_by(_user_auth_token=auth_token).first()

        if not (user and user._user_auth_token == auth_token):
            response = compose_response({
                "code": 20,
                "msg": "invalid token"
            },
                                        encoding=encoding)
            response.status_code = 400
            return response

        response = compose_response(
            {
                "user": {
                    "id": str(user._user_auth_token),
                    "email": str(user._user_email)
                }
            },
            encoding=encoding)
        response.status_code = 200
        return response

    def filter_ppgn_by_user_id(user_id):
        return Propagation.query.filter_by(ppgn_user_id=user_id)\
                                .filter_by(_ppgn_disabled=False)\
                                .filter_by(_ppgn_ancestor_disabled=False)\
                                .all()

    def create_tost_summary(ppgn_token, tost, body, encoding=None):
        return compose_response(
            {
                "tost": {
                    "access-token": str(ppgn_token),
                    "creator-id": str(tost.tost_creator_user_id),
                    "created-at": str(tost.tost_create_timestamp),
                    "updator-id": str(tost._tost_updator_user_id),
                    "updated-at": str(tost._tost_update_timestamp),
                    "body": str(body)
                }
            },
            encoding=encoding)

    @app.route("/tost", methods=["GET", "POST"])
    @auth.login_required
    def tost():
        encoding = get_header_encoding(request)
        email, auth_token = get_header_auth(request)
        user = User.query.filter_by(_user_auth_token=auth_token).first()

        if request.method == "GET":
            ppgns = filter_ppgn_by_user_id(user.user_id)

            result = {}
            for ppgn in ppgns:
                tost = Tost.query.filter_by(tost_id=ppgn.ppgn_tost_id).first()
                result[str(ppgn._ppgn_token)] = str(tost._tost_body[:32])

            response = compose_response(result, encoding=encoding)
            response.status_code = 200
            return response

        elif request.method == "POST":
            body = str(request.data.get("body", ""))
            creation_token = str(request.data.get("creation_token", ""))

            if not body:
                response = compose_response(
                    {
                        "code": 30,
                        "msg": "invalid",
                        "field": {
                            "tost": {
                                "body": "must not be blank"
                            }
                        }
                    },
                    encoding=encoding)
                response.status_code = 400
                return response

            tost = Tost(body, user.user_id, creation_token)
            tost.save()

            ppgn = Propagation(tost.tost_id, user.user_id)
            ppgn.save()

            response = create_tost_summary(ppgn._ppgn_token, tost, body,
                                           encoding)
            response.status_code = 200
            return response

    def get_tost_by_token(ppgn_token):
        ppgn = Propagation.query.filter_by(_ppgn_token=ppgn_token).first()
        return Tost.query.filter_by(tost_id=ppgn.ppgn_tost_id).first()

    def get_ppgn_by_token(ppgn_token):
        return Propagation.query.filter_by(_ppgn_token=ppgn_token)\
                                .filter_by(_ppgn_disabled=False)\
                                .filter_by(_ppgn_ancestor_disabled=False)\
                                .first()

    def get_ppgn_by_user_tost(user_id, tost_id):
        return Propagation.query.filter_by(ppgn_user_id=user_id)\
                                .filter_by(ppgn_tost_id=tost_id)\
                                .filter_by(_ppgn_disabled=False)\
                                .filter_by(_ppgn_ancestor_disabled=False)\
                                .first()

    def review_access_token(access_token, user_id):
        ppgn = get_ppgn_by_token(access_token)

        # case 1: propagation invalid
        if not ppgn:
            return 1, None

        user_ppgn = get_ppgn_by_user_tost(user_id, ppgn.ppgn_tost_id)

        # case 2: user visits resource for the first time
        if not user_ppgn:
            new_ppgn = Propagation(ppgn.ppgn_tost_id, user_id, ppgn.ppgn_id,
                                   ppgn._ppgn_rank + 1)
            new_ppgn.save()

            return 2, new_ppgn._ppgn_token

        # case 3: user is creator of tost that propagation points to
        if ppgn.ppgn_id == user_ppgn.ppgn_id:
            return 3, access_token

        # case 4: user propagation is of lower priority than propagation in URL
        if user_ppgn._ppgn_rank > ppgn._ppgn_rank + 1:
            user_ppgn._ppgn_parent_id = ppgn.ppgn_id
            user_ppgn._ppgn_rank = ppgn._ppgn_rank + 1
            user_ppgn.save()

            return 4, user_ppgn._ppgn_token

        # case 5: user propagation is of higher priority than propagation in URL
        if user_ppgn._ppgn_rank <= ppgn._ppgn_rank + 1:
            return 5, user_ppgn._ppgn_token

    @app.route("/tost/<access_token>", methods=["GET", "PUT"])
    @auth.login_required
    def view_tost(access_token):
        encoding = get_header_encoding(request)
        email, auth_token = get_header_auth(request)
        user = User.query.filter_by(_user_auth_token=auth_token).first()
        case, ppgn_token = review_access_token(access_token, user.user_id)

        if request.method == "GET":
            # case 1: propagation invalid
            if case == 1:
                response = compose_response(
                    {
                        "code": 40,
                        "msg": "tost not found"
                    }, encoding=encoding)
                response.status_code = 404
                return response

            # case 2: user visits resource for the first time
            # case 4: user propagation is of lower priority than propagation in URL
            # case 5: user propagation is of higher priority than propagation in URL
            if case in [2, 4, 5]:
                return redirect(url_for("view_tost", access_token=ppgn_token))

            # case 3: user is creator of tost that propagation points to
            tost = get_tost_by_token(ppgn_token)

            response = create_tost_summary(ppgn_token, tost, tost._tost_body,
                                           encoding)
            response.status_code = 200
            return response

        if request.method == "PUT":
            # case 1: propagation invalid
            if case == 1:
                response = compose_response(
                    {
                        "code": 40,
                        "msg": "tost not found"
                    }, encoding=encoding)
                response.status_code = 404
                return response

            # case 2: user visits resource for the first time
            # case 4: user propagation is of lower priority than propagation in URL
            # case 5: user propagation is of higher priority than propagation in URL
            if case in [2, 4, 5]:
                response = compose_response(
                    {
                        "code": 50,
                        "msg": "please use refreshed access token",
                        "access-token": str(ppgn_token)
                    },
                    encoding=encoding)
                response.status_code = 302
                return response

            # case 3: user is creator of tost that propagation points to
            tost = get_tost_by_token(ppgn_token)
            tost._tost_body = str(request.data.get("body", ""))
            tost._tost_updator_user_id = user.user_id
            tost._tost_update_timestamp = db.func.current_timestamp()
            tost.save()

            response = create_tost_summary(ppgn_token, tost, tost._tost_body,
                                           encoding)
            response.status_code = 200
            return response