question.py 13.2 KB
# coding=utf-8
from __future__ import unicode_literals, absolute_import, print_function
import datetime

from gm_types.mimas import CONTENT_CLASS
from django.conf import settings
from django.db.models import Max, Q

from gm_types.error import ERROR as CODES
from gm_types.mimas.enum import MEDIA_IMAGE_URL_SOURCE
from qa.models.answer import Question, Answer, AnswerVote, \
    AnswerReply, QuestionTag
from qa.service import QaFavorServices

from qa.tasks import add_question_view
from gm_rpcd.all import bind

from talos.cache.base import favor_cache
from talos.tools.favor_tool import FavorTool
from utils.rpc import gen, logging_exception, get_current_user


@bind('qa/question/polymers_extra')
def polymers_extra(polymers):
    # 新增问题数 + 新增回答数 + 新增评论数 + 新增点赞数

    date = datetime.date.today() - datetime.timedelta(days=1)

    if not isinstance(polymers, list):
        return {}

    items = {}
    for polymer in polymers:
        item = {
            "new_question_cnt": 0,
            "new_answer_cnt": 0,
            "new_vote_cnt": 0,
            "new_reply_cnt": 0,
        }
        question_types = polymer.get("question_types", [])
        if question_types:
            item["new_question_cnt"] = Question.objects.filter(
                question_type__in=question_types,
                create_time__year=date.year,
                create_time__month=date.month,
                create_time__day=date.day,
            ).count()
            item["new_answer_cnt"] = Answer.objects.filter(
                question__question_type__in=question_types,
                question__create_time__year=date.year,
                question__create_time__month=date.month,
                question__create_time__day=date.day,
            ).count()
            item["new_vote_cnt"] = AnswerVote.objects.filter(
                answer__question__question_type__in=question_types,
                answer__question__create_time__year=date.year,
                answer__question__create_time__month=date.month,
                answer__question__create_time__day=date.day,
            ).count()
            item["new_reply_cnt"] = AnswerReply.objects.filter(
                answer__question__question_type__in=question_types,
                answer__create_time__year=date.year,
                answer__create_time__month=date.month,
                answer__create_time__day=date.day,
            ).count()

        tags = polymer.get("tags", [])
        if tags:
            questions_ids = QuestionTag.objects.filter(tag__in=tags).values_list("question_id", flat=True)
            item["new_question_cnt"] += Question.objects.filter(
                pk__in=questions_ids,
                create_time__year=date.year,
                create_time__month=date.month,
                create_time__day=date.day,
            ).count()
            item["new_answer_cnt"] += Answer.objects.filter(
                question__pk__in=questions_ids,
                question__create_time__year=date.year,
                question__create_time__month=date.month,
                question__create_time__day=date.day,
            ).count()
            item["new_vote_cnt"] += AnswerVote.objects.filter(
                answer__question__pk__in=questions_ids,
                answer__question__create_time__year=date.year,
                answer__question__create_time__month=date.month,
                answer__question__create_time__day=date.day,
            ).count()
            item["new_reply_cnt"] += AnswerReply.objects.filter(
                answer__question__pk__in=questions_ids,
                answer__create_time__year=date.year,
                answer__create_time__month=date.month,
                answer__create_time__day=date.day,
            ).count()

        items[str(polymer["id"])] = item

    return items

@bind('qa/question_total_count_by_tag_ids')
def get_question_count_by_tag_ids(tag_ids):
    t_q_count = QuestionTag.objects.filter(tag__in=tag_ids).values_list('question_id', flat=True).distinct().count()
    #t_a_count = QuestionTag.objects.filter(tag__in=tag_ids).values_list('question__answers', flat=True).distinct().count()
    t_a_count = Answer.objects.filter(question__qtags__tag__in=tag_ids).values_list('id', flat=True).distinct().count()
    return {
        'question_count': t_q_count,
        'answer_count': t_a_count
    }


