Skip to content

Commit

Permalink
Add reply service (#189)
Browse files Browse the repository at this point in the history
* Add in reply service

* Use kwargs and use Reply obj

* use Reply obj

* Fix

* Fix test

* Fix discussion tests

* Update challengeutils/synapseservices/discussion.py
  • Loading branch information
thomasyu888 authored Jul 2, 2020
1 parent 9882357 commit e07651c
Show file tree
Hide file tree
Showing 3 changed files with 250 additions and 65 deletions.
85 changes: 47 additions & 38 deletions challengeutils/discussion.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
from synapseclient import Project, Synapse, UserProfile
from synapseclient.core.utils import id_of

from .synapseservices.discussion import Forum, Thread
from .synapseservices.discussion import Forum, Thread, Reply

QUERY_LIMIT = 1000

Expand All @@ -35,8 +35,7 @@ def get_forum(self, forumid: str) -> Forum:

def get_forum_threads(self, forumid: str,
query_filter: str = 'EXCLUDE_DELETED',
limit: int = 20,
offset: int = 0) -> Iterator[Thread]:
**kwargs) -> Iterator[Thread]:
"""Get N number of threads for a given forum ID
https://rest-docs.synapse.org/rest/GET/forum/forumId/threads.html
Expand All @@ -52,7 +51,7 @@ def get_forum_threads(self, forumid: str,
"""
uri = f'/forum/{forumid}/threads?filter={query_filter}'
threads = self.syn._GET_paginated(uri, limit=limit, offset=offset)
threads = self.syn._GET_paginated(uri, **kwargs)
for thread in threads:
yield Thread(**thread)

Expand All @@ -76,8 +75,7 @@ def post_thread(self, forumid: str, title: str, message: str) -> Thread:
return Thread(**thread)

def get_threads_referencing_entity(self, entityid: str,
limit: int = 20,
offset: int = 0) -> Iterator[Thread]:
**kwargs) -> Iterator[Thread]:
"""
Get N number of threads that belongs to projects user can
view and references the given entity
Expand All @@ -91,7 +89,7 @@ def get_threads_referencing_entity(self, entityid: str,
DiscussionThreadBundles
"""
threads = self.syn._GET_paginated(f"/entity/{entityid}/threads",
limit=limit, offset=offset)
**kwargs)
for thread in threads:
yield Thread(**thread)

Expand Down Expand Up @@ -119,32 +117,32 @@ def delete_thread(self, threadid: str):
"""
self.syn.restDELETE(f"/thread/{threadid}")

def restore_thread(self, threadid):
def restore_thread(self, threadid: str):
"""Restore a deleted thread
https://rest-docs.synapse.org/rest/PUT/thread/threadId/restore.html
"""
self.syn.restPUT(f"/thread/{threadid}/restore")

def pin_thread(self, threadid):
def pin_thread(self, threadid: str):
"""Pin a thread
https://rest-docs.synapse.org/rest/PUT/thread/threadId/pin.html
"""
self.syn.restPUT(f"/thread/{threadid}/pin")

def unpin_thread(self, threadid):
def unpin_thread(self, threadid: str):
"""Unpin a thread
https://rest-docs.synapse.org/rest/PUT/thread/threadId/unpin.html
"""
self.syn.restPUT(f"/thread/{threadid}/unpin")

def get_thread_message_url(self, messagekey):
def get_thread_message_url(self, messagekey: str) -> dict:
"""message URL of a thread. The message URL is the URL
to download the file which contains the thread message.
https://rest-docs.synapse.org/rest/GET/thread/messageUrl.html
"""
return self.syn.restGET(f"/thread/messageUrl?messageKey={messagekey}")

def post_reply(self, threadid, message):
def post_reply(self, threadid: str, message: str) -> Reply:
"""Create a new thread in a forum
https://rest-docs.synapse.org/rest/POST/reply.html
Expand All @@ -156,14 +154,17 @@ def post_reply(self, threadid, message):
DiscussionReplyBundle
"""
create_reply = {'threadId': threadid, 'messageMarkdown': message}
return self.syn.restPOST('/reply', body=json.dumps(create_reply))
return Reply(**self.syn.restPOST('/reply',
body=json.dumps(create_reply)))

def get_reply(self, replyid):
"""Get a reply"""
return self.syn.restGET(f'/reply/{replyid}')
def get_reply(self, replyid: str) -> Reply:
"""Get a reply
https://rest-docs.synapse.org/rest/GET/reply/replyId.html"""
return Reply(**self.syn.restGET(f'/reply/{replyid}'))

