Skip to content

Commit 15eb569

Browse files
committed
userid_resistratorを融合
1 parent 88d8e19 commit 15eb569

File tree

6 files changed

+262
-2
lines changed

6 files changed

+262
-2
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
__pycache__/

app.py

Lines changed: 259 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,215 @@
88
# get data from JMA and run the program each same time.
99
from initApp import initApp
1010

11+
import base64,hashlib,hmac #署名検証用
12+
import os,sys
13+
import psycopg2
14+
import uuid
15+
import secrets
16+
from linebot.models import TextSendMessage
17+
from linebot import(
18+
LineBotApi
19+
)
20+
import linebot
21+
1122
app = Flask(__name__)
1223

24+
#各種定数を定義
25+
DEBUG = os.environ.get('IS_DEBUG') == 'True' #デバッグ用のフラグ
26+
CHANNEL_SECRET = os.environ.get('CHANNEL_SECRET')
27+
ACCESS_TOKEN = os.environ.get('ACCESS_TOKEN')
28+
ROOT_URL = os.environ.get('ROOT_URL')
29+
CONSOLE_ROOT_URL = '{ROOT_URL}/control'.format(
30+
ROOT_URL=ROOT_URL
31+
)
32+
33+
@app.route('/control/<uuid:id>')
34+
def control_console(id):
35+
#DBへのコネクションを作成
36+
conn = db_connect()
37+
cursor = conn.cursor()
38+
39+
#DB上にidが存在するかを確認
40+
sql = "SELECT EXISTS (SELECT * FROM public.verify WHERE id='{}');".format(id)
41+
if DEBUG == True:
42+
print('SQL EXECUTE:{}'.format(sql))
43+
cursor.execute(sql)
44+
result = cursor.fetchone()
45+
conn.commit()
46+
47+
#データベース上に存在しない場合正規のリクエストではないため500を返す
48+
if result[0] == False:
49+
cursor.close()
50+
conn.close()
51+
return '',500,{}
52+
else:
53+
return render_template("control.html",title="登録",id=id)
54+
55+
@app.route('/control/form', methods=['POST'])
56+
def control_form():
57+
#送信データから値を抽出
58+
user_uuid = request.form.get('user_uuid')
59+
user_accept = request.form.get('accept')
60+
61+
#DBのコネクションを作成
62+
conn = db_connect()
63+
cursor = conn.cursor()
64+
65+
#user_accept==onの時ユーザーを登録
66+
if user_accept == 'on':
67+
#DBからuserのidを取得
68+
sql = "SELECT user_id FROM public.verify WHERE id='{}';".format(user_uuid)
69+
if DEBUG == True:
70+
print('SQL EXECUTE:{}'.format(sql))
71+
cursor.execute(sql)
72+
user_id = cursor.fetchone()[0]
73+
conn.commit()
74+
75+
#DBから函館の地域コードを取得
76+
sql = "SELECT id FROM public.area WHERE area_name='函館市';"
77+
if DEBUG == True:
78+
print('SQL EXECUTE:{}'.format(sql))
79+
cursor.execute(sql)
80+
area_id = cursor.fetchone()[0]
81+
conn.commit()
82+
83+
#resistrationに登録
84+
sql = "INSERT INTO public.resistration(user_id,area_id) VALUES('{user_id}','{area_id}');".format(
85+
user_id = user_id,
86+
area_id = area_id
87+
)
88+
if DEBUG == True:
89+
print('SQL EXECUTE:{}'.format(sql))
90+
cursor.execute(sql)
91+
conn.commit()
92+
93+
#verifyからユーザーを削除
94+
sql = "DELETE FROM public.verify WHERE id = '{}';".format(user_uuid)
95+
if DEBUG == True:
96+
print('SQL EXECUTE:{}'.format(sql))
97+
cursor.execute(sql)
98+
conn.commit()
99+
100+
cursor.close()
101+
conn.close()
102+
103+
return '<p>登録完了!!</p>'
104+
else:
105+
cursor.close()
106+
conn.close()
107+
108+
return '',200,{}
109+
110+
@app.route('/webhock', methods=['POST'])
111+
def webhock():
112+
113+
data = request.get_json() #user_id抽出用のリクエストデータ(json)
114+
print('data_type:{}'.format(type(data)))
115+
body = request.get_data(as_text=True) #検証用のリクエストデータ(string)
116+
117+
signature = request.headers.get('x-line-signature')
118+
119+
conn = db_connect()
120+
121+
if validation(body=body, signature=signature.encode('utf-8')) == True: #イベントの真贋判定
122+
if DEBUG == True:
123+
print('This is regular request!!')
124+
try:
125+
for line in data["events"]:
126+
user_id=''
127+
#ソースがユーザからのイベントである場合のみuser_idを抽出
128+
if line['source']['type'] == 'user':
129+
user_id = line["source"]['userId']
130+
if DEBUG == True:
131+
print('user_id:{}'.format(user_id))
132+
else:
133+
#ソースがユーザーからのイベントではない時400を返して処理を終える
134+
return '',200,{}
135+
136+
#DB操作用のカーソルを作成
137+
cursor = conn.cursor()
138+
139+
#user_idが既にDB上に存在しているか確認する
140+
sql = "SELECT EXISTS (SELECT * FROM public.user WHERE user_id='{}');".format(user_id)
141+
if DEBUG == True:
142+
print('SQL EXECUTE:{}'.format(sql))
143+
cursor.execute(sql)
144+
conn.commit()
145+
146+
result = cursor.fetchone()
147+
print('Result:{}'.format(result))
148+
149+
#存在しない時DBに登録
150+
if result[0] == False:
151+
sql = "INSERT INTO public.user(user_id) VALUES('{}');".format(user_id)
152+
if DEBUG == True:
153+
print('SQL EXECUTE:{}'.format(sql))
154+
cursor.execute(sql)
155+
conn.commit()
156+
157+
#イベントがmessageである時送信されたテキストの解析
158+
if line['type'] == 'message':
159+
if line['message']['text'] == '登録' or line['message']['text'] == '初期設定':
160+
#URL用のUUIDの生成
161+
user_uuid = uuid.uuid4()
162+
163+
#DBからuserのidを取得
164+
sql = "SELECT id FROM public.user WHERE user_id='{}'".format(user_id)
165+
if DEBUG == True:
166+
print('EXECUTE SQL:{}'.format(sql))
167+
cursor.execute(sql)
168+
id = cursor.fetchone()
169+
conn.commit()
170+
171+
#認証用のコード(6桁)を作成
172+
verify_code = secrets.randbelow(999999)
173+
verify_code = str(verify_code).zfill(6) #6桁になるように0埋め
174+
#認証用のコードをハッシュ化
175+
verify_hash = hashlib.sha256(verify_code.encode()).hexdigest()
176+
177+
#DBにUUIDとverify_hash,userのidを記録
178+
sql = "INSERT INTO public.verify(id,pass,user_id) VALUES ('{uuid}','{verify_pass}',{user_id});".format(
179+
uuid=user_uuid,
180+
verify_pass=verify_hash,
181+
user_id=id[0]
182+
)
183+
if DEBUG == True:
184+
print('SQL EXECUTE:{}'.format(sql))
185+
cursor.execute(sql)
186+
conn.commit()
187+
188+
#ユーザにURLと認証コードを送信
189+
190+
#URLを送信
191+
url_msg = '管理用コンソール用URL\n{root_url}/{uuid}'.format(
192+
root_url=CONSOLE_ROOT_URL,
193+
uuid=user_uuid
194+
)
195+
verify_code_msg = '確認コードは{}です。webページに戻り入力してください'.format(
196+
str(verify_code)
197+
)
198+
send_msg_with_line(user_id=user_id, msgs=[url_msg,verify_code_msg])
199+
200+
#DBとの接続を解除
201+
cursor.close()
202+
conn.close()
203+
204+
#messageではない時200を返して処理を終了
205+
else:
206+
return 'internal server error',200,{}
207+
208+
#全ての処理が正常終了した時200を返す
209+
return '',200,{}
210+
211+
except psycopg2.Error as e:
212+
print('DBへの書き込みエラー')
213+
print(e.pgerror)
214+
conn.close()
215+
216+
else:
217+
#正規のリクエストではないため200を返して終了
218+
return 'internal server error',400,{}
219+
13220
@app.route('/location', methods=['GET'])
14221
def get_location_get():
15222
return render_template('gps_design.html', title='Get Location App')
@@ -44,6 +251,58 @@ def get_location_post():
44251
)
45252
return "completed!"
46253

