Add subscribe/unsuscribe logic in browser-domain

Also, fix some backend bugs
This commit is contained in:
Santiago Lo Coco 2023-12-01 19:30:41 -03:00
parent 6c4aa99eb7
commit dc7c6f7439
14 changed files with 404 additions and 34 deletions

View File

@ -1,5 +1,5 @@
import { Axios, AxiosError } from "axios"; import { Axios, AxiosError } from "axios";
import { Credentials, Token, User, Flight, FlightCreate } from "./Types"; import { Credentials, Token, User, Flight, FlightCreate, SubscriptionsCreate } from "./Types";
const instance = new Axios({ const instance = new Axios({
baseURL: process.env.REACT_APP_ENDPOINT ? process.env.REACT_APP_ENDPOINT : "http://127.0.0.1:5000/", baseURL: process.env.REACT_APP_ENDPOINT ? process.env.REACT_APP_ENDPOINT : "http://127.0.0.1:5000/",
@ -24,6 +24,8 @@ instance.interceptors.response.use(
json["count"] = response.headers["x-count"] json["count"] = response.headers["x-count"]
console.log(json) console.log(json)
return json return json
} else if (response.status == 204) {
return response;
} }
return JSON.parse(response.data); return JSON.parse(response.data);
}, },
@ -75,4 +77,35 @@ export const createFlight = (
return instance.post("flights", flight_data, { return instance.post("flights", flight_data, {
headers: { Authorization: `Bearer ${token}` }, headers: { Authorization: `Bearer ${token}` },
}); });
};
export const subscribeToFlight = (subscription: SubscriptionsCreate, token: string): Promise<SubscriptionsCreate> => {
return instance.post("subscriptions", subscription, {
headers: { Authorization: `Bearer ${token}` },
});
};
export const getChatId = (user_id: number, token: string): Promise<Flight> => {
return instance.get("notifications?user_id=" + user_id, {
headers: { Authorization: `Bearer ${token}` },
});
};
export const getSubscription = (subscription: SubscriptionsCreate, token: string): Promise<SubscriptionsCreate> => {
return instance.get("subscriptions?user_id=" + subscription.user_id + "&flight_id=" +subscription.flight_id, {
headers: { Authorization: `Bearer ${token}` },
});
};
export const unsubscribeFromFlight = (subscription: SubscriptionsCreate, token: string): Promise<any> => {
return instance.delete("subscriptions", {
headers: { Authorization: `Bearer ${token}`},
data: subscription
});
};
export const fetchSubscriptions = (user_id: number, token: string): Promise<SubscriptionsCreate[]> => {
return instance.get("subscriptions?user_id=" + user_id, {
headers: { Authorization: `Bearer ${token}` },
});
}; };

View File

@ -45,4 +45,9 @@ export interface FlightCreate {
departure_time: string; departure_time: string;
arrival_time: string; arrival_time: string;
gate: string; gate: string;
}
export interface SubscriptionsCreate {
flight_id: number;
user_id: number;
} }

View File

