Exemple #1
0
    def typing(self, uid):
        try:
            # 바디 / 헤더
            headers = {'content-type': 'application/json'}
            body = {'recipient': {'id': uid}, 'sender_action': 'typing_on'}

            # 보낸다
            response = requests.post(self.endpoint + self.access_token,
                                     data=json.dumps(body),
                                     headers=headers,
                                     timeout=0.01)  # HACK

            j = response.json()
            if j.get('error'):
                from app.log import Logger
                Logger.log('[FB > typing] 그래프 API가 오류를 반환했습니다.', 'ERROR',
                           response.text)

        except requests.exceptions.ReadTimeout:  # HACK: https://stackoverflow.com/a/45601591
            pass
        except Exception as err:
            from app.log import Logger
            Logger.log('[FB > typing] 그래프 API 요청중 내부 오류 (Timeout 제외)', 'ERROR',
                       str(err))
        return
Exemple #2
0
def bugreport():
    if request.method == 'GET':
        u_id = request.args.get('id')
        if u_id:
            return render_template('bugreport.html', id=u_id)
        else:
            return render_template('bad.html', details='잘못된 접근이에요.')

    else:
        try:
            uid = request.form['id']
            title = request.form['title']
            details = request.form['steps_to_reproduce']

            contact = request.form.get('want_contact')
            if contact:
                contact = request.form['contact_information']

            if uid != request.args.get('id'):
                raise ValueError

            logger = Logger()
            logger.bugreport(uid, title, details, contact)

            return render_template('success.html')

        except (KeyError, ValueError):
            return render_template('bad.html', details='잘못된 접근이에요.')

        except Exception as err:
            return render_template('bad.html', details='처리되지 않은 오류입니다: ' + str(err))
Exemple #3
0
def old_deprecated():
    if request.method == 'GET':
        # Verification Test
        if request.args.get('hub.verify_token') == g_config['FACEBOOK']['OLD_VERIFY_TOKEN']:
            return request.args.get('hub.challenge')
        else:
            return 'Verification Failed!'

    if request.method == 'POST':
        try:
            req = request.get_json()

            for event in req['entry']:
                for e in event['messaging']:    # 요청의 단위 시작
                    if e.get('postback', {}).get('payload') or e.get('message'):
                        headers = {
                            'content-type': 'application/json'
                        }

                        body = {
                            'recipient': {
                                'id': e['sender']['id']
                            },
                            'message': {
                                'text': '이 버전의 급식봇은 서비스가 종료되었습니다. 새로운 급식봇5를 이용해 주세요!\n'
                                        'https://facebook.com/mealworm05/\n'
                                        '시작하기 전에 페이지 좋아요&팔로우는 필수! 아시죠?😎'
                            }
                        }

                        response = requests.post(
                            'https://graph.facebook.com/v7.0/me/messages?access_token=' +
                            g_config['FACEBOOK']['OLD_ACCESS_TOKEN'],
                            data=json.dumps(body),
                            headers=headers,
                            timeout=1.5
                        )

                        j = response.json()
                        if j.get('error'):
                            Logger.log('[OLD] 그래프 API가 오류를 반환했습니다.', 'ERROR', response.text)

                        break

        except Exception as e:
            print('F**k: {}'.format(str(e)))

        Logger.log('[OLD] Deprecated Request Processed.')
        return {
            'result': 'success',
            'details': 'Successfully processed deprecated /old request.'
        }
Exemple #4
0
    def send(self, recipient, thing, quick_replies=None):
        # 기본 헤더 / 바디
        headers = {'content-type': 'application/json'}
        body = {'recipient': {'id': recipient}, 'message': {}}

        # 단순 문자열일 때
        if isinstance(thing, str):
            body['message']['text'] = thing

        # 카드일 때
        elif isinstance(thing, MessageElements.Card):
            body['message']['attachment'] = {
                'type': 'template',
                'payload': {
                    'template_type': 'generic',
                    'elements': []
                }
            }

            for card in thing.payload:
                for key in card:
                    if type(card[key]) == str:
                        card[key] = card[key].replace('%rootdir%',
                                                      self.site_root)
                    elif type(card[key]) == list:
                        for en in enumerate(card[key]):
                            for nested_key in card[key][en[0]]:
                                card[key][en[0]][nested_key] = \
                                    card[key][en[0]][nested_key].replace('%rootdir%', self.site_root)
                body['message']['attachment']['payload']['elements'].append(
                    card)

        # 빠른 답장 추가하기
        if isinstance(quick_replies, MessageElements.QuickReply):
            body['message']['quick_replies'] = quick_replies.payload
        elif quick_replies:
            body['message']['quick_replies'] = quick_replies

        response = requests.post(self.endpoint + self.access_token,
                                 data=json.dumps(body),
                                 headers=headers,
                                 timeout=2)
        # Send에는 위 HACK을 적용하지 마세요!

        j = response.json()
        if j.get('error'):
            from app.log import Logger
            Logger.log('[FB > send] 그래프 API가 오류를 반환했습니다.', 'ERROR',
                       response.text)

        return
