Skip to content

Commit

Permalink
Merge pull request #6 from hibiya-itchief/公演の一括追加
Browse files Browse the repository at this point in the history
公演を一括追加する機能を追加
  • Loading branch information
aozoraUS authored May 8, 2024
2 parents bd3bf17 + 4328ab0 commit 71cd122
Show file tree
Hide file tree
Showing 13 changed files with 239 additions and 1 deletion.
124 changes: 124 additions & 0 deletions app/crud.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@

#from hashids import Hashids
import ulid
import pandas as pd
import numpy as np
from fastapi import HTTPException, Query
from sqlalchemy import and_, or_
from sqlalchemy.exc import IntegrityError
Expand Down Expand Up @@ -381,3 +383,125 @@ def set_hebe_upnext(db:Session,hebe:schemas.HebeResponse):
db.commit()
db.refresh(db_hebe)
return db_hebe

#受け取ったpandas.DataFrameをserializeする
#受け取った値についての検証はcolumnsだけ行う
def convert_df(df:pd.DataFrame) -> pd.DataFrame:
#カラムの数が正しいかの検証
if len(df.columns.values) != 12:
raise HTTPException(422, f'列の数が合いません。正しい列の数は12です。サンプルシートと比較して確認してください。')

converted_df = pd.DataFrame(columns=['group_id', 'eventname', 'lottery', 'target', 'ticket_stock', 'starts_at', 'ends_at', 'sell_starts', 'sell_ends'])

#1行ずつ取り出してserializeする
for i in range(len(df)):
try:
#時間の情報をserializeする
year = str(df.iat[i, 5])
month = str(df.iat[i, 6])
day = str(df.iat[i, 7])
hours = {
'starts_at':str(df.iat[i, 8]).split(':')[0],
'ends_at':str(df.iat[i, 9]).split(':')[0],
'sell_starts':str(df.iat[i, 10]).split(':')[0],
'sell_ends':str(df.iat[i, 11]).split(':')[0],
}

"""
month, day, hourのserialize
上の三つを時間にくっつける上で 9 → 09 みたいにする必要がある
"""
if len(month) == 1:
month = '0' + month
if len(day) == 1:
day = '0' + day

for key in ['starts_at', 'ends_at', 'sell_starts', 'sell_ends']:
if len(hours[key]) == 1:
hours[key] = '0' + hours[key]

times = {
'starts_at':hours['starts_at'] + ':' + str(df.iat[i , 8]).split(':')[1] + ':' + str(df.iat[i , 8]).split(':')[2],
'ends_at':hours['ends_at'] + ':' + str(df.iat[i , 9]).split(':')[1] + ':' + str(df.iat[i , 9]).split(':')[2],
'sell_starts':hours['sell_starts'] + ':' + str(df.iat[i , 10]).split(':')[1] + ':' + str(df.iat[i , 10]).split(':')[2],
'sell_ends':hours['sell_ends'] + ':' + str(df.iat[i , 11]).split(':')[1] + ':' + str(df.iat[i , 11]).split(':')[2],
}

converted_df = pd.concat([converted_df, pd.DataFrame(data={
'group_id':[df.iat[i , 0]],
'eventname':[df.iat[i , 1]],
'lottery':df.iat[i , 2],
'target':[df.iat[i , 3]],
'ticket_stock':[df.iat[i , 4]],
'starts_at':[ year + '-' + month + '-' + day + 'T' + times['starts_at'] + '+09:00'],
'ends_at':[ year + '-' + month + '-' + day + 'T' + times['ends_at'] + '+09:00'],
'sell_starts':[ year + '-' + month + '-' + day + 'T' + times['sell_starts'] + '+09:00'],
'sell_ends':[ year + '-' + month + '-' + day + 'T' + times['sell_ends'] + '+09:00'],
})], ignore_index=True)
except:
raise HTTPException(422, f"pandas.DataFrameの変換に失敗しました。表記方法が正しいことを確認してください。<エラー箇所> 行番号 : { i + 1 }")

