def post(self, match_id):
        """"
        TODO: 如果回调时赛事已满员则自动退款处理

        Parteam Api request example: {
          "message": "成功",
          "code": 200,
          "attribute": {
              "userId": 169,
              "orderNo": "11354642167546",
              "paymentMethod":1, // 支付类型 1微信,2支付宝
              "orderState":2 // // 订单状态 1 待付款 2 已付款 3 超时未付款 4 已发货
          }
        }
        """
        data = self.request.body.decode()
        data = json.loads(data)

        if not data.get("attribute"):
            raise ApiException(400, "未包含 attribute")

        order = data['attribute']
        member = MatchMember.get_or_404(pt_order_no=order['orderNo'])

        if order['orderState'] in (2, 4):

            # 将状态为未支付报名状态修改为正常
            if member.state == MatchMember.MatchMemberState.wait_pay:

                payment_method = (TeamOrder.OrderPaymentMethod.WXPAY,
                                  TeamOrder.OrderPaymentMethod.ALIPAY
                                  )[order['paymentMethod'] - 1]

                with self.db.transaction():
                    MatchMember.update(
                        state=MatchMember.MatchMemberState.normal).where(
                            MatchMember.id == member.id).execute()

                    TeamOrder.update(
                        paid=datetime.now(),
                        state=TeamOrder.OrderState.TRADE_BUYER_PAID,
                        gateway_trade_no=order['orderNo'],
                        payment_method=payment_method).where(
                            TeamOrder.id == member.order_id).execute()

                # 统计赛事人数
                Match.update_members_count(member.match_id)
                if member.group_id > 0:
                    MatchGroup.update_members_count(member.group_id)

            match_notify.join_match_done\
                .apply_async(args=[match_id, member.id], retry=True)

        self.write_success()