Exemple #5
0
 def get_meal(meal_id):
     try:
         client = MongoClient()
         db = client['mealworm5']
         meals = db.meals
         meal = meals.find_one({"meal_id": meal_id})
         if meal:
             return meal
         else:
             from app.log import Logger
             Logger.log('[DB > get_meal] {0}번 급식이 DB에 없어요.'.format(meal_id), 'INFO')
     except Exception as e:
         from app.log import Logger
         Logger.log('[DB > get_meal] {0}번 급식 DB 조회중 오류 발생!'.format(meal_id), 'ERROR', str(e))
         return None
Exemple #6
0
    def get_results(self, query, user_id, session):
        session = session_client.session_path(self.project_id,
                                              user_id + session)
        text_input = dialogflow.types.TextInput(text=query,
                                                language_code='ko_KR')
        query_input = dialogflow.types.QueryInput(text=text_input)
        response = session_client.detect_intent(session=session,
                                                query_input=query_input)

        Logger.log('[DF > get_intent] 인텐트 분석 완료.', 'INFO', '쿼리: %s' % query)

        entities = {}
        for e in response.query_result.parameters.fields:
            entities[e] = response.query_result.parameters.fields.get(
                e).string_value

        return {
            'intent': response.query_result.intent.display_name,
            'confidence': response.query_result.intent_detection_confidence,
            'entities': entities
        }
Exemple #7
0
    def search_meal(school_code, date, mealtime):
        try:
            client = MongoClient()
            db = client['mealworm5']
            meals = db.meals
            meal = meals.find_one({
                '$and': [
                    {'school_code': school_code},
                    {'date': date},
                    {'mealtime': int(mealtime)}
                ]
            })

            if meal:
                return meal
            else:
                from app.log import Logger
                Logger.log('[DB > search_meal] 급식이 DB에 없습니다.', 'INFO')
                return None
        except Exception as e:
            from app.log import Logger
            Logger.log('[DB > search_meal] DB에서 급식을 검색하 중 오류가 발생했어요..', 'INFO', str(e))
            return None
Exemple #8
0
    def save_bugreport(uid, title, details, contact):
        try:
            client = MongoClient()
            db = client['mealworm5']
            bugs = db.bugs
            bugs.insert_one({
                'report_id': '{0}_{1}'.format(
                        uid,
                        datetime.datetime.now(tz=pytz.timezone('Asia/Seoul')).strftime('%Y-%m-%d-%H-%M-%S')
                    ),
                'details': {
                    'uid': uid,
                    'title': title,
                    'details': details,
                    'contact': contact
                }
            })

        except Exception as e:
            from app.log import Logger
            Logger.log('[DB > save_bugreport] 버그 리포트 저장 실패.', 'ERROR', str(e))
            return None

        return True
Exemple #9
0
    def get_name(self, uid):
        """
        uid번 사용자의 이름을 Graph Api에서 가져온다.
        :param uid: Recipient_ID
        :return: str, 실패하면 유저N
        """
        # 페이스북 Graph Api 를 사용해 사용자의 진짜 이름을 가져옵니다.
        url = 'https://graph.facebook.com/v7.0/%s?fields=first_name,last_name&access_token=%s' \
              % (uid, self.config['FACEBOOK']['ACCESS_TOKEN'])

        try:
            resp = requests.get(url, timeout=3)
            resp_json = resp.json()
        except Exception as err:
            from app.log import Logger
            Logger.log(
                '[GP > get_name] 그래프 API 요청중 내부 오류 (Likely Timeout -> 3s).',
                'ERROR', str(err))
            return '유저{0}'.format(uid)

        if resp_json.get('error'):
            from app.log import Logger
            Logger.log('[GP > get_name] 그래프 API가 오류를 반환했습니다.', 'ERROR',
                       resp.text)

        try:
            if resp.status_code == 200:
                return resp_json['first_name']
            else:
                from app.log import Logger
                Logger.log('[Graph > get_name] API 응답 코드가 200이 아닙니다!', 'ERROR',
                           'RECIPIENT: {0}'.format(uid))
                return '유저{0}'.format(uid)
        except KeyError as e:
            from app.log import Logger
            Logger.log('[Graph > get_name] API KeyError가 발생했습니다!', 'ERROR',
                       'RECIPIENT: {0}, Error: {1}'.format(uid, str(e)))
            return '유저{0}'.format(uid)