return converted_df

#受け取ったpandas.DataFrameの形式が正しいかを検証する
def check_df(db:Session, df: pd.DataFrame) -> None:
#カラム名が正しいかの検証
columns = df.columns.values
correct_columns = ['group_id', 'eventname', 'lottery', 'target', 'ticket_stock', 'starts_at', 'ends_at', 'sell_starts', 'sell_ends']
for i in range(len(columns)):
if not (columns[i] == correct_columns[i]):
raise HTTPException(422, f'カラム名が正しいことを確認してください。<エラー箇所> 表記 : {columns[i]}, 正表記 : {correct_columns[i]}')

#group_idが正しいかの検証
for i in range(len(df)):
group = db.query(models.Group).filter(models.Group.id == df.iat[i, 0]).first()

if not group:
raise HTTPException(400, f"存在しないgroup_idが含まれています。<エラー箇所> 行番号 : {i + 1}, group_id : {df.iat[i, 0]}")

#時刻の表記の仕方が正しいかの判定
for m in range(len(df)):
for n in [5,6,7,8]:
try:
time = datetime.fromisoformat(df.iat[m, n])
except:
raise HTTPException(422, f"時刻の表記方法が正しいことを確認してください。<エラー箇所> 行番号 : {m + 1}, 列番号 : {n + 1}")

#時刻の設定に問題がないかを確認
for i in range(len(df)):
starts_at = datetime.fromisoformat(df.iat[i , 5])
ends_at = datetime.fromisoformat(df.iat[i , 6])
sell_starts = datetime.fromisoformat(df.iat[i , 7])
sell_ends = datetime.fromisoformat(df.iat[i , 8])

if starts_at > ends_at:
raise HTTPException(400,f"公演の開始時刻は終了時刻よりも前である必要があります。group_id : {df.iat[i , 0]}, eventname : {df.iat[i , 1]}")
if sell_starts > sell_ends:
raise HTTPException(400,f"配布開始時刻は配布終了時刻よりも前である必要があります。group_id : {df.iat[i , 0]}, eventname : {df.iat[i , 1]}")

#表記方法に問題なし
return None

#pandas.DataFrameの情報を元にDBにeventを追加
def create_events_from_df(db:Session, df: pd.DataFrame) -> None:
for i in range(len(df)):
group_id = df.iat[i , 0]

#pandas.DataFrameの情報を読み取ってスキーマに変換
event = schemas.EventDBInput(
eventname=df.iat[i , 1],
lottery=df.iat[i , 2],
target=df.iat[i , 3],
ticket_stock=df.iat[i , 4],
starts_at=df.iat[i , 5],
ends_at=df.iat[i , 6],
sell_starts=df.iat[i , 7],
sell_ends=df.iat[i , 8],
)

db_event = models.Event(id=ulid.new().str,group_id=group_id,**event.dict())
db.add(db_event)
db.commit()
db.refresh(db_event)

return None
23 changes: 23 additions & 0 deletions app/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@
from xml.dom.minidom import Entity

import requests
from io import StringIO
import pandas as pd
from fastapi import (Body, Depends, FastAPI, File, HTTPException, Query,
UploadFile, status)
from fastapi.middleware.cors import CORSMiddleware
Expand Down Expand Up @@ -733,3 +735,24 @@ def get_hebe_nowplaying(hebe:schemas.HebeResponse,permission:schemas.JWTUser=Dep
)
def get_hebe_nowplaying(hebe:schemas.HebeResponse,permission:schemas.JWTUser=Depends(auth.chief),db:Session = Depends(db.get_db)):
return crud.set_hebe_upnext(db,hebe)

@app.post(
"/support/events",
summary="公演の一括追加",
tags=["admin"],
description="csvファイルを元に公演を一斉に追加します。csvファイルについてはサンプルのエクセルと同じ書式で書いたものにしてください。正しく処理されません。"
)
async def create_all_events_from_csv(file: UploadFile = File(...), permission:schemas.JWTUser=Depends(auth.chief),db:Session = Depends(db.get_db)):
#pandasのDataFrameに読み込んだファイルを変換
content = file.file.read()
string_data = str(content, 'utf-8')
data = StringIO(string_data)
df = pd.read_csv(data)
data.close()
file.file.close()

converted_df = crud.convert_df(df)
crud.check_df(db,converted_df)
crud.create_events_from_df(db, converted_df)

return {'message' :[converted_df.iloc[i,:].to_json() for i in range(len(converted_df))]}
20 changes: 20 additions & 0 deletions app/test/factories.py
Original file line number Diff line number Diff line change
Expand Up @@ -158,6 +158,26 @@ class invalid_timetable3():
type=schemas.GroupType.play
)

# 変数
group3 = schemas.GroupCreate(
id="test_1",
groupname="テストグループ",
title="TEST_TEST",
description="TESTです",
enable_vote=True,
twitter_url=None,
instagram_url=None,
stream_url=None,
public_thumbnail_image_url=None,
public_page_content_url="<html><h1>宣伝ページ</h1></html>",
private_page_content_url="<html><h1>プライベート</h1></html>",
floor=4,
place="LL教室",
type=schemas.GroupType.test
)



