# coding=utf8 from __future__ import unicode_literals, absolute_import, print_function from django.conf import settings from django.db.models import Q from django.utils.html import escape from gm_rpcd.all import bind from gm_types.error import ERROR as CODES from gm_types.gaia import MY_COMMENT_TYPE from gm_types.gaia import PROBLEM_FLAG_CHOICES, NotificationType, PLATFORM_CHOICES from talos.models.topic import ReplyHeadline from talos.models.topic import Problem from talos.decorators import list_interface from talos.libs.datetime_utils import get_timestamp_or_none from talos.manager.topic_reply import ( comment_data_by_reply_ids, get_my_replies, get_diary_replies, get_reply_details_by_reply_ids, get_my_replies_count_from_mysql ) from talos.models.reply import ReplyCollect from talos.models.topic.topicreply import TopicReply from talos.models.topic import Problem from talos.rpc import bind_context from talos.services import get_user_from_context, DoctorService, UserService from talos.tools.reply_tool import topic_reply_common, get_topic_reply, get_xcx_topic_reply # TODO CR 这边需要重构 和重构的时候一起拆 from talos.cache.reply import reply_cache from utils.rpc import gen, rpc_client, get_current_user, logging_exception @bind_context("topic/topic_reply") # @bind_context("talos/topic/reply") @list_interface(offset_name='start_num', limit_name='count', element_model=TopicReply, element_func_list=[TopicReply.get_reply_detail]) def get_reply_info( ctx, id=None, only_doctor_reply=False, count=10, start_num=0, comment_id=None, new_sub_comment_count=False, platform=None, sort_type=None ): """话题评论详情 id:话题ID only_doctor_reply:只返回医生回复,默认False """ user = get_user_from_context(ctx) topic = Problem.get_by_id(id) if topic: if topic.flag == PROBLEM_FLAG_CHOICES.NORMAL and topic.is_online: # 小程序的日记帖评论 if platform in [PLATFORM_CHOICES.WECHATXCX]: return get_xcx_topic_reply(start_num, count, user, topic, sort_type, comment_id) else: replies = get_topic_reply(start_num=start_num, count=count, user=user, topic_obj=topic, only_doctor_reply=only_doctor_reply, comment_id=comment_id, new_sub_comment_count=new_sub_comment_count ) if new_sub_comment_count: return replies return replies.get("topic_replies", []) else: return gen(CODES.TOPIC_HAS_BEEN_DELETED) else: return gen(CODES.TOPIC_NOT_FOUND) @bind_context('topic/reply/sub_comment') def get_topic_reply_by_reply_id(ctx, reply_id, topic_id=None, start_num=0, count=10): """ 获取评论的子评论 :param ctx: :param reply_id: :param topic_id: :param start_num: :param count: :return: """ result = { 'replies': [] } if not reply_id: return result replies = [] if reply_id: replies = TopicReply.objects.filter( commented_reply_id=reply_id, is_online=True ).order_by('-id') if not replies: return result _replies = replies[start_num: start_num + count] reply_ids = [r.id for r in _replies] comments_data = comment_data_by_reply_ids(reply_ids) return { 'replies': comments_data } @bind("topic/topic_reply_create") # @bind_context("talos/reply/create") def topic_reply_create(topic_id, reply_id=None, content='', device_id=None, platform_channel=None): """话题回复. :param ctx: :param content: 回复的内容, :param reply_id: 评论ID,可选. 回复帖子时, 该字段为None; 回复其他评论时, 不可为空 :param topic_id: 话题ID, 必选 :param user: 用户 """ user = get_current_user() if not user: return gen(CODES.LOGIN_REQUIRED) # TODO CR topic_reply_common 这个先缓一缓... return topic_reply_common(user, topic_id, reply_id, content, device_id, platform_channel) @bind_context('topic/total_reply_num') def get_total_reply_num(ctx, topic_id=None): total_reply_num = TopicReply.objects.filter(problem=topic_id, is_online=True).count() return { 'total_reply_num': total_reply_num } @bind("topic/replies_my") # @bind_context("talos/reply/my_list") @list_interface(offset_name='start_num', limit_name='count', element_model=TopicReply, element_func_list=[TopicReply.get_reply_detail]) def get_replies_mine(start_num=0, count=10, send_or_receive=MY_COMMENT_TYPE.RECEIVED, with_comment=True): """received sent comments. args: send_or_receive: 0 as received, 1 as sent """ try: user = get_current_user() if not user: return gen(CODES.LOGIN_REQUIRED) result = [] reply_user_ids = [] un_read_reply_ids, replies = get_my_replies(user.id, send_or_receive, start_num, count) for reply in replies: try: result.append(reply.get_reply_for_mine()) reply_user_ids.append(reply.user_id) except AttributeError: result.append(reply) reply_user_ids.append(reply['user']['user_id']) reply_users = UserService.get_users_by_user_ids(reply_user_ids) _reply_doctors = DoctorService.get_doctor_from_user_ids(reply_user_ids) reply_doctors = {d.user_id: d for d in _reply_doctors} reply_topic_user_ids = [r.problem.user_id if hasattr(r, 'problem') and r.problem else None for r in replies] reply_diary_user_ids = [r.diary.user_id if hasattr(r, 'diary') and r.diary else None for r in replies] reply_answer_user_ids = [r.answer.user_id if hasattr(r, 'answer') and r.answer else None for r in replies] commented_answer_user_ids = [r.get('reply')['commented_author_id'] if isinstance(r, dict) and r.get('reply') and r.get('reply').get('commented_author_id') else None for r in replies] commented_topic_user_ids = [r.commented_reply.user_id if hasattr(r, 'problem') and r.problem and r.commented_reply else None for r in replies] user_ids = reply_diary_user_ids + reply_topic_user_ids + reply_answer_user_ids + \ commented_answer_user_ids + commented_topic_user_ids users = UserService.get_users_by_user_ids(user_ids) current_user = { 'nick_name': user.nick_name, 'portrait': user.portrait, } for r in result: uid = r['user']['user_id'] if uid in reply_users: r['user']['user_name'] = reply_users[uid].nickname r['user']['user_portrait'] = reply_users[uid].portrait if uid in reply_doctors: doctor = reply_doctors[uid] if not doctor.is_online: r['user']['doctor_id'] = doctor.id r['user']['doctor_name'] = doctor.name r['user']['doctor_portrait'] = doctor.portrait if r['diary']: duid = r['diary']['user']['id'] if duid in users: r['diary']['user']['nickname'] = users[duid].nickname r['diary']['user']['portrait'] = users[duid].portrait if r['topic']: tuid = r['commented_reply']['user_id'] if hasattr(r, 'reply') and r['reply'] and\ r['reply']['commented_user_id']\ else r['topic']['user']['id'] if tuid in users: r['topic']['user']['nickname'] = users[tuid].nickname r['topic']['user']['portrait'] = users[tuid].portrait r['topic']['title'] = r['reply']['commented_content'] if r['reply']['commented_content'] \ else r['topic']['title'] if r.get('answer', ''): auid = r['reply']['commented_author_id'] \ if r.get('reply').get('commented_author_id') \ else r['answer']['user']['id'] if auid in users: r['answer']['user']['nickname'] = users[auid].nickname r['answer']['user']['portrait'] = users[auid].portrait r['answer']['title'] = r['reply']['commented_content'] \ if r['reply'].get('commented_content') \ else r['answer']['title'] r.update({'current_user': current_user}) # 将所有回复设置为已读 # tips: answer reply 在获取reply data时update is_read=true TopicReply.objects.filter(id__in=un_read_reply_ids, is_new=True).update(is_new=False) return result except Problem.DoesNotExist: pass return None @bind("topic/replies/receive") def get_my_topic_replies_receive(replies_ids): """获取我收到的日记帖评论。""" user = get_current_user() if not user: return gen(CODES.LOGIN_REQUIRED) user_ids = [] topic_ids = [] topic_replies_dict = get_diary_replies(replies_ids) for _, reply in topic_replies_dict.items(): # reply.commented_reply 表示 被评论的回复,有则当前为二级评论 topic_ids.append(reply.problem_id) user_ids.append(reply.user_id) # 评论用户id topics = Problem.objects.filter(pk__in=topic_ids, is_online=True) for topic in topics: user_ids.append(topic.user_id) users_dict = UserService.get_users_by_user_ids(user_ids) doctors_dict = {} doctors = DoctorService.get_doctor_from_user_ids(user_ids) for doctor in doctors: doctors_dict[doctor.user_id] = doctor result = {} for reply_id, reply in topic_replies_dict.items(): reply_user = users_dict.get(reply.user_id, {}) doctor = doctors_dict.get(reply.user_id, {}) doctor_info = {} if doctor: doctor_info = { "user_id": doctor.user_id, "doctor_id": doctor.id, "name": doctor.name, } diary_info = {} if reply.diary: diary_info = { "id": reply.diary_id, "title": reply.diary.title, } topic_info = {} if reply.problem: topic_info = { "id": reply.problem.id, } my_content = '' if reply.commented_reply: my_content = reply.commented_reply.content elif reply.problem: my_content = reply.problem.answer info = { "id": reply_id, "reply_id": reply_id, "diary": diary_info, "topic": topic_info, # "msg_type": "回复了我的问答", # backend拼装 # "url": "gengmei://answer_detail?answer_id=531149&comment_id=152631" # backend拼装 "is_deleted": False, "is_new": False, "reply_date": get_timestamp_or_none(reply.reply_date), "reply_content": reply.content, "my_content": my_content, "reply_user": { "name": reply_user.nickname, "portrait": reply_user.portrait, }, "author": { "id": user.id, "name": user.nick_name, "portrait": user.portrait, }, "doctor": doctor_info, } result[str(reply_id)] = info return result @bind('topic/reply_info') def get_topicreply_info(reply_id=None): """ 获取指定id的回复 """ try: reply = TopicReply.objects.get(pk=reply_id) user = UserService.get_user_by_user_id(reply.user_id) result = { 'portrait': user.portrait, 'nick_name': user.nickname, 'reply_time': get_timestamp_or_none(reply.reply_date), 'content': reply.content, 'user_id': reply.user_id, 'is_hot': reply.is_elite(), 'membership_level': user.membership_level, 'is_recommend': ReplyHeadline.is_recommend(reply_id), 'doctor_id': '', 'hospital_id': '', } user_bz = UserService.get_doctor_hospital_id_by_user_id(reply.user_id) if user_bz: result['user_id'] = user_bz['user_id'] result['doctor_id'] = user_bz['doctor_id'] result['hospital_id'] = user_bz['hospital_id'] return result except TopicReply.DoesNotExist: return gen(CODES.TOPIC_REPLY_NOT_FOUND) # @bind('talos/first/topic_reply/content') # def trans_problem_answers(problem_id): # result = {} # reply = TopicReply.objects.filter(problem_id=problem_id) # if reply: # result['content'] = reply[0].content # return result @bind('topic/topic_reply/get_reply_info_by_ids') def topic_reply_info(ids): """ :param ids: topic_reply_id list :return: [ { 'id': 1, 'data': { 'id': 2, 'uid': 3, 'content': str, 'reply_time': xxx, 'images': [] 'is_online': bool, 'can_reply': bool } } ] """ if len(ids) == 0: return [] replies = TopicReply.objects.filter(id__in=ids) wanted_fields = [ 'id', 'user_id', 'content', 'replied_topic_id', 'is_online', 'reply_date', ] data = replies.values(*wanted_fields) result = [] for d in data: r = { 'id': d['id'], 'uid': d['user_id'], 'content': escape(d['content']), 'reply_time': get_timestamp_or_none(d['reply_date']), 'images': [], 'is_online': d['is_online'], 'can_reply': not d['replied_topic_id'], } d = { 'id': r['id'], 'data': r, } result.append(d) return result @bind('topic/topic_reply/update_reply_num_by_ids') def update_reply_num(ids, is_online=False): """ :param ids: topic_reply_id list is_online :return: [ { 'id': 1, 'data': bool, } ] """ if len(ids) == 0: return False replies = TopicReply.objects.filter(id__in=ids) result = [] for reply in replies: r = reply.update_reply_num(is_online) d = { 'id': reply.id, 'data': r, } result.append(d) return result @bind("topic/topic_reply/my_list_for_doctor") @list_interface(offset_name='start_num', limit_name='count', element_model=TopicReply, element_func_list=[TopicReply.get_reply_detail]) def get_my_reply_lsit_for_dotor( start_num=0, count=10, send_or_receive=MY_COMMENT_TYPE.RECEIVED, with_comment=True, filter_topic=False): """received sent comments. args: send_or_receive: 0 as received, 1 as sent filter_topic: 只刷选帖子相关的评论 """ result = [] try: user = get_current_user() if not user: return gen(CODES.LOGIN_REQUIRED) # TODO: @weijialiang if send_or_receive == MY_COMMENT_TYPE.RECEIVED: reply_ids = ReplyCollect.objects.filter(reply_user_id=user.id, topic_reply_id__isnull=False).order_by('-created_time').values_list('topic_reply_id', flat=True)[start_num:start_num + count] elif send_or_receive == MY_COMMENT_TYPE.SENT: reply_ids = ReplyCollect.objects.filter(user_id=user.id, topic_reply_id__isnull=False).order_by('-created_time').values_list('topic_reply_id', flat=True)[start_num:start_num + count] else: return gen(CODES.OPERATION_NOT_SUPPORTED) reply_ids = list(reply_ids) query = Q(id__in=reply_ids, is_online=True) if filter_topic: query &= Q(problem__isnull=False) replies = TopicReply.objects.filter(query).order_by('-id') if reply_ids: _reply_ids = list(replies.values_list('id', flat=True)) topicreplys_data = get_reply_details_by_reply_ids(_reply_ids) comments_ids = [] for r in replies: _comments_ids = list(r.comments.filter(is_online=True).values_list('id', flat=True)) comments_ids += _comments_ids comments_data = comment_data_by_reply_ids(comments_ids) for reply in replies: for _reply in topicreplys_data: if _reply['reply']['reply_id'] == reply.id: replies_data = _reply break else: continue if with_comment: replies_data['comments'] = [] _reply_comments_ids = list(reply.comments.filter(is_online=True).values_list('id', flat=True)) for c in comments_data: if c['comment_id'] in _reply_comments_ids: replies_data['comments'].append(c) result.append(replies_data) # 将所有回复设置为已读 TopicReply.objects.filter( id__in=reply_ids, is_new=True).update(is_new=False) return result except Problem.DoesNotExist: return None @bind_context('topic/replies_my/reseived_aggregation') def get_my_replies_count(ctx): No_new_msg = { 'is_about_me': False, 'toptitle': '', 'type': NotificationType.REPLY_ME, 'unread_count': 0, "title": u'回复', "url": "", "content": "", "create_time": "", "user": "", "is_view": False, "imgheader": settings.NOTIFICATION_REPLY_IMG, "pic": "", "id": '', } user = get_user_from_context(ctx) if not user: return No_new_msg info = get_my_replies_count_from_mysql(user.id) count = info["count"] last_user_id = info["last_user_id"] created_time = info["created_time"] if count == 0: return No_new_msg else: last_user_info = UserService.get_user_by_user_id(last_user_id) if last_user_id == user.id: return No_new_msg return { 'is_about_me': False, 'toptitle': '', 'type': NotificationType.REPLY_ME, 'unread_count': count, "title": u'{}等人回复你'.format(last_user_info.nickname) if count > 1 else u'{}回复了你'.format(last_user_info.nickname), "url": "", "content": "", "create_time": get_timestamp_or_none(created_time), "user": "", "is_view": False, "imgheader": last_user_info.portrait, "pic": "", "id": '', } @bind_context('topic/replies_my/reseived_aggregation/v1') def get_my_replies_count_v1(ctx): result = { "count": 0, "last_user_info": {}, "create_time": 0, } user = get_user_from_context(ctx) if not user: return result info = get_my_replies_count_from_mysql(user.id) count = info["count"] last_user_id = info["last_user_id"] created_time = info["created_time"] if not count or not last_user_id: return result last_user_info = UserService.get_user_by_user_id(last_user_id) result["count"] = count result["created_time"] = get_timestamp_or_none(created_time), result["last_user_info"].update({ "nickname": last_user_info.nickname, "portrait": last_user_info.portrait, }) return result @bind('topic/unread_comments/count') def user_unreadcomments(): user = get_current_user() if not user: return gen(CODES.LOGIN_REQUIRED) reply_ids = reply_cache.get_received_comment_ids(user.id) if reply_ids: replies = TopicReply.objects.filter(id__in=reply_ids) replies = replies.filter(is_new=True) return replies.count() return 0 @bind('topic/read_reply') def topic_read_reply(): user = get_current_user() if not user: return gen(CODES.LOGIN_REQUIRED) replies = ReplyCollect.objects.filter(reply_user_id=user.id).exclude( answer_id__isnull=False, user_id=user.id).order_by('-id') topic_reply_pks = [collect.topic_reply_id for collect in replies if collect.topic_reply_id] TopicReply.objects.filter(id__in=topic_reply_pks, is_new=True).update(is_new=False)