Exemple #10
0
    def save_meal(user, meal):
        from app.log import Logger
        try:
            meal['created_date'] = datetime.datetime.now(pytz.timezone('Asia/Seoul')).strftime('%Y-%m-%d-%H-%M-%S')

            client = MongoClient()
            db = client['mealworm5']
            meals = db.meals

            m = meals.find_one({"meal_id": meal['meal_id']})

            if not m:
                meals.insert_one(meal)
                Logger.log('[DB > save_meal] 급식 저장 완료!', 'INFO')
            else:
                Logger.log('[DB > save_meal] 급식 저장 건너뜁니다... (동시 실행)!', 'WARN')

            return True

        except Exception as e:
            from app.log import Logger
            Logger.log('[DB > save_meal] 급식 저장 실패. UID: {0}'.format(user.uid), 'ERROR', str(e))
            return None
Exemple #11
0
    def process_message(self, user, req_str, g_config):
        # 1. 오브젝트 만들기

        fm = FacebookMessenger(g_config)
        fm.typing(user.uid)

        from app.log import Logger
        Logger.log('[PS > process_message] 메시지 처리 시작: {0} -> \'{1}\''.format(
            user.uid, req_str))

        # 이스터 에그
        if req_str.strip() == '올때 메로나':
            fm.send(user.uid, 'ㅇㅇㄴㅇ', Templates.QuickReplies.after_action)
            return user

        if '섹스' in req_str:
            fm.send(user.uid, '시발 진짜 세상 살기 힘드네',
                    Templates.QuickReplies.after_user_error)
            return user

        # 2. DIALOGFLOW 리퀘스트
        try:
            from app.dialogflow import DialogFlowController
            df = DialogFlowController(g_config)
            df_result = df.get_results(req_str, user.uid,
                                       user.uid + str(user.use_count))
            intent = df_result['intent']

        except Exception as e:
            from app.log import Logger
            Logger.log('[PS > process_message] DF 오류!', 'ERROR',
                       'DETAILS: {0}'.format(e))
            fm.send(
                user.uid, '죄송합니다, 급식봇에 오류가 발생했습니다.\n'
                '자세한 정보: 알 수 없는 이유로 언어 분석에 실패했습니다.\n'
                '다시 시도해 주시고 오류가 지속되면 아래의 \'버그 신고하기\'를 이용해 주세요.',
                Templates.QuickReplies.after_system_error)
            return user

        # 3. Intent 분기
        if intent == 'Action.SourceCode':
            fm.send(user.uid, '급식봇5의 소스는 여기서 보실 수 있어요!')
            card = Elements.Card(Templates.Cards.view_source)
            fm.send(user.uid, card, Templates.QuickReplies.after_action)

        elif intent == 'Communication.Swear':
            fm.send(user.uid, ':(', Templates.QuickReplies.after_user_error)

        elif intent == 'Communication.Yes':
            fm.send(user.uid, ':)', Templates.QuickReplies.default)

        elif intent == 'Communication.Calling':
            fm.send(user.uid, '네, 여기 있어요.', Templates.QuickReplies.default)

        elif intent == 'Communication.ThankYou':
            fm.send(user.uid, '고마워요!', Templates.QuickReplies.default)

        elif intent == 'Action.Report':
            return self.process_postback(user, 'BUGREPORT', g_config)

        elif intent == 'Action.Help':
            return self.process_postback(user, 'HELP', g_config)

        elif intent == 'Communication.Hi':
            fm.send(user.uid, '안녕하세요, {0}님!'.format(user.name),
                    Templates.QuickReplies.default)

        elif intent == 'Communication.Bye':
            fm.send(user.uid, '👋', Templates.QuickReplies.default)

        elif intent == 'Action.GetMeal':  # 급식
            # i. 엔티티 추출 및 가공
            entities = df_result['entities']

            # 날짜 엔티티가 비어있는 경우 오늘 날짜로 만들어버리기
            if entities['date-time'] == '':
                d = datetime.datetime.now(pytz.timezone('Asia/Seoul'))
                entities['date-time'] = d.strftime(
                    '%Y-%m-%d') + 'T12:00:00+09:00'

            # mealtime 변환
            if entities['MealTime'] == '조식':
                mealtime = 1
            elif entities['MealTime'] == '석식':
                mealtime = 3
            else:
                mealtime = 2

            # ii. 학교명 유무에 따라 분기
            if (entities['SchoolName'] != '') or (user.last_school_code !=
                                                  ''):  # 학교명이 어디든 일단 있는경우
                if entities['SchoolName'] != '':  # 학교명을 직접 지정한 경우
                    try:
                        from app.neis import NEIS
                        neis = NEIS(g_config)
                        school_name = entities['SchoolName'].strip()

                        # 하드코딩된 화이트리스트에 있으면 대체
                        school_name_whitelist = {
                            '한대부중': '한양대학교사범대학부속중학교',
                            '한대부고': '한양대학교사범대학부속고등학교',
                            '서울과고': '서울과학고',
                            '경기과고': '경기과학고',
                            '세종과고': '세종과학고',
                            '한성과고': '한성과학고'
                        }
                        if school_name in school_name_whitelist:
                            school_name = school_name_whitelist[school_name]

                        school_list = neis.search_school(school_name)
                    except Exception as e:
                        fm.send(
                            user.uid, '학교 조회 중 오류가 발생했습니다. 잠시 후 다시 시도해 주세요.\n'
                            '문제가 계속될 경우, 아래 \'버그 신고하기\'로 신고해 주세요.',
                            Templates.QuickReplies.after_system_error)

                        Logger.log(
                            '[PS > process_message] 나이스 학교 조회중 오류!', 'ERROR',
                            'RECIPIENT: {0}, DETAILS: {1}, VALUE: {2}'.format(
                                user.uid, str(e), entities['SchoolName']))

                        return user

                    if len(school_list) == 0:  # 일치하는 학교가 없는 경우
                        fm.send(
                            user.uid, '학교 \'{0}\'를 찾을 수 없어요.'.format(
                                entities['SchoolName']),
                            Templates.QuickReplies.after_user_error)

                        return user

                    elif len(school_list) > 1:  # 나이스에서 2개 이상의 학교를 찾음
                        # 안내 메시지 보내기
                        fm.send(user.uid,
                                '여러 학교가 검색되었어요. 원하는 학교의 버튼을 선택해 주세요.')
                        fm.typing(user.uid)

                        [_, month,
                         day] = entities['date-time'].split('T')[0].split('-')

                        # 카드 만들어서 붙이기
                        school_cards = []
                        for sch in school_list:
                            school_cards.append({
                                'title':
                                sch.name + ' (%s)' % sch.region_hangul,
                                'image_url':
                                '',
                                'subtitle':
                                sch.address,
                                'buttons': [{
                                    'type':
                                    'postback',
                                    'title':
                                    '{0}월 {1}일 {2} ({3}) 의 급식 보기'.format(
                                        month, day, sch.name,
                                        sch.region_hangul),
                                    'payload':
                                    'M_{0}_{1}_{2}'.format(
                                        sch.code,
                                        entities['date-time'].split('T')[0],
                                        str(mealtime))
                                }]
                            })

                        # 유저한테 보내기
                        card = Elements.Card(school_cards)
                        fm.send(user.uid, card)
                        return user

                    else:  # 힉교가 정상적으로 하나만 나옴
                        sch = school_list[0]
                        self.process_postback(
                            user, 'M_{0}_{1}_{2}'.format(
                                sch.code, entities['date-time'].split('T')[0],
                                str(mealtime)), g_config)
                else:  # 학교명을 생략한 경우 -> 디비에 저장된 마지막 요청 학교를 가져온다.
                    self.process_postback(
                        user, 'M_{0}_{1}_{2}'.format(
                            user.last_school_code,
                            entities['date-time'].split('T')[0],
                            str(mealtime)), g_config)

            else:  # 학교 이름을 지정하지도 않았고 전에 사용한 기록도 없음.
                # 에러 / Abort
                fm.send(user.uid,
                        '이전에 요청한 학교가 없습니다. 처음 요청 시에는 학교 이름을 포함해서 요청해 주세요.',
                        Templates.QuickReplies.after_user_error)
                return user

        else:  # Unknown Intent
            Logger.log(
                '[PS > process_message] 알 수 없는 인텐트입니다: {0}. RECIPIENT: {1}'.
                format(intent, user.uid), 'WARN')
            fm.send(user.uid, '무슨 뜻인지 잘 모르겠어요.',
                    Templates.QuickReplies.after_user_error)
            return user

        return user
