1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
# coding=utf-8
import datetime
import logging
from django.db.models import Q
from gm_types.error import ERROR as CODES
from gm_types.gaia import DIARY_OPERATION, PLATFORM_CHANNEL, DOCTOR_PROCESS_STATUS
from gm_types.gaia import PROBLEM_FLAG_CHOICES, PRIVATE_STATUS, TOPIC_TYPE, FILTER_WORD_TYPE
from gm_types.mimas import TRACTATE_SORT_TYPE
from gm_types.user_hierarchy import EventType
from talos.tools.hospital_tool import HospitalTool
from ..models.topic import TopicScore, TopicReply, Problem
from talos.models.doctor import DoctorMessageList
from talos.libs.diaryrank_utils import DiaryRankTool
from talos.libs.reply import is_reply_num_gt_limit
from talos.services import DoctorService
from talos.tasks import push_diary_reply_message, applet_topic_replied_push, applet_topic_reply_summary_push
from talos.tools.filterword_tool import filterword_by_custom
from utils.rpc import gen, rpc_client, logging_exception
from user_hierarchy.portal import process_task
from utils.stat_log import SocialStatLogForUserAction
def update_topic_score(user_id, topic, score):
topic_score, created = TopicScore.objects.get_or_create(topic=topic, user_id=user_id)
topic_score.score = score
topic_score.save()
return topic_score.id
def topic_reply_common(user, topic_id, reply_id=None, content='', device_id=None, platform_channel=None):
# from ..models.topic import Problem
# TODO: user
"""话题回复.
:param content: 回复的内容,
:param reply_id: 评论ID,可选. 回复帖子时, 该字段为None; 回复其他评论时, 不可为空
:param topic_id: 话题ID, 必选
:param user: 用户
"""
result = {
'comment_data': {},
'reply_data': {},
'topic': {},
'doctor': {}, # if user is a doctor, add doctor.id
}
# check if content is empty
if not content.strip():
return gen(CODES.REPLY_CAN_NOT_BE_EMPTY)
# 检查用户在一分钟内回复(日记本/帖子)是否大于3条
if is_reply_num_gt_limit(user=user):
return gen(CODES.COMMENT_BUSY)
replied_reply = None
if reply_id:
replied_reply = TopicReply.objects.filter(id=reply_id).first()
# get right topic
if replied_reply and replied_reply.problem:
topic = replied_reply.problem
else:
try:
topic = Problem.objects.get(id=topic_id)
except Problem.DoesNotExist:
topic = None
if not topic:
return gen(CODES.TOPIC_NOT_FOUND)
# check if user is not in one organize
if topic.topic_type == TOPIC_TYPE.SHARE and not HospitalTool.in_one_hospital(topic, user.id):
return gen(CODES.TOPIC_REPLY_BAN_NOT_OWN)
result['topic']['id'] = topic.id
result['topic']['ask'] = topic.ask
result['topic']['topic_type'] = topic.topic_type
result['topic']['tags'] = topic.get_tags()
doctors = DoctorService.get_doctor_from_user_ids(user_ids=[user.id])
doctor = doctors[0] if doctors else None
if not (topic.flag == PROBLEM_FLAG_CHOICES.NORMAL or topic.is_online):
return gen(CODES.TOPIC_HAS_BEEN_DELETED)
#以前的代码进行了数字的过滤,本次沿用以前的逻辑
filterword_by_custom(filter_type=FILTER_WORD_TYPE.TOPIC_REPLY, content=content)
# check if content is same as the previous reply
try:
reply = TopicReply.objects.filter(problem=topic, user_id=user.id)
last_id = reply.latest('id')
previous_reply = TopicReply.objects.get(id=last_id.id)
if previous_reply.content == content:
return gen(CODES.REPLY_CAN_NOT_BE_REPEATED)
except TopicReply.DoesNotExist:
pass
d = topic.diary
if d is not None:
if d.user_id == user.id:
if reply_id and replied_reply:
d = DiaryRankTool(d.id)
t = datetime.datetime.now()
replied_user_id = replied_reply.user_id
d.add_heat(DIARY_OPERATION.SELF_REPLY, t, extra_id=replied_user_id)
elif device_id:
d = DiaryRankTool(d.id)
t = datetime.datetime.now()
d.add_heat(DIARY_OPERATION.OTHER_REPLY, t, extra_id=device_id)
topic.reply_num += 1
if topic.user_id == user.id:
topic.author_reply_num += 1
if doctor:
result['doctor']['id'] = doctor.id
# 限制民营医院医生
if topic.private_status == PRIVATE_STATUS.NORMAL:
reply_filter = Q(doctor_id=doctor.id) & Q(
problem__private_status=PRIVATE_STATUS.NORMAL)
today_reply_amount = TopicReply.objects.filter(reply_filter).extra(
where=['date(reply_date)=CURRENT_DATE']
).count()
if today_reply_amount >= doctor.reply_limit:
return gen(CODES.DOCTOR_REPLY_TOPIC_LIMITED)
rpc_client['doctor/update_last_answered_time'](doctor_id=doctor.id).unwrap()
# 如果是医生的回复,就把该问题标记成已经回答
topic.has_answer = True
# TODO 一个医生回答多次只记录一次
if topic.private_status == PRIVATE_STATUS.ASSIGN_DOCTOR_PRIVATE:
topic.private_status = PRIVATE_STATUS.ASSIGN_DOCTOR_PRIVATE_ANSWERED
elif topic.private_status == PRIVATE_STATUS.ASSIGN_DOCTOR:
topic.private_status = PRIVATE_STATUS.ASSIGN_DOCTOR_ANSWERED
topic.doctor_num += 1
topic.save()
doctor_today_reply_amount = TopicReply.objects.filter(
doctor_id=doctor.id,
reply_date__gt=datetime.date.today()
).count()
result['doctor']['today_reply_count'] = doctor_today_reply_amount
if not topic.is_topic and not topic.answer:
topic.answer = content
topic.assigned_doctor_id = user.id # TODO: check
topic.has_answer = True
topic.reply_num = 1
topic.doctor_num = 1
topic.save()
commented_reply = None
if replied_reply:
if replied_reply.commented_reply:
commented_reply = replied_reply.commented_reply
else:
commented_reply = replied_reply
topic_reply = TopicReply()
topic_reply.problem = topic
topic_reply.user_id = user.id
topic_reply.doctor_id = doctor.id if doctor else None
topic_reply.content = content
topic_reply.replied_topic = replied_reply
topic_reply.commented_reply = commented_reply
topic_reply.save()
# 给被评论的用户发小程序push
applet_topic_replied_push.delay(topic_reply.id)
# 24小时后,如果当前评论没有收到评论或点赞,则给当前评论用户发送相关小程序push
applet_topic_reply_summary_push.apply_async((topic_reply.id,), countdown=86400)
comment_reply_id = topic_reply.id if not reply_id else reply_id
if doctor:
DoctorMessageList.objects.filter(topic_id=topic.id, doctor_id=doctor.id,
process_status=DOCTOR_PROCESS_STATUS.unprocessed).\
update(process_status=DOCTOR_PROCESS_STATUS.processed)
if topic.diary:
from talos.cache.takesofacache import take_sofa_cache
take_sofa_cache.del_diary_cache_data(topic.diary_id)
if doctor:
update_topic_score(doctor.user_id, topic, 0)
elif replied_reply:
try:
is_doctor = DoctorService.get_doctor_by_user_id(user_id=replied_reply.user_id)
is_doctor = bool(is_doctor)
except IndexError:
is_doctor = False
if is_doctor:
update_topic_score(replied_reply.user_id, topic, 3)
topic.save()
logging.info("create new reply, topic id is: {}, reply id is: {}".format(
topic.id, topic_reply.id))
replied_reply_user_id = replied_reply.user_id if replied_reply else None
topic_user_id = topic.user_id if topic else None
push_diary_reply_message(user_id=user.id,
content=content,
reply_id=comment_reply_id,
topic_id=topic.id,
replied_reply_user_id=replied_reply_user_id,
topic_user_id=topic_user_id)
# 返回本身的数据
try:
reply_data = topic_reply.reply_data_after_create()
except:
reply_data = {}
logging_exception()
try:
comment_data = topic_reply.comment_data_after_create()
except:
logging_exception()
comment_data = {}
# 新加评论时,2h随机加赞2-4
# 产品需求, 将这段逻辑删除, 暂时保留防止有用
"""
try:
repeat_times, countdown = get_async_args(
const_strings.TOPIC_REPLY_FAKE_VOTE)
fake_vote.apply_async(args=(repeat_times, topic), countdown=countdown)
except:
logging_exception()
"""
# 用户行为埋点,评论相关
_topic_type = topic.topic_type
if _topic_type in [TOPIC_TYPE.ASK, TOPIC_TYPE.SHARE, TOPIC_TYPE.TOPIC]: # 日记帖
_stat_log_data = {
"user_id": user.id,
"content_id": topic.diary_id,
"content_type": SocialStatLogForUserAction.CONTENT_TYPE.diary
}
elif _topic_type in [TOPIC_TYPE.USER_ARTICLE, TOPIC_TYPE.COLUMN_ARTICLE]: # 专栏
_stat_log_data = {
"user_id": user.id,
"content_id": topic.id,
"content_type": SocialStatLogForUserAction.CONTENT_TYPE.article
}
else:
_stat_log_data = {}
if _stat_log_data:
SocialStatLogForUserAction.stat_log_for_reply(**_stat_log_data)
# add point, growth
growth_value, point_value, submit_count = 0, 0, 0
# if len(set(word for word in content)) > 5:
if not replied_reply and user.id != topic.user_id \
and topic.topic_type in [TOPIC_TYPE.ASK, TOPIC_TYPE.SHARE, TOPIC_TYPE.COLUMN_ARTICLE]:
# event_data = rpc_client['mimas/user/process_event_task'](
# user_id=user.id, event_type=EventType.COMMENT_OTHER, related_item=topic_reply.id).unwrap()
event_data = process_task(user_id=user.id, event_type=EventType.COMMENT_OTHER, related_item=topic_reply.id)
growth_value, point_value, submit_count = event_data['growth_value'], event_data['point_value'], event_data[
'submit_count']
result['comment_data'] = comment_data
result['reply_data'] = reply_data
result['point_value'] = point_value
result['growth_value'] = growth_value
result['submit_count'] = submit_count
return result
def get_xcx_topic_reply(start_num, count, user, topic, sort_type, comment_id):
"""
获取日记帖的评论
:param start_num:
:param count:
:param user:
:param topic:
:param sort_type:
:return:
"""
replies_list = []
if topic and topic.is_online and topic.flag == PROBLEM_FLAG_CHOICES.NORMAL:
query = Q(problem_id=topic.id, commented_reply_id__isnull=True, is_online=True)
# 小程序获取最新评论
if sort_type in [TRACTATE_SORT_TYPE.NEWEST]:
replies = TopicReply.objects.filter(query).order_by('-id')
else:
# 默认获取最热
replies = TopicReply.objects.filter(query).order_by('-like_num', 'id')
replies_list = TopicReply.get_replies_info(
user, replies, start_num=start_num, count=count, comment_id=comment_id, is_xcx=True
)
return replies_list
def get_topic_reply(
start_num, count, user, topic_obj=None, topic_id=None,
only_doctor_reply=False, is_new=False, comment_id=None,
new_sub_comment_count=False
):
"""
通过日记帖id or objects,获取该日记帖下的评论
:param topic_obj: 日记帖对象
:param topic_id: 日记帖id
:param start_num: 评论起始数
:param count: 个数
:param only_doctor_reply: 仅要医生的回复
:param is_new: 是否取最新评论
:param new_sub_comment_count: 子评论展示个数
:return: result dict
"""
result = {
"topic_replies": [],
}
if topic_id: # 优先获取topic_id
topic = Problem.get_by_id(topic_id)
elif topic_obj:
topic = topic_obj
if topic and topic.is_online and topic.flag == PROBLEM_FLAG_CHOICES.NORMAL:
query = Q(problem_id=topic.id, commented_reply_id__isnull=True, is_online=True)
if only_doctor_reply:
query = Q(doctor_id__isnull=False) & query
replies = TopicReply.objects.filter(query)
first_reply_count = replies.count()
replies = replies[start_num: start_num + count]
replies_list = TopicReply.get_replies_info(
user, replies, start_num=start_num, count=count, comment_id=comment_id,
new_sub_comment_count=new_sub_comment_count
)
else:
replies = TopicReply.objects.filter(query).order_by("-id")
first_reply_count = replies.count()
if is_new:
replies = replies[start_num: start_num + count]
replies_list = TopicReply.get_replies_info(
user, replies, start_num=0, count=count, comment_id=comment_id,
new_sub_comment_count=new_sub_comment_count
)
else:
replies_list = TopicReply.get_replies_list_info(
user, query, start_num=start_num, count=count, comment_id=comment_id,
new_sub_comment_count=new_sub_comment_count
)
result['first_reply_count'] = first_reply_count
result["topic_replies"] = replies_list
return result