예제 #1
0
def down_vote(video_id, **kwargs):
    user = kwargs['user']
    video = db.session.query(Video).filter_by(id=video_id).one_or_none()
    if not video:
        raise Error(StatusCode.FORBIDDEN, 'Video does not exist')

    if video.status != VideoStatus.VOTING:
        raise Error(StatusCode.FORBIDDEN, 'Not allow to vote')

    participant = db.session.query(RoomParticipant).filter_by(
        user_id=user.id, room_id=video.room_id).first()
    if participant.status == ParticipantStatus.IN:  # User is in the room that has that video to be able to vote
        vote = db.session.query(Vote).filter_by(user_id=user.id,
                                                video_id=video.id).first()
        if vote is None:
            raise Error(StatusCode.FORBIDDEN,
                        'You have to up-vote first in order to down-vote')
        if vote.status == VoteStatus.DOWNVOTE:
            raise Error(StatusCode.FORBIDDEN, 'Already down-voted')
        if vote.status == VoteStatus.UPVOTE:
            vote.status = VoteStatus.DOWNVOTE
            video.total_vote -= 1
            db.session.commit()
            data = {
                "name": user.name,
                "id": video.id,
                "total_vote": video.total_vote
            }

            pusher.trigger(video.room_id, PusherEvent.DOWN_VOTE, data)

            return jsonify({
                'message': 'Down-voted successfully',
                'data': VideoSchema().dump(video).data
            })
예제 #2
0
def up_vote(video_id, **kwargs):
    user = kwargs['user']
    video = db.session.query(Video).filter_by(id=video_id).one_or_none()
    if not video:
        raise Error(StatusCode.FORBIDDEN, 'Video does not exist')

    if video.status != VideoStatus.VOTING:
        raise Error(StatusCode.FORBIDDEN, 'Video cannot be voted')

    room_id = video.room_id
    participant = db.session.query(RoomParticipant).filter_by(
        user_id=user.id, room_id=room_id).one_or_none()

    if not participant or participant.status != ParticipantStatus.IN:
        raise Error(StatusCode.FORBIDDEN, 'Video cannot be voted')

    # User is in the room that has that video to be able to vote
    vote = db.session.query(Vote).filter_by(user_id=user.id,
                                            video_id=video.id).first()
    if vote is None:
        new_vote = Vote(user_id=user.id,
                        video_id=video.id,
                        status=VoteStatus.UPVOTE)
        video.total_vote += 1
        db.session.add(new_vote)
        db.session.commit()

        data = {
            "name": user.name,
            "id": video.id,
            "total_vote": video.total_vote
        }

        pusher.trigger(video.room_id, PusherEvent.UP_VOTE, data)

        return jsonify({
            'message': 'Upvote successfully',
            'data': VideoSchema().dump(video).data
        })
    if vote.status == VoteStatus.UPVOTE:
        raise Error(StatusCode.FORBIDDEN, 'Already up-voted')

    if vote.status == VoteStatus.DOWNVOTE:
        vote.status = VoteStatus.UPVOTE
        video.total_vote += 1
        db.session.commit()

        data = {
            "name": user.name,
            "id": video.id,
            "total_vote": video.total_vote
        }

        pusher.trigger(video.room_id, PusherEvent.UP_VOTE, data)

        return jsonify({
            'message': 'Upvote successfully',
            'data': VideoSchema().dump(video).data
        })