def get_thread_replies(self, threadid, query_filter='EXCLUDE_DELETED',
limit=20, offset=0):
def get_thread_replies(self, threadid: str,
query_filter: str = 'EXCLUDE_DELETED',
**kwargs):
"""Get N number of replies for a given thread ID
https://rest-docs.synapse.org/rest/GET/thread/threadId/replies.html
Expand All @@ -175,37 +176,44 @@ def get_thread_replies(self, threadid, query_filter='EXCLUDE_DELETED',
Yields:
list: Forum threads replies
"""
replies = f'/thread/{threadid}/replies?filter={query_filter}'
return self.syn._GET_paginated(replies, limit=limit, offset=offset)

def get_reply_message_url(self, messagekey):
replies = self.syn._GET_paginated(
f'/thread/{threadid}/replies?filter={query_filter}',
**kwargs
)
for reply in replies:
yield Reply(**reply)

def get_reply_message_url(self, messagekey: str) -> dict:
"""message URL of a thread. The message URL is the URL
to download the file which contains the thread message.
https://rest-docs.synapse.org/rest/GET/reply/messageUrl.html
"""
return self.syn.restGET(f"/reply/messageUrl?messageKey={messagekey}")

def get_forum_threadcount(self, forumid, query_filter='EXCLUDE_DELETED'):
def get_forum_threadcount(self, forumid: str,
query_filter: str = 'EXCLUDE_DELETED') -> int:
"""Total number of threads given forum ID
https://rest-docs.synapse.org/rest/GET/forum/forumId/threadcount.html
"""
threadcount = f'/forum/{forumid}/threadcount?filter={query_filter}'
return self.syn.restGET(threadcount)
return self.syn.restGET(threadcount)['count']

def get_thread_replycount(self, threadid, query_filter='EXCLUDE_DELETED'):
def get_thread_replycount(self, threadid: str,
query_filter: str = 'EXCLUDE_DELETED') -> int:
"""Total number of replies given thread ID
https://rest-docs.synapse.org/rest/GET/thread/threadId/replycount.html
"""
replycount = f'/thread/{threadid}/replycount?filter={query_filter}'
return self.syn.restGET(replycount)
return self.syn.restGET(replycount)['count']

def get_forum_moderators(self, forumid) -> Iterator[int]:
def get_forum_moderators(self, forumid: str) -> Iterator[int]:
"""Get moderators given a forum ID
https://rest-docs.synapse.org/rest/GET/forum/forumId/moderators.html
"""
return self.syn._GET_paginated(f'/forum/{forumid}/moderators')

def get_threadcount_referencing_entities(self, entityid_list):
def get_threadcount_referencing_entities(self,
entityid_list: list) -> list:
"""Get list of entity and count pairs, with count is the number of
threads that belongs to projects user can view and references
the given entity.
Expand Down Expand Up @@ -239,7 +247,7 @@ def get_forum_threads(syn: Synapse, ent: Union[Project, str],
return threads


def get_thread_replies(syn: Synapse, thread, **kwargs):
def get_thread_replies(syn: Synapse, thread: Thread, **kwargs):
"""Gets replies of a thread
Args:
Expand All @@ -255,11 +263,11 @@ def get_thread_replies(syn: Synapse, thread, **kwargs):
"""
api = DiscussionApi(syn)
threadid = id_of(thread)
response = api.get_thread_replies(threadid, **kwargs)
return response
replies = api.get_thread_replies(threadid, **kwargs)
return replies


def _get_text(url):
def _get_text(url: str):
'''
Get the text from a message url
Expand Down Expand Up @@ -293,10 +301,9 @@ def get_thread_text(syn: Synapse, thread: Thread) -> str:
return thread_response.text


def get_thread_reply_text(syn, messagekey):
def get_thread_reply_text(syn, reply: Reply) -> str:
'''
Get thread reply text by the messageKey that is returned by
getting thread replies
Get thread reply text
Args:
syn: Synapse object
Expand All @@ -306,7 +313,9 @@ def get_thread_reply_text(syn, messagekey):
str: Thread text
'''
api = DiscussionApi(syn)
url = api.get_reply_message_url(messagekey)
if not isinstance(reply, Reply):
reply = api.get_reply(reply)
url = api.get_reply_message_url(reply.messagekey)
thread_reply_response = _get_text(url)
return thread_reply_response.text

Expand Down Expand Up @@ -423,10 +432,10 @@ def copy_reply(syn, reply, thread):
dict: Reply bundle
"""
threadid = id_of(thread)
author = reply['createdBy']
author = reply.createdby
username = syn.getUserProfile(author)['userName']
on_behalf_of = "On behalf of @{user}\n\n".format(user=username)
text = get_thread_reply_text(syn, reply['messageKey'])
text = get_thread_reply_text(syn, reply)
new_reply_text = on_behalf_of + text
return create_thread_reply(syn, threadid, new_reply_text)

