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 })
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 })
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')
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 })
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)
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
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')
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)
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)
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')
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')
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
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 })
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
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)
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
def authenticate_user(user): res = authenticate(request, user) if not res: raise Error(status_code=400, message='Bad Request') return jsonify(res)
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)