Exemple #12
0
import os
from flask import Blueprint, request, jsonify, send_from_directory, current_app
from app.utils import SQL
from app.models.file import File
from app.models.user import User
from app.models.login import Login
from app.config import BASE_DIR
from pymysql import escape_string
from app.log import Logger

file = Blueprint("file", __name__)
log = Logger("file.log")


# [accesstoken]
# [format] 文件格式
@file.route('list', methods=['GET', 'POST'])
def get_list():
    try:
        pass
        # 权限鉴定
    except Exception as e:
        log.logger.warning(e)
        return jsonify({"status": "failed", "data": "错误请求"})


@file.route('download', methods=['GET', 'POST'])
def get_file():
    try:
        from .utils import get_obj_auth
Exemple #13
0
from app.template import render
from app.log import Logger

logger = Logger('main')


class TemplateView:
    template_name = 'template.html'

    def get_context_data(self):
        return {}

    def get_template(self):
        return self.template_name

    def render_template_with_context(self):
        template_name = self.get_template()
        context = self.get_context_data()
        logger.log(template_name)
        return '200 OK', render(template_name, **context)

    def __call__(self, request):
        return self.render_template_with_context()


class ListView(TemplateView):
    queryset = []
    template_name = 'list.html'
    context_object_name = 'objects_list'

    def get_queryset(self):
