def testResult(self):
        test_id = 'test'
        watches = []
        now_utc = utc_now() + timedelta(days=-1)
        for i in range(WATCH_COUNTS):
            watches.append(
                Watch(date=now_utc + timedelta(seconds=WATCH_INTERVAL *
                                               (i + 1)),
                      sent_count=1,
                      is_replied=True))

        drinking = Drinking(id=test_id,
                            mid=test_id,
                            start_date=now_utc,
                            is_done=True,
                            watches=watches)
        drinking.put()

        check_result()
        (status, info) = get_status(test_id)
        self.assertEqual(status, User.STAT_WAIT_RESULT)

        result = u'二日酔い'
        msg = handle_result(result, info)

        drinking = Drinking.get_key(test_id).get()
        self.assertEqual(drinking.result, result, drinking.result)
        self.assertEqual(drinking.sentiment, 0.0)
        self.assertEqual(drinking.magnitude, 0.0)
        self.assertTrue(msg.find(u'次回も大人飲み') >= 0, msg)
    def testWatchFinished(self):
        TEST_INTERVAL = 5
        test_id = 'test'
        watches = []
        now_utc = utc_now() + timedelta(seconds=TEST_INTERVAL)
        for i in range(WATCH_COUNTS):
            watches.append(
                Watch(date=now_utc + timedelta(seconds=TEST_INTERVAL *
                                               (i + 1))))

        drinking = Drinking(id=test_id,
                            mid=test_id,
                            start_date=now_utc,
                            watches=watches)
        drinking.put()

        sleep(TEST_INTERVAL * 2 + 2)

        watch_drinkings()
        (stat, info) = get_status(test_id, is_peek=True)
        msg = handle_reply(u'帰宅した', info)
        self.assertTrue(msg.startswith(u'お疲れさまでした'), msg)

        drinking = Drinking.get_key(test_id).get()
        self.assertEqual(drinking.finished_date.year, now_utc.year)
        self.assertEqual(drinking.finished_date.month, now_utc.month)
        self.assertEqual(drinking.finished_date.day, now_utc.day)
        self.assertEqual(drinking.finished_date.hour, now_utc.hour)
        for j, watch in enumerate(drinking.watches):
            self.assertEqual(watch.is_replied, True if j == 0 else False)
            self.assertEqual(watch.sent_count, 1 if j == 0 else 0)
        self.assertTrue(drinking.is_done)
    def testWatchDelayed(self):
        TEST_INTERVAL = 5
        test_id = 'test'
        watches = []
        now_utc = utc_now() + timedelta(seconds=TEST_INTERVAL)
        for i in range(WATCH_COUNTS):
            watches.append(
                Watch(date=now_utc + timedelta(seconds=TEST_INTERVAL *
                                               (i + 1))))

        drinking = Drinking(id=test_id,
                            mid=test_id,
                            start_date=now_utc,
                            watches=watches)
        drinking.put()

        sleep(TEST_INTERVAL * 2 + 2)

        for i in range(5):
            watch_drinkings()
            (status, info) = get_status(test_id, True)
            self.assertEqual(status, User.STAT_WAIT_REPLY)
            self.assertTrue(info is not None)
            self.assertEqual(info['key'], test_id, info['key'])
            self.assertEqual(info['idx'], 0)
            drinking = Drinking.get_key(test_id).get()
            for j, watch in enumerate(drinking.watches):
                self.assertEqual(watch.is_replied, False)
                self.assertEqual(watch.sent_count, i + 1 if j == 0 else 0)

        drinking = Drinking.get_key(test_id).get()
        self.assertFalse(drinking.is_done)
    def testWatch(self):
        TEST_INTERVAL = 10
        test_id = 'test'
        watches = []
        now_utc = utc_now() + timedelta(seconds=TEST_INTERVAL)
        for i in range(WATCH_COUNTS):
            watches.append(
                Watch(date=now_utc + timedelta(seconds=TEST_INTERVAL *
                                               (i + 1))))

        drinking = Drinking(id=test_id,
                            mid=test_id,
                            start_date=now_utc,
                            watches=watches)
        drinking.put()

        sleep(TEST_INTERVAL + 2)

        for i in range(WATCH_COUNTS):
            sleep(TEST_INTERVAL)

            watch_drinkings()
            (status, info) = get_status(test_id, is_peek=True)
            self.assertEqual(status, User.STAT_WAIT_REPLY)
            self.assertTrue(info is not None)
            self.assertEqual(info['key'], test_id, info['key'])
            self.assertEqual(info['idx'], i, info['idx'])
            drinking = Drinking.get_key(test_id).get()
            for j, watch in enumerate(drinking.watches):
                self.assertEqual(watch.is_replied, True if j < i else False)
                self.assertEqual(watch.sent_count, 1 if j <= i else 0)

            self.assertFalse(drinking.is_done)
            content = {
                "events": [{
                    "replyToken": "xxxx",
                    "type": "message",
                    "source": {
                        "type": "user",
                        "userId": test_id
                    },
                    "message": {
                        "type": "text",
                        "text": "OK"
                    }
                }]
            }
            recv_req = WebhookRequest(json.dumps(content))
            receive_message(recv_req)
            (status, info) = get_status(test_id)
            self.assertEqual(status, User.STAT_NONE)
            drinking = Drinking.get_key(test_id).get()
            for j, watch in enumerate(drinking.watches):
                self.assertEqual(watch.is_replied, True if j <= i else False)
                self.assertEqual(watch.sent_count, 1 if j <= i else 0)

        drinking = Drinking.get_key(test_id).get()
        self.assertFalse(drinking.is_done)
    def testHistory(self):
        test_id = 'test'
        test_msgs = [u'過去の飲みは?', u'これまでの呑みを', u'今までの呑みは?', u'前の呑み']
        for test_msg in test_msgs:
            msg = handle_message(test_id, test_msg)
            self.assertTrue(msg.startswith(u'まだ飲みの'), msg)

        user = User(id=test_id)
        user.put()
        for test_msg in test_msgs:
            msg = handle_message(test_id, test_msg)
            self.assertTrue(msg.startswith(u'過去の飲みは'), msg)

        user = User.get_key(test_id).get()
        self.assertTrue(user.history_url != None and len(user.history_url) > 0)
        self.assertTrue(user.history_expire < utc_now() +
                        timedelta(minutes=HISTORY_DURATION))

        sdt = utc_now() + timedelta(days=-2)
        check_sdt = []
        for i in range(MAX_HISTORY + 1):
            watches = []
            for j in range(WATCH_COUNTS):
                watches.append(
                    Watch(date=sdt + timedelta(minutes=WATCH_INTERVAL *
                                               (i + 1))))

            key = test_id + sdt.strftime('%Y%m%d%H%M')
            drinking = Drinking(id=key,
                                mid=test_id,
                                start_date=sdt,
                                watches=watches)
            drinking.put()
            check_sdt.append(
                format_jdate(sdt.replace(tzinfo=tz_utc).astimezone(tz_jst)))
            sdt = sdt + timedelta(days=-1)

        self.assertEqual(get_drinking_history_content(user.history_url[:-1]),
                         None)

        soup = BeautifulSoup(get_drinking_history_content(user.history_url),
                             'html.parser')
        trs = soup.body.div.table.tbody.findAll('tr')
        self.assertEqual(len(trs), MAX_HISTORY * 2)
        for i in range(MAX_HISTORY):
            self.assertEqual(trs[i * 2].td.text, check_sdt[i])
