-
Notifications
You must be signed in to change notification settings - Fork 40
Implement a comment/discussion system in GraphSpace #426
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Open
yash170106065
wants to merge
96
commits into
Murali-group:comment-system
Choose a base branch
from
yash170106065:comment-system
base: comment-system
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Changes from 17 commits
Commits
Show all changes
96 commits
Select commit
Hold shift + click to select a range
c1c914e
Architecture.png
melvin15may a66e227
Add files via upload
melvin15may 9d209ac
Added screen-casts for group notifications
melvin15may 3aa78a2
Delete add_new_member.webm
melvin15may b5ea257
Delete group-notification-tab.webm
melvin15may fc92a9a
Delete individual-notification.webm
melvin15may 3917fef
Delete mark-all-as-read-notification.webm
melvin15may 1c86293
Delete share-unshare-graph.webm
melvin15may b78cf01
Add files via upload
melvin15may 7125307
Delete share-layout.webm
melvin15may f1a7c6f
Delete graph_notification.gif
melvin15may a1dc11d
Delete layout_notification.gif
melvin15may 0a3804e
Delete group_notification.gif
melvin15may b016885
Delete group_update_notification.gif
melvin15may e55794d
Delete notification_page.gif
melvin15may b1afe02
Add files via upload
melvin15may d07fe12
Add files via upload
melvin15may 01fa25f
Merge remote-tracking branch 'upstream/master'
melvin15may f655860
started implementing comments system
bruce-wayne99 8cbc3cc
added models for comments, comment to node and comment to edge relati…
bruce-wayne99 71608b7
removed comments folder
bruce-wayne99 0d4493e
added views and controllers for creating comments
bruce-wayne99 f0b5d51
update dal.py and models.py
bruce-wayne99 6639114
added errorcode for creating comment
bruce-wayne99 ab79a78
removed comments related code from graphs
bruce-wayne99 87dd719
added comment-system application
bruce-wayne99 b308319
added views and routes to display and upload comments for testing
bruce-wayne99 bc2eda9
added asgi for sockets
bruce-wayne99 163e5c2
django channels added for real-time functionality
bruce-wayne99 c51eae5
added sockets for frontend and signals
bruce-wayne99 3f41a4a
added functionality to get edgeId/nodeId based on edge/node name
bruce-wayne99 db394d8
added ajax handlers to create comments by ajax request
bruce-wayne99 52b5bb0
added panel for adding comments, viewing comments
bruce-wayne99 fd0df77
update signals to handle delete,add,edit comments
bruce-wayne99 e6a5c7e
update controllers,dal,models to handle edit,delete,resolve,add,reply…
bruce-wayne99 903387c
added views to handle crud operations on comments
bruce-wayne99 e0a1276
added event listeners to comments for CRUD operations
bruce-wayne99 5b830aa
updated socket handler functions
bruce-wayne99 f572c90
added functionality for displaying updated time of comment in real-time
bruce-wayne99 58f2e66
added functionality for showing the graph associated with a comment
bruce-wayne99 5156c2a
fixed real-time functionality to highlight graph elements on hovering…
bruce-wayne99 e8f7940
added permissions for CRUD on comments
bruce-wayne99 3b3714e
added functionality frontend to highlight graph elements
bruce-wayne99 3574323
fixed bug real-time functionality
bruce-wayne99 e50f8d8
added implementation for visualizing comments based on selected graph
bruce-wayne99 58cc0dc
added functionality for comments dropdown
bruce-wayne99 dcfc9f3
fixed filtering comments to handle resolved comments
bruce-wayne99 38b59b7
added backend functionality to handle replies to resolved comments
bruce-wayne99 a500e07
added errorcodes on trying to reply to resolved comments
bruce-wayne99 7b48c78
added frontend and socket functionality to handle resolved comments
bruce-wayne99 e45ec93
did code clean up to remove unnecessary id's for elements
bruce-wayne99 1fba768
added backend implementation for pinning comments
bruce-wayne99 cd09b6f
added error codes to handle errors for pinning comments
bruce-wayne99 62d6c9e
Added frontend code for pinning comments and pagination
bruce-wayne99 d94f4f3
added real-time functionality to handle pin/unpin/resolve/reopen comm…
bruce-wayne99 dbd89e3
update graph_page.js, graphspace.css base.html for displaying resolve…
bruce-wayne99 e37760f
update graphspace.css, graph_page.js for pagination
bruce-wayne99 591b7b0
added real-time functionality for pagination
bruce-wayne99 ee2d892
added resolved checkbox for comments
bruce-wayne99 d025f3f
added functionality to allow owner of the graph to delete comments, a…
bruce-wayne99 d420f3b
Merge pull request #1 from bruce-wayne99/summer-work
bruce-wayne99 e4d9c1c
added code documentation
bruce-wayne99 6f14c60
Merge pull request #2 from bruce-wayne99/summer-work
bruce-wayne99 03f6fd0
removed upload comment method
bruce-wayne99 18c1650
changed port for redis server
bruce-wayne99 01f12c9
added docker configuration files
bruce-wayne99 bb36d69
update requirements.txt
bruce-wayne99 57fc838
added code for running the server
bruce-wayne99 75d3396
added changes for displaying ports
bruce-wayne99 a77a8d7
changed requirements file and fixed bugs in Dockerfile
bruce-wayne99 dbe0d2d
changed forwared docker ports
bruce-wayne99 3a42dcf
fixed bug in docker_command file
bruce-wayne99 bece9ef
Merge branch 'comment-system' of github.com:bruce-wayne99/GraphSpace …
yash170106065 1776df3
solve the merge conflicts
yash170106065 a75406b
created discussion app
yash170106065 e722c76
created table for discussions and updated base.py
yash170106065 ded5cc3
created add and view discussions on bootstrap table functionality (UI…
yash170106065 d1ad9fe
add urls and functions for discussion page
yash170106065 a9b0d7a
designed discussion page UI and backend for adding and view comments
yash170106065 71d1a2a
modified models for unique discussions in a group
yash170106065 54be9ec
adding functionality views.py for deleting editing discussions
yash170106065 5682340
functionality for search close and open discussions
yash170106065 dfa8fab
adding authorization and error codes for discussions and its function…
yash170106065 25ba9aa
added delete discussions modal
yash170106065 6edabc2
created a functionality for read-more and solved the bug for timeago …
yash170106065 559a9d5
designed the discussion page
yash170106065 f2d9d53
modified the bootstrap discussion table for discussions
yash170106065 1cf9dcc
updating the stylesheet for discussion page and table
yash170106065 b911da2
adding event listeners and CRUD functionalities for discussion page a…
yash170106065 3fcda4b
added real-time websockets functionalities for discussions
yash170106065 e24e689
modified comments and code
yash170106065 c9c1fc8
modified id and classes names and case
yash170106065 b3f07e8
changed the models and improve the functionalities with docstrings
yash170106065 2abca88
added the reaction system in discussions
yash170106065 4447c34
updated the comment system and resolve bugs
yash170106065 9335334
Resolve edit comment bug
yash170106065 File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
Empty file.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,3 @@ | ||
| from django.contrib import admin | ||
|
|
||
| # Register your models here. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,7 @@ | ||
| from __future__ import unicode_literals | ||
|
|
||
| from django.apps import AppConfig | ||
|
|
||
|
|
||
| class DiscussionsConfig(AppConfig): | ||
| name = 'discussions' |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,83 @@ | ||
| from sqlalchemy.exc import IntegrityError | ||
| import applications.discussions.dal as db | ||
| from graphspace.exceptions import ErrorCodes, BadRequest | ||
| from graphspace.wrappers import atomic_transaction | ||
|
|
||
|
|
||
| @atomic_transaction | ||
| def add_discussion(request, message=None, topic=None, group_id=None, is_resolved=0, owner_email=None, | ||
yash170106065 marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| parent_discussion_id=None): | ||
| # Construct new discussion to add to database | ||
| discussion = db.add_discussion(request.db_session, message=message, topic=topic, | ||
yash170106065 marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| owner_email=owner_email, | ||
| group_id=group_id, is_resolved=is_resolved, | ||
| parent_discussion_id=parent_discussion_id) | ||
| return discussion | ||
|
|
||
|
|
||
| def search_discussions_by_group_id(request, group_id=None, topic=None, limit=20, offset=0, order='desc', sort='created_at'): | ||
yash170106065 marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| if group_id is None: | ||
| raise Exception("Atleast one group id is required.") | ||
|
|
||
| if sort == 'topic': | ||
| sort_attr = db.Discussion.topic | ||
| else: | ||
| sort_attr = db.Discussion.created_at | ||
|
|
||
| if order == 'desc': | ||
| orber_by = db.asc(sort_attr) | ||
| else: | ||
| orber_by = db.desc(sort_attr) | ||
|
|
||
| total, discussions = db.get_discussions_by_group_id(request.db_session, | ||
yash170106065 marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| group_id=group_id, | ||
| topic=topic, | ||
| limit=limit, | ||
| offset=offset, | ||
| order_by=orber_by) | ||
|
|
||
| return total, discussions | ||
|
|
||
|
|
||
|
|
||
| def get_discussion_by_id(request, discussion_id): | ||
| return db.get_discussion(request.db_session, id=discussion_id) | ||
|
|
||
|
|
||
| def search_comments_by_discussion_id(request, group_id=None, discussion_id=None): | ||
yash170106065 marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| if group_id is None: | ||
| raise Exception("Atleast one group id is required.") | ||
| if discussion_id is None: | ||
| raise Exception("Atleast one discussion id is required.") | ||
| return db.get_comments_by_discussion_id(request.db_session, group_id=group_id, discussion_id=discussion_id) | ||
|
|
||
|
|
||
| def is_user_authorized_to_delete_discussion(request, username, discussion_id): | ||
| is_authorized = False | ||
|
|
||
| discussion = db.get_discussion(request.db_session, discussion_id) | ||
|
|
||
| if discussion is not None: | ||
| if discussion.owner_email == username: | ||
| is_authorized = True | ||
|
|
||
| return is_authorized | ||
|
|
||
|
|
||
| def delete_discussion_by_id(request, discussion_id): | ||
| db.delete_discussion(request.db_session, id=discussion_id) | ||
| return | ||
|
|
||
|
|
||
| def update_discussion(request, discussion_id, message, is_resolved): | ||
| discussion = {} | ||
yash170106065 marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| if message is not None: | ||
| discussion['message'] = message | ||
| return db.update_discussion(request.db_session, id=discussion_id, updated_discussion=discussion) | ||
| if is_resolved is not None: | ||
| if is_resolved == u'1': | ||
| discussion['is_resolved'] = is_resolved | ||
| return db.resolve_discussion(request.db_session, id=discussion_id, updated_discussion=discussion) | ||
| if is_resolved == u'0': | ||
| discussion['is_resolved'] = is_resolved | ||
| return db.reopen_discussion(request.db_session, id=discussion_id, updated_discussion=discussion) | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,126 @@ | ||
| from sqlalchemy import and_, or_, desc, asc, event | ||
| from sqlalchemy.orm import joinedload, subqueryload | ||
| from graphspace.wrappers import with_session | ||
| from applications.discussions.models import * | ||
| from applications.users.dal import * | ||
| from applications.users.models import * | ||
| import graphspace.signals as socket | ||
| from graphspace.database import * | ||
|
|
||
| @with_session | ||
| def add_discussion(db_session, message, topic, group_id, owner_email=None, is_resolved=0, parent_discussion_id=None): | ||
| discussion = Discussion(owner_email=owner_email, group_id=group_id, | ||
| is_resolved=is_resolved, parent_discussion_id=parent_discussion_id, message=message, topic=topic) | ||
| group = get_group(db_session, group_id) | ||
| group.group_discussions.append(discussion) | ||
| db_session.add(discussion) | ||
| return discussion | ||
|
|
||
|
|
||
| @with_session | ||
| def get_discussions_by_group_id(db_session, group_id, topic, limit, offset, order_by=desc(Discussion.created_at)): | ||
|
|
||
| query = db_session.query(Discussion).filter(Discussion.group_id == group_id) | ||
| query = query.filter(Discussion.parent_discussion_id == None) | ||
| if order_by is not None: | ||
| query = query.order_by(order_by) | ||
| if topic is not None: | ||
| query1 = query.filter(Discussion.topic.ilike(topic)) | ||
| query2 = query.filter(Discussion.owner_email.ilike(topic)) | ||
| query3 = query.filter(Discussion.message.ilike(topic)) | ||
| query4 = query1.union(query2) | ||
| query = query3.union(query4) | ||
| total = query.count() | ||
|
|
||
| if offset is not None and limit is not None: | ||
| query = query.limit(limit).offset(offset) | ||
|
|
||
| return total, query.all() | ||
|
|
||
| @with_session | ||
| def get_discussion(db_session, id): | ||
| """ | ||
| Get discussion by discussion id. | ||
| :param db_session: Database session. | ||
| :param id: Unique ID of the discussion | ||
| :return: Discussion if id exists else None | ||
| """ | ||
| return db_session.query(Discussion).filter(Discussion.id == id).one_or_none() | ||
| def get_comments_by_discussion_id(db_session, group_id, discussion_id): | ||
| query = db_session.query(Discussion).filter(Discussion.group_id == group_id) | ||
| query = query.filter(Discussion.parent_discussion_id == discussion_id) | ||
| return query.count(), query.all() | ||
|
|
||
| @with_session | ||
| def delete_discussion(db_session, id): | ||
| """ | ||
| Delete discussion from Discussion table. | ||
| :param db_session: Database session. | ||
| :param id: Unique ID of the discussion | ||
| :return: discussion | ||
| """ | ||
| discussion = db_session.query(Discussion).filter(Discussion.id == id).one_or_none() | ||
| query = db_session.query(Discussion).filter(Discussion.parent_discussion_id == id).all() | ||
| db_session.delete(discussion) | ||
| for ele in query: | ||
| db_session.delete(ele) | ||
| return discussion | ||
|
|
||
| @with_session | ||
| def update_discussion(db_session, id, updated_discussion): | ||
| """ | ||
| Update discussion row entry. | ||
| :param db_session: Database session. | ||
| :param id: Unique ID of the discussion | ||
| :param updated_discussion: Updated discussion row entry | ||
| :return: Discussion if id exists else None | ||
| """ | ||
| discussion = db_session.query(Discussion).filter(Discussion.id == id).one_or_none() | ||
| for (key, value) in updated_discussion.items(): | ||
| setattr(discussion, key, value) | ||
| send_discussion(discussion, event="edited") | ||
| return discussion | ||
|
|
||
| @with_session | ||
| def resolve_discussion(db_session, id, updated_discussion): | ||
| """ | ||
| Update discussion row entry. | ||
| :param db_session: Database session. | ||
| :param id: Unique ID of the discussion | ||
| :param updated_discussion: Updated discussion row entry | ||
| :return: Discussion if id exists else None | ||
| """ | ||
| discussion = db_session.query(Discussion).filter(Discussion.id == id).one_or_none() | ||
| for (key, value) in updated_discussion.items(): | ||
| setattr(discussion, key, value) | ||
| send_discussion(discussion, event="resolve") | ||
| return discussion | ||
|
|
||
| @with_session | ||
| def reopen_discussion(db_session, id, updated_discussion): | ||
| """ | ||
| Update discussion row entry. | ||
| :param db_session: Database session. | ||
| :param id: Unique ID of the discussion | ||
| :param updated_discussion: Updated discussion row entry | ||
| :return: Discussion if id exists else None | ||
| """ | ||
| discussion = db_session.query(Discussion).filter(Discussion.id == id).one_or_none() | ||
| for (key, value) in updated_discussion.items(): | ||
| setattr(discussion, key, value) | ||
| send_discussion(discussion, event="reopen") | ||
| return discussion | ||
|
|
||
|
|
||
| @event.listens_for(Discussion, 'after_insert') | ||
| def update_listener(mapper, connection, discussion): | ||
| send_discussion(discussion, event="insert") | ||
|
|
||
| @event.listens_for(Discussion, 'after_delete') | ||
| def delete_listener(mapper, connection, discussion): | ||
| send_discussion(discussion, event="delete") | ||
|
|
||
| def send_discussion(discussion, event): | ||
| users_list = get_users_by_group(Database().session(), discussion.group_id) | ||
| socket.send_discussion(discussion=discussion, type="private", users=users_list, event=event) | ||
|
|
Empty file.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,51 @@ | ||
| from __future__ import unicode_literals | ||
|
|
||
| from applications.users.models import * | ||
| from django.conf import settings | ||
| from graphspace.mixins import * | ||
| import json | ||
yash170106065 marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| from sqlalchemy import ForeignKeyConstraint, text, Enum, Boolean | ||
| from sqlalchemy import String, ForeignKey, UniqueConstraint | ||
| Base = settings.BASE | ||
|
|
||
|
|
||
| # ================== Table Definitions =================== # | ||
|
|
||
| class Discussion(IDMixin, TimeStampMixin, Base): | ||
yash170106065 marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| __tablename__ = 'discussion' | ||
|
|
||
| message = Column(String, nullable=False) | ||
yash170106065 marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| is_resolved = Column(Integer, nullable=False, default=0) | ||
yash170106065 marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| topic = Column(String, nullable=True) | ||
|
|
||
| owner_email = Column(String, ForeignKey('user.email', ondelete="CASCADE", onupdate="CASCADE"), nullable=False) | ||
| owner = relationship("User", back_populates="owned_discussions", uselist=False) | ||
|
|
||
| group_id = Column(Integer, ForeignKey('group.id', ondelete="CASCADE", onupdate="CASCADE"), nullable=False) | ||
| group = relationship("Group", back_populates="group_discussions", uselist=False) | ||
|
|
||
| parent_discussion_id = Column(Integer, ForeignKey('discussion.id', ondelete="CASCADE", onupdate="CASCADE"), | ||
yash170106065 marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| nullable=True) | ||
yash170106065 marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| constraints = (UniqueConstraint('topic', 'group_id', name='_discussion_uc_topic_group_id'),) | ||
| indices = () | ||
|
|
||
| @declared_attr | ||
| def __table_args__(cls): | ||
| args = cls.constraints + cls.indices | ||
| return args | ||
|
|
||
| def serialize(cls, **kwargs): | ||
| return { | ||
| 'id': cls.id, | ||
| 'owner_email': cls.owner_email, | ||
| 'message': cls.message, | ||
| 'topic': cls.topic, | ||
| 'is_resolved': cls.is_resolved, | ||
| 'group_id': cls.group_id, | ||
| 'parent_discussion_id': cls.parent_discussion_id, | ||
| 'group_owner_email': cls.group.owner_email, | ||
| 'created_at': cls.created_at.isoformat(), | ||
| 'updated_at': cls.updated_at.isoformat() | ||
| } | ||
|
|
||
|
|
||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.