예제 #3
0
def add_participant_to_room(room_id, user, args):
    room = db.session.query(Room).filter_by(id=room_id).one_or_none()

    if room is None:
        raise Error(StatusCode.BAD_REQUEST, 'Invalid room id')

    # Only room member can add new participant
    checked_participant = db.session.query(RoomParticipant).filter_by(
        user_id=user.id, room_id=room_id).one_or_none()
    if checked_participant is None or checked_participant.status == ParticipantStatus.DELETED:
        raise Error(StatusCode.FORBIDDEN,
                    'You\'re not allowed to add new member to this room')

    added_user = User.query.filter_by(email=args['email']).one_or_none()
    if not added_user:
        raise Error(StatusCode.BAD_REQUEST, 'This user does not exist')

    is_participant = RoomParticipant.query.filter_by(
        user_id=added_user.id, room_id=room_id).one_or_none()
    if not is_participant:
        new_participant = RoomParticipant(user_id=user.id,
                                          room_id=room_id,
                                          status=ParticipantStatus.OUT)
        db.session.add(new_participant)
        db.session.commit()

        notification = {
            "name": added_user.name,
            "user_id": added_user.id,
            "room": room_id
        }

        pusher.trigger(room_id, PusherEvent.NEW_PARTICIPANT, notification)

        return jsonify({
            'message':
            'New participant to the room is created',
            'data':
            RoomParticipantSchema().dump(new_participant).data
        }), 200
    elif is_participant.status == ParticipantStatus.OUT or is_participant.status == ParticipantStatus.DELETED:
        # User is re-added to this room
        checked_participant.status = ParticipantStatus.IN
        db.session.commit()

        notification = {"name": user.name, "user_id": user.id, "room": room_id}

        pusher.trigger(room_id, PusherEvent.NEW_PARTICIPANT, notification)

        return jsonify({
            'message':
            'Participant is re-added to the room',
            'data':
            RoomParticipantSchema().dump(checked_participant).data
        }), 200
    raise Error(StatusCode.UNAUTHORIZED,
                'This user is already a member of this room')
예제 #4
0
def add_video(user, args):
    room_id = args['room_id']
    room = db.session.query(Room).filter_by(id=room_id).one_or_none()

    if room is None:
        raise Error(StatusCode.BAD_REQUEST, 'Invalid room id')

    participant = db.session.query(RoomParticipant).filter_by(
        user_id=user.id, room_id=args['room_id']).first()

    # check whether user is in the room or not to add video
    if not participant or participant.status != ParticipantStatus.IN:
        raise Error(StatusCode.FORBIDDEN, 'Not allow to add video')

    new_video = Video(**args,
                      creator_id=user.id,
                      total_vote=1,
                      status=VideoStatus.VOTING)

    db.session.add(new_video)
    db.session.flush()

    pusher.trigger(room_id, PusherEvent.NEW_VIDEO,
                   VideoSchema().dump(new_video).data)

    new_vote = Vote(video_id=new_video.id,
                    user_id=user.id,
                    status=VoteStatus.UPVOTE)
    db.session.add(new_vote)
    db.session.commit()

    # Play the newest proposed video if current_video is not set
    if not room.current_video:
        new_video.status = VideoStatus.PLAYING
        current_video = video_engine.set_current_video(room_id, new_video.id)

        parsed_current_video = VideoSchema().dump(current_video).data
        parsed_current_video['video_time'] = 0
        parsed_current_video['status'] = VideoStatus.PAUSING

        pusher.trigger(room_id, PusherEvent.PROCEED, parsed_current_video)
        video_engine.set_online_users_video_status(room_id,
                                                   VideoStatus.PAUSING)

    return jsonify({
        'message': 'Video added to room successfully',
        'data': VideoSchema().dump(new_video).data
    })
예제 #5
0
def get_song(room_id, user, args):
    type = args['type']

    room_participant = RoomParticipant.query \
        .filter(RoomParticipant.room_id == room_id) \
        .filter(RoomParticipant.user_id == user.id) \
        .one_or_none()

    if not room_participant:
        raise Error(StatusCode.FORBIDDEN,
                    message='You are not a member of this room')

    if type == 'next':
        song = video_engine.get_next_video(room_id)
        res = {
            'message': 'Get next song successfully',
            'data': VideoSchema().dump(song).data
        }
        if song is None:
            res['message'] = 'There is no available next song'

    elif type == 'current':
        song = video_engine.get_current_video(room_id)
        res = {
            'message': 'Get current song successfully',
            'data': VideoSchema().dump(song).data
        }
        if song is None:
            res['message'] = 'There is no available song'

    return jsonify(res)