Exemple #14
0
def hello_world():
    # Make it Ra1n
    Logger.log('Hello, world!', 'INFO', 'This is a test.')
    return '<code>Notice Me!</code>'
Exemple #15
0
from flask import Blueprint, request, jsonify
from app.extensions import db
from app.models import people
from pymysql import escape_string
from app.utils import SQL
from app.log import Logger
sz = Blueprint('szjs', __name__)
log = Logger("sz.log")


# 师资团队列表
# 人数多的情况下可以按页查询
@sz.route('list', methods=['GET', 'POST'])
def get_list():
    try:
        page = int(request.args.get('page') or "1")
        psize = int(request.args.get('psize') or "50")
        pno = (page - 1) * psize
        s = SQL()
        # 按职称分别查询
        job = ["教授", "副教授", "讲师", "其他"]
        res = {}
        for t in job:
            condition = "where job = '%s'" % t
            sql = "select `id`,`name`,`header`,`job` from `people` where `job` = '%s';" % t
            res[t] = s.query(sql)
        return jsonify({"status": "ok", "data": res})
    except Exception as e:
        log.logger.warning(e)
        return jsonify({"status": "failed", "data": "error:%s" % e})
Exemple #16
0
from flask import Blueprint, request, jsonify
from app.utils import SQL
from app.models.news import News
from pymysql import escape_string
from app.log import Logger
news = Blueprint('news', __name__)
log = Logger(filename="news.log")


# 获取新闻列表
# 新闻类别
# page - 新闻页数
# psize - 每页条数
@news.route('list', methods=['GET', 'POST'])
def get_list():
    try:
        page = int(request.args.get('page') or "1")
        psize = int(request.args.get('psize') or "8")
        ntype = escape_string(request.args.get("type") or "news")

        pno = (page - 1) * psize
        s = SQL()
        # 补充查询条件
        condition = "where 1 = 1 and `status` = 'valid' and `type` = '%s'" % ntype
        sql = "select `id`,`title`,`pub_date`,`album`,`author`,`type` from " \
              "(select * from `news` order by pub_date desc ) tmp %s limit %d , %d" % (condition, pno, psize)
        return jsonify({"status": "ok", "data": s.query(sql)})
    except Exception as e:
        print(e)
        log.logger.warning(e)
        return jsonify({"status": "failed", "data": "error:%s" % e})
Exemple #17
0
import math
import pymysql
from app.config import ProductionConfig as Pr
from app.log import Logger
log = Logger("SQL.log")


def custom_paginator(current_page, num_page, max_page):
    middle = math.ceil(max_page / 2)
    if num_page <= max_page:
        start = 1
        end = num_page
    elif current_page <= middle:
        start = 1
        end = max_page
    elif middle < current_page < num_page - middle + 1:
        start = current_page - middle
        end = current_page + middle - 1
    else:
        start = num_page - max_page + 1
        end = num_page
    return start, end


class SQL:
    db = None

    def __init__(self):
        # 读入配置文件
        self.db = pymysql.connect(host=Pr.SQL_HOST,
                                  user=Pr.SQL_USER,
Exemple #18
0
from flask import Blueprint, request, jsonify
from app.utils import SQL
from .utils import check_mani
from app.models import notice
from pymysql import escape_string
from app.log import Logger
notice = Blueprint('notice', __name__)
log = Logger("notice.log")


@notice.route("list", methods=['GET', 'POST'])
def get_list():
    try:
        page = int(request.args.get('page') or "1")
        psize = int(request.args.get('psize') or "8")
        pno = (page - 1) * psize
        s = SQL()
        condition = "where 1 = 1"
        sql = "select `id`,`pub_date`,`tag`,`title`,`type` from (select * from `notice` order by pub_date desc ) " \
              "tmp %s limit %d , %d " % (condition, pno, psize)
        return jsonify({"status": "ok", "data": s.query(sql)})
    except Exception as e:
        log.logger.warning(e)
        return jsonify({"status": "failed", "data": "error:%s" % e})


# 公告详情
# id
@notice.route("detail", methods=['GET', 'POST'])
def get_detail():
    try:
Exemple #19
0
def webhook():
    # Verification Test
    if request.method == 'GET':
        if request.args.get('hub.verify_token') == g_config['FACEBOOK']['VERIFY_TOKEN']:
            return request.args.get('hub.challenge')
        else:
            return 'Verification Failed!'

    # Messenger Callback
    if request.method == 'POST':
        try:
            req = request.get_json()
            for event in req['entry']:
                for e in event['messaging']:
                    # 메시지 시작
                    # 에코 메시지라면 스킵
                    if e.get('message', {}).get('is_echo'):
                        continue

                    # 1. 디비에서 사용자 정보 가져오기
                    try:
                        usr = db.get_user(e['sender']['id'], g_config)
                    except Exception as err:
                        Logger.log(f'[APP] db.get_user 오류', 'ERROR', str(err))

                        from app.facebook import FacebookMessenger
                        from app.template import Templates
                        fm = FacebookMessenger(g_config)
                        fm.send(e['sender']['id'], '데이터베이스 오류가 발생했습니다. 잠시 후 다시 이용해주세요.',
                                Templates.QuickReplies.after_system_error)
                        continue

                    # 1.1. 신규 유저
                    if not usr:
                        usr = User({'new_user': True, 'uid': e['sender']['id']}, g_config)
                        Logger.log(f'[APP] 신규 유저: {usr.uid}', 'INFO')

                    # 2. 포스트백 처리
                    if e.get('postback', {}).get('payload'):
                        usr = ps.process_postback(usr, e['postback']['payload'], g_config)
                        try:
                            db.save_user(usr)
                            Logger.log(f'[APP] 포스트백 처리후 유저 {usr.uid} 세이브 완료.', 'INFO')
                        except Exception as err:
                            Logger.log(f'[APP] 포스트백 처리후 유저 {usr.uid} 세이브중 오류 발생!', 'ERROR', str(err))

                            from app.facebook import FacebookMessenger
                            from app.template import Templates
                            fm = FacebookMessenger(g_config)
                            fm.send(e['sender']['id'], '데이터베이스 오류가 발생했습니다. 잠시 후 다시 이용해주세요.',
                                    Templates.QuickReplies.after_system_error)
                        continue

                    # 3. 메시지 처리
                    elif e.get('message'):
                        # 3.1. 빠른 답장 포스트백 처리
                        if e['message'].get('quick_reply', {}).get('payload'):
                            usr = ps.process_postback(usr, e['message']['quick_reply']['payload'], g_config)
                            try:
                                db.save_user(usr)
                                Logger.log(f'[APP] 빠른 답장 처리후 유저 {usr.uid} 세이브 완료.', 'INFO')
                            except Exception as err:
                                Logger.log(f'[APP] 빠른 답장 처리후 유저 {usr.uid} 세이브중 오류 발생!', 'ERROR', str(err))

                                from app.facebook import FacebookMessenger
                                from app.template import Templates
                                fm = FacebookMessenger(g_config)
                                fm.send(e['sender']['id'], '데이터베이스 오류가 발생했습니다. 잠시 후 다시 이용해주세요.',
                                        Templates.QuickReplies.after_system_error)
                            continue

                        # 3.2. 텍스트 메시지 처리
                        if e['message'].get('text'):
                            usr = ps.process_message(usr, e['message']['text'], g_config)
                            try:
                                db.save_user(usr)
                                Logger.log(f'[APP] 메시지 처리후 유저 {usr.uid} 세이브 완료.', 'INFO')
                                # 최적화: 전날 급식 캐시 제거
                            except Exception as err:
                                Logger.log(f'[APP] 메시지 처리후 유저 {usr.uid} 세이브중 오류 발생!', 'ERROR', str(err))

                                from app.facebook import FacebookMessenger
                                from app.template import Templates
                                fm = FacebookMessenger(g_config)
                                fm.send(e['sender']['id'], '데이터베이스 오류가 발생했습니다. 잠시 후 다시 이용해주세요.',
                                        Templates.QuickReplies.after_system_error)
                            continue

                        # 1-2-3. 첨부파일 등이 있는 메시지
                        if e['message'].get('attachments'):
                            ps.process_postback(usr, 'ATTACHMENTS', g_config)
                            continue

                    try:
                        db.save_user(usr)
                        Logger.log(f'[APP] 처리 없이 유저 {usr.uid} 세이브 완료.', 'INFO')
                    except Exception as err:
                        Logger.log(f'[APP] 처리 없이 유저 {usr.uid} 세이브중 오류 발생!', 'ERROR', str(err))

                        from app.facebook import FacebookMessenger
                        from app.template import Templates
                        fm = FacebookMessenger(g_config)
                        fm.send(e['sender']['id'], '데이터베이스 오류가 발생했습니다. 잠시 후 다시 이용해주세요.',
                                Templates.QuickReplies.after_system_error)

            return {'result': 'success'}

        except Exception as err:
            traceback.print_exc()
            Logger.log(f'[APP] 알 수 없는 치명적 오류 발생!', 'ERROR', str(err))

            try:
                from app.facebook import FacebookMessenger
                from app.template import Templates
                fm = FacebookMessenger(g_config)
                fm.send(e['sender']['id'],
                        f'죄송합니다, 급식봇에 처리되지 않은 오류가 발생했습니다.\n'
                        f'다시 시도해 주시고, 계속 오류가 발생할 경우 아래 \'버그 신고하기\' '
                        f'기능을 통해서 신고해 주세요.{str(err)}',
                        Templates.QuickReplies.after_system_error)
            except:
                pass

            return {'result': 'error'}  # 오류시에도 200 리턴
Exemple #20
0
    def process_postback(user, payload, g_config):
        # 1. 오브젝트 만들기
        from app.facebook import FacebookMessenger
        fm = FacebookMessenger(g_config)
        fm.typing(user.uid)

        from app.log import Logger
        Logger.log('[PS > process_postback] 요청: {0}->\'{1}\''.format(
            user.uid, payload))

        # 2. 페이로드 분기
        if payload == 'FACEBOOK_WELCOME':
            fm.send(user.uid, '안녕하세요, {0}님! 만나서 반가워요🤗'.format(user.name))
            fm.send(user.uid, '저는 급식봇이라고 해요.')
            fm.send(
                user.uid, '제 안에 있는 인공지능 덕분에 저는 다양한 말을 알아들을 수 있어요😎\n'
                '이제 제가 할 수 있는 일을 알아볼까요?', Templates.QuickReplies.intro)
            return user

        elif payload == 'INTRO_MORE':
            card = Elements.Card(Templates.Cards.intro_features)
            fm.send(user.uid, card)
            return user

        # 사용법
        elif payload == 'HELP':
            # 1/3 (Text)
            msg_str = '다양한 방법으로 급식을 가져올 수 있어요!\n' \
                      '예시:\n' \
                      '> 급식고등학교 내일 저녁\n' \
                      '> 3월 14일 급식고등학교 급식\n' \
                      '> 급식고등학교\n' \
                      '> 내일은?\n' \
                      '기본값은 오늘 날짜의 중식이에요.'
            fm.send(user.uid, msg_str)

            # 2/3 (Text)
            msg_str = '학교 이름을 생략한 경우, 바로 전에 요청하셨던 학교의 급식을 자동으로 가져올 거에요.\n' \
                      '예시:\n' \
                      '12:00 > 오늘 다솜중 급식이 뭐야?\n' \
                      '12:01 > 내일은?\n' \
                      '그렇기 때문에, 위의 경우에는 다솜중학교의 \'내일\' 급식을 가져옵니다.'
            fm.send(user.uid, msg_str)

            # 3/3 (Text)
            fm.send(user.uid, '혹시라도 잘 이해가 가지 않으시면 그냥 학교 이름을 입력해 보세요.')

            return user

        # 급식 급식 급식!
        elif payload.startswith('M_'):
            # user.use_count 를 올린다.
            user.use_count = user.use_count + 1

            # 파라미터 값을 추출한다.
            [_, school_code, tmp_date, mealtime] = payload.split('_')
            user.last_school_code = school_code
            date = datetime.datetime.strptime(tmp_date, '%Y-%m-%d')

            # 급식 가져오기
            from app.neis import NEIS
            neis = NEIS(g_config)

            try:
                sch = neis.school_from_code(school_code)
            except ValueError as e:
                fm.send(user.uid, '나이스 조회중 오류가 발생했습니다: 중복 조회되었습니다.',
                        Templates.QuickReplies.after_system_error)
                Logger.log('[PS > process_postback] 나이스 재조회중 학교 중복 오류!',
                           'ERROR', str(e))
                return user
            except Exception as e:
                fm.send(user.uid, '나이스 조회중 오류가 발생했습니다: 알 수 없는 오류.',
                        Templates.QuickReplies.after_system_error)
                Logger.log('[PS > process_postback] 나이스 재조회중 기타 오류!', 'ERROR',
                           str(e))
                return user

            db_meal = db.search_meal(school_code, tmp_date, mealtime)
            if db_meal:  # 디비에서 저장된 급식을 가져왔을 때
                meal = db_meal['meal']
                meal_id = db_meal['meal_id']
                nutrition = db_meal['nutrition']
            else:  # 디비에 없을때
                meal_id = '#{0}{1}'.format(user.uid, user.use_count)
                try:
                    meal, nutrition = sch.get_meal(date, int(mealtime))
                except TypeError:
                    # 급식이 없음
                    meal = []
                    nutrition = None
                except Exception as e:
                    Logger.log('[PS > process_postback] 급식 조회 중 오류!', 'ERROR',
                               str(e))
                    fm.send(user.uid, '급식 조회중 오류가 발생했습니다: 처리되지 않은 오류.',
                            Templates.QuickReplies.after_system_error)
                    return user

            if int(mealtime) == 1:
                mt_text = '아침'
            elif int(mealtime) == 3:
                mt_text = '저녁'
            else:
                mt_text = '점심'

            # 잘 포장해서 보낸다
            if len(meal) != 0:  # 급식이 존재할 때
                meal_text = ''
                for menu in meal:
                    meal_text = meal_text + menu + '\n'
                meal_text = meal_text.rstrip()

                # 랜덤으로 보내기
                from random import randint
                rand_num = randint(0, 11)

                if rand_num == 0:
                    fm.send(user.uid,
                            '급식봇을 {0}번째로 사용하고 계시네요!'.format(user.use_count))
                else:
                    msg_str = [
                        '',  # 0
                        '이 냄새는 바로!',
                        '반찬 남기지 마세요',
                        '골고루 드세요',
                        '헤헷',
                        '어디서 주웠어요.',
                        '오다가 잊어버릴 뻔했어요',
                        '훗',
                        '오다가 주웠어요',
                        '히힛',
                        '맛나게 드십쇼',
                        '맛있게 드세요'
                    ]
                    fm.send(user.uid, msg_str[rand_num])

                quick_replies = Templates.QuickReplies.after_meal
                quick_replies[0]['payload'] = 'N_{0}'.format(meal_id)

                # 급식을 보낸다
                fm.send(
                    user.uid, '{0} {1}/{2}\n급식 #{3}:\n{4}'.format(
                        tmp_date, sch.name, mt_text, meal_id[-6:], meal_text),
                    quick_replies)

                if not db_meal:
                    # FS에 급식을 세이브한다.
                    me = {
                        'meal_id': meal_id,
                        'meal': meal,
                        'school_code': school_code,
                        'school_name': sch.name,
                        'date': tmp_date,
                        'mealtime': int(mealtime),
                        'nutrition': nutrition
                    }
                    db.save_meal(user, me)

                return user

            else:  # 밥없음
                fm.send(
                    user.uid,
                    '%d년 %d월 %d일 %s의 %s 메뉴가 없어요.\n(또는 나이스에 등록이 안된 것일수도 있어요.)' %
                    (int(date.year), int(date.month), int(
                        date.day), sch.name, mt_text),
                    Templates.QuickReplies.after_nutrition)

            return user

        # 영양소 정보 보기
        elif payload.startswith('N_'):
            # 파라미터 값을 추출한다.
            _, meal_code = payload.split('_')

            # 급식 NO. 를 이용해서 급식을 가져온다.
            db_meal = db.get_meal(meal_code)
            if db_meal:  # 디비에서 저장된 급식을 가져왔을 때
                nutrition = db_meal['nutrition']  # str
                date = db_meal['date']
                school_name = db_meal['school_name']
                mealtime_hangul = ['아침', '점심',
                                   '저녁'][int(db_meal['mealtime']) - 1]

                fm.send(
                    user.uid, '{0} {1}의 {2} 메뉴: 영양소 정보:\n{3}'.format(
                        date, school_name, mealtime_hangul, nutrition),
                    Templates.QuickReplies.after_nutrition)

                return user
            else:  # 디비에 없을때
                fm.send(user.uid, '죄송합니다, DB에서 급식의 영양소 정보를 찾을 수 없었어요.',
                        Templates.QuickReplies.after_system_error)
                return user

        elif payload == 'BUGREPORT':
            fm.send(user.uid, '아래 버튼을 눌러서 신고해주세요.')

            tmp_c = Templates.Cards.bug_report
            tmp_c[0]['buttons'][0]['url'] += user.uid
            card = Elements.Card(tmp_c)
            fm.send(user.uid, card, Templates.QuickReplies.after_action)

            return user

        elif payload == 'ATTACHMENTS':
            fm.send(user.uid, ':)', Templates.QuickReplies.after_action)
            return user

        return user
Exemple #21
0
from flask import Blueprint, request, jsonify
from app.extensions import db
from app.models import user, login
from app.log import Logger
from app.utils import SQL
from pymysql import escape_string

users = Blueprint('users', __name__)
log = Logger("user.log")


@users.route('/query', methods=['GET', 'POST'])
def index():
    try:
        s = SQL()
        sql = "select * from `user`"
        return jsonify({"status": "ok", "data": s.query(sql)})
    except Exception as e:
        log.logger.warning(e)
        return jsonify({"status": "failed", "data": "error:%s" % e})


# 注册、添加用户
# 账号
# 密码
# 验证码
@users.route('/add', methods=['GET', 'POST'])
def add_user():
    try:
        pass
    except Exception as e: