def api_user_unfollow(): try: data = json.loads(request.data, object_hook=lambda x: defaultdict(lambda: None, x)) except JSONDecodeError: return error_response(["Invalid request."]) if "id" not in data: return error_response(["User ID required"]) current_id = int(current_user.get_id()) user_to_unfollow = User.query.get(int(data["id"])) if user_to_unfollow is None: return error_response(["User cannot be found"]) if user_to_unfollow.followers.filter_by(id=current_id).count() < 1: return error_response(["You aren't following that user"]) query = (follows.delete().where(follows.c.follower_id == current_id).where( follows.c.following_id == int(data["id"]))) db.session.execute(query) db.session.commit() user = User.query.get(current_id) ids = user.following.with_entities(User.id).all() return success_response([item for sublist in ids for item in sublist])
def api_tweet(): try: data = json.loads( request.data, object_hook=lambda x: defaultdict(lambda: None, x) ) except JSONDecodeError: return error_response(["Invalid request."]) tweet_text = data["text"] or "" tweet_text = tweet_text.strip().replace("\r\n", "\n") tweet_len = len(tweet_text) if tweet_len < 1: return error_response(["Your tweet must be at least one character."]) if tweet_len > 120: return error_response(["Your tweet must be at most 120 characters."]) image_id = data["imageId"] if image_id is not None: image_exists = Image.query.filter_by(id=image_id).count() > 0 if not image_exists: return error_response(["Image not found"]) tweet = Tweet( text=tweet_text, poster_id=int(current_user.get_id()), image_id=image_id ) db.session.add(tweet) db.session.commit() return success_response(tweet.to_dict())
def api_file_info(name: str): file = Image.query.filter_by(name=name).first() if file is None: return error_response(["File not found"]) return success_response(file.to_dict())
def api_login(): try: data = json.loads(request.data, object_hook=lambda x: defaultdict(lambda: None, x)) except JSONDecodeError: return error_response(["Invalid request."]) user = User.query.filter_by(username=data["username"]).first() or User( password="") # Password is checked irregardless of whether # the user was found to avoid exposing a timing oracle valid_credentials = User.check_password(user.password, data["password"]) if not valid_credentials: return error_response(["Invalid credentials."]) login_user(user=user, remember=data["rememberMe"]) return success_response(user.to_dict())
def api_file_upload(): if "file" not in request.files: return error_response(["File must be provided"]) file: FileStorage = request.files["file"] if not file or file.filename == "": return error_response(["File must be provided"]) if file.mimetype not in {"image/jpeg", "image/gif"}: return error_response( ["Invalid image format. Must be a .jpg, .jpeg or .gif file."]) user_id = int(current_user.get_id()) filename_len = 10 filename = "".join( random.choices(string.ascii_letters + string.digits, k=filename_len)) ts = calendar.timegm(time.gmtime()) filename = "%s-%d-%s.jpg" % (user_id, ts, filename) fs_path = os.path.join(app.config["UPLOAD_DIR"], filename) file.save(fs_path) file_hash = hash_file(fs_path) image = Image( name=filename, original_name=file.filename, fs_path=fs_path, hash=file_hash, mime_type=file.mimetype, uploader_id=user_id, ) db.session.add(image) db.session.commit() return success_response(image.to_dict())
def api_delete_tweet(tweet_id: int): tweet = Tweet.query.get(tweet_id) if not tweet or tweet.poster_id != int(current_user.get_id()): return error_response(["You don't have permission to do that."]) db.session.delete(tweet) if tweet.image: db.session.delete(tweet.image) db.session.commit() return success_response(None)
def api_register(): try: data = json.loads(request.data) except JSONDecodeError: return error_response(["Invalid request."]) required_fields = ["username", "password", "passwordRepeat"] has_required = all(field in data for field in required_fields) if not has_required: return error_response(["Please fill in all required fields."]) password_too_short = len(data["password"]) < 8 if password_too_short: return error_response(["Your password is too short."]) passwords_match = data["password"] == data["passwordRepeat"] if not passwords_match: return error_response(["Passwords must match."]) username_taken = User.query.filter_by( username=data["username"]).first() is not None if username_taken: return error_response(["Username is already taken"]) user = User(username=data["username"]).set_password(data["password"]) db.session.add(user) db.session.commit() login_user(user=user) return success_response(user.to_dict())
def api_user_search(): try: data = json.loads(request.data, object_hook=lambda x: defaultdict(lambda: None, x)) except JSONDecodeError: return error_response(["Invalid request."]) page = data["page"] or 1 try: page = int(page) except ValueError: page = 1 query = data["query"] or "" query = "%{}%".format(query) users = User.query.filter(User.username.ilike(query)) return paginated_query(query=users, page=page)