@bind('qa/question/get_qa_data')
def get_qa_data(user_id, start_num=0, count=10):
    if not user_id:
        return gen(CODES.PARAMS_INVALID)

    try:
        answer = Answer.objects.filter(user=user_id, is_online=True).\
                                order_by('-update_time')[start_num:start_num+count]
    except:
        logging_exception()
        return gen(CODES.ANSWER_NOT_FOUND)

    qa_data = {
        "qa": []
    }
    for item in answer:
        data = {
            'answer_content': item.content,
            'answer_id': item.id,
            'question_id': item.question.id,
            'question_content': item.question.content,
            'images': [image.image_url for image in item.images.filter(
                image_url_source=MEDIA_IMAGE_URL_SOURCE.CREATE).all()],
            'question_title': item.question.title,
        }
        qa_data['qa'].append(data)
    return qa_data


@bind("qa/question/list_for_web_by_ids")
def get_qa_card_by_ids_for_web(question_ids):
    """
    pc站,m站问答卡片列表数据
    :param question_ids:
    :return:
    """
    assert isinstance(question_ids, list)
    assert len(question_ids) <= 100

    user = get_current_user()

    questions = Question.objects.filter(is_online=True, id__in=question_ids)

    question_dict = {}
    for question_item in questions:
        _q_id = question_item.id
        _q_data = question_item.data_for_my_list(need_view_amount=False)
        _q_data.update({
            'user_id': question_item.user.id,
            'user_name': question_item.user.nickname,
            'user_portrait': question_item.user.portrait,
            'timestamp': int(question_item.create_time.strftime("%s")),
        })
        question_dict[str(_q_id)] = {"question": _q_data}

    question_ids = list(map(int, question_dict.keys()))
    _answer_ids = list(Answer.objects.filter(
        is_online=True,
        question_id__in=question_ids,
        level__in=[CONTENT_CLASS.BAD, CONTENT_CLASS.GENERAL, CONTENT_CLASS.FINE, CONTENT_CLASS.EXCELLENT, CONTENT_CLASS.OUTSTANDING]
    ).values("question_id").annotate(_id=Max("id")).values_list("_id", flat=True))
    answers = Answer.objects.filter(id__in=_answer_ids)

    for answer in answers:
        _question_id = str(answer.question_id)
        _question_dict = question_dict.get(_question_id, {})
        if _question_dict:
            _question_dict["answer"] = answer.data_for_es(need_view_amount=False)

    return {
        "qa_cards": question_dict,
    }


@bind("qa/quetion/get_random_questions_for_seo")
def get_random_questions_for_pc(count=10):
    """
    为pc站随机获取问题数据
    :return:
    """
    result = {
        "questions": [],
    }

    _sql = "SELECT id, title FROM api_question WHERE is_online=1 and id >= (" \
           "((SELECT MAX(id) FROM api_question) - (SELECT MIN(id) FROM api_question)) * RAND() + (SELECT MIN(id) FROM api_question)" \
           ") limit {_count};".format(_count=count)

    for q_obj in Question.objects.using(settings.SLAVE_DB_NAME).raw(_sql):
        _dic = {
            "question_id": q_obj.id,
            "title": q_obj.title,
        }
        result["questions"].append(_dic)

    return result


@bind("qa/question/get_share_data")
def get_question_share_data_by_id(question_id):
    try:
        question = Question.objects.get(pk=question_id)
    except Question.DoesNotExist:
        return gen(CODES.QUESTION_NOT_FOUND)

    user = get_current_user()
    user_id = user and user.id
    if not question.user_can_view(user_id):
        return gen(CODES.QUESTION_NOT_FOUND)

    base_query = Q(question_id=question_id, is_online=True)

    _recommend_answer = Answer.objects.filter(base_query & Q(is_recommend=True)).first()
    if _recommend_answer:
        answer = _recommend_answer
    else:
        _hot_answer = Answer.objects.filter(
            base_query & Q(is_recommend=False, like_num__gte=4)).order_by("rank", "-like_num", "-id").first()
        if _hot_answer:
            answer = _hot_answer
        else:
            _last_answer = Answer.objects.filter(
                base_query & Q(is_recommend=False, like_num__gte=2)).order_by("-update_time").first()

            if _last_answer:
                answer = _last_answer
            else:
                answer = None

    _data = {
        "question_id": question_id,
        "answer_id": answer and answer.id or 0,
        "answer_content": answer and answer.content or "",
        "question_content": question.content,
        "question_tags": [tag_obj.tag for tag_obj in question.tags],
        "question_old_images": question.content_images,
        "answer_old_images":  answer and answer.content_images or [],
        "answer_num": question.answer_num,
    }

    return _data