@ -1,10 +1,14 @@
import React from "react"; import React, { useEffect, useState } from "react";
import { Avatar, Space, Typography, Tag } from "antd"; import { Link } from "react-router-dom";
import { Avatar, Space, Typography, Tag, Button, Modal } from "antd";
import { RightOutlined, ClockCircleOutlined, SwapOutlined, EnvironmentOutlined, CalendarOutlined } from "@ant-design/icons"; import { RightOutlined, ClockCircleOutlined, SwapOutlined, EnvironmentOutlined, CalendarOutlined } from "@ant-design/icons";
import "./Card.css"; import "./Card.css";
import { getChatId, getSubscription, subscribeToFlight, unsubscribeFromFlight } from "../../../Api";
import { User } from "../../../Types";
interface FlightProps { interface FlightProps {
id: number;
flight_code: string; flight_code: string;
status: string; status: string;
origin: string; origin: string;
@ -16,11 +20,110 @@ interface FlightProps {
interface CardProps { interface CardProps {
flight: FlightProps; flight: FlightProps;
user: User | undefined;
subscribed: boolean;
refresh: any;
} }
const { Text } = Typography; const { Text } = Typography;
export const Card: React.FC<CardProps> = ({ flight }) => { export const Card: React.FC<CardProps> = ({ flight, user, subscribed, refresh }) => {
// const [error, setError] = useState<string | null>(null);
// const [subscribed, setSubscribed] = useState<boolean>(false);
// useEffect(() => {
// setError(null);
// const token = localStorage.getItem("token");
// if (!token || !user) {
// setError("No token!");
// return;
// }
// const data = {
// user_id: user.id,
// flight_id: flight.id
// }
// getSubscription(data, token)
// .then((data) => {
// setSubscribed(true);
// })
// .catch((error) => {
// setError(error as string);
// });
// }, [user]);
const [modalVisible, setModalVisible] = useState<boolean>(false);
const handleSubscribe = async (event: React.FormEvent) => {
event.preventDefault();
// setError(null);
const token = localStorage.getItem("token");
if (!token || !user) {
// setError("No token!");
return;
}
const data = {
user_id: user.id,
flight_id: flight.id
}
console.log(data)
subscribeToFlight(data, token)
.then(() => {
refresh()
getChatId(user.id, token)
.then(() => {})
.catch((error) => {
console.log("NO CHAT")
setModalVisible(true);
// setError(error as string);
})
})
.catch((error) => {
// setError(error as string);
});
};
const handleModalClose = () => {
setModalVisible(false);
};
const handleUnsubscribe = async (event: React.FormEvent) => {
event.preventDefault();
// setError(null);
const token = localStorage.getItem("token");
if (!token || !user) {
// setError("No token!");
return;
}
const data = {
user_id: user.id,
flight_id: flight.id
}
console.log(data)
unsubscribeFromFlight(data, token)
.then(() => {
console.log("?")
refresh()
})
.catch((error) => {
// setError(error as string);
});
};
console.log(subscribed)
return ( return (
<div className="flight-card"> <div className="flight-card">
<Space size={8} align="center"> <Space size={8} align="center">
@ -32,7 +135,7 @@ export const Card: React.FC<CardProps> = ({ flight }) => {
</div> </div>
</Space> </Space>
<div className="flight-details"> <div className="flight-details">
<Space size={8} direction="vertical"> <Space size={8} direction="horizontal">
<Text strong>Status:</Text> <Text strong>Status:</Text>
<Tag color={flight.status === "Scheduled" ? "green" : "orange"}>{flight.status}</Tag> <Tag color={flight.status === "Scheduled" ? "green" : "orange"}>{flight.status}</Tag>
</Space> </Space>
@ -50,11 +153,41 @@ export const Card: React.FC<CardProps> = ({ flight }) => {
{flight.arrival_time} {flight.arrival_time}
</Space> </Space>
</Space> </Space>
<Space size={8} direction="vertical"> <Space size={8} direction="horizontal">
<Text strong>Gate:</Text> <Text strong>Gate:</Text>
<Text>{flight.gate}</Text> <Text>{flight.gate}</Text>
</Space> </Space>
<Space size={8} direction="horizontal">
<Text strong>ID:</Text>
<Text>{flight.id}</Text>
</Space>
</div> </div>
{!(subscribed) ?
<Button type="primary" onClick={handleSubscribe}>
Subscribe
</Button>
:
<Button type="primary" onClick={handleUnsubscribe}>
Unsubscribe
</Button>
}
<Modal
title="Error"
visible={modalVisible}
onCancel={handleModalClose}
footer={[
<Button key="ok" type="primary" onClick={handleModalClose}>
OK
</Button>
]}
>
<p>To start receiving messages open this link on your smartphone:
</p>
<Link to={`https://t.me/fids_system_bot?start=${user?.id}`} target="_blank">
{`https://t.me/fids_system_bot?start=${user?.id}`}
</Link>
</Modal>
</div> </div>
); );
}; };

View File

@ -1,9 +1,11 @@
import React, { useEffect, useState } from "react"; import React, { useEffect, useState } from "react";
import { Card } from "./Card/Card"; import { Card } from "./Card/Card";
import { useFetchFlights } from "../../hooks/useFetchFlights"; import { useFetchFlights } from "../../hooks/useFetchFlights";
import { Flight } from "../../Types"; import { Flight, SubscriptionsCreate } from "../../Types";
import { useNavigate } from "react-router"; import { useNavigate } from "react-router";
import useAuth from "../../useAuth"; import useAuth from "../../useAuth";
import { useFetchSubscriptions } from "../../hooks/useFetchSubscriptions";
import { fetchSubscriptions } from "../../Api";
interface Props { interface Props {
flights?: Flight[]; flights?: Flight[];
@ -17,7 +19,9 @@ export const Home: React.FC<Props> = (props) => {
const navigate = useNavigate() const navigate = useNavigate()
const [currentPage, setCurrentPage] = useState(initialPage); const [currentPage, setCurrentPage] = useState(initialPage);
const { loading, isAirline } = useAuth(); const { loading, isAirline, user, token } = useAuth();
const { subscriptions, loading: subsLoading, fetchData } = useFetchSubscriptions(user, token);
useEffect(() => { useEffect(() => {
const newParams = new URLSearchParams(window.location.search); const newParams = new URLSearchParams(window.location.search);
@ -25,6 +29,25 @@ export const Home: React.FC<Props> = (props) => {
navigate(`?${newParams.toString()}`); navigate(`?${newParams.toString()}`);
}, [currentPage, navigate]); }, [currentPage, navigate]);
// const [errorSub, setErrorSub] = useState<string | null>(null);
// const [subscriptions, setSubscriptions] = useState<SubscriptionsCreate[]>([]);
// useEffect(() => {
// setErrorSub(null);
// console.log(user)
// console.log(token)
// if (!user || !token) {
// return;
// }
// fetchSubscriptions(user.id, token)
// .then((data) => {
// setSubscriptions(data);
// })
// .catch((error) => { });
// }, [user, token, loading]);
const goToPrevPage = () => { const goToPrevPage = () => {
if (currentPage > 1) { if (currentPage > 1) {
setCurrentPage(currentPage - 1); setCurrentPage(currentPage - 1);
@ -47,13 +70,15 @@ export const Home: React.FC<Props> = (props) => {
return <div>Loading...</div>; return <div>Loading...</div>;
} }
// console.log(subscriptions)
return ( return (
<div className="Box"> <div className="Box">
{isAirline ? <button onClick={() => { navigate("/create-flight") }}>Create flight</button> : <></>} {isAirline ? <button onClick={() => { navigate("/create-flight") }}>Create flight</button> : <></>}
<h2>Flights</h2> <h2>Flights</h2>
<div className="Items"> <div className="Items">
{(props.flights ? props.flights : flights).map((u) => { {(props.flights ? props.flights : flights).map((f) => {
return <Card key={u.id} flight={u} />; return <Card key={f.id} flight={f} user={user} subscribed={subscriptions.some((i => i.flight_id === f.id))} refresh={fetchData} />;
})} })}
{error ? <div className="Disconnected">{error}</div> : <></>} {error ? <div className="Disconnected">{error}</div> : <></>}
</div> </div>

View File

@ -8,6 +8,7 @@ export const LogIn = () => {
const [email, setEmail] = useState(""); const [email, setEmail] = useState("");
const [password, setPassword] = useState(""); const [password, setPassword] = useState("");
const navigate = useNavigate(); const navigate = useNavigate();
console.log(error)
return ( return (
<div className="Box Small"> <div className="Box Small">
@ -39,7 +40,7 @@ export const LogIn = () => {
Sign up Sign up
</Button> </Button>
{error ? ( {error ? (
<div className="Disconnected">{error}</div> <div className="Disconnected">{error?.message}</div>
) : ( ) : (
<></> <></>
)} )}

View File

@ -0,0 +1,46 @@
import React, { useEffect, useCallback } from "react";
import { useState } from "react";
import { User, Flight, SubscriptionsCreate } from "../Types";
import { fetchSubscriptions } from "../Api";
export const useFetchSubscriptions = (user: User | undefined, token: string | undefined) => {
const [error, setError] = useState<string | null>(null);
const [subscriptions, setSubscriptions] = useState<SubscriptionsCreate[]>([]);
const [loading, setLoading] = useState<boolean>(true);
const fetchData = useCallback(async () => {
setError(null);
if (!user || !token || !loading) {
return;
}
fetchSubscriptions(user.id, token)
.then((data) => {
setSubscriptions(data);
setLoading(false)
})
.catch((error) => { });
}, [user, token]);
useEffect(() => {
fetchData()
}, [fetchData]);
// useEffect(() => {
// setError(null);
// if (!user || !token || !loading) {
// return;
// }
// fetchSubscriptions(user.id, token)
// .then((data) => {
// setSubscriptions(data);
// setLoading(false)
// })
// .catch((error) => { });
// }, [user, token]);
return { subscriptions, error, loading, fetchData };
};

View File

@ -8,6 +8,7 @@ interface AuthContextType {
user?: User; user?: User;
loading: boolean; loading: boolean;
isAirline: boolean; isAirline: boolean;
token?: string;
error?: any; error?: any;
login: (credentials: Credentials) => void; login: (credentials: Credentials) => void;
signUp: (email: string, name: string, password: string) => void; signUp: (email: string, name: string, password: string) => void;
@ -25,6 +26,7 @@ export function AuthProvider({
}): JSX.Element { }): JSX.Element {
const [user, setUser] = useState<User>(); const [user, setUser] = useState<User>();
const [error, setError] = useState<any>(); const [error, setError] = useState<any>();
const [token, setToken] = useState<string>();
const [loading, setLoading] = useState<boolean>(false); const [loading, setLoading] = useState<boolean>(false);
const [loadingInitial, setLoadingInitial] = useState<boolean>(true); const [loadingInitial, setLoadingInitial] = useState<boolean>(true);
const [isAirline, setIsAirline] = useState(false); const [isAirline, setIsAirline] = useState(false);
@ -51,7 +53,10 @@ export function AuthProvider({
.then((res) => fetchUserById(res.id, existingToken) .then((res) => fetchUserById(res.id, existingToken)
.then((res) => setUser(res)) .then((res) => setUser(res))
.catch((_error) => { }) .catch((_error) => { })
.finally(() => setLoadingInitial(false)) .finally(() => {
setToken(existingToken)
setLoadingInitial(false)
})
) )
.catch((_error) => { .catch((_error) => {
setLoadingInitial(false) setLoadingInitial(false)
@ -73,6 +78,7 @@ export function AuthProvider({
const user = fetchUserById(x.user_id as number, x.access_token) const user = fetchUserById(x.user_id as number, x.access_token)
.then(y => { .then(y => {
setUser(y); setUser(y);
setToken(x.access_token)
navigate("/home") navigate("/home")
}) })
.catch((error) => setError(error)) .catch((error) => setError(error))
@ -87,6 +93,7 @@ export function AuthProvider({
function logout() { function logout() {
localStorage.removeItem("token"); localStorage.removeItem("token");
setUser(undefined); setUser(undefined);
setToken(undefined)
navigate("/login") navigate("/login")
} }
@ -95,6 +102,7 @@ export function AuthProvider({
user, user,
loading, loading,
isAirline, isAirline,
token,
error, error,
login, login,
signUp, signUp,

View File

@ -49,9 +49,9 @@ async def update_flight(
req: Request, req: Request,
authorization: Annotated[str | None, Header()] = None, authorization: Annotated[str | None, Header()] = None,
): ):
id = await checkAuth(req, authorization, isAirline=True) user_id = await checkAuth(req, authorization, isAirline=True)
update = flight_update.model_dump() update = flight_update.model_dump()
update["user_id"] = id update["user_id"] = user_id
request_id = req.state.request_id request_id = req.state.request_id
header = {"x-api-request-id": request_id} header = {"x-api-request-id": request_id}
(response, status, _) = await request( (response, status, _) = await request(

View File

@ -1,7 +1,10 @@
from typing import Annotated
from asyncreq import request from asyncreq import request
from fastapi import APIRouter, HTTPException, Request from fastapi import APIRouter, Header, HTTPException, Request
from src.api.config import API_NOTIFICATIONS from src.api.config import API_NOTIFICATIONS
from src.api.routes.auth import checkAuth
from src.api.schemas.notification import Update as Message from src.api.schemas.notification import Update as Message
router = APIRouter() router = APIRouter()
@ -18,3 +21,22 @@ async def receive_message(message: Message, req: Request):
if status < 200 or status > 204: if status < 200 or status > 204:
raise HTTPException(status_code=status, detail=response) raise HTTPException(status_code=status, detail=response)
return response return response
@router.get("")
async def get_chat_by_user_id(
req: Request,
user_id: int,
authorization: Annotated[str | None, Header()] = None,
):
await checkAuth(req, authorization)
query = {}
query["user_id"] = user_id
request_id = req.state.request_id
header = {"x-api-request-id": request_id}
(response, status, _) = await request(
f"{API_NOTIFICATIONS}", "GET", query=query, headers=header
)
if status < 200 or status > 204:
raise HTTPException(status_code=status, detail=response)
return response

View File

@ -1,4 +1,4 @@
from typing import Annotated from typing import Annotated, Optional
from asyncreq import request from asyncreq import request
from fastapi import APIRouter, Header, HTTPException, Request from fastapi import APIRouter, Header, HTTPException, Request
@ -25,3 +25,42 @@ async def create_subscription(
if status < 200 or status > 204: if status < 200 or status > 204:
raise HTTPException(status_code=status, detail=response) raise HTTPException(status_code=status, detail=response)
return response return response
@router.delete("")
async def delete_subscription(
subscription: Subscription,
req: Request,
authorization: Annotated[str | None, Header()] = None,
):
await checkAuth(req, authorization)
request_id = req.state.request_id
header = {"x-api-request-id": request_id}
(response, status, _) = await request(
f"{API_SUBSCRIPTIONS}", "DELETE", json=subscription.model_dump(), headers=header
)
if status < 200 or status > 204:
raise HTTPException(status_code=status, detail=response)
return response
@router.get("")
async def get_subscriptions(
req: Request,
user_id: int,
flight_id: Optional[int] = None,
authorization: Annotated[str | None, Header()] = None,
):
await checkAuth(req, authorization)
query = {}
query["user_id"] = user_id
if flight_id:
query["flight_id"] = flight_id
request_id = req.state.request_id
header = {"x-api-request-id": request_id}
(response, status, _) = await request(
f"{API_SUBSCRIPTIONS}", "GET", query=query, headers=header
)
if status < 200 or status > 204:
raise HTTPException(status_code=status, detail=response)
return response

View File

@ -9,7 +9,20 @@ def get_subscriptions(db: Session, user_id: int):
return db.query(Subscription).filter(Subscription.user_id == user_id).all() return db.query(Subscription).filter(Subscription.user_id == user_id).all()
def get_subscription(db: Session, user_id: int, flight_id: int):
return (
db.query(Subscription)
.filter(Subscription.user_id == user_id, Subscription.flight_id == flight_id)
.first()
)
def create_subscription(db: Session, subscription: SubscriptionPydantic): def create_subscription(db: Session, subscription: SubscriptionPydantic):
if get_subscription(
db, user_id=subscription.user_id, flight_id=subscription.flight_id
):
raise ValueError
db_subscription = Subscription( db_subscription = Subscription(
user_id=subscription.user_id, user_id=subscription.user_id,
flight_id=subscription.flight_id, flight_id=subscription.flight_id,
@ -22,7 +35,7 @@ def create_subscription(db: Session, subscription: SubscriptionPydantic):
def remove_subscription(db: Session, user_id: int, flight_id: int): def remove_subscription(db: Session, user_id: int, flight_id: int):
db.query(Subscription).filter( db.query(Subscription).filter(
Subscription.user_id == user_id and Subscription.flight_id == flight_id Subscription.user_id == user_id, Subscription.flight_id == flight_id
).delete() ).delete()
db.commit() db.commit()

View File

@ -1,7 +1,7 @@
import re import re
from asyncreq import request from asyncreq import request
from fastapi import APIRouter, BackgroundTasks, Depends, Response from fastapi import APIRouter, BackgroundTasks, Depends, HTTPException, Response
from sqlalchemy.orm import Session from sqlalchemy.orm import Session
from src.api.config import API_FLIGHTS from src.api.config import API_FLIGHTS
@ -10,11 +10,15 @@ from src.api.cruds import subscription as subs_crud
from src.api.db import get_db from src.api.db import get_db
from src.api.schemas.chat import Chat, Update from src.api.schemas.chat import Chat, Update
from src.api.utils import telegram from src.api.utils import telegram
from src.api.utils.messages import get_flight_message, get_invalid_message from src.api.utils.messages import (
get_flight_message,
get_invalid_message,
get_start_message,
)
router = APIRouter() router = APIRouter()
msg_options = re.compile(r"^/(flight \d+|stop|start)$") msg_options = re.compile(r"^/(flight \d+|stop|start \d+)$")
@router.post("") @router.post("")
@ -33,8 +37,11 @@ async def create_chat(
action = text.partition(" ")[0] action = text.partition(" ")[0]
if action == "/start": if action == "/start":
user_id = int(message["text"].partition(" ")[2]) user_id = int(message["text"].partition(" ")[2])
new_chat = Chat(chat_id=str(message["chat"]["id"]), user_id=user_id) chat_id = str(message["chat"]["id"])
new_chat = Chat(chat_id=chat_id, user_id=user_id)
notif_crud.create_chat(db=db, chat=new_chat) notif_crud.create_chat(db=db, chat=new_chat)
msg = get_start_message()
background_tasks.add_task(telegram.send_message, chat_id, msg)
elif action == "/stop": elif action == "/stop":
chat_id = str(message["chat"]["id"]) chat_id = str(message["chat"]["id"])
user_id = notif_crud.get_user_from_chat(db=db, chat_id=chat_id).user_id user_id = notif_crud.get_user_from_chat(db=db, chat_id=chat_id).user_id
@ -50,3 +57,11 @@ async def create_chat(
background_tasks.add_task(telegram.send_message, chat_id, msg) background_tasks.add_task(telegram.send_message, chat_id, msg)
return Response(status_code=204) return Response(status_code=204)
@router.get("")
def get_chat_by_user_id(user_id: int, db: Session = Depends(get_db)):
db_chat = notif_crud.get_chat_id(db=db, user_id=user_id)
if db_chat is None:
raise HTTPException(status_code=404, detail="Chat not found")
return db_chat

View File

@ -1,31 +1,52 @@
from typing import Optional
from fastapi import APIRouter, Depends, HTTPException, Response from fastapi import APIRouter, Depends, HTTPException, Response
from sqlalchemy.orm import Session from sqlalchemy.orm import Session
from src.api.cruds import subscription as sub_crud from src.api.cruds import subscription as sub_crud
from src.api.db import get_db from src.api.db import get_db
from src.api.schemas.subscription import Subscription, SubscriptionRemove from src.api.schemas.subscription import Subscription
router = APIRouter() router = APIRouter()
@router.post("") @router.post("")
def create_subscription(subscription: Subscription, db: Session = Depends(get_db)): def create_subscription(subscription: Subscription, db: Session = Depends(get_db)):
return sub_crud.create_subscription(db=db, subscription=subscription) try:
db_subscription = sub_crud.create_subscription(db=db, subscription=subscription)
except ValueError:
raise HTTPException(status_code=409, detail="User already suscribed")
# if notif_crud.get_chat_id(subscription.user_id) is None:
# raise HTTPException(status_code=424, detail="First you need to create a chat")
return db_subscription
@router.get("/{user_id}", response_model=list[Subscription]) # @router.get("/{user_id}", response_model=list[Subscription])
def get_subscriptions(user_id: int, db: Session = Depends(get_db)): # def get_subscriptions(user_id: int, db: Session = Depends(get_db)):
db_subscriptions = sub_crud.get_subscriptions(db=db, user_id=user_id) # db_subscriptions = sub_crud.get_subscriptions(db=db, user_id=user_id)
# if db_subscriptions is None:
# raise HTTPException(status_code=404, detail="Subscription not found")
# return db_subscriptions
@router.get("")
def get_subscription(
user_id: int, flight_id: Optional[int] = None, db: Session = Depends(get_db)
):
if flight_id:
db_subscriptions = sub_crud.get_subscription(
db=db, user_id=user_id, flight_id=flight_id
)
else:
db_subscriptions = sub_crud.get_subscriptions(db=db, user_id=user_id)
if db_subscriptions is None: if db_subscriptions is None:
raise HTTPException(status_code=404, detail="Subscription not found") raise HTTPException(status_code=404, detail="Subscription not found")
return db_subscriptions return db_subscriptions
@router.delete("/{user_id}") @router.delete("")
def delete_subscription( def delete_subscription(subscription: Subscription, db: Session = Depends(get_db)):
user_id: int, subscription: SubscriptionRemove, db: Session = Depends(get_db)
):
sub_crud.remove_subscription( sub_crud.remove_subscription(
db=db, user_id=user_id, flight_id=subscription.flight_id db=db, user_id=subscription.user_id, flight_id=subscription.flight_id
) )
return Response(status_code=204) return Response(status_code=204)

View File

@ -30,7 +30,16 @@ def get_flight_message(flight: dict):
def get_invalid_message(): def get_invalid_message():
return ( return (
"Invalid option!\nPlease use:\n" "Invalid option!\nPlease use:\n"
"\n/flights NUMBER (e.g., /flights 1) for flight details" "\n/flight NUMBER (e.g., /flight 1) for flight details"
"\n/start to start receiving messages" # "\n/start to start receiving messages"
"\n/stop to manage updates." "\n/stop to stop receiving updates."
)
def get_start_message():
return (
"Thanks for using fids! You will now start getting updates from your subscriptions!\n"
"Meanwhile you can type:\n"
"\n/flight NUMBER (e.g., /flight 1) for flight details"
"\n/stop to stop receiving updates."
) )