예제 #6
0
def decode(access_token):
    try:
        token = jwt.decode(access_token,
                           config.SECRET_KEY,
                           algorithms=['HS256'])
    except jwt.ExpiredSignatureError:
        # Check that token is expired
        errors = {"token": "Token has expired. Please login again"}
        raise Error(StatusCode.UNAUTHORIZED,
                    "Your session has expired. Please login again", errors)
    except jwt.InvalidTokenError as e:
        # Check that token is invalid
        logging.error(e)
        errors = {"token": "Invalid token"}
        raise Error(StatusCode.UNAUTHORIZED, "Request unauthorized", errors)

    return token
예제 #7
0
def participant_exit_room(room_id, **kwargs):
    user = kwargs['user']
    room = db.session.query(Room).filter_by(id=room_id).first()
    if room is None:
        raise Error(StatusCode.BAD_REQUEST, 'Invalid room id')

    participant = db.session.query(RoomParticipant).filter_by(
        user_id=user.id, room_id=room_id).first()
    if participant.status == ParticipantStatus.IN:
        participant.status = ParticipantStatus.OUT
        db.session.commit()

        notification = {"name": user.name, "user_id": user.id, "room": room_id}

        pusher.trigger(room_id, PusherEvent.EXIT_PARTICIPANT, notification)

        return jsonify({'message': 'Participant exited successfully'}), 200
    raise Error(StatusCode.UNAUTHORIZED, 'participant failed to exit')
예제 #8
0
 def decorated_function(*args, **kwargs):
     request_args = request.get_json() or {}
     if request.method == 'GET':
         request_args = request.args.to_dict()
     parsed_args, errors = schema.load(request_args)
     if errors:
         raise Error(StatusCode.BAD_REQUEST, 'Bad request', errors)
     kwargs['args'] = parsed_args
     return f(*args, **kwargs)
예제 #9
0
    def decorated_function(*args, **kwargs):
        authorization = None
        if 'Authorization' in request.headers:
            authorization = request.headers['Authorization']

        if not authorization or not authorization.startswith('Bearer '):
            errors = {'token': 'Invalid authorization header'}
            logging.error('Invalid authorization header')
            raise Error(StatusCode.BAD_REQUEST, 'Bad request', errors)

        # Decode the token which has been passed in the request headers
        token = decode(authorization[len('Bearer '):])

        account = db.session.query(User).filter_by(
            id=token['sub']).one_or_none()

        if not account:
            raise Error(StatusCode.UNAUTHORIZED, 'Unauthorized')

        kwargs['user'] = account
        return f(*args, **kwargs)
예제 #10
0
def login(args):
    user = db.session.query(User).filter_by(email=args['email']).one_or_none()
    if user is not None and pw.generate_hash(args['password'], user.password_salt) == user.password_hash:
        user.online = 1
        db.session.commit()

        return jsonify({
            'message': 'Login success',
            'access_token': encode(user),
            'data': UserSchema().dump(user).data
        }), 200

    raise Error(StatusCode.UNAUTHORIZED, 'Email or password is incorrect')
예제 #11
0
def delete_video(video_id, **kwargs):
    user = kwargs['user']
    video = db.session.query(Video).filter_by(creator_id=user.id,
                                              id=video_id).first()
    if video is not None:
        if video.status == VideoStatus.ACTIVE:
            video.status = VideoStatus.DELETED
            db.session.commit()
            return jsonify({
                'message': 'Deleted successfully',
                'data': VideoSchema().dump(video).data
            }), 200
    raise Error(StatusCode.BAD_REQUEST, 'Cannot delete video')