group1_update = schemas.GroupUpdate(
id="28r",
groupname="2年8組",
Expand Down
52 changes: 52 additions & 0 deletions app/test/test_crud.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
from requests import Session
from typing_extensions import assert_type
import pytest
import pandas as pd

client = TestClient(app)

Expand Down Expand Up @@ -95,3 +96,54 @@ def test_add_tag(db):
crud.add_tag(db, factories.group1.id, tag)
assert err.value.status_code == 200
assert err.value.detail == 'Already Registed'

def test_convert_df():
origin_df = pd.read_csv('/workspace/csv/sample-sheet-v2.csv')
converted_df = pd.read_csv('/workspace/csv/sample-sheet-v1.csv')

res_df = crud.convert_df(origin_df)

for m in range(len(origin_df)):
for n in range(len(converted_df.columns.values)):
assert res_df.iat[m, n] == converted_df.iat[m, n]

def test_check_df(db):
correct_df = pd.read_csv(filepath_or_buffer='/workspace/csv/sample-sheet.csv')
incorrect_title_df = pd.read_csv(filepath_or_buffer='/workspace/csv/incorrect-title-sheet.csv')
incorrect_groupid_df = pd.read_csv(filepath_or_buffer='/workspace/csv/incorrect-groupid-sheet.csv')
incorrect_time_df = pd.read_csv(filepath_or_buffer='/workspace/csv/incorrect-time-sheet.csv')
incorrect_time_start = pd.read_csv(filepath_or_buffer='/workspace/csv/incorrect-time-setting-start-sheet.csv')
incorrect_time_sell = pd.read_csv(filepath_or_buffer='/workspace/csv/incorrect-time-setting-sell-sheet.csv')

group = factories.group3
crud.create_group(db, group)

assert crud.check_df(db,correct_df) == None

with pytest.raises(HTTPException) as err1:
crud.check_df(db,incorrect_title_df)
assert err1.value.status_code == 422

with pytest.raises(HTTPException) as err2:
crud.check_df(db, incorrect_groupid_df)
assert err2.value.status_code == 400

with pytest.raises(HTTPException) as err3:
crud.check_df(db,incorrect_time_df)
assert err3.value.status_code == 422

with pytest.raises(HTTPException) as err4:
crud.check_df(db, incorrect_time_start)
assert err4.value.status_code == 400

with pytest.raises(HTTPException) as err5:
crud.check_df(db, incorrect_time_sell)
assert err5.value.status_code == 400

def test_create_events_from_df(db):
df = pd.read_csv(filepath_or_buffer='/workspace/csv/sample-sheet.csv')

group = factories.group3
crud.create_group(db, group)

assert crud.create_events_from_df(db, df) == None
2 changes: 2 additions & 0 deletions csv/incorrect-groupid-sheet.csv
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
group_id,eventname,lottery,target,ticket_stock,starts_at,ends_at,sell_starts,sell_ends
89898989,テストイベント1,FALSE,everyone,50,2024-09-16T09:30:00+09:00,2024-09-16T10:30:00+09:00,2024-09-16T08:30:00+09:00,2024-09-16T09:20:00+09:00
2 changes: 2 additions & 0 deletions csv/incorrect-time-setting-sell-sheet.csv
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
group_id,eventname,lottery,target,ticket_stock,starts_at,ends_at,sell_starts,sell_ends
test_1,テストイベント1,FALSE,everyone,50,2024-09-16T09:30:00+09:00,2024-09-16T10:30:00+09:00,2024-09-16T08:30:00+09:00,2024-09-16T07:20:00+09:00
2 changes: 2 additions & 0 deletions csv/incorrect-time-setting-start-sheet.csv
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
group_id,eventname,lottery,target,ticket_stock,starts_at,ends_at,sell_starts,sell_ends
test_1,テストイベント1,FALSE,everyone,50,2024-09-16T09:30:00+09:00,2024-09-16T08:30:00+09:00,2024-09-16T08:30:00+09:00,2024-09-16T09:20:00+09:00
2 changes: 2 additions & 0 deletions csv/incorrect-time-sheet.csv
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
group_id,eventname,lottery,target,ticket_stock,starts_at,ends_at,sell_starts,sell_ends
test_1,テストイベント1,FALSE,everyone,50,2024-09-16T09:30:0+09:00,2024-0916T10:30:00+09:00,2024-09-16T08:30:00+09:00,2024-09-16T09:20:00+09:00
2 changes: 2 additions & 0 deletions csv/incorrect-title-sheet.csv
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
group_i,eventname,lottery,taret,ticket_stock,starts_at,ends_at,sell_starts,sell_nds
test_1,テストイベント1,FALSE,everyone,50,2024-09-16T09:30:00+09:00,2024-09-16T10:30:00+09:00,2024-09-16T08:30:00+09:00,2024-09-16T09:20:00+09:00
3 changes: 3 additions & 0 deletions csv/sample-sheet-v1.csv
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
group_id,eventname,lottery,target,ticket_stock,starts_at,ends_at,sell_starts,sell_ends
test_1,テストイベント1,FALSE,everyone,50,2024-09-16T09:30:00+09:00,2024-09-16T10:30:00+09:00,2024-09-16T08:30:00+09:00,2024-09-16T09:00:00+09:00
test_2,テストイベント2,FALSE,admin,50,2024-09-16T12:30:00+09:00,2024-09-16T13:30:00+09:00,2024-09-16T10:00:00+09:00,2024-09-16T11:00:00+09:00
3 changes: 3 additions & 0 deletions csv/sample-sheet-v2.csv
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
group_id,eventname,lottery,target,ticket_stock,year,month,day,starts_at,ends_at,sell_starts,sell_ends
test_1,テストイベント1,FALSE,everyone,50,2024,9,16,9:30:00,10:30:00,8:30:00,9:00:00
test_2,テストイベント2,FALSE,admin,50,2024,9,16,12:30:00,13:30:00,10:00:00,11:00:00
2 changes: 2 additions & 0 deletions csv/sample-sheet.csv
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
group_id,eventname,lottery,target,ticket_stock,starts_at,ends_at,sell_starts,sell_ends
test_1,テストイベント1,FALSE,everyone,50,2024-09-16T09:30:00+09:00,2024-09-16T10:30:00+09:00,2024-09-16T08:30:00+09:00,2024-09-16T09:20:00+09:00
3 changes: 2 additions & 1 deletion requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -26,4 +26,5 @@ cryptography
redis[hiredis]
google-api-python-client
google-analytics-data
oauth2client
oauth2client
pandas

0 comments on commit 71cd122

Please sign in to comment.