diff options
-rw-r--r-- | .gitignore | 1 | ||||
-rw-r--r-- | README | 1 | ||||
-rw-r--r-- | bot.py | 51 | ||||
-rw-r--r-- | callback.py | 51 | ||||
-rw-r--r-- | command.py | 7 | ||||
-rw-r--r-- | dbstore/dbm_store.py | 34 | ||||
-rw-r--r-- | dbstore/peewee_store.py | 59 | ||||
-rw-r--r-- | foursquare/poi.py | 5 | ||||
-rw-r--r-- | requirements.txt | 15 |
9 files changed, 139 insertions, 85 deletions
@@ -2,6 +2,7 @@ foursquare/*_example.json | |||
2 | config.ini | 2 | config.ini |
3 | .idea/ | 3 | .idea/ |
4 | fsq_poi.db | 4 | fsq_poi.db |
5 | checkinbot.db | ||
5 | # Byte-compiled / optimized / DLL files | 6 | # Byte-compiled / optimized / DLL files |
6 | __pycache__/ | 7 | __pycache__/ |
7 | *.py[cod] | 8 | *.py[cod] |
@@ -11,3 +11,4 @@ TODO: | |||
11 | - OAuth login to Mastodon/Pleroma | 11 | - OAuth login to Mastodon/Pleroma |
12 | - Delayed checkins | 12 | - Delayed checkins |
13 | - user usage count, add Telegram payment option | 13 | - user usage count, add Telegram payment option |
14 | - connect one Telegram user to multiple Fediverse accounts | ||
@@ -61,6 +61,7 @@ from config import ( | |||
61 | ) | 61 | ) |
62 | from mastodon import Mastodon | 62 | from mastodon import Mastodon |
63 | 63 | ||
64 | from dbstore.peewee_store import db, User | ||
64 | 65 | ||
65 | # Enable logging | 66 | # Enable logging |
66 | logging.basicConfig( | 67 | logging.basicConfig( |
@@ -72,39 +73,35 @@ logger = logging.getLogger(__name__) | |||
72 | @dataclass | 73 | @dataclass |
73 | class FediLoginCallbackUpdate: | 74 | class FediLoginCallbackUpdate: |
74 | code: str | 75 | code: str |
75 | state: int | 76 | state: str |
76 | 77 | ||
77 | 78 | ||
78 | class FediLoginCallbackContext(CallbackContext[ExtBot, dict, dict, dict]): | 79 | class FediLoginCallbackContext(CallbackContext[ExtBot, dict, dict, dict]): |
79 | @classmethod | 80 | pass |
80 | def from_update( | ||
81 | cls, | ||
82 | update: object, | ||
83 | application: "Application", | ||
84 | ) -> "FediLoginCallbackContext": | ||
85 | if isinstance(update, FediLoginCallbackUpdate): | ||
86 | return cls(application=application, user_id=update.state) | ||
87 | return super().from_update(update, application) | ||
88 | 81 | ||
89 | 82 | ||
90 | async def process_oauth_login_callback(update: FediLoginCallbackUpdate, context: FediLoginCallbackContext) -> None: | 83 | async def process_oauth_login_callback(update: FediLoginCallbackUpdate, context: FediLoginCallbackContext) -> None: |
91 | # query client_id and client_secret from in memory database | 84 | state = update.state |
92 | client_id = "" | 85 | |
93 | client_secret = "" | 86 | with db.connection_context(): |
94 | home_instance = "" | 87 | user = User.get(User.state == state) |
95 | |||
96 | mastodon_client = Mastodon(client_id=client_id, client_secret=client_secret, api_base_url=home_instance) | ||
97 | access_token = mastodon_client.log_in( | ||
98 | code=update.code, | ||
99 | redirect_uri="{}{}".format(BOT_DOMAIN, FEDI_LOGIN_CALLBACK_URL), | ||
100 | scopes=BOT_SCOPE | ||
101 | ) | ||
102 | 88 | ||
103 | # TODO | 89 | client_id = user.client_id |
104 | # save access_token to database | 90 | client_secret = user.client_secret |
91 | home_instance = user.home_instance | ||
92 | |||
93 | if len(user.access_key) == 0: | ||
94 | mastodon_client = Mastodon(client_id=client_id, client_secret=client_secret, api_base_url=home_instance) | ||
95 | access_token = mastodon_client.log_in( | ||
96 | code=update.code, | ||
97 | redirect_uri="{}{}".format(BOT_DOMAIN, FEDI_LOGIN_CALLBACK_URL), | ||
98 | scopes=BOT_SCOPE | ||
99 | ) | ||
100 | user.access_key = access_token | ||
101 | user.save() | ||
105 | 102 | ||
106 | text = "You have successfully logged in to your Mastodon account!" | 103 | text = "You have successfully logged in to your Mastodon account!" |
107 | await context.bot.send_message(chat_id=update.state, text=text) | 104 | await context.bot.send_message(chat_id=user.telegram_user_id, text=text) |
108 | 105 | ||
109 | 106 | ||
110 | async def main() -> None: | 107 | async def main() -> None: |
@@ -112,7 +109,7 @@ async def main() -> None: | |||
112 | # Here we set updater to None because we want our custom webhook server to handle the updates | 109 | # Here we set updater to None because we want our custom webhook server to handle the updates |
113 | # and hence we don't need an Updater instance | 110 | # and hence we don't need an Updater instance |
114 | application = ( | 111 | application = ( |
115 | Application.builder().token(BOT_TOKEN).context_types(context_types).build() | 112 | Application.builder().updater(None).token(BOT_TOKEN).context_types(context_types).build() |
116 | ) | 113 | ) |
117 | 114 | ||
118 | checkin_handler = ConversationHandler( | 115 | checkin_handler = ConversationHandler( |
@@ -171,7 +168,7 @@ async def main() -> None: | |||
171 | """ | 168 | """ |
172 | try: | 169 | try: |
173 | code = request.query_params["code"] | 170 | code = request.query_params["code"] |
174 | state = int(request.query_params.get("state")) | 171 | state = request.query_params.get("state") |
175 | except KeyError: | 172 | except KeyError: |
176 | return PlainTextResponse( | 173 | return PlainTextResponse( |
177 | status_code=HTTPStatus.BAD_REQUEST, | 174 | status_code=HTTPStatus.BAD_REQUEST, |
diff --git a/callback.py b/callback.py index c7cb60c..4fe0540 100644 --- a/callback.py +++ b/callback.py | |||
@@ -7,13 +7,23 @@ from telegram.error import BadRequest | |||
7 | from telegram.ext import CallbackContext | 7 | from telegram.ext import CallbackContext |
8 | 8 | ||
9 | from command import * | 9 | from command import * |
10 | from dbstore.dbm_store import get_loc | 10 | from dbstore.peewee_store import get_poi_by_fsq_id |
11 | from foursquare.poi import OSM_ENDPOINT | 11 | from foursquare.poi import OSM_ENDPOINT |
12 | from foursquare.poi import query_poi | 12 | from foursquare.poi import query_poi |
13 | # from toot import mastodon_client | ||
14 | from config import BOT_SCOPE | 13 | from config import BOT_SCOPE |
14 | from dbstore.peewee_store import User, db | ||
15 | import uuid | ||
15 | 16 | ||
16 | mastodon_client = None | 17 | |
18 | def generate_uuid(): | ||
19 | return str(uuid.uuid4()) | ||
20 | |||
21 | |||
22 | def get_mastodon_client(user_id: int): | ||
23 | with db.connection_context(): | ||
24 | user = User.get(User.telegram_user_id == user_id) | ||
25 | if user.home_instance and user.access_key: | ||
26 | return Mastodon(access_token=user.access_key, api_base_url=user.home_instance) | ||
17 | 27 | ||
18 | 28 | ||
19 | def generate_toot_text(poi_name, poi_locality, poi_region, poi_lat, poi_lon): | 29 | def generate_toot_text(poi_name, poi_locality, poi_region, poi_lat, poi_lon): |
@@ -41,6 +51,7 @@ async def get_img_file_bytes(telegram_media_file): | |||
41 | async def process_media_group(context: CallbackContext): | 51 | async def process_media_group(context: CallbackContext): |
42 | context.job.data = cast(List[MsgDict], context.job.data) | 52 | context.job.data = cast(List[MsgDict], context.job.data) |
43 | 53 | ||
54 | mastodon_client = get_mastodon_client(context.user_data["user_id"]) | ||
44 | media_id = [] | 55 | media_id = [] |
45 | chat_id = context.job.data[0].get("chat_id") | 56 | chat_id = context.job.data[0].get("chat_id") |
46 | for media_dict in context.job.data: | 57 | for media_dict in context.job.data: |
@@ -61,9 +72,6 @@ async def process_media_group(context: CallbackContext): | |||
61 | 72 | ||
62 | 73 | ||
63 | async def callback_generate_fedi_login_url(update: Update, context: ContextTypes.DEFAULT_TYPE) -> int: | 74 | async def callback_generate_fedi_login_url(update: Update, context: ContextTypes.DEFAULT_TYPE) -> int: |
64 | # generate fedi OAuth login url | ||
65 | global mastodon_client | ||
66 | |||
67 | home_instance = update.effective_message.text | 75 | home_instance = update.effective_message.text |
68 | client_id, client_secret = Mastodon.create_app( | 76 | client_id, client_secret = Mastodon.create_app( |
69 | "Checkin.bot", | 77 | "Checkin.bot", |
@@ -71,13 +79,25 @@ async def callback_generate_fedi_login_url(update: Update, context: ContextTypes | |||
71 | redirect_uris="{}{}".format(BOT_DOMAIN, FEDI_LOGIN_CALLBACK_URL), | 79 | redirect_uris="{}{}".format(BOT_DOMAIN, FEDI_LOGIN_CALLBACK_URL), |
72 | api_base_url=home_instance, | 80 | api_base_url=home_instance, |
73 | ) | 81 | ) |
82 | print("client_id: {}".format(client_id)) | ||
83 | print("client_secret: {}".format(client_secret)) | ||
84 | |||
74 | m = Mastodon(client_id=client_id, client_secret=client_secret, api_base_url=home_instance) | 85 | m = Mastodon(client_id=client_id, client_secret=client_secret, api_base_url=home_instance) |
75 | 86 | ||
76 | # TODO | 87 | user_id = update.effective_user.id |
77 | # generate random string as OAuth state | 88 | state = generate_uuid() |
89 | |||
90 | db.connect() | ||
91 | u = User.get_or_none(telegram_user_id=user_id) | ||
92 | if u is None: | ||
93 | u = User.create(telegram_user_id=user_id, access_key="", home_instance=home_instance, | ||
94 | client_id=client_id, client_secret=client_secret, state=state) | ||
95 | u.save() | ||
96 | db.close() | ||
97 | |||
78 | oauth_url = m.auth_request_url(redirect_uris="{}{}".format(BOT_DOMAIN, FEDI_LOGIN_CALLBACK_URL), | 98 | oauth_url = m.auth_request_url(redirect_uris="{}{}".format(BOT_DOMAIN, FEDI_LOGIN_CALLBACK_URL), |
79 | scopes=BOT_SCOPE, | 99 | scopes=BOT_SCOPE, |
80 | state=update.effective_user.id) | 100 | state=state) |
81 | 101 | ||
82 | await update.message.reply_text(PROMPT_FEDI_LOGIN, | 102 | await update.message.reply_text(PROMPT_FEDI_LOGIN, |
83 | reply_markup=InlineKeyboardMarkup([[InlineKeyboardButton("Login", url=oauth_url)]]), | 103 | reply_markup=InlineKeyboardMarkup([[InlineKeyboardButton("Login", url=oauth_url)]]), |
@@ -93,9 +113,9 @@ async def callback_location_sharing(update: Update, context: ContextTypes.DEFAUL | |||
93 | context.user_data["latitude"] = update.message.venue.location.latitude | 113 | context.user_data["latitude"] = update.message.venue.location.latitude |
94 | context.user_data["longitude"] = update.message.venue.location.longitude | 114 | context.user_data["longitude"] = update.message.venue.location.longitude |
95 | 115 | ||
96 | poi = get_loc(context.user_data.get("fsq_id")) | 116 | poi = get_poi_by_fsq_id(context.user_data.get("fsq_id")) |
97 | content = generate_toot_text(poi["name"], poi["locality"], poi["region"], poi["latitude"], poi["longitude"]) | 117 | content = generate_toot_text(poi["name"], poi["locality"], poi["region"], poi["latitude"], poi["longitude"]) |
98 | status = mastodon_client.status_post(content, visibility=DEFAULT_TOOT_VISIBILITY, media_ids=[]) | 118 | status = get_mastodon_client(update.effective_user.id).status_post(content, visibility=DEFAULT_TOOT_VISIBILITY, media_ids=[]) |
99 | 119 | ||
100 | context.user_data[KEY_TOOT_STATUS_ID] = status["id"] | 120 | context.user_data[KEY_TOOT_STATUS_ID] = status["id"] |
101 | context.user_data[KEY_TOOT_STATUS_CONTENT] = content | 121 | context.user_data[KEY_TOOT_STATUS_CONTENT] = content |
@@ -165,12 +185,12 @@ async def callback_skip_location_keyword_search(update: Update, context: Context | |||
165 | async def _process_location_selection(context: ContextTypes.DEFAULT_TYPE) -> int: | 185 | async def _process_location_selection(context: ContextTypes.DEFAULT_TYPE) -> int: |
166 | poi_name = context.user_data.get("poi_name") | 186 | poi_name = context.user_data.get("poi_name") |
167 | if context.user_data.get("fsq_id") is not None: | 187 | if context.user_data.get("fsq_id") is not None: |
168 | poi = get_loc(context.user_data.get("fsq_id")) | 188 | poi = get_poi_by_fsq_id(context.user_data.get("fsq_id")) |
169 | content = generate_toot_text(poi["name"], poi["locality"], poi["region"], poi["latitude"], poi["longitude"]) | 189 | content = generate_toot_text(poi["name"], poi["locality"], poi["region"], poi["latitude"], poi["longitude"]) |
170 | else: | 190 | else: |
171 | content = generate_toot_text(poi_name, "", "", context.user_data.get("latitude"), context.user_data.get("longitude")) | 191 | content = generate_toot_text(poi_name, "", "", context.user_data.get("latitude"), context.user_data.get("longitude")) |
172 | 192 | ||
173 | status = mastodon_client.status_post(content, visibility=DEFAULT_TOOT_VISIBILITY, media_ids=[]) | 193 | status = get_mastodon_client(context.user_data["user_id"]).status_post(content, visibility=DEFAULT_TOOT_VISIBILITY, media_ids=[]) |
174 | 194 | ||
175 | context.user_data[KEY_TOOT_STATUS_ID] = status["id"] | 195 | context.user_data[KEY_TOOT_STATUS_ID] = status["id"] |
176 | context.user_data[KEY_TOOT_STATUS_CONTENT] = content | 196 | context.user_data[KEY_TOOT_STATUS_CONTENT] = content |
@@ -192,6 +212,7 @@ async def callback_location_confirmation(update: Update, context: ContextTypes.D | |||
192 | query = update.callback_query | 212 | query = update.callback_query |
193 | await query.answer() | 213 | await query.answer() |
194 | context.user_data["fsq_id"] = query.data | 214 | context.user_data["fsq_id"] = query.data |
215 | context.user_data["user_id"] = update.effective_user.id | ||
195 | await query.delete_message() | 216 | await query.delete_message() |
196 | 217 | ||
197 | context.user_data["chat_id"] = update.effective_chat.id | 218 | context.user_data["chat_id"] = update.effective_chat.id |
@@ -202,6 +223,7 @@ async def callback_location_confirmation(update: Update, context: ContextTypes.D | |||
202 | async def callback_manual_location(update: Update, context: ContextTypes.DEFAULT_TYPE) -> int: | 223 | async def callback_manual_location(update: Update, context: ContextTypes.DEFAULT_TYPE) -> int: |
203 | context.user_data["poi_name"] = update.effective_message.text | 224 | context.user_data["poi_name"] = update.effective_message.text |
204 | context.user_data["chat_id"] = update.effective_chat.id | 225 | context.user_data["chat_id"] = update.effective_chat.id |
226 | context.user_data["user_id"] = update.effective_user.id | ||
205 | 227 | ||
206 | return await _process_location_selection(context) | 228 | return await _process_location_selection(context) |
207 | 229 | ||
@@ -219,7 +241,7 @@ async def callback_add_comment(update: Update, context: ContextTypes.DEFAULT_TYP | |||
219 | await context.bot.delete_message(update.effective_chat.id, context.user_data.get(PROMPT_ADD_COMMENT)) | 241 | await context.bot.delete_message(update.effective_chat.id, context.user_data.get(PROMPT_ADD_COMMENT)) |
220 | 242 | ||
221 | comment = update.effective_message.text | 243 | comment = update.effective_message.text |
222 | mastodon_client.status_update(id=context.user_data.get(KEY_TOOT_STATUS_ID), | 244 | get_mastodon_client(update.effective_user.id).status_update(id=context.user_data.get(KEY_TOOT_STATUS_ID), |
223 | status=f"{comment} " + context.user_data.get(KEY_TOOT_STATUS_CONTENT)) | 245 | status=f"{comment} " + context.user_data.get(KEY_TOOT_STATUS_CONTENT)) |
224 | context.user_data[KEY_TOOT_STATUS_CONTENT] = f"{comment} " + context.user_data.get(KEY_TOOT_STATUS_CONTENT) | 246 | context.user_data[KEY_TOOT_STATUS_CONTENT] = f"{comment} " + context.user_data.get(KEY_TOOT_STATUS_CONTENT) |
225 | 247 | ||
@@ -243,6 +265,7 @@ async def callback_add_media(update: Update, context: CallbackContext): | |||
243 | if "not found" in str(e.message): | 265 | if "not found" in str(e.message): |
244 | pass | 266 | pass |
245 | 267 | ||
268 | mastodon_client = get_mastodon_client(update.effective_user.id) | ||
246 | status_id = context.user_data.get(KEY_TOOT_STATUS_ID) | 269 | status_id = context.user_data.get(KEY_TOOT_STATUS_ID) |
247 | status_content = context.user_data.get(KEY_TOOT_STATUS_CONTENT) | 270 | status_content = context.user_data.get(KEY_TOOT_STATUS_CONTENT) |
248 | 271 | ||
@@ -15,13 +15,6 @@ async def start_command(update: Update, context: ContextTypes.DEFAULT_TYPE) -> i | |||
15 | 15 | ||
16 | 16 | ||
17 | async def fedi_login_command(update: Update, context: ContextTypes.DEFAULT_TYPE) -> int: | 17 | async def fedi_login_command(update: Update, context: ContextTypes.DEFAULT_TYPE) -> int: |
18 | # generate fedi OAuth login url | ||
19 | |||
20 | # mastodon_client = Mastodon(client_id=MASTODON_CLIENT_ID_FILE, api_base_url=TOOT_API_BASE_URL) | ||
21 | # oauth_url = mastodon_client.auth_request_url(redirect_uris="{}/{}".format(BOT_DOMAIN, FEDI_LOGIN_CALLBACK_URL), | ||
22 | # scopes=['write:media', 'write:statuses']) | ||
23 | # | ||
24 | # await update.message.reply_text(PROMPT_FEDI_LOGIN.format(oauth_url), parse_mode=ParseMode.MARKDOWN) | ||
25 | await update.message.reply_text(PROMPT_FEDI_LOGIN_WHERE_IS_INSTANCE, parse_mode=ParseMode.MARKDOWN) | 18 | await update.message.reply_text(PROMPT_FEDI_LOGIN_WHERE_IS_INSTANCE, parse_mode=ParseMode.MARKDOWN) |
26 | return FEDI_LOGIN | 19 | return FEDI_LOGIN |
27 | 20 | ||
diff --git a/dbstore/dbm_store.py b/dbstore/dbm_store.py deleted file mode 100644 index fedb505..0000000 --- a/dbstore/dbm_store.py +++ /dev/null | |||
@@ -1,34 +0,0 @@ | |||
1 | import dbm | ||
2 | |||
3 | db = None | ||
4 | store_file = "fsq_poi.db" | ||
5 | |||
6 | |||
7 | def get_loc(fsq_id): | ||
8 | global db | ||
9 | if db is None: | ||
10 | db = dbm.open(store_file, 'c') | ||
11 | if fsq_id in db: | ||
12 | res = db[fsq_id].decode("utf-8").split("|") | ||
13 | return { | ||
14 | "name": res[0], | ||
15 | "locality": res[1], | ||
16 | "region": res[2], | ||
17 | "latitude": res[3], | ||
18 | "longitude": res[4], | ||
19 | "osm_url": res[5], | ||
20 | } | ||
21 | else: | ||
22 | return None | ||
23 | |||
24 | |||
25 | def store_loc(loc): | ||
26 | global db | ||
27 | if db is None: | ||
28 | db = dbm.open(store_file, 'c') | ||
29 | db[loc["fsq_id"]] = "{}|{}|{}|{}|{}|{}".format(loc["name"], | ||
30 | loc["locality"], | ||
31 | loc["region"], | ||
32 | loc["latitude"], | ||
33 | loc["longitude"], | ||
34 | loc["osm_url"]) | ||
diff --git a/dbstore/peewee_store.py b/dbstore/peewee_store.py new file mode 100644 index 0000000..37b8c01 --- /dev/null +++ b/dbstore/peewee_store.py | |||
@@ -0,0 +1,59 @@ | |||
1 | from peewee import * | ||
2 | |||
3 | db = SqliteDatabase("checkinbot.db") | ||
4 | db.connect(reuse_if_open=True) | ||
5 | |||
6 | |||
7 | class BaseModel(Model): | ||
8 | class Meta: | ||
9 | database = db | ||
10 | |||
11 | |||
12 | class User(BaseModel): | ||
13 | telegram_user_id = CharField(unique=True, primary_key=True) | ||
14 | access_key = CharField(max_length=64) | ||
15 | home_instance = CharField(max_length=128) | ||
16 | state = CharField(max_length=128) | ||
17 | client_id = CharField(max_length=128) | ||
18 | client_secret = CharField(max_length=128) | ||
19 | |||
20 | |||
21 | class Location(BaseModel): | ||
22 | fsq_id = CharField(unique=True, primary_key=True) | ||
23 | name = CharField(max_length=128) | ||
24 | locality = CharField(max_length=128) | ||
25 | region = CharField(max_length=128) | ||
26 | latitude = CharField(max_length=128) | ||
27 | longitude = CharField(max_length=128) | ||
28 | |||
29 | |||
30 | with db.connection_context(): | ||
31 | db.create_tables([User, Location]) | ||
32 | |||
33 | |||
34 | def get_poi_by_fsq_id(fsq_id) -> dict: | ||
35 | with db.connection_context(): | ||
36 | try: | ||
37 | poi = Location.get(Location.fsq_id == fsq_id) | ||
38 | return { | ||
39 | "name": poi.name, | ||
40 | "locality": poi.locality, | ||
41 | "region": poi.region, | ||
42 | "latitude": poi.latitude, | ||
43 | "longitude": poi.longitude, | ||
44 | } | ||
45 | except DoesNotExist: | ||
46 | return {} | ||
47 | |||
48 | |||
49 | def create_poi(poi: dict): | ||
50 | with db.connection_context(): | ||
51 | poi = Location.create( | ||
52 | fsq_id=poi["fsq_id"], | ||
53 | name=poi["name"], | ||
54 | locality=poi["locality"], | ||
55 | region=poi["region"], | ||
56 | latitude=poi["latitude"], | ||
57 | longitude=poi["longitude"], | ||
58 | ) | ||
59 | poi.save() | ||
diff --git a/foursquare/poi.py b/foursquare/poi.py index 5e67d1c..45b4fa9 100644 --- a/foursquare/poi.py +++ b/foursquare/poi.py | |||
@@ -3,7 +3,7 @@ import json | |||
3 | import requests | 3 | import requests |
4 | 4 | ||
5 | from config import FSQ_API_KEY | 5 | from config import FSQ_API_KEY |
6 | from dbstore.dbm_store import store_loc | 6 | from dbstore.peewee_store import create_poi |
7 | 7 | ||
8 | POI_API_ENDPOINT = "https://api.foursquare.com/v3/places/nearby?ll={}%2C{}&limit=10" | 8 | POI_API_ENDPOINT = "https://api.foursquare.com/v3/places/nearby?ll={}%2C{}&limit=10" |
9 | POI_SEARCH_API_ENDPOINT = "https://api.foursquare.com/v3/places/search?query={}&ll={}%2C{}&radius=2000&limit=10" | 9 | POI_SEARCH_API_ENDPOINT = "https://api.foursquare.com/v3/places/search?query={}&ll={}%2C{}&radius=2000&limit=10" |
@@ -33,8 +33,7 @@ def query_poi(search, latitude, longitude): | |||
33 | "osm_url": OSM_ENDPOINT.format(poi["geocodes"]["main"]["latitude"], poi["geocodes"]["main"]["longitude"]) | 33 | "osm_url": OSM_ENDPOINT.format(poi["geocodes"]["main"]["latitude"], poi["geocodes"]["main"]["longitude"]) |
34 | } | 34 | } |
35 | locations.append(loc) | 35 | locations.append(loc) |
36 | print(loc) | 36 | create_poi(loc) |
37 | store_loc(loc) | ||
38 | 37 | ||
39 | return locations | 38 | return locations |
40 | 39 | ||
diff --git a/requirements.txt b/requirements.txt index c031383..c3166b6 100644 --- a/requirements.txt +++ b/requirements.txt | |||
@@ -1,8 +1,12 @@ | |||
1 | anyio==3.6.2 | 1 | anyio==3.6.2 |
2 | APScheduler==3.10.0 | ||
3 | asgiref==3.6.0 | ||
2 | blurhash==1.1.4 | 4 | blurhash==1.1.4 |
3 | certifi==2022.12.7 | 5 | certifi==2022.12.7 |
4 | charset-normalizer==3.0.1 | 6 | charset-normalizer==3.0.1 |
7 | click==8.1.3 | ||
5 | decorator==5.1.1 | 8 | decorator==5.1.1 |
9 | greenlet==2.0.2 | ||
6 | h11==0.14.0 | 10 | h11==0.14.0 |
7 | h2==4.1.0 | 11 | h2==4.1.0 |
8 | hpack==4.0.0 | 12 | hpack==4.0.0 |
@@ -11,11 +15,22 @@ httpx==0.23.3 | |||
11 | hyperframe==6.0.1 | 15 | hyperframe==6.0.1 |
12 | idna==3.4 | 16 | idna==3.4 |
13 | Mastodon.py==1.8.0 | 17 | Mastodon.py==1.8.0 |
18 | peewee==3.15.4 | ||
19 | Pillow==9.4.0 | ||
14 | python-dateutil==2.8.2 | 20 | python-dateutil==2.8.2 |
15 | python-magic==0.4.27 | 21 | python-magic==0.4.27 |
16 | python-telegram-bot==20.1 | 22 | python-telegram-bot==20.1 |
23 | pytz==2022.7.1 | ||
24 | pytz-deprecation-shim==0.1.0.post0 | ||
17 | requests==2.28.2 | 25 | requests==2.28.2 |
18 | rfc3986==1.5.0 | 26 | rfc3986==1.5.0 |
19 | six==1.16.0 | 27 | six==1.16.0 |
20 | sniffio==1.3.0 | 28 | sniffio==1.3.0 |
29 | SQLAlchemy==2.0.4 | ||
30 | sqlparse==0.4.3 | ||
31 | starlette==0.25.0 | ||
32 | typing_extensions==4.5.0 | ||
33 | tzdata==2022.7 | ||
34 | tzlocal==4.2 | ||
21 | urllib3==1.26.14 | 35 | urllib3==1.26.14 |
36 | uvicorn==0.20.0 | ||