@bind("mimas/question/list")
def get_question_list_by_user_id(user_id, offset=0, count=10):
    questions = Question.objects.filter(user=user_id, is_online=True).order_by('-id')[offset:offset+count]

    question_ids = [question.id for question in questions]
    result = [question.data_for_my_list() for question in questions]

    #增加浏览量
    add_question_view.delay(question_ids)
    return result


@bind('mimas/qa/favor')
def qa_favor_create(question_id=None, answer_id=None):
    """
    问题或回答的收藏
    :param question_id:
    :param answer_id:
    :return:
    """
    if not any([question_id, answer_id]):
        return gen(CODES.PARAMS_INCOMPLETE)

    if answer_id:
        answer = QaFavorServices.answer_healthy(answer_id)
    if question_id:
        question = QaFavorServices.question_healthy(question_id)

    user = get_current_user()
    if not user:
        return gen(CODES.LOGIN_REQUIRED)

    result = QaFavorServices.create(user_id=user.id, question_id=question_id, answer_id=answer_id)
    if answer_id:
        favor_tool = FavorTool(redis_c=favor_cache, user_id=answer.user_id)
        favor_tool.receive_answer_favor(result.get('id'))
    else:
        favor_tool = FavorTool(redis_c=favor_cache, user_id=question.user_id)
        favor_tool.receive_question_favor(result.get('id'))

    return result


@bind('qa/favor/bulk_favor_question')
def bulk_favor_question(user_id, question_ids):
    """
    内部调用接口,批量关注问题。不关注返回值
    :param user_id:
    :param question_ids:
    :return:
    """
    for question_id in question_ids:
        try:
            question = QaFavorServices.question_healthy(question_id)
            result = QaFavorServices.create(user_id=user_id, question_id=question_id)

            favor_tool = FavorTool(redis_c=favor_cache, user_id=question.user_id)
            favor_tool.receive_question_favor(result.get('id'))
        except:
            continue


@bind('mimas/qa/favor/cancel')
def qa_favor_cancel(question_id=None, answer_id=None):
    """
    问题或回答的收藏取消
    :param question_id:
    :param answer_id:
    :return:
    """
    if not any([question_id, answer_id]):
        return gen(CODES.PARAMS_INCOMPLETE)

    if answer_id:
        answer = QaFavorServices.answer_healthy(answer_id)
    if question_id:
        question = QaFavorServices.question_healthy(question_id)

    user = get_current_user()
    if not user:
        return gen(CODES.LOGIN_REQUIRED)

    result = QaFavorServices.cancel(user_id=user.id, question_id=question_id, answer_id=answer_id)
    if answer_id:
        favor_tool = FavorTool(redis_c=favor_cache, user_id=answer.user_id)
        favor_tool.remove_answer_favor(result.get('id'))
    else:
        favor_tool = FavorTool(redis_c=favor_cache, user_id=question.user_id)
        favor_tool.remove_question_favor(result.get('id'))

    return result


@bind('mimas/attention_page/questions')
def attention_page_question_list(question_ids):
    """
    消息-关注页面问题列表
    :param question_ids:
    :return:
    """
    if not question_ids:
        return []
    question_ids = list(map(int, question_ids))
    questions = Question.objects.using(settings.SLAVE_DB_NAME).filter(
        id__in=question_ids)

    data = []
    for question in questions:
        data.append(question.data_for_list())
    add_question_view.delay(question_ids)

    return data


@bind('mimas/qa_favor/read')
def qa_favor_read_all():
    """
    消息页收藏tab 问答收藏已读
    :return:
    """
    user = get_current_user()
    if not user:
        return gen(CODES.SUCCESS)

    QaFavorServices.message_favor_tab_read(user.id)

    return gen(CODES.SUCCESS)


@bind('mimas/qa_favor/get_unread_count')
def qa_favor_get_unread_count():
    """
    消息页收藏tab 问答收藏已读
    :return:
    """
    result = {
        'count': 0
    }
    user = get_current_user()
    if not user:
        return result

    question_unread_count = QaFavorServices.get_message_tab_question_favor_count(user.id)
    answer_unread_count = QaFavorServices.get_message_tab_answer_favor_count(user.id)

    result['count'] = question_unread_count.get('count', 0) + answer_unread_count.get('count', 0)

    return result