Esempio n. 1
0
    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)
Esempio n. 2
0
    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)
Esempio n. 3
0
def cancel_drinking(mid):
    query = Drinking.query(Drinking.mid == mid, Drinking.is_done == False)
    drinkings = query.fetch(keys_only=True)
    if len(drinkings) == 0:
        return u'予約された飲みはありません'

    # delete drinking entry
    Drinking.delete_drinkings(drinkings)
    return u'予約された飲みをキャンセルしました'
Esempio n. 4
0
def cancel_drinking(mid):
    query = Drinking.query(Drinking.mid == mid, Drinking.is_done == False)
    drinkings = query.fetch(keys_only=True)
    if len(drinkings) == 0:
        return u'予約された飲みはありません'

    # delete drinking entry
    Drinking.delete_drinkings(drinkings)
    return u'予約された飲みをキャンセルしました'
Esempio n. 5
0
def handle_reply(text, watch_info):
    drinking = Drinking.get_key(watch_info['key']).get()
    (elms, drink_id, cancel_id, finished_id, history_id) = parse_message(text)
    if drinking:
        summary = parse_drinking_amount(text, drinking.summary)
        drinking.watches[watch_info['idx']].reply = text
        drinking.watches[watch_info['idx']].is_replied = True
        drinking.summary = summary
        if len(summary):
            msg = u'これまで合計\n'
            for kind in summary:
                msg += u'%s %d杯\n' % (kind, summary[kind])
            msg += u'飲みました!\n'
        else:
            msg = u''

        if finished_id >= 0:
            # it is finished
            msg += finish_the_drinkig(drinking)
        else:
            msg += u'引き続き大人飲みでいきましょう!'
            drinking.put()
        return msg
    else:
        return None
Esempio n. 6
0
def handle_reply(text, watch_info):
    drinking = Drinking.get_key(watch_info['key']).get()
    (elms, drink_id, cancel_id, finished_id, history_id) = parse_message(text)
    if drinking:
        summary = parse_drinking_amount(text, drinking.summary)
        drinking.watches[watch_info['idx']].reply = text
        drinking.watches[watch_info['idx']].is_replied = True
        drinking.summary = summary
        if len(summary):
            msg = u'これまで合計\n'
            for kind in summary:
                msg += u'%s %d杯\n' % (kind, summary[kind])
            msg += u'飲みました!\n'
        else:
            msg = u''
        
        if finished_id >= 0:
            # it is finished
            msg += finish_the_drinkig(drinking)
        else:
            msg += u'引き続き大人飲みでいきましょう!'
            drinking.put()
        return msg
    else:
        return None
Esempio n. 7
0
    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])
Esempio n. 8
0
def finish_drinking(mid):
    query = Drinking.query(Drinking.mid == mid, Drinking.is_done == False)
    drinkings = query.fetch(1)
    if len(drinkings) == 0:
        return u'すでに帰宅されているようです'

    # finish the drinking
    return finish_the_drinkig(drinkings[0])
Esempio n. 9
0
def finish_drinking(mid):
    query = Drinking.query(Drinking.mid == mid, Drinking.is_done == False)
    drinkings = query.fetch(1)
    if len(drinkings) == 0:
        return u'すでに帰宅されているようです'

    # finish the drinking
    return finish_the_drinkig(drinkings[0])
Esempio n. 10
0
    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)
Esempio n. 11
0
    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)
Esempio n. 12
0
def handle_result(text, info):
    drinking = Drinking.get_key(info['key']).get()
    if drinking:
        (sentiment, magnitude) = call_google_sentiment_analytics(text)
        drinking.result = text
        drinking.sentiment = sentiment
        drinking.magnitude = magnitude
        drinking.put()
        msg = u'昨日は' + get_drinking_quality_word(sentiment, magnitude) + \
              u'\n次回も大人飲みのお手伝いをします。またメッセージくださいね!'
        return msg
    else:
        return None
Esempio n. 13
0
def handle_result(text, info):
    drinking = Drinking.get_key(info['key']).get()
    if drinking:
        (sentiment, magnitude) = call_google_sentiment_analytics(text)
        drinking.result = text
        drinking.sentiment = sentiment
        drinking.magnitude = magnitude
        drinking.put()
        msg = u'昨日は' + get_drinking_quality_word(sentiment, magnitude) + \
              u'\n次回も大人飲みのお手伝いをします。またメッセージくださいね!'
        return msg
    else:
        return None
