Previously, an error was raised if the comments service returned data including an unexpected field, which unnecessarily complicated the release path for new features, since the list of allowed fields would need to be modified before cs_comments_service could be modified, and only then could edx-platform take advantage of the new CS feature. We still log a warning if an unexpected field is returned, so we will still be able to tell if the CS returns a corrupt response. JIRA: FOR-180
170 lines
6.2 KiB
Python
170 lines
6.2 KiB
Python
from .utils import merge_dict, perform_request, CommentClientRequestError
|
|
|
|
import models
|
|
import settings
|
|
|
|
|
|
class User(models.Model):
|
|
|
|
accessible_fields = ['username', 'follower_ids', 'upvoted_ids', 'downvoted_ids',
|
|
'id', 'external_id', 'subscribed_user_ids', 'children', 'course_id',
|
|
'subscribed_thread_ids', 'subscribed_commentable_ids',
|
|
'subscribed_course_ids', 'threads_count', 'comments_count',
|
|
'default_sort_key'
|
|
]
|
|
|
|
updatable_fields = ['username', 'external_id', 'default_sort_key']
|
|
initializable_fields = updatable_fields
|
|
|
|
metric_tag_fields = ['course_id']
|
|
|
|
base_url = "{prefix}/users".format(prefix=settings.PREFIX)
|
|
default_retrieve_params = {'complete': True}
|
|
type = 'user'
|
|
|
|
@classmethod
|
|
def from_django_user(cls, user):
|
|
return cls(id=str(user.id),
|
|
external_id=str(user.id),
|
|
username=user.username)
|
|
|
|
def follow(self, source):
|
|
params = {'source_type': source.type, 'source_id': source.id}
|
|
response = perform_request(
|
|
'post',
|
|
_url_for_subscription(self.id),
|
|
params,
|
|
metric_action='user.follow',
|
|
metric_tags=self._metric_tags + ['target.type:{}'.format(source.type)],
|
|
)
|
|
|
|
def unfollow(self, source):
|
|
params = {'source_type': source.type, 'source_id': source.id}
|
|
response = perform_request(
|
|
'delete',
|
|
_url_for_subscription(self.id),
|
|
params,
|
|
metric_action='user.unfollow',
|
|
metric_tags=self._metric_tags + ['target.type:{}'.format(source.type)],
|
|
)
|
|
|
|
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 CommentClientRequestError("Can only vote / unvote for threads or comments")
|
|
params = {'user_id': self.id, 'value': value}
|
|
response = perform_request(
|
|
'put',
|
|
url,
|
|
params,
|
|
metric_action='user.vote',
|
|
metric_tags=self._metric_tags + ['target.type:{}'.format(voteable.type)],
|
|
)
|
|
voteable._update_from_response(response)
|
|
|
|
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 CommentClientRequestError("Can only vote / unvote for threads or comments")
|
|
params = {'user_id': self.id}
|
|
response = perform_request(
|
|
'delete',
|
|
url,
|
|
params,
|
|
metric_action='user.unvote',
|
|
metric_tags=self._metric_tags + ['target.type:{}'.format(voteable.type)],
|
|
)
|
|
voteable._update_from_response(response)
|
|
|
|
def active_threads(self, query_params={}):
|
|
if not self.course_id:
|
|
raise CommentClientRequestError("Must provide course_id when retrieving active threads for the user")
|
|
url = _url_for_user_active_threads(self.id)
|
|
params = {'course_id': self.course_id}
|
|
params = merge_dict(params, query_params)
|
|
response = perform_request(
|
|
'get',
|
|
url,
|
|
params,
|
|
metric_action='user.active_threads',
|
|
metric_tags=self._metric_tags,
|
|
paged_results=True,
|
|
)
|
|
return response.get('collection', []), response.get('page', 1), response.get('num_pages', 1)
|
|
|
|
def subscribed_threads(self, query_params={}):
|
|
if not self.course_id:
|
|
raise CommentClientRequestError("Must provide course_id when retrieving subscribed threads for the user")
|
|
url = _url_for_user_subscribed_threads(self.id)
|
|
params = {'course_id': self.course_id}
|
|
params = merge_dict(params, query_params)
|
|
response = perform_request(
|
|
'get',
|
|
url,
|
|
params,
|
|
metric_action='user.subscribed_threads',
|
|
metric_tags=self._metric_tags,
|
|
paged_results=True
|
|
)
|
|
return response.get('collection', []), response.get('page', 1), response.get('num_pages', 1)
|
|
|
|
def _retrieve(self, *args, **kwargs):
|
|
url = self.url(action='get', params=self.attributes)
|
|
retrieve_params = self.default_retrieve_params
|
|
if self.attributes.get('course_id'):
|
|
retrieve_params['course_id'] = self.course_id
|
|
try:
|
|
response = perform_request(
|
|
'get',
|
|
url,
|
|
retrieve_params,
|
|
metric_action='model.retrieve',
|
|
metric_tags=self._metric_tags,
|
|
)
|
|
except CommentClientRequestError as e:
|
|
if e.status_code == 404:
|
|
# attempt to gracefully recover from a previous failure
|
|
# to sync this user to the comments service.
|
|
self.save()
|
|
response = perform_request(
|
|
'get',
|
|
url,
|
|
retrieve_params,
|
|
metric_action='model.retrieve',
|
|
metric_tags=self._metric_tags,
|
|
)
|
|
else:
|
|
raise
|
|
self._update_from_response(response)
|
|
|
|
|
|
def _url_for_vote_comment(comment_id):
|
|
return "{prefix}/comments/{comment_id}/votes".format(prefix=settings.PREFIX, comment_id=comment_id)
|
|
|
|
|
|
def _url_for_vote_thread(thread_id):
|
|
return "{prefix}/threads/{thread_id}/votes".format(prefix=settings.PREFIX, thread_id=thread_id)
|
|
|
|
|
|
def _url_for_subscription(user_id):
|
|
return "{prefix}/users/{user_id}/subscriptions".format(prefix=settings.PREFIX, user_id=user_id)
|
|
|
|
|
|
def _url_for_user_active_threads(user_id):
|
|
return "{prefix}/users/{user_id}/active_threads".format(prefix=settings.PREFIX, user_id=user_id)
|
|
|
|
|
|
def _url_for_user_subscribed_threads(user_id):
|
|
return "{prefix}/users/{user_id}/subscribed_threads".format(prefix=settings.PREFIX, user_id=user_id)
|
|
|
|
def _url_for_user_stats(user_id,course_id):
|
|
return "{prefix}/users/{user_id}/stats?course_id={course_id}".format(prefix=settings.PREFIX, user_id=user_id,course_id=course_id)
|
|
|
|
|