diff --git a/client/src/services/socketio.js b/client/src/services/socketio.js index 97be5dd7..256b3e0e 100644 --- a/client/src/services/socketio.js +++ b/client/src/services/socketio.js @@ -1,5 +1,5 @@ import socketIOClient from "socket.io-client"; - +// Controls reconnect attempts const io = socketIOClient(process.env.REACT_APP_SERVER_URL, { withCredentials: true, reconnectionAttempts: 1, diff --git a/server/inquire/mongo.py b/server/inquire/mongo.py index de6327eb..80741c50 100644 --- a/server/inquire/mongo.py +++ b/server/inquire/mongo.py @@ -85,6 +85,7 @@ class UserCourse(EmbeddedMongoModel): nickname = fields.CharField(blank=True) color = fields.CharField(blank=True) role = fields.CharField(required=True) + viewed = fields.DictField(default={}) ''' diff --git a/server/inquire/resources/comments.py b/server/inquire/resources/comments.py index cb8873ee..0f77b0e7 100644 --- a/server/inquire/resources/comments.py +++ b/server/inquire/resources/comments.py @@ -14,6 +14,7 @@ from inquire.mongo import * from inquire.socketio_app import io +import datetime class Comments(Resource): @permission_layer(require_joined_course=True) @@ -42,6 +43,10 @@ def get(self, courseId=None, postId=None): post = self.retrieve_post(postId) if post is None: return abort(400, errors=["Bad post id"]) + # Marking that the current_user just viewed this post + if (course := current_user.get_course(courseId)) != None: + course.viewed[postId] = datetime.datetime.now() + current_user.save() return [self.serialize(comment) for comment in Comment.objects.raw({'postId': postId})] diff --git a/server/inquire/resources/posts.py b/server/inquire/resources/posts.py index a739dcd1..bb945e78 100644 --- a/server/inquire/resources/posts.py +++ b/server/inquire/resources/posts.py @@ -7,6 +7,7 @@ Last Modified Date: 03/12/2021 ''' +import datetime from flask import jsonify, request, current_app from flask_restful import reqparse, Resource from inquire.auth import current_user, permission_layer @@ -99,6 +100,13 @@ def post(self, courseId=None): return {"errors": str(exc)} result = self.serialize(post) + + # Marking that the creator of the post has viewed their own post + if (course := current_user.get_course(courseId)) != None: + course.viewed[result["_id"]] = datetime.datetime.now() + current_user.save() + + if not result['isPrivate'] and current_app.config['include_socketio']: current_app.socketio.emit('Post/create', result, room=courseId) return result, 200 @@ -239,6 +247,11 @@ def get(self, courseId=None): # Get the json for all the posts we want to display result = [self.serialize(post) for post in query] + # Setting "read" property of each post based on UserCourse.viewed dict + if (course := current_user.get_course(courseId)) !=None: + viewed = course.viewed + for post in result: + self.set_read(post, viewed) return result, 200 @@ -436,6 +449,23 @@ def serialize(self, post): self.anonymize_poll_content(post["content"]) return result + def set_read(self, post, viewed): + """Modifies a dictionary representing a post by setting a new key-value + pair of either "read": True or "read": False depending on the contents + of the viewed dict. + + Args: + post (dict): Dictionary representing a post + viewed (dict): Dictionary representing the last time a user viewed the comments on a post. + Keys are post id strings, values are datetime objects. If post id is not a key in the dict, + the user has never viewed the post. + """ + post_id = post["_id"] + if post_id in viewed and viewed[post_id] > post['updatedDate']: + post['read'] = True + else: + post['read'] = False + def anonymize_poll_content(poll): for field_name in poll["fields"]: poll["fields"][field_name].pop("users")