예제 #12
0
def get_room_info(user, room_id, **kwargs):
    room = db.session.query(Room).filter_by(id=room_id).one_or_none()
    if room is None:
        raise Error(StatusCode.BAD_REQUEST, 'Invalid room id')

    participant = RoomParticipant.query.filter_by(
        room_id=room_id, user_id=user.id).one_or_none()

    if not participant or participant.status == ParticipantStatus.DELETED:
        raise Error(StatusCode.FORBIDDEN,
                    'You are not allowed to access room information')

    # Return list of online user
    participants = db.session.query(RoomParticipant).filter_by(
        room_id=room_id, status=ParticipantStatus.IN).all()
    messages = db.session.query(Message).filter_by(room_id=room_id).all()
    videos = db.session.query(Video).filter_by(room_id=room_id).filter_by(
        status=VideoStatus.VOTING).all()

    for video in videos:
        user_vote = Vote.query \
            .filter_by(video_id=video.id, user_id=user.id, status=VoteStatus.UPVOTE).one_or_none()
        # Check if user has voted for available video
        if user_vote:
            setattr(video, 'is_voted', True)
        else:
            setattr(video, 'is_voted', False)

    return jsonify({
        'message': 'Room Information',
        'data': {
            'fingerprint': room.fingerprint,
            'name': room.name,
            'participants':
            RoomParticipantSchema(many=True).dump(participants).data,
            'messages': MessageSchema(many=True).dump(messages).data,
            'videos': VideoSchema(many=True).dump(videos).data
        }
    }), 200
예제 #13
0
def join_room_by_fingerprint(user, args):
    fingerprint = args['fingerprint']
    room = Room.query.filter(Room.fingerprint == fingerprint).one_or_none()
    if room is None:
        raise Error(StatusCode.BAD_REQUEST, 'Invalid room fingerprint')
    if room.status == RoomStatus.DELETED:
        raise Error(StatusCode.FORBIDDEN, 'This room no longer exists')

    participant = RoomParticipant.query.filter_by(
        user_id=user.id, room_id=room.id).one_or_none()
    if participant is None:
        participant = RoomParticipant(user_id=user.id,
                                      room_id=room.id,
                                      status=ParticipantStatus.IN)
        db.session.add(participant)
    else:
        participant.status = ParticipantStatus.IN

    db.session.commit()
    return jsonify({
        'message': 'You have joined this room',
        'data': RoomSchema().dump(room).data
    })
예제 #14
0
def register_new_user(**kwargs):
    args = kwargs['args']
    email = args['email']

    if User.get_user_by_email(email) is not None:
        raise Error(StatusCode.BAD_REQUEST, 'This email has been registered before')

    user = User(**args, status=UserStatus.ACTIVE, online=0)
    db.session.add(user)
    db.session.commit()
    return jsonify({
        'message': 'Your account was created successfully',
        'data': UserSchema().dump(user).data
    }), 200
예제 #15
0
def get_next_song(user, args):
    room_id = args.get('room_id')
    room_participant = RoomParticipant.query \
        .filter(RoomParticipant.room_id == room_id) \
        .filter(RoomParticipant.user_id == user.id) \
        .one_or_none()

    if room_participant.status is not ParticipantStatus.IN:
        raise Error(StatusCode.FORBIDDEN,
                    message='You are not a member of this room')

    song = Video.query \
        .filter(Video.room_id == room_id) \
        .filter(Video.status == VideoStatus.VOTING) \
        .filter(func.max(Video.total_vote)) \
        .first()
    res = {
        'message': 'Get next song successfully',
        'data': VideoSchema.dumps(song).data
    }
    return jsonify(res)
예제 #16
0
def send_message(user, args):
    room_id = args['room_id']

    participant = db.session.query(RoomParticipant).filter_by(
        room_id=args['room_id'], user_id=user.id).first()
    if participant.status != ParticipantStatus.IN:
        raise Error(StatusCode.FORBIDDEN, message='Invalid room access')

    message = Message(user_id=user.id, **args)
    db.session.add(message)
    db.session.commit()

    data = {
        'user_id': user.id,
        'username': user.name,
        'room_id': room_id,
        'content': args['content']
    }
    pusher.trigger(room_id, PusherEvent.NEW_MESSAGE, data)

    return jsonify({
        'message': 'Message added successfully',
        'data': MessageSchema().dump(message).data
    }), 200
예제 #17
0
def authenticate_user(user):
    res = authenticate(request, user)
    if not res:
        raise Error(status_code=400, message='Bad Request')

    return jsonify(res)
예제 #18
0
def update_video_status(room_id, user, args):
    status = args['status']

    room = Room.query.filter(Room.id == room_id).one()

    # Limit user from seeking or pausing video in a room
    if not room.current_video:
        raise Error(StatusCode.BAD_REQUEST,
                    'There is no current media in this room')

    meta_data = {'room': room_id, 'video': room.current_video, 'user': user.id}
    rlimit = RateLimit(10, 3 * 60, meta_data)
    if status in (VideoStatus.SEEKING, VideoStatus.PAUSING):
        if rlimit.is_over_limit:
            raise Error(
                StatusCode.FORBIDDEN,
                'You have been seeking or pausing too many times recently')

        rlimit.increase()

    if status == VideoStatus.READY:
        # Only play video when all members are ready
        room_member = RoomParticipant.query.filter(RoomParticipant.room_id == room_id) \
                                            .filter(RoomParticipant.user_id == user.id) \
                                            .one()
        room_member.video_status = VideoStatus.READY
        res = {
            'message': 'Waiting for other members to be ready',
        }
        if video_engine.check_all_user_have_same_video_status(
                room_id, VideoStatus.READY):
            current_video = video_engine.get_current_video(room_id)
            event_data = {
                'event': VideoStatus.PLAYING,
                'data': VideoSchema().dump(current_video).data
            }
            pusher.trigger(room_id, PusherEvent.VIDEO_STATUS_CHANGED,
                           event_data)
            video_engine.set_online_users_video_status(room_id,
                                                       VideoStatus.PLAYING)
            room.status = VideoStatus.PLAYING

    if status == VideoStatus.PLAYING:
        # Force all members to play video
        room.video_time = args['video_time']
        room.status = status
        video_engine.set_online_users_video_status(room_id,
                                                   VideoStatus.PLAYING)
        current_song = video_engine.get_current_video(room_id)
        event_data = {
            'event': VideoStatus.PLAYING,
            'data': VideoSchema().dump(current_song).data
        }
        pusher.trigger(room_id, PusherEvent.VIDEO_STATUS_CHANGED, event_data)
        res = {'message': 'Play video'}
    if status == VideoStatus.PAUSING:
        # Force all members to pause
        room.video_time = args['video_time']
        room.status = status
        video_engine.set_online_users_video_status(room_id,
                                                   VideoStatus.PAUSING)
        current_song = video_engine.get_current_video(room_id)
        event_data = {
            'event': VideoStatus.PAUSING,
            'data': VideoSchema().dump(current_song).data
        }
        pusher.trigger(room_id, PusherEvent.VIDEO_STATUS_CHANGED, event_data)
        res = {'message': 'Pause video'}
    if status == VideoStatus.SEEKING:
        # If someone seek videos, pause video at that time, and wait for all members to be ready
        room.video_time = args['video_time']
        room.status = VideoStatus.PAUSING
        video_engine.set_online_users_video_status(room_id,
                                                   VideoStatus.PAUSING)
        current_song = video_engine.get_current_video(room_id)
        event_data = {
            'event': VideoStatus.SEEKING,
            'data': VideoSchema().dump(current_song).data
        }
        pusher.trigger(room_id, PusherEvent.VIDEO_STATUS_CHANGED, event_data)
        res = {'message': 'Seek video'}
    if status == VideoStatus.FINISHED:
        room_member = RoomParticipant.query.filter(RoomParticipant.room_id == room_id) \
            .filter(RoomParticipant.user_id == user.id) \
            .one()

        room.video_time = args['video_time']
        room_member.video_status = VideoStatus.FINISHED

        # If all members are finished their current video, then choose next song to play
        if video_engine.check_all_user_have_same_video_status(
                room_id, VideoStatus.FINISHED):
            current_song = Video.query.filter(
                Video.id == room.current_video).one()
            current_song.status = VideoStatus.FINISHED

            video_engine.set_online_users_video_status(room_id,
                                                       VideoStatus.PAUSING)
            next_video = video_engine.set_current_video(room_id)
            parsed_next_video = VideoSchema().dump(next_video).data
            if parsed_next_video:
                parsed_next_video['video_time'] = 0
                parsed_next_video['status'] = VideoStatus.PAUSING
            pusher.trigger(room_id, PusherEvent.PROCEED, parsed_next_video)

        res = {'message': 'Wait for other member to finish their video'}

    db.session.commit()
    return jsonify(res)