254+
#LINEユーザにメッセージを送信する関数
255+
def send_msg_with_line(user_id,msgs):
256+
send_msg = TextSendMessage(text='')
257+
try:
258+
line_bot_api = LineBotApi(ACCESS_TOKEN)
259+
260+
for msg in msgs:
261+
if DEBUG == True:
262+
print('SENDING MESSAGE:{}'.format(msg))
263+
send_msg = TextSendMessage(text=msg)
264+
line_bot_api.push_message(user_id,send_msg)
265+
except linebot.exceptions.LineBotApiError as e:
266+
print(e.error.message)
267+
print(e.error.details)
268+
269+
for msg in msgs:
270+
if DEBUG == True:
271+
print('SENNDING MESSAGE:{}'.format(msg))
272+
273+
#署名検証用の関数
274+
def validation(body,signature):
275+
hash = hmac.new(CHANNEL_SECRET.encode('utf-8'),
276+
body.encode('utf-8'), hashlib.sha256).digest()
277+
val_signature = base64.b64encode(hash)
278+
279+
#ローカルでバック用のバイパス
280+
if DEBUG == True:
281+
return True
282+
283+
if val_signature == signature:
284+
return True
285+
else:
286+
return False
287+
288+
#DB接続用の関数
289+
def db_connect():
290+
#環境変数からデータベースの情報を取得
291+
DATABASE_URL = os.environ.get('DATABASE_URL')
292+
293+
#接続先文字列の生成
294+
connection_info = DATABASE_URL
295+
296+
print('Connecting:{info}'.format(info=connection_info))
297+
conn = ''
298+
try:
299+
conn = psycopg2.connect(connection_info)
300+
except psycopg2.Error:
301+
print('Database connection failed!!') #DBとの接続に失敗した場合は終了する
302+
sys.exit()
303+
304+
return conn
305+
47306
if __name__ == "__main__":
48307
initApp()
49308
initData()

requirements.txt

1.26 KB
Binary file not shown.
Binary file not shown.
Binary file not shown.

src/getInfoFromJMA/data/lastInfo.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
11
{
2-
"Earthquake": "http://www.data.jma.go.jp/developer/xml/data/20211212101622_0_VFVO52_400000.xml",
3-
"Warning": "http://www.data.jma.go.jp/developer/xml/data/20211212101907_0_VPWW53_471000.xml"
2+
"Earthquake": "http://www.data.jma.go.jp/developer/xml/data/20211212140030_0_VFVO53_010000.xml",
3+
"Warning": "http://www.data.jma.go.jp/developer/xml/data/20211212131730_0_VPTA50_010000.xml"
44
}

0 commit comments

Comments
 (0)