diff --git a/README.md b/README.md index bd2dd7e..42a5f66 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,7 @@ # Name + Stevens Login Jason Rossi, jrossi3@stevens.edu Nouman Syed, nsyed1@stevens.edu +Atishay Jain, ajain70@stevens.edu # The URL of your public GitHub repo https://github.com/Jrossi3/WebForum @@ -40,3 +41,14 @@ We tested persistence in a very simple way. We ran the command "curl http://127. 3) Persistence We tested persistence through 2 different ways. Our first way was restarting the server through running two commands to end and start the server. There is a "kill $PID" command and a "flask run &" command to end and start the server resepctively. The second way of testing was giving it a bad request. The exact command is "curl http://127.0.0.1:5000/post/fulltext" and here this is a bad request because it is an unfinished request and therefore will return an error. Then there is a test to see if the post is still existing after the command is run. There are many comments in the testing to show the exact specifics of when these tests occur. + +4) Threaded replies + +We tested threaded replies for which we have send a POST request to the URL with an 'id' parameter and a JSON object containing a 'msg' field. For testing we first created a command just to generate a new post, using the command: "curl http://127.0.0.1:5000/post" and gave the msg as "First". Now that we have the first post available, our job is to now add threaded replies inside of this 1st post. The exact command is "curl http://127.0.0.1:5000/post/1" in which we gave a msg "First Reply".When then check if the threaded reply gets inserted inside of the thread array or not.it should finally generate a reply id, a msg, and timestamp when returning. + +We tested the threaded replies + + +5) Date based range queries + +We tested date based range queries by running: curl "http://127.0.0.1:5000/post/2023-04-30T21:13:52Z/2023-04-30T21:13:44Z" for example. Here the two parameters after /post are start and end timestamps. They result with posts in between the two timestamps. We have added three more cases for this. First case if the user wants to give the start timestamp as none, second in which the end time is none and the third one in which both are none. The program will handle the first two out of three but for the third one in which both are entered as none, then it would just give a 404 and throw an error. \ No newline at end of file diff --git a/app.py b/app.py index f55d4f5..36735b7 100644 --- a/app.py +++ b/app.py @@ -39,7 +39,6 @@ def post_request(): post_id = max_id + 1 # Get the current time - timestamp = datetime.utcnow().strftime('%Y-%m-%dT%H:%M:%SZ') # Generate a random key @@ -68,69 +67,90 @@ def post_request(): @app.route("/post/", methods=["POST"]) def threaded_replies(id): - body = request.get_json(force=True) msg = body['msg'] - # key = body['key'] if not isinstance(msg, str) or msg is None: return "Post content should be of type string", 400 - - # Get the parent post object - parent_post = db["posts_collection"].find_one({"id": id}) - if parent_post is None: - return "Parent post not found", 404 key = secrets.token_hex(16) + # parent_post = db["posts_collection"].find_one({"id": id}) + # if parent_post is None: + # return "Parent post not found", 404 + + - # if parent_post["key"] != key: - # return "Key is invalid" + # # Generate a new reply id + # max_reply_id = parent_post.get("max_reply_id", 0) + # reply_id = max_reply_id + 1 + timestamp = datetime.utcnow().strftime('%Y-%m-%dT%H:%M:%SZ') + # Generate a new UUID for the post + max_id_doc = db["posts_collection"].find_one(sort=[("id", -1)]) + if max_id_doc is None: + max_id = 0 + else: + max_id = max_id_doc["id"] - # Generate a new UUID for the reply - max_id = 0 - for thread in parent_post["thread"]: - if thread["id"] > max_id: - max_id = thread["id"] + # Generate a new post_id by incrementing the maximum post_id reply_id = max_id + 1 - timestamp = datetime.now() + reply = { "id": reply_id, "msg": msg, "key": key, - "timestamp": timestamp + "timestamp": timestamp, + # "parent_id": parent_post["id"], + "thread": [] } - + # Insert the new post object into the database with lock: posts_collection = db["posts_collection"] - posts_collection.update_one({"_id": ObjectId(parent_post["_id"])}, - {"$push": {"thread": reply}}) + posts_collection.insert_one(reply) - inserted_reply = posts_collection.find_one( - {"id": id, "thread.id": reply_id}, - {"_id": 0, "thread.$": 1} - ) + with lock: + posts_collection = db["posts_collection"] + posts_collection.update_one( + {"id": id}, + {"$push": {"thread": reply_id}} + ) - return jsonify(inserted_reply["thread"][0]), 200 + inserted_post = posts_collection.find_one({"id": reply_id}) + post_dict = dict(inserted_post) + post_dict.pop("_id", None) + post_dict.pop("key", None) + post_dict.pop("thread", None) + return jsonify(post_dict), 200 + # return jsonify(reply), 200 -@app.route("/post//thread", methods=['GET']) -def get_thread_queries(id): - # Get the threads of a post from the database by ID +@app.route("/post//", methods=['GET']) +def date_time_queries(start, end): + if start.lower() == "none": + start = start.lower() + if end.lower() == "none": + end = end.lower() + # print(end) + timestamp = datetime.utcnow().strftime('%Y-%m-%dT%H:%M:%SZ') with lock: posts_collection = db["posts_collection"] - post = posts_collection.find_one({"id": id}) - threads_in_post = post["thread"] - - if post is None: - return f"Post with ID: {id} not found", 404 - - threads_list = list(threads_in_post) - for thread in threads_list: - thread.pop("_id", None) - - return jsonify(threads_list), 200 + if start == "none" and end == "none": + return "Both Start and End cannot be None", 404 + elif start == "none": + posts = posts_collection.find({"timestamp": {"$lte": end}}) + elif end == "none": + posts = posts_collection.find({"timestamp": {"$gte": start}}) + else: + posts = posts_collection.find({"timestamp": {"$gte": start, "$lte": end}}) + + result = [] + for post in posts: + post_dict = dict(post) + post_dict.pop("_id", None) + post_dict.pop("key", None) + result.append(post_dict) + return jsonify(result), 200 @app.route("/post/", methods=['GET']) def get_post(id): diff --git a/test.sh b/test.sh index 44a7054..c0b6fad 100644 --- a/test.sh +++ b/test.sh @@ -1,8 +1,8 @@ #!/bin/bash # echo "├─ pymongo" -# pip3 install pymongo +pip3 install pymongo # echo "├─ secrets" -# pip3 install secrets +pip3 install secrets # Start the app in the background python3 app.py & @@ -15,14 +15,15 @@ sleep 2 # Test POST /post and GET /post/id # This test will exit immediately if the POST /post or GET /post/id fails. -curl http://127.0.0.1:5000/post -X POST -d '{"msg": "hi my name is jason"}' -RESPONSE=$(curl http://localhost:5000/post/1) +RESPONSE=$(curl http://127.0.0.1:5000/post -X POST -d '{"msg": "hi my name is jason"}') +echo "$RESPONSE" key=$(echo $RESPONSE | jq -r '.key') timestamp=$(echo $RESPONSE | jq -r '.timestamp') id=$(echo $RESPONSE | jq -r '.id') +TEST=$(curl http://127.0.0.1:5000/post/1) # GET /post/id test -if [ "$RESPONSE" == "Post with ID: 1 not found" ]; then +if [ "$TEST" == "Post with ID: {$id} not found" ]; then echo "Get /post/id failed." exit 1 else @@ -31,7 +32,7 @@ fi # Check if the response matches the expected output # POST /post test -EXPECTED={'"id"':$id,'"key"':'"'$key'"','"msg"':'"hi my name is jason"','"thread"':[],'"timestamp"':'"'$timestamp'"'} +EXPECTED={'"id"':$id,'"key"':'"'$key'"','"timestamp"':'"'$timestamp'"'} if [[ "$RESPONSE" != *"$EXPECTED"* ]]; then echo "ERROR: POST /post failed" echo "Expected: $EXPECTED" @@ -77,22 +78,16 @@ else fi # Testing the delete function by creating 4 more posts and then deleting all 5 of the posts -# This test will exit immediately if the deletion fails. -counter=2 -while [ $counter -le 5 ] -do - curl http://127.0.0.1:5000/post -X POST -d '{"msg": "hi my name is jason"}' - ((counter++)) -done - +# This test will exit immediately if the deletion fails. counter=1 while [ $counter -le 5 ] do - RESPONSE=$(curl http://localhost:5000/post/$counter) + RESPONSE=$(curl http://127.0.0.1:5000/post -X POST -d '{"msg": "hi my name is jason"}') key=$(echo $RESPONSE | jq -r '.key') - curl -X DELETE http://127.0.0.1:5000/post/$counter/delete/$key - EXISTS=$(curl http://localhost:5000/post/$counter) - if [ "$EXISTS" = "Post with ID: $counter not found" ]; then + id=$(echo $RESPONSE | jq -r '.id') + curl -X DELETE http://127.0.0.1:5000/post/$id/delete/$key + EXISTS=$(curl http://localhost:5000/post/$id) + if [ "$EXISTS" = "Post with ID: $id not found" ]; then echo "Delete passed." else echo "Delete failed." @@ -103,15 +98,14 @@ done # Test the update function # This should return "Message updated." Otherwise, the test will exit immediately. - -curl http://127.0.0.1:5000/post -X POST -d '{"msg": "hi my name is jason"}' -RESPONSE=$(curl http://localhost:5000/post/1) +RESPONSE=$(curl http://127.0.0.1:5000/post -X POST -d '{"msg": "hi my name is jason"}') +Old_post=$(curl http://localhost:5000/post/$id) key=$(echo $RESPONSE | jq -r '.key') id=$(echo $RESPONSE | jq -r '.id') -msg=$(echo $RESPONSE | jq -r '.msg') +msg=$(echo $Old_post | jq -r '.msg') curl -X PUT -d '{"msg": "hello I am update"}' http://127.0.0.1:5000/post/$id/update/$key -New=$(curl http://localhost:5000/post/1) -newMsg=$(echo $New | jq -r '.msg') +New_post=$(curl http://localhost:5000/post/$id) +newMsg=$(echo $New_post | jq -r '.msg') if [ "$msg" == "$newMsg" ]; then echo "Message update failed." @@ -120,60 +114,178 @@ else echo "Message update passed." fi -# Clean up -key=$(echo $New | jq -r '.key') curl -X DELETE http://127.0.0.1:5000/post/$id/delete/$key # Running the same test as before except commenting out the update function to show that the update will not happen # This is to show that the update function is actually updating the message -# This should return "Message not updated." Otherwise, the test will exit immediately. +# This should return "Message update failed." Otherwise, the test will exit immediately. -curl http://127.0.0.1:5000/post -X POST -d '{"msg": "hi my name is jason"}' -RESPONSE=$(curl http://localhost:5000/post/1) +RESPONSE=$(curl http://127.0.0.1:5000/post -X POST -d '{"msg": "hi my name is jason"}') +Old_post=$(curl http://localhost:5000/post/$id) key=$(echo $RESPONSE | jq -r '.key') id=$(echo $RESPONSE | jq -r '.id') -msg=$(echo $RESPONSE | jq -r '.msg') +msg=$(echo $Old_post | jq -r '.msg') # curl -X PUT -d '{"msg": "hello I am update"}' http://127.0.0.1:5000/post/$id/update/$key -New=$(curl http://localhost:5000/post/1) -newMsg=$(echo $New | jq -r '.msg') +New_post=$(curl http://localhost:5000/post/$id) +newMsg=$(echo $New_post | jq -r '.msg') -if [ "$msg" != "$newMsg" ]; then - echo "Message updated." - exit 1 +if [ "$msg" == "$newMsg" ]; then + echo "Message update failed." else - echo "Message not updated." + echo "Message update passed." + exit 1 fi -# Clean up -key=$(echo $New | jq -r '.key') curl -X DELETE http://127.0.0.1:5000/post/$id/delete/$key -# Write tests for Fulltext search +# Testing for fulltext search +# Creating multiple posts and then checking if the fulltext search works on each post # This will exit immediately if the fulltext search fails curl http://127.0.0.1:5000/post -X POST -d '{"msg": "hi my name is jason"}' +curl http://127.0.0.1:5000/post -X POST -d '{"msg": "hi my name is jason"}' RESPONSE=$(curl http://127.0.0.1:5000/post/fulltext/"hi%20my%20name%20is%20jason") -echo "$RESPONSE" -key=$(echo $RESPONSE | jq -r '.[0].key') -timestamp=$(echo $RESPONSE | jq -r '.[0].timestamp') -id=$(echo $RESPONSE | jq -r '.[0].id') -thread=$(echo $RESPONSE | jq -r '.[0].thread') -msg=$(echo $RESPONSE | jq -r '.[0].msg') -EXPECTED=[{'"id"':$id,'"key"':'"'$key'"','"msg"':'"'$msg'"','"thread"':$thread,'"timestamp"':'"'$timestamp'"'}] -echo "$EXPECTED" - -if [ "$RESPONSE" == "$EXPECTED" ]; then - echo "Fulltext search passed." +counter=0 +while [ 1 ] +do + msg=$(echo $RESPONSE | jq -r '.[0].msg') + if [ "$msg" != "hi my name is jason" ]; then + echo "Fulltext search failed." + exit 1 + fi + RESPONSE=$(echo "$RESPONSE" | jq 'del(.[0])') + if [ "$RESPONSE" == [] ]; then + echo "Fulltext search passed." + break + fi +done + +# Clean up +DB_NAME="web_forum_database" +mongo <