Esempio n. 2
0
def scan_match_start_time():
    """
    定时扫描 Match 表, 提前两小时发送比赛开始通知
    :return:
    """
    now = datetime.now()
    max_dt = now + timedelta(hours=2)
    min_dt = now - timedelta(minutes=10)
    matches = Match.select().where(Match.pushed.is_null(),
                                   Match.start_time >= min_dt,
                                   Match.start_time <= max_dt)
    for match in matches:
        match_start.delay(match_id=match.id)
        Match.update(pushed=now).where(Match.id == match.id).execute()
 def get_object(self, match_id: int, preview: bool = False):
     try:
         if preview:
             query = Match.select().where(Match.id == match_id)
         else:
             query = Match.select()\
                 .where(Match.id == match_id,
                        (Match.state == Match.MatchState.closed.value) |
                        (Match.state == Match.MatchState.cancelled.value) |
                        (Match.state == Match.MatchState.opening.value) |
                        (Match.state == Match.MatchState.finished.value))
         obj = query.get()
     except Match.DoesNotExist:
         raise ApiException(404, "赛事不存在")
     return obj
    def post(self, match_id: int):
        """
        提交退塞请求,
        http_form:
            reason: 退赛原因,
            insists: 强制退出, 强制退出比赛无退款
        :param match_id: int, Match.id
        """
        form = self.validated_arguments

        insists = form.pop("insists", False)
        match = Match.get_or_404(id=match_id)
        if not insists:
            self.can_leave(match, self.current_user.id)
        member = self.has_joined_match(match, user_id=self.current_user.id)

        notify_url = urljoin(self.request.full_url(),
                             self.reverse_url("rest_matches_refund_callback"))
        try:
            MatchService.leave(user_id=self.current_user.id,
                               match=match,
                               notify_url=notify_url,
                               insists=insists)
        except MatchException as e:
            logging.error(e)
            msg = "退出赛事失败, 原因: `{0}`".format(str(e))
            raise ApiException(422, msg)
        self.set_status(204, "退出赛事成功")
        self.finish()
    def get(self, match_id):
        match = Match.get_or_404(id=match_id)

        query = MatchMember.select(MatchMember, MatchGroup).join(
            MatchGroup,
            join_type=JOIN_LEFT_OUTER,
            on=(MatchMember.group_id == MatchGroup.id).alias("group")).where(
                MatchMember.match_id == match.id).order_by(
                    MatchMember.id.desc())

        group_query = MatchGroup.select() \
            .where(MatchGroup.match_id == match_id)
        self.logger.debug(group_query.sql())
        groups = []
        for group in group_query:
            groups.append({"name": group.name})

        group_name = self.get_argument("group_name", "")
        if group_name:
            query = query.where(MatchGroup.name == group_name)

        members = self.paginate_query(query)

        sum_fee = MatchMember.select(
            fn.SUM(MatchMember.total_fee).alias("sum")).where(
                MatchMember.match_id == match_id).scalar()

        self.render("match/match_members_list.html",
                    sum_fee=sum_fee,
                    groups=groups,
                    match=match,
                    members=members,
                    pagination=members.pagination)
    def get(self, user_id):
        """ 获取用户参与的比赛
        """

        paid = self.get_argument("paid", None)

        query = Match.select(Match, MatchMember, Team).join(
            MatchMember,
            on=(MatchMember.match_id == Match.id
                ).alias("member")).switch(Match).join(
                    Team, on=(Match.team_id == Team.id).alias("team")).where(
                        MatchMember.user_id == user_id)

        if paid == "0":
            query = query.where(
                MatchMember.state == MatchMember.MatchMemberState.wait_pay)
        elif paid == "1":
            query = query.where(
                MatchMember.state > MatchMember.MatchMemberState.wait_pay)

        query = self.paginate_query(query)
        filtered = self.filter_query(query)
        page = self.paginate_query(filtered)

        data = self.get_paginated_data(page=page, alias='matches')

        self.write(data)
    def _ban(self, member_id):
        """
        ban 成员,并保存原有状态
        """

        member = MatchMember.get_or_404(id=member_id)

        if member.state == MatchMember.MatchMemberState.banned:
            self.write_success()
        else:
            MatchMember.update(state=MatchMember.MatchMemberState.banned,
                               state_before_ban=member.state).where(
                                   MatchMember.id == member_id).execute()

            Match.update_members_count(member.match_id)
            self.write_success()
    def get(self, round_id):

        match_round = MatchRound.get_or_404(id=round_id)
        match = Match.get_or_404(id=match_round.match_id)

        query = MatchMember.select().where(
            MatchMember.match_id == match.id,
            MatchMember.state == MatchMember.MatchMemberState.normal)

        members = []
        for member in query:
            members.append({"id": member.id, "name": member.name})

        query = MatchAgainst.select().where(
            MatchAgainst.round_id == match_round.id).order_by(
                MatchAgainst.id.asc())

        againsts = []
        for against in query:
            againsts.append(against.info)

        match_options = MatchOption.select().where(
            MatchOption.match_id == match.id)

        self.render("match/round_againsts.html",
                    match=match,
                    match_round=match_round,
                    members=members,
                    againsts=againsts,
                    match_options=match_options)
Esempio n. 9
0
def new_match_status(self, match_id: int):
    """
    主办方发布新战报时向赛事成员推送信息
    :param self:
    :param match_id:
    :return:
    """
    match = Match.get(id=match_id)  # type: Match
    team = Team.get(id=match.team_id)  # type: Team
    members = MatchService.members(match,
                                   state=MatchMember.MatchMemberState.normal)

    infos = []
    for member in members:
        infos.append({"mobile": member.mobile, "userId": member.user_id})

    message = NewMatchScheduleMessage(
        user_infos=infos,
        match_id=match_id,
        match_name=match.title,
        sponsor_name=team.name,
        sponsor_pic_url=team.get_cover_url(size="medium"))

    pt = Parteam(app.settings["parteam_api_url"])
    if not pt.push_message(message):
        self.retry(ParteamRequestError("调用派队推送接口失败"))
