# -*- coding: utf8 -*- from __future__ import unicode_literals, absolute_import, print_function from collections import defaultdict from django.conf import settings from django.utils.html import escape from gm_types.gaia import DOCTOR_TYPE, MY_COMMENT_TYPE from gm_types.gaia import PROBLEM_FLAG_CHOICES from gm_types.gaia import TOPIC_TYPE from gm_types.gaia import USER_TYPE from qa.portal import get_unread_count_by_user_id, get_answer_reply_by_pks, update_answer_reply_read_status from qa.libs import get_answer_reply_new from ..models.topic import TopicReplyVote, TopicReply from talos.cache.reply import reply_cache from talos.libs.datetime_utils import get_timestamp_or_none from talos.models import ReplyCollect from talos.rpc import CODES from talos.rpc import RPCMixin from talos.rpc import gen from talos.rpc import get_objects_from_queryset_and_pk_list from talos.services.doctor import DoctorService from talos.services.user import UserService from django.db.models import Q from qa.models import AnswerReply def _get_reply_topic_user_nicknames_by_replies(replies): ds = replies.values('id', 'replied_topic__user_id', 'problem__user_id') replied_topic_user_id_reply_id_dict = {d['replied_topic__user_id']: d['id'] for d in ds if d['replied_topic__user_id']} problem_user_id_reply_id_dict = {d['problem__user_id']: d['id'] for d in ds if d['problem__user_id']} r_user_ids = replied_topic_user_id_reply_id_dict.keys() p_user_ids = problem_user_id_reply_id_dict.keys() user_ids = list(r_user_ids) + list(p_user_ids) users = UserService.get_users_by_user_ids(user_ids) result = {} for u in users.values(): uid = u.id if uid in r_user_ids: key = replied_topic_user_id_reply_id_dict[uid] value = u.nickname elif uid in p_user_ids: key = problem_user_id_reply_id_dict[uid] value = u.nickname else: continue result[key] = value return result def _get_reply_topic_info(reply): """ NOTE: 获取回复相关的帖子topic信息 :return: """ topic_info = { 'id': reply.problem_id, 'title': ( reply.replied_topic and reply.replied_topic.id and escape(reply.replied_topic.content) or escape(reply.problem.answer) ), 'problem_ask': escape(reply.problem.ask), 'problem_answer': escape(reply.problem.answer), 'is_deleted': ( reply.problem.flag == PROBLEM_FLAG_CHOICES.MARK_DELETED or not reply.problem.is_online ), 'user': { 'id': reply.problem.user_id, # 'nickname': reply.replied_topic and self.replied_topic.user.nickname or self.user.nickname }, } if reply.problem.topic_type == TOPIC_TYPE.WEIXIN_NUM: topic_info['title'] = reply.problem.get_title() return topic_info def _get_reply_diary_info(reply): """ NOTE: 获取回复相关的日记本信息 其中 显示的title做特殊处理 title = 'tag'+'日记' :return: """ title = escape(reply.diary.title) tags_new_era = reply.diary.tags_new_era if tags_new_era: title = tags_new_era[0]['name'] + u'日记' diary_info = { 'id': reply.diary.id, 'title': title, 'is_deleted': not reply.diary.is_online, 'user': { 'id': reply.diary.user_id, # 'nickname': UserService.get_user_by_user_id(self.diary.user_id).nickname, }, } return diary_info def get_reply_details_by_reply_ids(reply_ids, user_id=None): from talos.models.topic import ReplyHeadline replies = TopicReply.objects.filter(id__in=reply_ids) _replies = get_objects_from_queryset_and_pk_list(replies, reply_ids) result = [] reply_user_ids = list(replies.values_list('user_id', flat=True)) 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} self_reply_doctor_ids = list(replies.values_list('doctor_id', flat=True)) _doctors = DoctorService.get_doctor_from_doctor_ids(self_reply_doctor_ids) self_doctors = {d.id: d for d in _doctors} doctor_hospitals = {} for d in _doctors: if d.hospital_id: doctor_hospitals[d.id] = d.hospital reply_ids = list(replies.values_list('id', flat=True)) topicreply_votes = list(TopicReplyVote.objects.filter(topic_reply_id__in=reply_ids).values('topic_reply_id', 'user_id')) recommend_reply_ids = ReplyHeadline.get_recommend_reply_ids(reply_ids) user_nicknames = _get_reply_topic_user_nicknames_by_replies(replies) for reply in _replies: if reply.user_id and reply.user_id in reply_users.keys(): city_name = reply_users[reply.user_id].city_name portrait = reply_users[reply.user_id].portrait else: city_name = u'' portrait = u'' user_type = 0 if reply.user_id and reply.user_id in reply_doctors.keys(): doctor_info = reply_doctors[reply.user_id] if doctor_info.is_online: doctor = doctor_info if doctor.doctor_type == DOCTOR_TYPE.OFFICER: user_type = USER_TYPE.OFFICER hospital_id = doctor_info.hospital_id else: user_type = USER_TYPE.EXPERT hospital_id = None else: doctor = None hospital_id = None else: doctor = None hospital_id = None if reply.doctor_id and reply.doctor_id in doctor_hospitals.keys(): hospital_name_full = doctor_hospitals[reply.doctor_id].name or u'' else: hospital_name_full = u'' hospital_name = hospital_name_full[:14] if len(hospital_name_full) <= 14 else hospital_name_full[:14] + '...' if reply.doctor_id and reply.doctor_id in self_doctors.keys(): doctor_portrait = self_doctors[reply.doctor_id].portrait else: doctor_portrait = '' if bool(user_id): k = { 'user_id': user_id, 'topic_reply_id': reply.id, } is_voted = k in topicreply_votes else: is_voted = False is_recommand = reply.id in recommend_reply_ids self_user = reply_users[reply.user_id] reply_data = { 'user': { 'user_id': reply.user_id, 'user_name': self_user.nickname, 'is_doctor': True if doctor else False, 'is_hospital': True if hospital_id else False, 'doctor_id': doctor.id if doctor else '', 'doctor_name': doctor and doctor.name, 'hospital_id': hospital_id if hospital_id else '', 'portrait': portrait, 'user_type': user_type, 'membership_level': self_user.membership_level, }, 'is_private': bool(user_id) and user_id == reply.user_id, 'doctor_portrait': doctor_portrait, 'hospital_name': hospital_name, 'is_recommend_doctor': False, 'recommend_doctor_title': '', 'favored': False, 'images': [], 'is_star_user': False, 'city': city_name, 'is_topic_append': reply.is_topic_append, 'reply': { 'reply_id': reply.id, 'content': escape(reply.content), 'favor_amount': reply.like_num, 'reply_time': get_timestamp_or_none(reply.reply_date), 'is_voted': is_voted, 'image': reply.image, 'is_new': reply.is_new, 'replied_topic_id': reply.replied_topic_id or '', 'reply_date': get_timestamp_or_none(reply.reply_date), 'commented_reply_id': reply.replied_topic_id and reply.commented_reply_id or '', 'like_num': reply.like_num, 'is_best_reply': reply.is_best_reply(), 'is_recommand': is_recommand, 'is_elite': reply.is_elite(), 'comments_num': reply.comments.count(), } } reply_data['diary'], reply_data['topic'] = None, None if reply.id in user_nicknames: nickname = user_nicknames[reply.id] else: nickname = None if reply.problem_id: topic_info = _get_reply_topic_info(reply) topic_info['user']['nickname'] = nickname reply_data['topic'] = topic_info if reply.diary_id: diary_info = _get_reply_diary_info(reply) diary_info['user']['nickname'] = nickname reply_data['diary'] = diary_info result.append(reply_data) return result def comment_data_by_reply_ids(reply_ids): result = [] replies = TopicReply.objects.filter(id__in=reply_ids) _replies = get_objects_from_queryset_and_pk_list(replies, reply_ids) replied_topic_user_ids = list(replies.values_list('replied_topic__user_id', flat=True)) _replied_doctor_infos = DoctorService.get_doctor_from_user_ids(replied_topic_user_ids) replied_doctor_infos = defaultdict(lambda: None) for d in _replied_doctor_infos: replied_doctor_infos[d.user_id] = d _replied_user_infos = UserService.get_users_by_user_ids(replied_topic_user_ids) replied_user_infos = defaultdict(lambda: None) for k, v in _replied_user_infos.items(): replied_user_infos[k] = v self_user_ids = list(replies.values_list('user_id', flat=True)) _self_user_infos = UserService.get_users_by_user_ids(self_user_ids) self_user_infos = defaultdict(lambda: None) for k, v in _self_user_infos.items(): self_user_infos[k] = v _self_user_doctor_infos = DoctorService.get_doctor_from_user_ids(self_user_ids) self_user_doctor_infos = defaultdict(lambda: None) for d in _self_user_doctor_infos: self_user_doctor_infos[d.id] = d self_doctor_ids = list(replies.values_list('doctor_id', flat=True)) _self_doctor_infos = DoctorService.get_doctor_from_doctor_ids(self_doctor_ids) self_doctor_infos = defaultdict(lambda: None) for d in _self_doctor_infos: self_doctor_infos[d.id] = d for index, reply in enumerate(_replies): if reply.replied_topic: if reply.replied_topic.user_id == reply.user_id: at_nickname = u'' at_doctor = None at_hospital_id = None else: if reply.replied_topic.user_id is not None: replied_doctor_info = replied_doctor_infos[reply.replied_topic.user_id] at_doctor = replied_doctor_info if at_doctor and at_doctor.is_online and at_doctor.doctor_type == DOCTOR_TYPE.OFFICER: at_hospital_id = at_doctor.hospital_id else: at_hospital_id = None else: at_doctor = None at_hospital_id = None at_nickname = replied_user_infos[reply.replied_topic.user_id].nickname or u'昵称未设置' else: at_nickname = u'昵称未设置' at_doctor = None at_hospital_id = None if reply.user_id: portrait = self_user_infos[reply.user_id].portrait membership_level = self_user_infos[reply.user_id].membership_level if self_user_doctor_infos[reply.user_id] and self_user_doctor_infos[reply.user_id].is_online: doctor = self_user_doctor_infos[reply.user_id] if doctor.doctor_type == DOCTOR_TYPE.OFFICER: hospital_id = doctor.hospital_id else: hospital_id = None else: doctor = None hospital_id = None else: portrait = '' membership_level = None doctor = None hospital_id = None data = { 'type': 0, 'content': escape(reply.content), 'at_nickname': at_nickname, 'at_doctor_id': at_doctor.id if at_doctor else '', 'at_hospital_id': at_hospital_id if at_hospital_id is not None else '', 'user_portrait': portrait, 'at_user_id': reply.replied_topic.user_id if reply.replied_topic else '', 'nickname': '', 'comment_id': reply.id, 'comment_time': reply.reply_date.strftime('%m.%d'), 'comment_expert_id': doctor.id if doctor else '', 'at_expert_id': at_doctor.id if at_doctor else '', 'user_id': reply.user_id, 'user_is_doctor': True if doctor else False, 'user_is_hospital': True if hospital_id is not None else False, 'doctor_id': doctor.id if doctor else '', 'hospital_id': hospital_id if hospital_id is not None else '', 'membership_level': membership_level, 'is_best_reply': reply.is_best_reply(), } if self_doctor_infos[reply.doctor_id]: d = self_doctor_infos[reply.doctor_id] data['nickname'] = d.name if d.user_id != settings.SUOZHANG_UID: data['nickname'] += u'医生' else: data['nickname'] = self_user_infos[reply.user_id].nickname or u'昵称未设置' result.append(data) return result def get_diary_replies(topic_reply_ids): # 我收到的评论 topic_replies = TopicReply.objects.filter( pk__in=topic_reply_ids, is_online=True ) topic_replies_dict = {reply.id: reply for reply in topic_replies} return topic_replies_dict def get_my_replies(user_id, send_or_receive, start_num, count): if settings.REPLIES_READ_MYSQL_FLAG: return get_my_replies_mysql(user_id, send_or_receive, start_num, count) else: return get_my_replies_redis(user_id, send_or_receive, start_num, count) def get_my_replies_redis(user_id, send_or_receive, start_num, count): def cmp(x, y): if x > 0 and y > 0: return int(y)-int(x) return int(x)-int(y) if send_or_receive == MY_COMMENT_TYPE.RECEIVED: reply_ids = reply_cache.get_received_comment_ids(user_id) elif send_or_receive == MY_COMMENT_TYPE.SENT: reply_ids = reply_cache.get_sent_comment_ids(user_id) else: return gen(CODES.OPERATION_NOT_SUPPORTED) reply_ids = sorted(reply_ids, cmp=cmp) reply_ids = reply_ids[start_num:start_num + count] answer_reply_pks = [pk.replace("-", "") for pk in reply_ids if pk.startswith("-")] topic_reply_pks = [pk for pk in reply_ids if not pk.startswith("-")] answer_reply = get_answer_reply_by_pks(pks=answer_reply_pks) update_answer_reply_read_status(answer_reply_pks) # 更新回答回复的已读状态 topic_reply = TopicReply.objects.filter(pk__in=topic_reply_pks, is_online=True) return topic_reply_pks, answer_reply + topic_reply def get_my_replies_mysql(user_id, send_or_receive, start_num, count): if send_or_receive == MY_COMMENT_TYPE.RECEIVED: replys = ReplyCollect.objects.filter(reply_user_id=user_id).exclude( answer_id__isnull=False, user_id=user_id).order_by('-created_time')[start_num: start_num+count] elif send_or_receive == MY_COMMENT_TYPE.SENT: replys = ReplyCollect.objects.filter(user_id=user_id).order_by('-created_time')[start_num:start_num+count] else: return gen(CODES.OPERATION_NOT_SUPPORTED) answer_reply_pks = [collect.answer_id for collect in replys if collect.answer_id] topic_reply_pks = [collect.topic_reply_id for collect in replys if collect.topic_reply_id] answer_replies = get_answer_reply_by_pks(pks=answer_reply_pks) update_answer_reply_read_status(answer_reply_pks) # 更新回答回复的已读状态 topic_replies = TopicReply.objects.filter(pk__in=topic_reply_pks, is_online=True) answer_replies_dict = {reply['reply']['reply_id']: reply for reply in answer_replies} topic_replies_dict = {reply.id: reply for reply in topic_replies} sorted_replies = [] for reply in replys: if reply.answer_id: _r = answer_replies_dict.get(reply.answer_id, False) if _r: sorted_replies.append(_r) if reply.topic_reply_id: _r = topic_replies_dict.get(reply.topic_reply_id, False) if _r: sorted_replies.append(_r) return topic_reply_pks, sorted_replies def get_my_replies_count_from_mysql(user_id, send_or_receive=MY_COMMENT_TYPE.RECEIVED): if send_or_receive == MY_COMMENT_TYPE.RECEIVED: replies = ReplyCollect.objects.filter(reply_user_id=user_id).exclude(answer_id__isnull=False, user_id=user_id).order_by('-created_time') if replies.filter(answer_id__isnull=False).exists(): answer_replies_count = get_unread_count_by_user_id(user_id) # 排除自己给自己评论的数据 else: answer_replies_count = 0 topic_reply_pks = [collect.topic_reply_id for collect in replies if collect.topic_reply_id] if topic_reply_pks: topic_replies_count = TopicReply.objects.filter(id__in=topic_reply_pks, is_new=True, is_online=True).count() else: topic_replies_count = 0 count = topic_replies_count + answer_replies_count return { "count": count, "last_user_id": replies.first().user_id if count else None, "created_time": replies.first().created_time if count else None, } elif send_or_receive == MY_COMMENT_TYPE.SENT: replies = ReplyCollect.objects.filter(user_id=user_id).order_by('-created_time') count = replies.count() return { "count": count, "last_user_id": replies.first().reply_user_id if count else None, "created_time": replies.first().created_time if count else None, } else: return gen(CODES.OPERATION_NOT_SUPPORTED)