Commit d6f34929 by Rocky Duan

replaced comment client sym link

parent 12897fff
......@@ -25,3 +25,4 @@ Gemfile.lock
.env/
lms/static/sass/*.css
cms/static/sass/*.css
lms/lib/comment_client/python
/Users/dementrock/coding/cs_comments_client_python/comment_client
\ No newline at end of file
from comment_client import *
from utils import CommentClientError, CommentClientUnknownError
import requests
import json
import models
from utils import *
SERVICE_HOST = 'http://localhost:4567'
PREFIX = SERVICE_HOST + '/api/v1'
class Comment(models.Model):
accessible_fields = [
'id', 'body', 'anonymous', 'course_id',
'endorsed', 'parent_id', 'thread_id',
'username', 'votes', 'user_id', 'closed',
'created_at', 'updated_at', 'depth',
'at_position_list',
]
base_url = "{prefix}/comments".format(prefix=PREFIX)
type = 'comment'
class Thread(models.Model):
accessible_fields = [
'id', 'title', 'body', 'anonymous',
'course_id', 'closed', 'tags', 'votes',
'commentable_id', 'username', 'user_id',
'created_at', 'updated_at', 'comments_count',
'at_position_list', 'children',
]
base_url = "{prefix}/threads".format(prefix=PREFIX)
default_retrieve_params = {'recursive': False}
type = 'thread'
@classmethod
def search(cls, query_params, *args, **kwargs):
default_params = {'page': 1,
'per_page': 20,
'course_id': query_params['course_id'],
'recursive': False}
params = merge_dict(default_params, strip_none(query_params))
if query_params['text'] or query_params['tags']:
url = cls.url(action='search')
else:
url = cls.url(action='get_all', commentable_id=params['commentable_id'])
del params['commentable_id']
response = perform_request('get', url, params, *args, **kwargs)
return response.get('collection', []), response.get('page', 1), response.get('num_pages', 1)
@classmethod
def url_for_threads(cls, *args, **kwargs):
return "{prefix}/{commentable_id}/threads".format(prefix=PREFIX, commentable_id=kwargs.get('commentable_id'))
@classmethod
def url_for_search_threads(cls, *args, **kwargs):
return "{prefix}/search/threads".format(prefix=PREFIX)
@classmethod
def url(cls, *args, **kwargs):
action = kwargs.get('action')
if action in ['get_all', 'post']:
return cls.url_for_threads(commentable_id=kwargs.get('commentable_id'))
elif action == 'search':
return cls.url_for_search_threads()
else:
return super(Thread, cls).url(*args, **kwargs)
def _retrieve(self, *args, **kwargs):
url = self.url(action='get', id=self.id)
response = perform_request('get', url, {'recursive': kwargs.get('recursive')})
self.update_attributes(**response)
class Commentable(models.Model):
base_url = "{prefix}/commentables".format(prefix=PREFIX)
type = 'commentable'
class User(models.Model):
accessible_fields = ['username', 'follower_ids', 'upvoted_ids', 'downvoted_ids',
'id', 'external_id', 'subscribed_user_ids', 'children',
'subscribed_thread_ids', 'subscribed_commentable_ids',
]
base_url = "{prefix}/users".format(prefix=PREFIX)
default_retrieve_params = {'complete': True}
type = 'user'
@classmethod
def from_django_user(cls, user):
return cls(id=str(user.id))
def follow(self, source):
params = {'source_type': source.type, 'source_id': source.id}
response = perform_request('post', _url_for_subscription(self.id), params)
def unfollow(self, source):
params = {'source_type': source.type, 'source_id': source.id}
response = perform_request('delete', _url_for_subscription(self.id), params)
def vote(self, voteable, value):
if voteable.type == 'thread':
url = _url_for_vote_thread(voteable.id)
elif voteable.type == 'comment':
url = _url_for_vote_comment(voteable.id)
else:
raise CommentClientError("Can only vote / unvote for threads or comments")
params = {'user_id': self.id, 'value': value}
request = perform_request('put', url, params)
voteable.update_attributes(request)
def unvote(self, voteable):
if voteable.type == 'thread':
url = _url_for_vote_thread(voteable.id)
elif voteable.type == 'comment':
url = _url_for_vote_comment(voteable.id)
else:
raise CommentClientError("Can only vote / unvote for threads or comments")
params = {'user_id': self.id}
request = perform_request('delete', url, params)
voteable.update_attributes(request)
def search_similar_threads(course_id, recursive=False, query_params={}, *args, **kwargs):
default_params = {'course_id': course_id, 'recursive': recursive}
attributes = dict(default_params.items() + query_params.items())
return perform_request('get', _url_for_search_similar_threads(), attributes, *args, **kwargs)
def search_recent_active_threads(course_id, recursive=False, query_params={}, *args, **kwargs):
default_params = {'course_id': course_id, 'recursive': recursive}
attributes = dict(default_params.items() + query_params.items())
return perform_request('get', _url_for_search_recent_active_threads(), attributes, *args, **kwargs)
def search_trending_tags(course_id, query_params={}, *args, **kwargs):
default_params = {'course_id': course_id}
attributes = dict(default_params.items() + query_params.items())
return perform_request('get', _url_for_search_trending_tags(), attributes, *args, **kwargs)
def _url_for_search_similar_threads():
return "{prefix}/search/threads/more_like_this".format(prefix=PREFIX)
def _url_for_search_recent_active_threads():
return "{prefix}/search/threads/recent_active".format(prefix=PREFIX)
def _url_for_search_trending_tags():
return "{prefix}/search/tags/trending".format(prefix=PREFIX)
def _url_for_subscription(user_id):
return "{prefix}/users/{user_id}/subscriptions".format(prefix=PREFIX, user_id=user_id)
def _url_for_vote_comment(comment_id):
return "{prefix}/comments/{comment_id}/votes".format(prefix=PREFIX, comment_id=comment_id)
def _url_for_vote_thread(thread_id):
return "{prefix}/threads/{thread_id}/votes".format(prefix=PREFIX, thread_id=thread_id)
def delete_threads(commentable_id, *args, **kwargs):
return _perform_request('delete', _url_for_commentable_threads(commentable_id), *args, **kwargs)
def get_threads(commentable_id, recursive=False, query_params={}, *args, **kwargs):
default_params = {'page': 1, 'per_page': 20, 'recursive': recursive}
attributes = dict(default_params.items() + query_params.items())
response = _perform_request('get', _url_for_threads(commentable_id), \
attributes, *args, **kwargs)
return response.get('collection', []), response.get('page', 1), response.get('num_pages', 1)
def search_threads(course_id, recursive=False, query_params={}, *args, **kwargs):
default_params = {'page': 1, 'per_page': 20, 'course_id': course_id, 'recursive': recursive}
attributes = dict(default_params.items() + query_params.items())
response = _perform_request('get', _url_for_search_threads(), \
attributes, *args, **kwargs)
return response.get('collection', []), response.get('page', 1), response.get('num_pages', 1)
def search_similar_threads(course_id, recursive=False, query_params={}, *args, **kwargs):
default_params = {'course_id': course_id, 'recursive': recursive}
attributes = dict(default_params.items() + query_params.items())
return _perform_request('get', _url_for_search_similar_threads(), attributes, *args, **kwargs)
def search_recent_active_threads(course_id, recursive=False, query_params={}, *args, **kwargs):
default_params = {'course_id': course_id, 'recursive': recursive}
attributes = dict(default_params.items() + query_params.items())
return _perform_request('get', _url_for_search_recent_active_threads(), attributes, *args, **kwargs)
def search_trending_tags(course_id, query_params={}, *args, **kwargs):
default_params = {'course_id': course_id}
attributes = dict(default_params.items() + query_params.items())
return _perform_request('get', _url_for_search_trending_tags(), attributes, *args, **kwargs)
def create_user(attributes, *args, **kwargs):
return _perform_request('post', _url_for_users(), attributes, *args, **kwargs)
def update_user(user_id, attributes, *args, **kwargs):
return _perform_request('put', _url_for_user(user_id), attributes, *args, **kwargs)
def get_threads_tags(*args, **kwargs):
return _perform_request('get', _url_for_threads_tags(), {}, *args, **kwargs)
def tags_autocomplete(value, *args, **kwargs):
return _perform_request('get', _url_for_threads_tags_autocomplete(), {'value': value}, *args, **kwargs)
def create_thread(commentable_id, attributes, *args, **kwargs):
return _perform_request('post', _url_for_threads(commentable_id), attributes, *args, **kwargs)
def get_thread(thread_id, recursive=False, *args, **kwargs):
return _perform_request('get', _url_for_thread(thread_id), {'recursive': recursive}, *args, **kwargs)
def update_thread(thread_id, attributes, *args, **kwargs):
return _perform_request('put', _url_for_thread(thread_id), attributes, *args, **kwargs)
def create_comment(thread_id, attributes, *args, **kwargs):
return _perform_request('post', _url_for_thread_comments(thread_id), attributes, *args, **kwargs)
def delete_thread(thread_id, *args, **kwargs):
return _perform_request('delete', _url_for_thread(thread_id), *args, **kwargs)
def get_comment(comment_id, recursive=False, *args, **kwargs):
return _perform_request('get', _url_for_comment(comment_id), {'recursive': recursive}, *args, **kwargs)
def update_comment(comment_id, attributes, *args, **kwargs):
return _perform_request('put', _url_for_comment(comment_id), attributes, *args, **kwargs)
def create_sub_comment(comment_id, attributes, *args, **kwargs):
return _perform_request('post', _url_for_comment(comment_id), attributes, *args, **kwargs)
def delete_comment(comment_id, *args, **kwargs):
return _perform_request('delete', _url_for_comment(comment_id), *args, **kwargs)
def vote_for_comment(comment_id, user_id, value, *args, **kwargs):
return _perform_request('put', _url_for_vote_comment(comment_id), {'user_id': user_id, 'value': value}, *args, **kwargs)
def undo_vote_for_comment(comment_id, user_id, *args, **kwargs):
return _perform_request('delete', _url_for_vote_comment(comment_id), {'user_id': user_id}, *args, **kwargs)
def vote_for_thread(thread_id, user_id, value, *args, **kwargs):
return _perform_request('put', _url_for_vote_thread(thread_id), {'user_id': user_id, 'value': value}, *args, **kwargs)
def undo_vote_for_thread(thread_id, user_id, *args, **kwargs):
return _perform_request('delete', _url_for_vote_thread(thread_id), {'user_id': user_id}, *args, **kwargs)
def get_notifications(user_id, *args, **kwargs):
return _perform_request('get', _url_for_notifications(user_id), *args, **kwargs)
def get_user_info(user_id, complete=True, *args, **kwargs):
return _perform_request('get', _url_for_user(user_id), {'complete': complete}, *args, **kwargs)
def subscribe(user_id, subscription_detail, *args, **kwargs):
return _perform_request('post', _url_for_subscription(user_id), subscription_detail, *args, **kwargs)
def subscribe_user(user_id, followed_user_id, *args, **kwargs):
return subscribe(user_id, {'source_type': 'user', 'source_id': followed_user_id})
follow = subscribe_user
def subscribe_thread(user_id, thread_id, *args, **kwargs):
return subscribe(user_id, {'source_type': 'thread', 'source_id': thread_id})
def subscribe_commentable(user_id, commentable_id, *args, **kwargs):
return subscribe(user_id, {'source_type': 'other', 'source_id': commentable_id})
def unsubscribe(user_id, subscription_detail, *args, **kwargs):
return _perform_request('delete', _url_for_subscription(user_id), subscription_detail, *args, **kwargs)
def unsubscribe_user(user_id, followed_user_id, *args, **kwargs):
return unsubscribe(user_id, {'source_type': 'user', 'source_id': followed_user_id})
unfollow = unsubscribe_user
def unsubscribe_thread(user_id, thread_id, *args, **kwargs):
return unsubscribe(user_id, {'source_type': 'thread', 'source_id': thread_id})
def unsubscribe_commentable(user_id, commentable_id, *args, **kwargs):
return unsubscribe(user_id, {'source_type': 'other', 'source_id': commentable_id})
def _perform_request(method, url, data_or_params=None, *args, **kwargs):
if method in ['post', 'put', 'patch']:
response = requests.request(method, url, data=data_or_params)
else:
response = requests.request(method, url, params=data_or_params)
if 200 < response.status_code < 500:
raise CommentClientError(response.text)
elif response.status_code == 500:
raise CommentClientUnknownError(response.text)
else:
if kwargs.get("raw", False):
return response.text
else:
return json.loads(response.text)
def _url_for_threads(commentable_id):
return "{prefix}/{commentable_id}/threads".format(prefix=PREFIX, commentable_id=commentable_id)
def _url_for_thread(thread_id):
return "{prefix}/threads/{thread_id}".format(prefix=PREFIX, thread_id=thread_id)
def _url_for_thread_comments(thread_id):
return "{prefix}/threads/{thread_id}/comments".format(prefix=PREFIX, thread_id=thread_id)
def _url_for_comment(comment_id):
return "{prefix}/comments/{comment_id}".format(prefix=PREFIX, comment_id=comment_id)
def _url_for_vote_comment(comment_id):
return "{prefix}/comments/{comment_id}/votes".format(prefix=PREFIX, comment_id=comment_id)
def _url_for_vote_thread(thread_id):
return "{prefix}/threads/{thread_id}/votes".format(prefix=PREFIX, thread_id=thread_id)
def _url_for_notifications(user_id):
return "{prefix}/users/{user_id}/notifications".format(prefix=PREFIX, user_id=user_id)
def _url_for_subscription(user_id):
return "{prefix}/users/{user_id}/subscriptions".format(prefix=PREFIX, user_id=user_id)
def _url_for_user(user_id):
return "{prefix}/users/{user_id}".format(prefix=PREFIX, user_id=user_id)
def _url_for_search_threads():
return "{prefix}/search/threads".format(prefix=PREFIX)
def _url_for_search_similar_threads():
return "{prefix}/search/threads/more_like_this".format(prefix=PREFIX)
def _url_for_search_recent_active_threads():
return "{prefix}/search/threads/recent_active".format(prefix=PREFIX)
def _url_for_search_trending_tags():
return "{prefix}/search/tags/trending".format(prefix=PREFIX)
def _url_for_threads_tags():
return "{prefix}/threads/tags".format(prefix=PREFIX)
def _url_for_threads_tags_autocomplete():
return "{prefix}/threads/tags/autocomplete".format(prefix=PREFIX)
def _url_for_users():
return "{prefix}/users".format(prefix=PREFIX)
from utils import *
class Model(object):
accessible_fields = ['id']
base_url = None
default_retrieve_params = {}
DEFAULT_ACTIONS_WITH_ID = ['get', 'put', 'delete']
DEFAULT_ACTIONS_WITHOUT_ID = ['get_all', 'post']
DEFAULT_ACTIONS = DEFAULT_ACTIONS_WITH_ID + DEFAULT_ACTIONS_WITHOUT_ID
def __init__(self, *args, **kwargs):
self.attributes = extract(kwargs, self.accessible_fields)
self.retrieved = False
def __getattr__(self, name):
if name == 'id':
return self.attributes.get('id', None)
try:
return self.attributes[name]
except KeyError:
if self.retrieved or self.id == None:
raise AttributeError("Field {0} does not exist".format(name))
self.retrieve()
return self.__getattr__(name)
def __setattr__(self, name, value):
if name == 'attributes' or name not in self.accessible_fields:
super(Model, self).__setattr__(name, value)
else:
self.attributes[name] = value
def __getitem__(self, key):
if key not in self.accessible_fields:
raise KeyError("Field {0} does not exist".format(key))
return self.attributes.get(key)
def __setitem__(self, key, value):
if key not in self.accessible_fields:
raise KeyError("Field {0} does not exist".format(key))
self.attributes.__setitem__(key, value)
def get(self, *args, **kwargs):
return self.attributes.get(*args, **kwargs)
def to_dict(self):
self.retrieve()
return self.attributes
def retrieve(self, *args, **kwargs):
if not self.retrieved:
self._retrieve(*args, **kwargs)
self.retrieved = True
return self
def _retrieve(self, *args, **kwargs):
url = self.url(action='get', id=self.id)
response = perform_request('get', url, self.default_retrieve_params)
self.update_attributes(**response)
@classmethod
def find(cls, id):
return cls(id=id)
def update_attributes(self, *args, **kwargs):
for k, v in kwargs.items():
if k in self.accessible_fields:
self.__setattr__(k, v)
else:
raise AttributeError("Field {0} does not exist".format(k))
def save(self):
if self.id: # if we have id already, treat this as an update
url = self.url(action='put', id=self.id)
response = perform_request('put', url, self.attributes)
else: # otherwise, treat this as an insert
url = self.url(action='post', id=self.id)
response = perform_request('post', url, self.attributes)
self.retrieved = True
self.update_attributes(**response)
@classmethod
def url_with_id(cls, *args, **kwargs):
return cls.base_url + '/' + str(kwargs.get('id'))
@classmethod
def url_without_id(cls, *args, **kwargs):
return cls.base_url
@classmethod
def url(cls, *args, **kwargs):
if cls.base_url is None:
raise CommentClientError("Must provide base_url when using default url function")
id = kwargs.get('id')
action = kwargs.get('action')
if not action:
raise CommentClientError("Must provide action")
elif action not in cls.DEFAULT_ACTIONS:
raise ValueError("Invalid action {0}. The supported action must be in {1}".format(action, str(cls.DEFAULT_ACTIONS)))
elif action in cls.DEFAULT_ACTIONS_WITH_ID:
if not id:
raise CommentClientError("Cannot perform action {0} without id".format(action))
return cls.url_with_id(id=id)
else: # action must be in DEFAULT_ACTIONS_WITHOUT_ID now
return cls.url_without_id()
import requests
import json
def strip_none(dic):
def _is_none(v):
return v is None or (isinstance(v, str) and len(v.strip()) == 0)
return dict([(k, v) for k, v in dic.iteritems() if not _is_none(v)])
def extract(dic, keys):
return strip_none({k: dic.get(k) for k in keys})
def merge_dict(dic1, dic2):
return dict(dic1.items() + dic2.items())
def perform_request(method, url, data_or_params=None, *args, **kwargs):
if method in ['post', 'put', 'patch']:
response = requests.request(method, url, data=data_or_params)
else:
response = requests.request(method, url, params=data_or_params)
if 200 < response.status_code < 500:
raise CommentClientError(response.text)
elif response.status_code == 500:
raise CommentClientUnknownError(response.text)
else:
if kwargs.get("raw", False):
return response.text
else:
return json.loads(response.text)
class CommentClientError(Exception):
def __init__(self, msg):
self.message = msg
def __str__(self):
return repr(self.message)
class CommentClientUnknownError(CommentClientError):
pass
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment