async def signup(user: SignupInfo): """ サインアップ """ # dbから参照 with session_scope() as s: u = s.query(User).filter(User.email == user.email).first() # すでに登録者がいる場合 if u: return {"status": "failed"} # ユーザー登録 # パスワードのハッシュ化 salt = bcrypt.gensalt(rounds=10, prefix=b'2a') hashed_passwd = bcrypt.hashpw(user.password.encode(), salt) # userを追加 u = User(name=user.name, email=user.email, password=hashed_passwd) with session_scope() as s: s.add(u) s.commit() user_id = u.id tkn = token_urlsafe(16) # tokenを発行 with session_scope() as s: s.add(Token(token=tkn, user_id=user_id)) return {"status": "success", "access_token": f"{tkn}"} return {"status": "failed"}
async def add_travel(travel: str, current_user=Depends(get_current_user)): """ 旅行のアルバムを作成する """ # DBにアルバムを追加 t = Travel(title=f"{travel}") with session_scope() as s: s.add(t) s.commit() tid = t.id with session_scope() as s: s.add(TravelUser(user_id=current_user, travel_id=tid)) return "succeed"
async def get_spot_list(travel_id: int): # TODO: TOKEN認証 """ spotsを返す """ # travel_idを使ってSpotを参照 result = SpotInfo(data=[]) with session_scope() as s: data = s.query(Spot).filter(Spot.travel_id == travel_id).all() if data: for d in data: # SpotとMemoryContentを内部結合してサムネイルを生成 spt = s.query(Spot, MemoryContent).join(MemoryContent).filter( Spot.travel_id == d.id).first() if spt: result.data.append( SpotItem(id=d.id, name=f"{d.name}", created_at=f"{d.created_at}", latitude=f"{d.latitude}", longitude=f"{d.longitude}", thumbnail_url=f"{spt[1].content_url}")) else: result.data.append( SpotItem(id=d.id, name=f"{d.name}", created_at=f"{d.created_at}", latitude=f"{d.latitude}", longitude=f"{d.longitude}", thumbnail_url="")) return result
async def get_recomend_list(latitude: float, longitude: float): # TODO: TOKEN認証 """ recomendsを返す """ result = RecomendInfo(data=[]) # 緯度経度情報から近いスポット5個をピックアップ t = text(f""" SELECT id, name, content_url, latitude, longitude, ( 6371 * acos( -- kmの場合は6371、mileの場合は3959 cos(radians({latitude})) * cos(radians(latitude)) * cos(radians(longitude) - radians({longitude})) + sin(radians({latitude})) * sin(radians(latitude)) ) ) AS distance FROM recomend ORDER BY distance LIMIT 5; """) with session_scope() as s: # 内部結合 for d in s.execute(t): result.data.append( RecomendItem(name=f"{d.name}", thumbnail_url=f"{d.content_url}")) return result
async def get_travel_list(current_user=Depends(get_current_user)): """ ユーザーが持つ旅行の一覧を参照 """ # TODO: DBからユーザーが持つtravelの一覧を参照 print(current_user) result = TravelInfo(data=[]) with session_scope() as s: # TravelUserとTravelを内部結合してUserから所有するTravelを参照 data = s.query(TravelUser, Travel).join(Travel).filter( TravelUser.user_id == current_user).all() for d in data: # SpotとMemoryContentを内部結合してサムネイルを生成 spt = s.query(Spot, MemoryContent).join(MemoryContent).filter( Spot.travel_id == d[1].id).first() if spt: result.data.append( TravelItem(id=d[1].id, name=f"{d[1].title}", period=f"{d[1].created_at}", thumbnail_url=f"{spt[1].content_url}")) else: result.data.append( TravelItem(id=d[1].id, name=f"{d[1].title}", period=f"{d[1].created_at}", thumbnail_url="")) return result
async def login(user: LoginInfo): """ ログイン """ # dbから参照 with session_scope() as s: u = s.query(User).filter(User.email == user.email).first() # userがいない場合 if not u: return {"status": "failed"} user_id = u.id saved_password = u.password # 認証 if saved_password: if bcrypt.checkpw(user.password.encode(), saved_password.encode()): # ログイン成功後トークンを記録/伝達 tkn = token_urlsafe(16) with session_scope() as s: s.add(Token(token=tkn, user_id=user_id)) return {"status": "success", "access_token": f"{tkn}"} return {"status": "failed"}
async def add_content(content: ContentRequest): """ スポットに紐付けられたコンテンツを追加する """ s = MemoryContent(spot_id=content.spot_id, content_url=f"{content.content_url}") try: with session_scope() as ss: ss.add(s) return "success" except: return "failed"
async def add_spot(spot: SpotRequest): """ 旅行のアルバムに紐付けられたスポットを追加する """ s = Spot(name=f"{spot.name}", latitude=spot.latitude, longitude=spot.longitude, travel_id=spot.travel_id, arrived_at=dt.strptime(spot.arrived_at, '%Y-%m-%d %H:%M:%S')) with session_scope() as ss: ss.add(s) return "success"
async def get_content_list(travel_id: int): # TODO: TOKEN認証 """ contentsを返す """ # travel_idを使ってSpotを参照 result = ContentInfo(data=[]) with session_scope() as s: # SpotとMemoryContentを内部結合してcontent一覧を生成 data = s.query(Spot, MemoryContent).join(MemoryContent).filter( Spot.travel_id == travel_id).all() for d in data: result.data.append( ContentItem(id=d[1].id, spot_id=d[0].id, file_url=f"{d[1].content_url}")) return result
def get_current_user(cred: HTTPAuthorizationCredentials = Depends( HTTPBearer())): """ トークン認証しユーザー情報を返す """ try: # token認証 with session_scope() as s: u = s.query(Token).filter(Token.token == cred.credentials).first() # userがいる場合 if u: return u.user_id else: raise Exception except Exception: raise HTTPException( status_code=status.HTTP_401_UNAUTHORIZED, detail='Invalid authentication credentials', headers={'WWW-Authenticate': 'Bearer'}, )
import datetime from datetime import timedelta # パスワードのハッシュ化 salt = bcrypt.gensalt(rounds=10, prefix=b'2a') password = "******".encode() hashed_passwd = bcrypt.hashpw(password, salt) # userを追加 user_samples = [ User(name='ken', email='*****@*****.**', password=hashed_passwd), User(name='susan', email='*****@*****.**', password=hashed_passwd), User(name='leo', email='*****@*****.**', password=hashed_passwd), User(name='edd', email='*****@*****.**', password=hashed_passwd), User(name='queen', email='*****@*****.**', password=hashed_passwd) ] with session_scope() as s: for us in user_samples: s.add(us) # travelを追加 travel_samples = [ Travel(title="沖縄旅行"), Travel(title="修学旅行"), Travel(title="パリ研修"), Travel(title="北海道旅行"), Travel(title="京都"), Travel(title="アメリカ") ] with session_scope() as s: for ts in travel_samples: s.add(ts) # traveluser