Esempio n. 10
0
    def get(self, match_id):
        keyword = self.get_argument("kw", "")
        match = Match.get_or_404(id=match_id)
        query = MatchMember.query_all_members(match_id)

        group_query = MatchGroup.select() \
            .where(MatchGroup.match_id == match_id)
        self.logger.debug(group_query.sql())
        groups = []
        for group in group_query:
            groups.append({"name": group.name})

        group_name = self.get_argument("group_name", "")
        if group_name:
            query = query.where(MatchGroup.name == group_name)

        if keyword:
            if is_mobile(keyword):
                query = query.where(MatchMember.mobile == keyword)
            else:
                query = query.where(MatchMember.name.contains(keyword))

        members = self.paginate_query(query)

        sum_fee = MatchMember.select(
            fn.SUM(MatchMember.total_fee).alias("sum")).where(
                MatchMember.match_id == match_id).scalar()

        self.render("match/match_members_list.html",
                    sum_fee=sum_fee,
                    match=match,
                    groups=groups,
                    members=members,
                    pagination=members.pagination)
Esempio n. 11
0
def match_start(self, match_id: int):
    """
    赛事开始前, 调用派队消息推送接口
    :param self: celery task Context
    :param match_id:
    :return:
    """
    match = Match.get(id=match_id)  # type: Match
    team = Team.get(id=match.team_id)  # type: Team
    members = MatchService.members(match,
                                   state=MatchMember.MatchMemberState.normal)
    infos = []
    for member in members:
        infos.append({"userId": member.user_id, "mobile": member.mobile})

    message = MatchStartMessage(
        user_infos=infos,
        match_id=match_id,
        match_name=match.title,
        sponsor_name=team.name,
        sponsor_pic_url=team.get_cover_url(size="medium"))

    pt = Parteam(app.settings["parteam_api_url"])
    if not pt.push_message(message=message):
        self.retry(exc=ParteamRequestError("调用派队推送接口失败"))
Esempio n. 12
0
    def post(self, match_id):

        match = Match.get_or_404(id=match_id)
        form = CreateCoverForm(self.arguments)

        if form.validate():

            cover = MatchCover(match_id=match.id)
            form.populate_obj(cover)

            if "coverfile" in self.request.files:
                to_bucket = self.settings['qiniu_avatar_bucket']
                to_key = "match:cover:%s%s" % (match_id, time.time())
                to_key = hashlib.md5(to_key.encode()).hexdigest()

                cover_key = self.upload_file(
                    "coverfile",
                    to_bucket=to_bucket,
                    to_key=to_key,
                )

                cover.cover_key = cover_key

            cover.save()

            self.redirect(self.reverse_url("admin_match_detail", match_id))
            return

        self.render("match/add_cover.html", form=form, match=match)
Esempio n. 13
0
    def post(self, match_id, status_id):
        match = Match.get_or_404(id=match_id)
        status = MatchStatus.get_or_404(id=status_id)
        delete_photo_keys = self.get_argument("delete-photo-keys", "")

        form = MatchStatusForm(self.arguments)

        if not form.validate():
            self.render("match/statuses_edit.html",
                        match=match,
                        status=status,
                        form=form)
        else:
            if delete_photo_keys:
                delete_photo_keys_list = delete_photo_keys.split(",")
            else:
                delete_photo_keys_list = []

            if "photos" in self.request.files:
                photo_keys_list = self.upload_photos(match_id)
            else:
                photo_keys_list = []

            new_photos_set = set(status.photos) ^ set(delete_photo_keys_list)
            new_photos_set = new_photos_set.union(set(photo_keys_list))

            form.populate_obj(status)
            status.photos = list(new_photos_set)
            status.save()

            self.redirect(self.reverse_url("admin_match_statuses", match_id))