Expand Down
157 changes: 157 additions & 0 deletions challengeutils/synapseservices/discussion.py
Original file line number Diff line number Diff line change
Expand Up @@ -273,3 +273,160 @@ def is_pinned(self):
@is_pinned.setter
def is_pinned(self, value):
self._is_pinned = value


class Reply(Service):
def __init__(
self, id: str = None, threadId: str = None, forumId: str = None,
projectId: str = None, createdOn: str = None,
createdBy: str = None, modifiedOn: str = None, etag: str = None,
messageKey: str = None, isEdited: bool = False,
isDeleted: bool = False
):

self.openapi_types = {
'id': str,
'threadid': str,
'forumid': str,
'projectid': str,
'createdon': str,
'createdby': str,
'modifiedon': str,
'etag': str,
'messagekey': str,
'is_edited': bool,
'is_deleted': bool,
}

self.attribute_map = {
'id': 'id',
'threadid': 'threadId',
'forumid': 'forumId',
'projectid': 'projectId',
'createdon': 'createdOn',
'createdby': 'createdBy',
'modifiedon': 'modifiedOn',
'etag': 'etag',
'messagekey': 'messageKey',
'is_edited': 'isEdited',
'is_deleted': 'isDeleted',
}

self._id = id
self._threadid = threadId
self._forumid = forumId
self._projectid = projectId
self._createdon = createdOn
self._createdby = createdBy
self._modifiedon = modifiedOn
self._etag = etag
self._messagekey = messageKey
self._is_edited = isEdited
self._is_deleted = isDeleted

@classmethod
def from_dict(cls, dikt) -> 'Thread':
"""Returns the dict as a model"""
return deserialize_model(dikt, cls)

@property
def id(self):
"""The `id` property of this Challenge."""
return self._id

@id.setter
def id(self, value):
self._id = value

@property
def threadid(self):
"""The `threadid` property of this Challenge."""
return self._threadid

@threadid.setter
def threadid(self, value):
self._threadid = value

@property
def forumid(self):
"""The `forumid` property of this Challenge."""
return self._forumid

@forumid.setter
def forumid(self, value):
self._forumid = value

@property
def projectid(self):
"""The `projectid` property of this Challenge."""
return self._projectid

@projectid.setter
def projectid(self, value):
if value is None:
raise ValueError("Invalid value for `projectid`, must not be `None`") # noqa: E501

self._projectid = value

@property
def createdon(self):
"""The `createdon` property of this Challenge."""
return self._createdon

@createdon.setter
def createdon(self, value):
self._createdon = value

@property
def createdby(self):
"""The `createdby` property of this Challenge."""
return self._createdby

@createdby.setter
def createdby(self, value):
self._createdby = value

@property
def modifiedon(self):
"""The `modifiedon` property of this Challenge."""
return self._modifiedon

@modifiedon.setter
def modifiedon(self, value):
self._modifiedon = value

@property
def etag(self):
"""The `etag` property of this Challenge."""
return self._etag

@etag.setter
def etag(self, value):
self._etag = value

@property
def messagekey(self):
"""The `projectId` property of this Challenge."""
return self._messagekey

@messagekey.setter
def messagekey(self, value):
self._messagekey = value

@property
def is_edited(self):
"""The `is_edited` property of this Challenge."""
return self._is_edited

@is_edited.setter
def is_edited(self, value):
self._is_edited = value

@property
def is_deleted(self):
"""The `is_deleted` property of this Challenge."""
return self._is_deleted

@is_deleted.setter
def is_deleted(self, value):
self._is_deleted = value
Loading

0 comments on commit e07651c

Please sign in to comment.