def like_post(post_id, username): try: post_data = PostModel.like_post( post_id=post_id, username=username, ) post_username = post_data['username'] post_title = post_data['title'] UserModel.add_notification_message(post_username, f'liked your post {post_title}', user_ref=username, post_ref=post_id) return make_response( jsonify({ 'status': 'success', 'message': 'Post successfully liked.', 'data': post_data }), 200) except OperationFailure as e: return make_response( jsonify({ 'status': 'fail', 'message': f'DB Operation Error: {str(e)}', }), 400) except ConnectionFailure as e: return make_response( jsonify({ 'status': 'fail', 'message': f'DB Connection Error: {str(e)}', }), 500)
def add_post_comment(post_id, username, text): try: timestamp = datetime.utcnow().isoformat() post_data = PostModel.add_comment(post_id=post_id, username=username, text=text, timestamp=timestamp) post_username = post_data['username'] post_title = post_data['title'] UserModel.add_notification_message( post_username, f'commented on your post {post_title}', user_ref=username, post_ref=post_id) return make_response( jsonify({ 'status': 'success', 'message': 'Comment successfully added to post.', 'data': post_data }), 200) except OperationFailure as e: return make_response( jsonify({ 'status': 'fail', 'message': f'DB Operation Error: {str(e)}', }), 400) except ConnectionFailure as e: return make_response( jsonify({ 'status': 'fail', 'message': f'DB Connection Error: {str(e)}', }), 500)
def unfollow(username, other_username): try: user_app_data = UserModel.unfollow(username, other_username)[0] user_auth_data = AuthUtil.get_user(username) data = { 'username': user_auth_data['username'], 'email': user_auth_data['email'], 'followers': user_app_data['followers'], 'followings': user_app_data['followings'], 'posts': user_app_data['posts'], } return make_response( jsonify({ 'status': 'success', 'message': f'Successfully followed {other_username}.', 'data': data }), 200) except Auth0Error as e: return make_response( jsonify({ 'status': 'fail', 'message': f'Auth0 Error: {str(e)}', }), 400) except OperationFailure as e: return make_response( jsonify({ 'status': 'fail', 'message': f'DB Operation Error: {str(e)}', }), 400) except ConnectionFailure as e: return make_response( jsonify({ 'status': 'fail', 'message': f'DB Connection Error: {str(e)}', }), 500)
def get_user_posts(username, skip=0, limit=10): user = UserModel.get_user(username) if user: posts = [PostModel.get_post(post_id) for post_id in user['posts']] posts.sort(key=lambda post: post['timestamp'], reverse=True) return posts[skip:skip + limit] raise WriteError(f'Error in querying posts. User may not exist.')
def add_user_post(username, post_id, title, audio_link, timestamp, description=None, image_link=None): user = UserModel.get_user(username) if user: DB.posts.insert({ '_id': post_id, 'username': username, 'title': title, 'description': description, 'audio_link': audio_link, 'image_link': image_link, 'timestamp': timestamp, 'comments': [], 'liked_by': [], 'view_count': 0 }) DB.users.find_one_and_update({'_id': username}, {'$addToSet': { 'posts': post_id }}) return PostModel.get_post(post_id) raise WriteError('Error in creating post. User may not exist.')
def get_user_discover_posts(username, skip=0, limit=10, seed=0): user = UserModel.get_user(username) if user: all_posts = list(DB.posts.find({'username': {'$ne': username}})) permuted_posts = PostModel.permute_with_discovery_algorithm( all_posts, seed) return permuted_posts[skip:skip + limit] raise WriteError(f'Error in querying posts. User may not exist.')
def login_user(username_or_email, password): try: user_token = AuthUtil.get_user_token( username_or_email=username_or_email, password=password) username = AuthUtil.decode_user_token(user_token) user_auth_data = AuthUtil.get_user(username) if user_auth_data['email_verified']: user_app_data = UserModel.get_user(username, show_following_pics=True, show_follower_pics=True) data = { 'username': user_auth_data['username'], 'email': user_auth_data['email'], 'email_verified': user_auth_data['email_verified'], 'followers': user_app_data['followers'], 'followings': user_app_data['followings'], 'posts': user_app_data['posts'], 'number_of_followers': len(user_app_data['followers']), 'number_of_following': len(user_app_data['followings']), 'number_of_posts': len(user_app_data['posts']), 'description': user_app_data['description'], 'notifications': user_app_data['notifications'], 'picture': user_app_data['picture'], 'user_token': user_token } return make_response( jsonify({ 'status': 'success', 'message': 'User successfully login.', 'data': data }), 200) else: return make_response( jsonify({ 'status': 'fail', 'message': 'User email not verified. Please verify email to login.', }), 400) except Auth0Error as e: return make_response( jsonify({ 'status': 'fail', 'message': f'Auth0 Error: {str(e)}', }), 400) except OperationFailure as e: return make_response( jsonify({ 'status': 'fail', 'message': f'DB Operation Error: {str(e)}', }), 400) except ConnectionFailure as e: return make_response( jsonify({ 'status': 'fail', 'message': f'DB Connection Error: {str(e)}', }), 500)
def like_post(post_id, username): user = UserModel.get_user(username) post = PostModel.get_post(post_id) if user and post: DB.posts.find_one_and_update({'_id': post_id}, {'$addToSet': { 'liked_by': username }}) return PostModel.get_post(post_id) raise WriteError(f'Error in liking post. User or post may not exist.')
def get_user_feed_posts(username, skip=0, limit=10): user = UserModel.get_user(username) if user: followings = [username for username in user['followings']] posts = [] for username in followings: posts.extend(PostModel.get_user_posts(username)) posts.sort(key=lambda post: post['timestamp'], reverse=True) return posts[skip:skip + limit] raise WriteError(f'Error in querying posts. User may not exist.')
def remove_user_post(username, post_id): user = UserModel.get_user(username) post = PostModel.get_post(post_id) if post['_id'] in user['posts']: post_resp = DB.posts.find_one_and_delete({'_id': post_id}) user_resp = DB.users.find_one_and_update( {'_id': username}, {'$pull': { 'posts': post_id }}) return user_resp, post_resp raise WriteError( f'Error in removing post. User may not be authorized to remove this post.' )
def follow(username, other_username): try: user_app_data = UserModel.follow(username, other_username)[0] UserModel.add_notification_message(other_username, f'followed you!', user_ref=username) data = { 'username': user_app_data['_id'], 'email': user_app_data['email'], 'followers': user_app_data['followers'], 'followings': user_app_data['followings'], 'posts': user_app_data['posts'], } return make_response( jsonify({ 'status': 'success', 'message': f'Successfully followed {other_username}.', 'data': data }), 200) except Auth0Error as e: return make_response( jsonify({ 'status': 'fail', 'message': f'Auth0 Error: {str(e)}', }), 400) except OperationFailure as e: return make_response( jsonify({ 'status': 'fail', 'message': f'DB Operation Error: {str(e)}', }), 400) except ConnectionFailure as e: return make_response( jsonify({ 'status': 'fail', 'message': f'DB Connection Error: {str(e)}', }), 500)
def update_user(username, **updates): try: if ('picture_filepath' in updates) and (updates['picture_filepath'] is not None): updates['picture'] = upload_file(updates['picture_filepath'], uuid.uuid4().hex) # user_auth_data = AuthUtil.update_user(username, **updates) user_app_data = UserModel.update_user(username, **updates) data = { 'username': username, 'email': user_app_data['email'], 'followers': user_app_data['followers'], 'followings': user_app_data['followings'], 'posts': user_app_data['posts'], 'number_of_followers': len(user_app_data['followers']), 'number_of_following': len(user_app_data['followings']), 'number_of_posts': len(user_app_data['posts']), 'description': user_app_data['description'], 'picture': user_app_data['picture'], } return make_response( jsonify({ 'status': 'success', 'message': 'User successfully updated.', 'data': data }), 201) except Auth0Error as e: return make_response( jsonify({ 'status': 'fail', 'message': f'Auth0 Error: {str(e)}', }), 400) except OperationFailure as e: return make_response( jsonify({ 'status': 'fail', 'message': f'DB Operation Error: {str(e)}', }), 400) except ConnectionFailure as e: return make_response( jsonify({ 'status': 'fail', 'message': f'DB Connection Error: {str(e)}', }), 500) except ClientError as e: return make_response( jsonify({ 'status': 'fail', 'message': f'S3 Connection Error: {str(e)}', }), 500)
def add_comment(post_id, username, text, timestamp): post = PostModel.get_post(post_id) user = UserModel.get_user(username) if user and post: comment = { 'username': username, 'text': text, 'timestamp': timestamp } DB.posts.find_one_and_update({'_id': post_id}, {'$push': { 'comments': comment }}) return PostModel.get_post(post_id) raise WriteError( f'Error in adding comment. User or post may not exist.')
def get_user(username, auth_info=True): try: user_data = UserModel.get_user(username, show_following_pics=True, show_follower_pics=True) data = {'username': username} data.update({ 'followers': user_data['followers'], 'followings': user_data['followings'], 'posts': user_data['posts'], 'number_of_followers': len(user_data['followers']), 'number_of_following': len(user_data['followings']), 'number_of_posts': len(user_data['posts']), 'description': user_data['description'], 'picture': user_data['picture'], }) if auth_info: data.update({ 'email': user_data['email'], 'notifications': user_data['notifications'] }) return make_response( jsonify({ 'status': 'success', 'message': 'User successfully retrieved.', 'data': data }), 200) except Auth0Error as e: return make_response( jsonify({ 'status': 'fail', 'message': f'Auth0 Error: {str(e)}', }), 400) except OperationFailure as e: return make_response( jsonify({ 'status': 'fail', 'message': f'DB Operation Error: {str(e)}', }), 400) except ConnectionFailure as e: return make_response( jsonify({ 'status': 'fail', 'message': f'DB Connection Error: {str(e)}', }), 500)
def update_user_post(username, post_id, **updates): user = UserModel.get_user(username) post = PostModel.get_post(post_id) if post['_id'] in user['posts']: updated_document = {'_id': post_id} if 'title' in updates: updated_document['title'] = updates['title'] if 'description' in updates: updated_document['description'] = updates['description'] if 'audio_link' in updates: updated_document['audio_link'] = updates['audio_link'] if 'image_link' in updates: updated_document['image_link'] = updates['image_link'] DB.posts.find_one_and_update({'_id': post_id}, {'$set': updated_document}) return PostModel.get_post(post_id) raise WriteError( f'Error in removing post. User may not be authorized to remove this post.' )
def search_user(query='', skip=0, limit=10): try: users = [] if query == '' else UserModel.search_user( query=query, skip=skip, limit=limit) return make_response( jsonify({ 'status': 'success', 'message': f'Successfully retrieved users.', 'data': users }), 200) except OperationFailure as e: return make_response( jsonify({ 'status': 'success', 'message': f'Successfully retrieved users.', 'data': [] }), 200) except ConnectionFailure as e: return make_response( jsonify({ 'status': 'fail', 'message': f'DB Connection Error: {str(e)}', }), 500)
def is_following(username, other_username): try: res = UserModel.is_following(username, other_username) message_verb = 'follows' if res else 'does not follow' return make_response( jsonify({ 'status': 'success', 'message': f'{username} {message_verb} {other_username}.', 'data': res }), 200) except OperationFailure as e: return make_response( jsonify({ 'status': 'fail', 'message': f'DB Operation Error: {str(e)}', }), 400) except ConnectionFailure as e: return make_response( jsonify({ 'status': 'fail', 'message': f'DB Connection Error: {str(e)}', }), 500)
def get_post(post_id): try: post_data = PostModel.get_post(post_id) profile_picture = UserModel.get_user( post_data["username"])['picture'] post_data["profile_picture"] = profile_picture return make_response( jsonify({ 'status': 'success', 'message': 'Posts successfully queried.', 'data': post_data }), 200) except OperationFailure as e: return make_response( jsonify({ 'status': 'fail', 'message': f'DB Operation Error: {str(e)}', }), 400) except ConnectionFailure as e: return make_response( jsonify({ 'status': 'fail', 'message': f'DB Connection Error: {str(e)}', }), 500)
def create_user_post(username, title, audio_file, description=None, image_file=None): try: post_id = uuid.uuid4().hex timestamp = datetime.utcnow().isoformat() file_name, file_ext = os.path.splitext(audio_file.filename) # todo: multithread or multiprocess the audio conversion cos it's blocking and uses high cpu audio = AudioSegment.from_file(audio_file, format=file_ext.lstrip('.')) if len(audio ) > 12 * 60 * 1000: # len(audio) is audio duration in ms return make_response( jsonify({ 'status': 'fail', 'message': f'Audio duration is longer than 12 minutes, actual duration = {len(audio)/1000/60}min.' }), 400) # export in memory, not stored to disk audio_buffer = io.BytesIO() # normalize audio amplitude (volume) to -20 dBFS (smaller is quieter) # src: https://github.com/jiaaro/pydub/issues/90#issuecomment-75551606 target_dBFS = -20 change_in_dBFS = target_dBFS - audio.dBFS normalized_audio = audio.apply_gain(change_in_dBFS) normalized_audio.export(audio_buffer, format='mp3') audio_link = upload(audio_buffer, uuid.uuid4().hex + '.mp3') audio_buffer.close() image_link = None if image_file is not None: file_name, file_ext = os.path.splitext(image_file.filename) image_buffer = io.BytesIO() process_image(image_file, image_buffer) image_link = upload(image_buffer, uuid.uuid4().hex + file_ext) image_buffer.close() post_data = PostModel.add_user_post(username=username, post_id=post_id, title=title, timestamp=timestamp, audio_link=audio_link, description=description, image_link=image_link) user_data = UserModel.get_user(username) for follower_username in user_data['followers']: UserModel.add_notification_message( follower_username, f'made a new post!', user_ref=username, post_ref=post_id, ) return make_response( jsonify({ 'status': 'success', 'message': 'Post successfully created.', 'data': post_data }), 201) except CouldntDecodeError as e: return make_response( jsonify({ 'status': 'fail', 'message': f'PyDub failed to decode: {str(e)}', }), 400) except CouldntEncodeError as e: return make_response( jsonify({ 'status': 'fail', 'message': f'PyDub failed to encode: {str(e)}', }), 500) except UnidentifiedImageError as e: return make_response( jsonify({ 'status': 'fail', 'message': f'PIL failed to read image: {str(e)}', }), 400) except OperationFailure as e: return make_response( jsonify({ 'status': 'fail', 'message': f'DB Operation Error: {str(e)}', }), 400) except ConnectionFailure as e: return make_response( jsonify({ 'status': 'fail', 'message': f'DB Connection Error: {str(e)}', }), 500) except ClientError as e: return make_response( jsonify({ 'status': 'fail', 'message': f'S3 Connection Error: {str(e)}', }), 500)
def register_user(username, email, password, description=None, picture=None): try: # Add to MongoDB user_db_data = UserModel.add_user(username=username, email=email, description=description, picture=picture) # Add to Auth0 user_auth_data = AuthUtil.create_user(username=username, email=email, password=password) rtn_user_data = { 'username': user_auth_data['username'], 'email': user_auth_data['email'], 'email_verified': user_auth_data['email_verified'], 'followers': user_db_data['followers'], 'followings': user_db_data['followings'], 'posts': user_db_data['posts'], 'number_of_followers': len(user_db_data['followers']), 'number_of_following': len(user_db_data['followings']), 'number_of_posts': len(user_db_data['posts']), 'description': user_db_data['description'], 'picture': user_db_data['picture'], } return make_response( jsonify({ 'status': 'success', 'message': 'User successfully registered.', 'data': rtn_user_data }), 201) except Auth0Error as e: return make_response( jsonify({ 'status': 'fail', 'message': f'Auth0 Error: {str(e)}', }), 400) except OperationFailure as e: return make_response( jsonify({ 'status': 'fail', 'message': f'DB Operation Error: {str(e)}', }), 400) except ConnectionFailure as e: return make_response( jsonify({ 'status': 'fail', 'message': f'DB Connection Error: {str(e)}', }), 500) except ClientError as e: return make_response( jsonify({ 'status': 'fail', 'message': f'S3 Connection Error: {str(e)}', }), 500)