Esempio n. 14
0
 def _settlement_application(self, match_id):
     # 提交结算申请
     match = Match.get_or_404(id=match_id)
     if not match.can_apply_settlement():
         self.write_error(403, "此活动不能手动结算")
     else:
         MatchService.settlement_application(self.current_user, match)
         self.write_success()
Esempio n. 15
0
    def get(self, round_id):

        match_round = MatchRound.get_or_404(id=round_id)
        match = Match.get_or_404(id=match_round.match_id)

        form = EditRoundForm(obj=match_round)

        self.render("match/round_edit.html", form=form, match=match)
Esempio n. 16
0
    def get(self, match_id):

        match = Match.get_or_404(id=match_id)
        cover = MatchCover(match_id=match_id)

        form = CreateCoverForm(obj=cover)

        self.render("match/add_cover.html", form=form, match=match)
Esempio n. 17
0
    def get(self, match_id):

        match = Match.get_or_404(id=match_id)
        match_round = MatchRound(match_id=match_id)

        form = CreateRoundForm(obj=match_round)

        self.render("match/round_create.html", form=form, match=match)
Esempio n. 18
0
    def get(self, match_id, state):
        match = Match.get_or_404(id=match_id)

        if state == "normal":
            # 查询正常参赛成员
            members = MatchMember\
                .query_all_members(match_id)\
                .where(MatchMember.state == MatchMember.MatchMemberState.normal)
        else:
            members = MatchMember.query_all_members(match_id)

        # 排除文件和图片项
        option_info_list = [
            option_info for option_info in match.option_info_list
            if not (option_info.is_photo() or option_info.is_file() or
                    option_info.is_avatar() or option_info.is_idcard_photo())
        ]

        option_name_list = [
            option_info.option_name for option_info in option_info_list
        ]
        option_name_list.extend(["报名时间", "状态"])

        file_name = "{match_name}成员列表.xlsx"\
            .format(match_name=match.title)
        # temp_file_name = str(uuid.uuid4())

        o = io.BytesIO()
        with Workbook(o) as workbook:
            worksheet = workbook.add_worksheet()
            row, col = 0, 0
            worksheet.write_row(row, col, option_name_list)
            for member in members:
                row, col = row + 1, 0
                assert isinstance(member, MatchMember)
                for option_info in option_info_list:
                    option_value = option_info.get_option_value(member)
                    # 处理布尔值显示
                    if option_info.is_leader_check() or option_info.is_boolean(
                    ):
                        option_value = "是" if option_value else "否"
                    if option_info.is_gender():
                        option_value = member.display_gender()
                    worksheet.write(row, col, option_value)
                    col += 1
                worksheet.write(row, col, member.created.strftime('%Y.%m.%d'))
                worksheet.write(row, col + 1, member.state_name)

        data = o.getvalue()
        o.close()

        self.set_header("Content-Type", "application/octet-stream")
        self.set_header("Content-Disposition",
                        "attachment; filename={0}".format(file_name))
        self.add_header("Content-Length", len(data))
        self.set_header("Content-Transfer-Encoding", "binary")
        self.write(data)
Esempio n. 19
0
    def get(self, match_id, status_id):
        match = Match.get_or_404(id=match_id)
        status = MatchStatus.get_or_404(id=status_id)

        form = MatchStatusForm(obj=status)
        self.render("match/statuses_edit.html",
                    match=match,
                    status=status,
                    form=form)