Exemple #6
0
def handle_message(user_id, msg):
    mid = user_id
    (elms, drink_id, cancel_id, finished_id, history_id) = parse_message(msg)

    if history_id >= 0 and drink_id >= 0 and depends_drink(
            history_id, elms, drink_id):
        # this is request for drinking history
        return history_drinking(mid)

    if finished_id >= 0:
        # this is finish message
        return finish_drinking(mid)

    if cancel_id >= 0:
        # this is cancel message
        return cancel_drinking(mid)

    if drink_id == -1:
        # this is not nomi message...
        return None

    # user can have only one drink
    if has_drinking(mid):
        return u'飲みは1つしか予約できません。予約した飲みをキャンセルするには「やめ」とメッセージしてください。'

    # 3rd, determine date and time
    now = utc_now().replace(second=0, microsecond=0)
    s_date = datetime.now(tz=tz_jst).replace(second=0, microsecond=0)
    for id, elm in elms.items():
        if depends_drink(id, elms, drink_id):
            start_info = ''
            for morphem in elm['morphemlist']:
                start_info += morphem['surface']

            # find time
            time_patterns = [
                u'(\d\d)[時じ::](\d\d)\D', '(\d\d)(\d\d)', u'(\d+)[時じ::](\d+)',
                u'(\d+)[時じ]'
            ]
            for pattern in time_patterns:
                mo = re.search(pattern, start_info)
                if mo:
                    hour = int(mo.group(1))
                    minute = int(mo.group(2)) if mo.lastindex == 2 else 0
                    if hour < 12 and \
                       (start_info.find('PM') >= 0 or
                        start_info.find('pm') >= 0 or
                        start_info.find(u'午後') >= 0 or
                        start_info.find(u'ごご') >= 0):
                        hour += 12
                    s_date = s_date.replace(hour=hour, minute=minute)
                    break

            # find date
            if start_info.find(u'明日') >= 0 or \
               start_info.find(u'あした') >= 0 or \
               start_info.find(u'あす') >= 0:
                s_date = s_date + timedelta(days=1)
            elif start_info.find(u'明後日') >= 0 or \
                 start_info.find(u'あさって') >= 0:
                s_date = s_date + timedelta(days=2)
            else:
                date_patterns = [u'(\d+)月(\d+)', '(\d+)/(\d+)']
                for pattern in date_patterns:
                    mo = re.search(pattern, start_info)
                    if mo:
                        month = int(mo.group(1))
                        day = int(mo.group(2))
                        s_date = s_date.replace(month=month, day=day)
                        break

    # store data
    watches = []
    utc_s_date = s_date.astimezone(tz_utc).replace(tzinfo=None)
    s_date_str = u'%d月%d日%d時%d分' % (s_date.month, s_date.day, s_date.hour,
                                    s_date.minute)

    # check if s_date is valid
    if utc_s_date < now:
        # past date !!
        return s_date_str + u'は過去です。'

    # check duplicate
    key = mid + s_date.strftime('%Y%m%d%H%M')
    if is_duplicated_drinking(key):
        return s_date_str + u'からの飲みは登録済みです。'

    for i in range(WATCH_COUNTS):
        watches.append(
            Watch(date=utc_s_date + timedelta(minutes=WATCH_INTERVAL *
                                              (i + 1))))

    drinking = Drinking(id=key,
                        mid=mid,
                        start_date=utc_s_date,
                        watches=watches)
    drinking.put()

    msg = s_date_str + u'から飲むのですね!\n約%d分毎に%d回メッセージを送信しますので、何を何杯飲んだかなど、状況を返信してくださいね。帰宅したら帰宅とメッセージしてください。' % (
        WATCH_INTERVAL, WATCH_COUNTS)

    # past drinkings
    query = Drinking.query(
        Drinking.mid == mid,
        Drinking.is_done == True).order(-Drinking.start_date)
    prev_drinkings = query.fetch(1)
    if len(prev_drinkings):
        prev_drinking = prev_drinkings[0]
        msg += u'\n\nちなみに前回の飲みは%sで、その時は%s\n' % (format_jdate(
            prev_drinking.start_date.replace(
                tzinfo=tz_utc).astimezone(tz_jst)),
                                                get_drinking_quality_word(
                                                    prev_drinking.sentiment,
                                                    prev_drinking.magnitude))
        sep = u''
        for kind in prev_drinking.summary:
            msg += sep + u'   %s %d 杯' % (kind, prev_drinking.summary[kind])
            sep = u'\n'

    return msg