Skip to content

Commit b770f91

Browse files
committed
feat: more user friendly position removal
1 parent 8d80a7a commit b770f91

File tree

11 files changed

+1194
-1040
lines changed

11 files changed

+1194
-1040
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ __pycache__/
55

66
sql_app.db
77
*.swp
8+
*.log
89
.venv/
910
.env
1011
tags

Dockerfile

Lines changed: 0 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -3,14 +3,5 @@ FROM tiangolo/uvicorn-gunicorn:python3.9
33
COPY requirements.txt /tmp/requirements.txt
44
RUN pip install --no-cache-dir -r /tmp/requirements.txt
55

6-
# Install redis
7-
RUN set -ex; \
8-
apt-get update; \
9-
apt-get install -y --no-install-recommends \
10-
redis-server \
11-
; \
12-
rm -rf /var/lib/apt/lists/*
13-
146
COPY . .
15-
167
CMD ["uvicorn", "telegram_bot.app:app", "--host", "0.0.0.0", "--port", "8080", "--workers", "2"]

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,4 +43,4 @@ Q. 有考虑支持多地区订阅吗(比如关心亲朋好友和出差人员)?
4343
A. 支持 `add_sub_locations `命令添加子城市,`delete_sub_locations` 命令清除。
4444

4545
Q. 希望能支持 docker 部署 ,还有说明一下,哪些参数要改?
46-
A.
46+
A. WIP..

poetry.lock

Lines changed: 1099 additions & 997 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

telegram_bot/app.py

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111
from telegram_bot.cron import cron, scheduler
1212
from telegram_bot.database import models
1313
from telegram_bot.database.database import engine
14-
from telegram_bot.settings import settings, aio_lru_cache_1h
14+
from telegram_bot.settings import settings
1515

1616
# 日志格式设置
1717
logger.remove()
@@ -25,7 +25,6 @@
2525
app.include_router(release.router)
2626

2727

28-
@aio_lru_cache_1h
2928
@app.on_event("startup")
3029
async def startup_event():
3130
# 定时任务

telegram_bot/database/crud.py

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -164,13 +164,15 @@ def remove_ding_bot(db: Session, chat_id: str):
164164
return False
165165

166166

167-
def remove_sub_locations(db: Session, chat_id: str):
168-
locations = filter_locations(db, chat_id)
169-
if locations:
170-
for location in locations:
171-
db.delete(location)
167+
def remove_sub_location(db: Session, location_id: str) -> bool:
168+
location = (
169+
db.query(models.Locations).filter(models.Locations.id == location_id).first()
170+
)
171+
if location:
172+
db.delete(location)
172173
db.commit()
173174
return True
175+
return False
174176

175177

176178
def get_cron_job(db, chat_id, hour):

telegram_bot/database/database.py

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,9 +10,11 @@
1010

1111
connect_args = {}
1212
if not settings.is_production:
13-
connect_args = {'check_same_thread': False}
13+
connect_args["check_same_thread"] = False
1414

15-
engine = create_engine(SQLALCHEMY_DATABASE_URL, connect_args=connect_args)
15+
engine = create_engine(
16+
SQLALCHEMY_DATABASE_URL, connect_args=connect_args, pool_pre_ping=True
17+
)
1618
SessionLocal = sessionmaker(autocommit=False, autoflush=False, bind=engine)
1719

1820
Base = declarative_base()

telegram_bot/settings.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@
55

66
from aiocache import cached, Cache
77
from aiogram.contrib.fsm_storage.redis import RedisStorage
8-
from aiogram.contrib.fsm_storage.memory import MemoryStorage
98
from pydantic import BaseSettings, SecretStr
109

1110

telegram_bot/telegram/callbacks.py

Lines changed: 39 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@
77
from telegram_bot.settings import aio_lru_cache_24h
88
from telegram_bot.telegram.dispatcher import dp
99
from telegram_bot.telegram.keyboard.keyboard_markup_factory import (
10+
HOURS_TEMPLATE,
11+
REMOVE_LOCATION_PREFIX,
1012
KeyboardMarkUpFactory,
1113
WELCOME_TEXT,
1214
GET_WEATHER,
@@ -15,7 +17,7 @@
1517
DISABLE_SUB,
1618
UPDATE_SUB_CRON,
1719
BACK,
18-
HOURS,
20+
hour_decode,
1921
)
2022
from telegram_bot.telegram.update_location import update_location
2123

@@ -163,9 +165,9 @@ async def exit_callback_handler(query: types.CallbackQuery):
163165
await query.answer("")
164166

165167

166-
@dp.callback_query_handler(lambda callback_query: callback_query.data in HOURS)
168+
@dp.callback_query_handler(lambda callback_query: callback_query.data in HOURS_TEMPLATE)
167169
async def sub_cron_update_callback_handler(query: types.CallbackQuery):
168-
hour = query.data
170+
hour = hour_decode(query.data)
169171
chat_id = query.message.chat.id
170172

171173
with get_db_session() as db:
@@ -183,3 +185,37 @@ async def sub_cron_update_callback_handler(query: types.CallbackQuery):
183185
db.refresh(user)
184186
cron_sub_menu = KeyboardMarkUpFactory.build_cron_options(user)
185187
await query.message.edit_reply_markup(cron_sub_menu)
188+
189+
190+
@dp.message_handler(commands=["delete_sub_locations"])
191+
async def remove_ding_token(message: types.Message) -> None:
192+
chat_id = str(message.chat.id)
193+
with get_db_session() as db:
194+
locations = crud.filter_locations(db, chat_id)
195+
if not locations:
196+
await message.reply("不存在其他子位置")
197+
return
198+
199+
mark_up = KeyboardMarkUpFactory.build_sub_locations(locations)
200+
await TelegramMessageService.send_keyboard_markup(
201+
dp.bot, chat_id, "单击城市删除👇", mark_up
202+
)
203+
204+
205+
@dp.callback_query_handler(
206+
lambda callback_query: REMOVE_LOCATION_PREFIX in callback_query.data
207+
)
208+
async def delete_sub_location_update_callback_handler(query: types.CallbackQuery):
209+
location_id = query.data.replace(REMOVE_LOCATION_PREFIX, "")
210+
chat_id = str(query.message.chat.id)
211+
212+
with get_db_session() as db:
213+
deleted = crud.remove_sub_location(db, location_id)
214+
if not deleted:
215+
return
216+
217+
await query.answer("删除成功")
218+
219+
locations = crud.filter_locations(db, chat_id)
220+
cron_sub_menu = KeyboardMarkUpFactory.build_sub_locations(locations)
221+
await query.message.edit_reply_markup(cron_sub_menu)

telegram_bot/telegram/keyboard/keyboard_markup_factory.py

Lines changed: 42 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,10 @@
1-
from typing import Optional
1+
import itertools
2+
from typing import List, Optional, Union
23

34
from aiogram.types import InlineKeyboardMarkup, InlineKeyboardButton
45

5-
from telegram_bot.database import models
6+
from telegram_bot.database import crud, models
7+
from telegram_bot.database.database import get_db, get_db_session
68

79
WELCOME_TEXT = """\
810
基于「和风」的天气预报机器人;根据定位查询精准实时天气,并每天自动播报。
@@ -15,7 +17,14 @@
1517
UPDATE_SUB_CRON = "update_cron"
1618
BACK = "back"
1719

20+
REMOVE_LOCATION_PREFIX = "remove_location_"
21+
22+
# fmt: off
23+
def hour_encode(hour: Union[int, str]) -> str: return f"cron_{hour}"
24+
def hour_decode(hour: str) -> str: return hour.replace("cron_", "")
25+
# fmt: on
1826
HOURS = tuple(str(x) for x in range(0, 24, 2))
27+
HOURS_TEMPLATE = tuple(hour_encode(x) for x in range(0, 24, 2))
1928

2029

2130
class KeyboardMarkUpFactory:
@@ -24,16 +33,20 @@ def build_main_menu(chat: "models.Chat") -> InlineKeyboardMarkup:
2433
keyboard_markup = InlineKeyboardMarkup(row_width=6)
2534

2635
# 第一行:天气获取
27-
weather_button = InlineKeyboardButton('获取实时天气', callback_data=GET_WEATHER)
36+
weather_button = InlineKeyboardButton("获取实时天气", callback_data=GET_WEATHER)
2837
keyboard_markup.add(weather_button)
2938

3039
# 第二行:自定义配置
31-
inline_buttons = [InlineKeyboardButton('更新位置', callback_data=UPDATE_LOCATION)]
40+
inline_buttons = [InlineKeyboardButton("更新位置", callback_data=UPDATE_LOCATION)]
3241
if chat and chat.is_location_exist:
33-
sub_cron_button = InlineKeyboardButton('定时订阅', callback_data=UPDATE_SUB_CRON)
42+
sub_cron_button = InlineKeyboardButton(
43+
"定时订阅", callback_data=UPDATE_SUB_CRON
44+
)
3445
inline_buttons.append(sub_cron_button)
3546

36-
star_button = InlineKeyboardButton('关注项目✨', url="https://github.com/daya0576/he_weather_bot")
47+
star_button = InlineKeyboardButton(
48+
"关注项目✨", url="https://github.com/daya0576/he_weather_bot"
49+
)
3750
inline_buttons.append(star_button)
3851
keyboard_markup.row(*inline_buttons)
3952

@@ -49,12 +62,33 @@ def build_cron_options(chat: "models.Chat") -> Optional[InlineKeyboardMarkup]:
4962
chunk_size = 6
5063
for x in range(0, len(HOURS), chunk_size):
5164
inline_btn_list = []
52-
for hour in HOURS[x:x + chunk_size]:
65+
for hour in HOURS[x : x + chunk_size]:
5366
hour_formatted = f"{hour}✓" if hour in chat.sub_hours else hour
54-
btn = InlineKeyboardButton(hour_formatted, callback_data=hour)
67+
btn = InlineKeyboardButton(
68+
hour_formatted, callback_data=hour_encode(hour)
69+
)
5570
inline_btn_list.append(btn)
5671
keyboard_markup.row(*inline_btn_list)
5772

5873
back_btn = InlineKeyboardButton("返回", callback_data=BACK)
5974
keyboard_markup.add(back_btn)
6075
return keyboard_markup
76+
77+
@staticmethod
78+
def build_sub_locations(
79+
locations: List["models.Locations"],
80+
) -> Optional[InlineKeyboardMarkup]:
81+
keyboard_markup = InlineKeyboardMarkup(row_width=6)
82+
83+
chunk_size = 4
84+
for i in range(0, len(locations), chunk_size):
85+
inline_position_list = []
86+
for location in locations[i : i + chunk_size]:
87+
btn = InlineKeyboardButton(
88+
str(location.city_name),
89+
callback_data=f"{REMOVE_LOCATION_PREFIX}{location.id}",
90+
)
91+
inline_position_list.append(btn)
92+
keyboard_markup.row(*inline_position_list)
93+
94+
return keyboard_markup

0 commit comments

Comments
 (0)