Esempio n. 20
0
    def get(self, match_id):
        match = Match.get_or_404(id=match_id)

        # 获取赛事分组信息
        groups = MatchGroup.select().where(
            MatchGroup.match_id == match.id).order_by(
                MatchGroup.sort_num.desc())

        # 获取报名表自定义选项
        custom_options = MatchOption.select().where(
            MatchOption.match_id == match.id).order_by(
                MatchOption.sort_num.desc())

        rounds = MatchRound.select(MatchRound, ).where(
            MatchRound.match_id == match.id).order_by(MatchRound.created.asc(),
                                                      MatchRound.id.asc())

        covers = MatchCover.select().where(
            MatchCover.match_id == match.id).order_by(MatchCover.id.desc())

        # 获取对阵图
        RightMember = MatchMember.alias()

        against_query = MatchAgainst.select(
            MatchAgainst, MatchMember, RightMember).join(
                MatchMember,
                on=(MatchAgainst.left_member_id == MatchMember.id
                    ).alias("left_member")).switch(MatchAgainst).join(
                        RightMember,
                        join_type=JOIN_LEFT_OUTER,
                        on=(MatchAgainst.right_member_id == RightMember.id
                            ).alias("right_member")).where(
                                MatchAgainst.match_id == match_id).order_by(
                                    MatchAgainst.start_time.asc())

        againsts = {}
        for against in against_query:
            if against.round_id not in againsts:
                againsts[against.round_id] = []

            againsts[against.round_id].append(against)

        # 如果已经结束 获取是否已经提交了结算申请
        is_application_exist =\
            SettlementApplication.is_application_exist(match_id)

        self.render("match/detail.html",
                    match=match,
                    rounds=rounds,
                    groups=groups,
                    custom_options=custom_options,
                    covers=covers,
                    againsts=againsts,
                    is_application_exist=is_application_exist)
Esempio n. 21
0
    def get(self, match_id):

        match = Match.get_or_404(id=match_id)

        query = MatchStatus.select(
            MatchStatus, ).where(MatchStatus.match_id == match.id).order_by(
                MatchStatus.created.desc())

        statuses = self.paginate_query(query)

        self.render("match/statuses.html", statuses=statuses, match=match)
Esempio n. 22
0
    def cancel(cls, match: Match, user: User):
        """
        主办方取消赛事
        :param match:
        :param user:
        :return:
        """
        from yiyun.tasks.match import batch_refund_worker
        if not match.can_cancel():
            raise MatchStateError("当前赛事状态无法取消: {0}".format(match.state))

        with cls.database.transaction():
            Match.update(state=Match.MatchState.cancelled.value)\
                .where(Match.id == match.id).execute()

            members = MatchMember.select()\
                .where(MatchMember.match_id == match.id,
                       MatchMember.state >= MatchMember.MatchMemberState.wait_pay.value,
                       MatchMember.state <= MatchMember.MatchMemberState.normal.value)
            for member in members:
                batch_refund_worker.delay(member_id=member.id)
Esempio n. 23
0
    def _unban(self, member_id):
        """
        unban 成员,并恢复到 ban 时原状态
        """

        member = MatchMember.get_or_404(id=member_id)
        match = Match.get_or_404(id=member.match_id)

        if member.state != MatchMember.MatchMemberState.banned:
            self.write_success()
        else:
            # 判断是不是人数已满等 以确定是否可以恢复
            res = match.can_join()
            if res["can"]:
                MatchMember.update(state=member.state_before_ban).where(
                    MatchMember.id == member_id).execute()
                Match.update_members_count(member.match_id)

                self.write_success()
            else:
                self.set_status(403)
                self.write({"reason": res["reason"]})
Esempio n. 24
0
    def post(self, round_id):
        match_round = MatchRound.get_or_404(id=round_id)
        match = Match.get_or_404(id=match_round.match_id)
        form = EditRoundForm(self.arguments)

        if form.validate():
            form.populate_obj(match_round)
            match_round.save()

            self.redirect(self.reverse_url("admin_match_detail", match.id))
            return

        self.render("match/round_edit.html", form=form, match=match)