Esempio n. 14
0
def check_result():
    req_to_send = {}
    yesterday = (utc_now()+timedelta(days=-1)).replace(hour=0, minute=0, second=0, microsecond=0)
    query = Drinking.query(Drinking.start_date >= yesterday,
                           Drinking.start_date < yesterday+timedelta(days=1),
                           Drinking.result == None)
    drinkings_to_req = query.fetch()
    for drinking in drinkings_to_req:
        req_to_send[drinking.mid] = { 'key' : drinking.key.id(), 'result' : True }
        if drinking.is_done == False:
            drinking.is_done = True
            drinking.put()

    if len(req_to_send):
        send_request_message(req_to_send)
Esempio n. 15
0
def watch_drinkings():
    watches_to_send = {}
    now = utc_now()
    query = Drinking.query(Drinking.is_done == False,
                           Drinking.watches.date <= now, Drinking.watches.is_replied == False)
    drinkings_to_watch = query.fetch()
    for drinking in drinkings_to_watch:
        for i, watch in enumerate(drinking.watches):
            if watch.is_replied == False and \
               (watch.date <= now and now <= watch.date+timedelta(minutes=WATCH_TIMEOUT)):
                watches_to_send[drinking.mid] = { 'key' : drinking.key.id(), 'idx' : i }
                watch.sent_count += 1
                drinking.put()
                break

    if len(watches_to_send):
        send_watch_message(watches_to_send)
Esempio n. 16
0
def check_result():
    req_to_send = {}
    yesterday = (utc_now() + timedelta(days=-1)).replace(hour=0,
                                                         minute=0,
                                                         second=0,
                                                         microsecond=0)
    query = Drinking.query(Drinking.start_date >= yesterday,
                           Drinking.start_date < yesterday + timedelta(days=1),
                           Drinking.result == None)
    drinkings_to_req = query.fetch()
    for drinking in drinkings_to_req:
        req_to_send[drinking.mid] = {'key': drinking.key.id(), 'result': True}
        if drinking.is_done == False:
            drinking.is_done = True
            drinking.put()

    if len(req_to_send):
        send_request_message(req_to_send)
Esempio n. 17
0
def watch_drinkings():
    watches_to_send = {}
    now = utc_now()
    query = Drinking.query(Drinking.is_done == False,
                           Drinking.watches.date <= now,
                           Drinking.watches.is_replied == False)
    drinkings_to_watch = query.fetch()
    for drinking in drinkings_to_watch:
        for i, watch in enumerate(drinking.watches):
            if watch.is_replied == False and \
               (watch.date <= now and now <= watch.date+timedelta(minutes=WATCH_TIMEOUT)):
                watches_to_send[drinking.mid] = {
                    'key': drinking.key.id(),
                    'idx': i
                }
                watch.sent_count += 1
                drinking.put()
                break

    if len(watches_to_send):
        send_watch_message(watches_to_send)
Esempio n. 18
0
def is_duplicated_drinking(key):
    drinking = Drinking.get_key(key).get()
    return drinking != None
Esempio n. 19
0
def get_drinking_history(mid, num=MAX_HISTORY):
    dt = utc_now().replace(hour=0, minute=0, second=0, microsecond=0)
    query = Drinking.query(
        Drinking.mid == mid,
        Drinking.start_date < dt).order(-Drinking.start_date)
    return query.fetch(num)
Esempio n. 20
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
Esempio n. 21
0
def get_worst_dinking(mid):
    query = Drinking.query(Drinking.mid==mid, Drinking.is_done==True).order(Drinking.sentiment)
    drinkings = query.fetch(1)
    return drinkings[0] if len(drinkings) > 0 else None
Esempio n. 22
0
def get_drinking_history(mid, num=MAX_HISTORY):
    dt = utc_now().replace(hour=0, minute=0, second=0, microsecond=0)
    query = Drinking.query(Drinking.mid==mid, Drinking.start_date<dt).order(-Drinking.start_date)
    return query.fetch(num)
Esempio n. 23
0
def get_worst_dinking(mid):
    query = Drinking.query(Drinking.mid == mid,
                           Drinking.is_done == True).order(Drinking.sentiment)
    drinkings = query.fetch(1)
    return drinkings[0] if len(drinkings) > 0 else None
Esempio n. 24
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
Esempio n. 25
0
def is_duplicated_drinking(key):
    drinking = Drinking.get_key(key).get()
    return drinking != None
Esempio n. 26
0
def has_drinking(mid):
    query = Drinking.query(Drinking.mid == mid, Drinking.is_done == False)
    drinkings = query.fetch()
    return len(drinkings) > 0
Esempio n. 27
0
def has_drinking(mid):
    query = Drinking.query(Drinking.mid == mid, Drinking.is_done == False)
    drinkings = query.fetch()
    return len(drinkings) > 0