Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

公演を一括追加する機能を追加 #6

Merged
merged 1 commit into from
May 8, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
Loading