Esempio n. 25
0
    def post(self, match_id):

        action = self.get_argument("action")
        match = Match.get_or_404(id=match_id)

        if action == "pass":
            Match.update(
                state=Match.MatchState.opening, updated=datetime.now()).where(
                    Match.id == match.id, Match.state <<
                    [Match.MatchState.wait_review, Match.MatchState.in_review
                     ]).execute()

        elif action == "reject":
            Match.update(
                state=Match.MatchState.rejected,
                reject_time=datetime.now(),
                reject_reason=self.get_argument("reject_reason", "")).where(
                    Match.id == match.id, Match.state <<
                    [Match.MatchState.wait_review, Match.MatchState.in_review
                     ]).execute()

        self.write_success()
Esempio n. 26
0
    def get(self, match_id):
        match = Match.get_or_404(id=match_id)
        qr = MatchService.get_preview_qrcode(match.id)
        o = io.BytesIO()
        qr.save(o, format="JPEG")
        qr_obj = o.getvalue()
        o.close()

        self.set_header('Expires', '0')
        self.set_header('Cache-Control',
                        'must-revalidate, post-check=0, pre-check=0')
        self.set_header('Content-type', 'image/jpg')
        self.set_header('Content-length', len(qr_obj))
        self.write(qr_obj)
Esempio n. 27
0
    def post(self):
        to_bucket = self.settings['qiniu_file_bucket']
        to_key = "match:rules:image:%s%s" % (self.current_user.id, time.time())
        to_key = hashlib.md5(to_key.encode()).hexdigest()
        image_key = self.upload_file('image',
                                     to_bucket=to_bucket,
                                     to_key=to_key)
        url_dict = Match.get_cover_urls(image_key)

        if url_dict:
            mini_url = url_dict['url'] + url_dict['sizes'][0]
        else:
            mini_url = ""
        self.write(mini_url)
Esempio n. 28
0
    def post(self, match_id):

        match = Match.get_or_404(id=match_id)
        form = CreateRoundForm(self.arguments)

        match_round = MatchRound(match_id=match.id)
        if form.validate():
            form.populate_obj(match_round)
            match_round.save()

            service.match.MatchService.add_match_status_notify(match)
            self.redirect(self.reverse_url("admin_match_detail", match_id))
            return

        self.render("match/round_create.html", form=form, match=match)
Esempio n. 29
0
    def can_leave(self, match: Match, user_id: int) -> bool:
        """
        赛事是否可以退出
        :param match:
        :param user_id:
        :return:
        """

        # 先判断是否加入过赛事
        self.has_joined_match(match, user_id)

        # 当前赛事状态是不是允许退出
        if match.can_leave():
            return True
        raise ApiException(422, "不满足赛事退塞条件, 无法退出")
Esempio n. 30
0
    def get(self, match_id):
        """ 获取赛事轮次列表
        """

        match = Match.get_or_404(id=match_id)

        query = MatchRound.select().where(
            MatchRound.match_id == match.id).order_by(
                MatchRound.start_time.asc())

        rounds = []
        for match_round in query:
            rounds.append(match_round.info)

        RightMember = MatchMember.alias()

        against_query = MatchAgainst.select(
            MatchAgainst, MatchMember, RightMember).join(
                MatchMember,
                on=(MatchAgainst.left_member_id == MatchMember.id
                    ).alias("left_member")).switch(MatchAgainst).join(
                        RightMember,
                        join_type=JOIN_LEFT_OUTER,
                        on=(MatchAgainst.right_member_id == RightMember.id
                            ).alias("right_member")).where(
                                MatchAgainst.match_id == match_id).order_by(
                                    MatchAgainst.start_time.asc())

        againsts = {}
        for against in against_query:
            if against.round_id not in againsts:
                againsts[against.round_id] = []

            against_info = against.info
            against_info['left_member'] = against.left_member.mini_info

            if against.right_member:
                against_info['right_member'] = against.right_member.mini_info

            againsts[against.round_id].append(against_info)

        for i in range(0, len(rounds)):
            round_id = rounds[i]['id']
            rounds[i]['against_mapping'] = againsts.get(round_id, [])

        self.write({"rounds": rounds})