second one
This commit is contained in:
1
.gitignore
vendored
1
.gitignore
vendored
@ -2,3 +2,4 @@
|
|||||||
config.py
|
config.py
|
||||||
*.pyc
|
*.pyc
|
||||||
**/__pycache__
|
**/__pycache__
|
||||||
|
**/.state-save
|
||||||
168
bot/app/bot.py
168
bot/app/bot.py
@ -35,22 +35,18 @@ session: Session = None
|
|||||||
class States(StatesGroup):
|
class States(StatesGroup):
|
||||||
default = State()
|
default = State()
|
||||||
newfund_amount = State()
|
newfund_amount = State()
|
||||||
|
close_fund = State()
|
||||||
|
|
||||||
|
|
||||||
# Utils
|
# Utils
|
||||||
|
|
||||||
|
|
||||||
def get_fund_text(fund: Fund):
|
def get_fund_text(fund: Fund):
|
||||||
count = len(fund.members)
|
count = fund.members.count()
|
||||||
contributors = len(list(filter(lambda m: m.contributed, fund.members)))
|
contributors = fund.members.filter(FundMember.contributed).count()
|
||||||
personal_amount = math.ceil(fund.amount / count)
|
personal_amount = math.ceil(fund.amount / count)
|
||||||
return (
|
return textbook.fund.format(
|
||||||
"🟢 {name}\n\n",
|
active="🟢" if fund.active else "🔴",
|
||||||
"💵 Сумма: {amount}р\n\n",
|
|
||||||
"<b>Каждый скидывает по {personal_amount}</b>\n",
|
|
||||||
"Уже собрано: {collected_amount}\n\n",
|
|
||||||
"👥 Скинули: {contributors}/{count} чел.",
|
|
||||||
).format(
|
|
||||||
name=fund.name,
|
name=fund.name,
|
||||||
amount=fund.amount,
|
amount=fund.amount,
|
||||||
personal_amount=personal_amount,
|
personal_amount=personal_amount,
|
||||||
@ -74,7 +70,7 @@ def get_user(tg_user: TgUser) -> User:
|
|||||||
|
|
||||||
|
|
||||||
def get_group(tg_chat: TgChat) -> Group:
|
def get_group(tg_chat: TgChat) -> Group:
|
||||||
if group := session.query(User).filter(User.id == tg_chat.id).first():
|
if group := session.query(Group).filter(Group.id == tg_chat.id).first():
|
||||||
return group
|
return group
|
||||||
group = Group(
|
group = Group(
|
||||||
id=tg_chat.id,
|
id=tg_chat.id,
|
||||||
@ -86,6 +82,7 @@ def get_group(tg_chat: TgChat) -> Group:
|
|||||||
|
|
||||||
# Bot logic
|
# Bot logic
|
||||||
|
|
||||||
|
|
||||||
@bot.message_handler(commands=["start"])
|
@bot.message_handler(commands=["start"])
|
||||||
async def start(msg: Message):
|
async def start(msg: Message):
|
||||||
if msg.chat.type == "private":
|
if msg.chat.type == "private":
|
||||||
@ -103,7 +100,10 @@ async def start(msg: Message):
|
|||||||
# session.add(user)
|
# session.add(user)
|
||||||
# session.commit()
|
# session.commit()
|
||||||
user = get_user(msg.from_user)
|
user = get_user(msg.from_user)
|
||||||
await bot.send_message(chat_id=msg.chat.id, text=textbook.start_private.format(count=len(user.fund_members)))
|
await bot.send_message(
|
||||||
|
chat_id=msg.chat.id,
|
||||||
|
text=textbook.start_private.format(count=user.fund_members.count()),
|
||||||
|
)
|
||||||
|
|
||||||
elif msg.chat.type in ("group", "supergroup"):
|
elif msg.chat.type in ("group", "supergroup"):
|
||||||
get_group(msg.chat)
|
get_group(msg.chat)
|
||||||
@ -122,7 +122,7 @@ async def setup(msg: Message):
|
|||||||
@bot.callback_query_handler(func=lambda c: c.data == "register_group_member")
|
@bot.callback_query_handler(func=lambda c: c.data == "register_group_member")
|
||||||
async def register_group_member(call: types.CallbackQuery):
|
async def register_group_member(call: types.CallbackQuery):
|
||||||
new = False
|
new = False
|
||||||
user = get_user(call.from_user.id)
|
get_user(call.from_user)
|
||||||
if (
|
if (
|
||||||
group_member := session.query(GroupMember)
|
group_member := session.query(GroupMember)
|
||||||
.filter(
|
.filter(
|
||||||
@ -150,10 +150,11 @@ async def register_group_member(call: types.CallbackQuery):
|
|||||||
@bot.message_handler(commands=["newfund"])
|
@bot.message_handler(commands=["newfund"])
|
||||||
async def newfund(msg: Message):
|
async def newfund(msg: Message):
|
||||||
if msg.chat.type in ("group", "supergroup"):
|
if msg.chat.type in ("group", "supergroup"):
|
||||||
if session.query(Group).filter(Group.id == msg.chat.id).first():
|
if group := get_group(msg.chat):
|
||||||
|
if group.group_members.count():
|
||||||
if (
|
if (
|
||||||
session.query(Fund)
|
session.query(Fund)
|
||||||
.filter(Fund.group_id == msg.chat.id, Fund.active == True)
|
.filter(Fund.group_id == msg.chat.id, Fund.active)
|
||||||
.first()
|
.first()
|
||||||
):
|
):
|
||||||
await bot.send_message(
|
await bot.send_message(
|
||||||
@ -169,14 +170,15 @@ async def newfund(msg: Message):
|
|||||||
await bot.send_message(
|
await bot.send_message(
|
||||||
chat_id=msg.chat.id,
|
chat_id=msg.chat.id,
|
||||||
text=textbook.newfund_amount.format(
|
text=textbook.newfund_amount.format(
|
||||||
user=user_link(msg.from_user)),
|
user=user_link(msg.from_user)
|
||||||
|
),
|
||||||
reply_markup=keyboards.cancel(),
|
reply_markup=keyboards.cancel(),
|
||||||
parse_mode="html",
|
parse_mode="html",
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
await bot.send_message(
|
await bot.send_message(
|
||||||
chat_id=msg.chat.id,
|
chat_id=msg.chat.id,
|
||||||
text=textbook.not_initialized
|
text=textbook.not_set_up,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
@ -187,6 +189,7 @@ async def cancel_newfund_amount(call: types.CallbackQuery):
|
|||||||
await bot.set_state(
|
await bot.set_state(
|
||||||
user_id=call.from_user.id, chat_id=call.message.chat.id, state=States.default
|
user_id=call.from_user.id, chat_id=call.message.chat.id, state=States.default
|
||||||
)
|
)
|
||||||
|
await bot.delete_message(chat_id=call.message.chat.id, message_id=call.message.id)
|
||||||
await bot.answer_callback_query(
|
await bot.answer_callback_query(
|
||||||
callback_query_id=call.id,
|
callback_query_id=call.id,
|
||||||
text=textbook.cancel,
|
text=textbook.cancel,
|
||||||
@ -208,15 +211,13 @@ async def newfund_amount(msg: Message):
|
|||||||
user_id=msg.from_user.id, chat_id=msg.chat.id, state=States.default
|
user_id=msg.from_user.id, chat_id=msg.chat.id, state=States.default
|
||||||
)
|
)
|
||||||
fund = Fund(
|
fund = Fund(
|
||||||
owner_id=msg.from_user.id, group_id=msg.chat.id, amount=int(
|
owner_id=msg.from_user.id, group_id=msg.chat.id, amount=int(msg.text)
|
||||||
msg.text)
|
|
||||||
)
|
)
|
||||||
session.add(fund)
|
session.add(fund)
|
||||||
for group_member in session.query(GroupMember).filter(
|
for group_member in session.query(GroupMember).filter(
|
||||||
GroupMember.group_id == msg.chat.id
|
GroupMember.group_id == msg.chat.id
|
||||||
):
|
):
|
||||||
fund_member = FundMember(
|
fund_member = FundMember(user_id=group_member.user.id, fund_id=fund.id)
|
||||||
user_id=group_member.user.id, fund_id=fund.id)
|
|
||||||
session.add(fund_member)
|
session.add(fund_member)
|
||||||
session.commit()
|
session.commit()
|
||||||
await bot.send_message(
|
await bot.send_message(
|
||||||
@ -228,6 +229,7 @@ async def newfund_amount(msg: Message):
|
|||||||
chat_id=msg.chat.id,
|
chat_id=msg.chat.id,
|
||||||
text=get_fund_text(fund),
|
text=get_fund_text(fund),
|
||||||
reply_markup=keyboards.fund_markup(),
|
reply_markup=keyboards.fund_markup(),
|
||||||
|
parse_mode="html",
|
||||||
)
|
)
|
||||||
|
|
||||||
else:
|
else:
|
||||||
@ -241,6 +243,132 @@ async def newfund_amount(msg: Message):
|
|||||||
|
|
||||||
@bot.message_handler(commands=["fund"])
|
@bot.message_handler(commands=["fund"])
|
||||||
async def fund(msg: Message):
|
async def fund(msg: Message):
|
||||||
|
if msg.chat.type in ("group", "supergroup"):
|
||||||
|
group = get_group(msg.chat)
|
||||||
|
if (
|
||||||
|
fund := session.query(Fund)
|
||||||
|
.filter(Fund.group_id == group.id, Fund.active == True)
|
||||||
|
.first()
|
||||||
|
):
|
||||||
|
await bot.send_message(
|
||||||
|
chat_id=msg.chat.id,
|
||||||
|
text=get_fund_text(fund),
|
||||||
|
reply_markup=keyboards.fund_markup(),
|
||||||
|
parse_mode="html",
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
await bot.send_message(
|
||||||
|
chat_id=msg.chat.id,
|
||||||
|
text=textbook.fund_not_found,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@bot.callback_query_handler(func=lambda c: c.data == "close_fund")
|
||||||
|
async def close_fund_prompt(call: types.CallbackQuery):
|
||||||
|
if group := get_group(call.message.chat):
|
||||||
|
if fund := group.funds.filter(Fund.active).first():
|
||||||
|
if call.from_user.id == fund.owner_id:
|
||||||
|
await bot.edit_message_text(
|
||||||
|
text=textbook.close_fund_prompt,
|
||||||
|
chat_id=call.message.chat.id,
|
||||||
|
message_id=call.message.id,
|
||||||
|
reply_markup=keyboards.yes_no(),
|
||||||
|
parse_mode="html",
|
||||||
|
)
|
||||||
|
await bot.set_state(
|
||||||
|
user_id=call.from_user.id,
|
||||||
|
chat_id=call.message.chat.id,
|
||||||
|
state=States.close_fund,
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
await bot.answer_callback_query(
|
||||||
|
callback_query_id=call.id,
|
||||||
|
text=textbook.not_owner.format(owner_name=fund.owner.name),
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
await bot.send_message(
|
||||||
|
chat_id=call.message.chat.id,
|
||||||
|
text=textbook.fund_not_found,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@bot.callback_query_handler(
|
||||||
|
func=lambda c: c.data in ("yes", "no"), state=States.close_fund
|
||||||
|
)
|
||||||
|
async def close_fund(call: types.CallbackQuery):
|
||||||
|
if group := get_group(call.message.chat):
|
||||||
|
if fund := group.funds.filter(Fund.active).first():
|
||||||
|
if call.from_user.id == fund.owner_id:
|
||||||
|
if call.data == "yes":
|
||||||
|
setattr(fund, "active", False)
|
||||||
|
session.commit()
|
||||||
|
await bot.edit_message_text(
|
||||||
|
text=textbook.fund_closed.format(
|
||||||
|
name=fund.name, fund_text=get_fund_text(fund)
|
||||||
|
),
|
||||||
|
chat_id=call.message.chat.id,
|
||||||
|
message_id=call.message.id,
|
||||||
|
parse_mode="html",
|
||||||
|
)
|
||||||
|
elif call.data == "no":
|
||||||
|
await bot.edit_message_text(
|
||||||
|
text=get_fund_text(fund),
|
||||||
|
chat_id=call.message.chat.id,
|
||||||
|
message_id=call.message.id,
|
||||||
|
reply_markup=keyboards.fund_markup(),
|
||||||
|
parse_mode="html",
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
await bot.answer_callback_query(
|
||||||
|
callback_query_id=call.id,
|
||||||
|
text=textbook.not_owner.format(owner_name=fund.owner.name),
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
await bot.send_message(
|
||||||
|
chat_id=call.message.chat.id,
|
||||||
|
text=textbook.fund_not_found,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@bot.callback_query_handler(func=lambda c: c.data == "contributed")
|
||||||
|
async def contributed(call: types.CallbackQuery):
|
||||||
|
group = get_group(call.message.chat)
|
||||||
|
user = get_user(call.from_user)
|
||||||
|
if fund := group.funds.filter(Fund.active).first():
|
||||||
|
if fund_user := fund.members.filter(
|
||||||
|
FundMember.user_id == call.from_user.id
|
||||||
|
).first():
|
||||||
|
if not fund_user.contributed:
|
||||||
|
setattr(fund_user, "contributed", True)
|
||||||
|
session.commit()
|
||||||
|
await bot.answer_callback_query(
|
||||||
|
callback_query_id=call.id,
|
||||||
|
text=textbook.contributed,
|
||||||
|
)
|
||||||
|
await bot.edit_message_text(
|
||||||
|
text=get_fund_text(fund),
|
||||||
|
chat_id=call.message.chat.id,
|
||||||
|
message_id=call.message.id,
|
||||||
|
reply_markup=keyboards.fund_markup(),
|
||||||
|
parse_mode="html",
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
await bot.answer_callback_query(
|
||||||
|
callback_query_id=call.id,
|
||||||
|
text=textbook.already_contributed,
|
||||||
|
show_alert=True,
|
||||||
|
)
|
||||||
|
|
||||||
|
else:
|
||||||
|
await bot.answer_callback_query(
|
||||||
|
callback_query_id=call.id,
|
||||||
|
text=textbook.not_fund_member,
|
||||||
|
show_alert=True,
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
await bot.answer_callback_query(
|
||||||
|
callback_query_id=call.id, text=textbook.fund_not_found, show_alert=True
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
@bot.message_handler(commands=["mystate"])
|
@bot.message_handler(commands=["mystate"])
|
||||||
|
|||||||
@ -16,9 +16,9 @@ class User(Base):
|
|||||||
name = Column(String(64))
|
name = Column(String(64))
|
||||||
username = Column(String(32))
|
username = Column(String(32))
|
||||||
|
|
||||||
owns_funds = relationship("Fund", backref="owner")
|
owns_funds = relationship("Fund", backref="owner", lazy="dynamic")
|
||||||
fund_members = relationship("FundMember", backref="user")
|
fund_members = relationship("FundMember", backref="user", lazy="dynamic")
|
||||||
group_members = relationship("GroupMember", backref="user")
|
group_members = relationship("GroupMember", backref="user", lazy="dynamic")
|
||||||
|
|
||||||
|
|
||||||
class Group(Base):
|
class Group(Base):
|
||||||
@ -26,9 +26,9 @@ class Group(Base):
|
|||||||
|
|
||||||
id = Column(BigInteger, primary_key=True)
|
id = Column(BigInteger, primary_key=True)
|
||||||
|
|
||||||
funds = relationship("Fund", backref="group")
|
funds = relationship("Fund", backref="group", lazy="dynamic")
|
||||||
|
|
||||||
group_members = relationship("GroupMember", backref="group")
|
group_members = relationship("GroupMember", backref="group", lazy="dynamic")
|
||||||
|
|
||||||
|
|
||||||
class GroupMember(Base):
|
class GroupMember(Base):
|
||||||
@ -52,7 +52,7 @@ class Fund(Base):
|
|||||||
amount = Column(Integer)
|
amount = Column(Integer)
|
||||||
active = Column(Boolean, default=True)
|
active = Column(Boolean, default=True)
|
||||||
|
|
||||||
members = relationship("FundMember", backref="fund")
|
members = relationship("FundMember", backref="fund", lazy="dynamic")
|
||||||
|
|
||||||
|
|
||||||
class FundMember(Base):
|
class FundMember(Base):
|
||||||
|
|||||||
@ -23,6 +23,16 @@ def cancel() -> keyboard:
|
|||||||
def fund_markup() -> keyboard:
|
def fund_markup() -> keyboard:
|
||||||
return keyboard(
|
return keyboard(
|
||||||
keyboard=[
|
keyboard=[
|
||||||
|
[button(text="✅ Я скинул", callback_data="contributed")],
|
||||||
[button(text="🏁 Завершить сбор", callback_data="close_fund")],
|
[button(text="🏁 Завершить сбор", callback_data="close_fund")],
|
||||||
]
|
]
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def yes_no() -> keyboard:
|
||||||
|
return keyboard(
|
||||||
|
keyboard=[
|
||||||
|
[button(text="✅ Да", callback_data="yes")],
|
||||||
|
[button(text="❌ Нет", callback_data="no")],
|
||||||
|
]
|
||||||
|
)
|
||||||
|
|||||||
@ -15,3 +15,15 @@ not_number = 'Вы ввели не число. {user}, напишите сумм
|
|||||||
fund_created = "Создан новый сбор: {fund}"
|
fund_created = "Создан новый сбор: {fund}"
|
||||||
|
|
||||||
fund_not_found = "На данный момент в этом чате сборов нет! Создать новый - /newfund"
|
fund_not_found = "На данный момент в этом чате сборов нет! Создать новый - /newfund"
|
||||||
|
|
||||||
|
|
||||||
|
fund = "{active} {name}\n\n💵 Сумма: {amount}р\n\n<b>Каждый скидывает по {personal_amount}р</b>\nУже собрано: {collected_amount}р\n👥 Скинули: {contributors}/{count} чел."
|
||||||
|
|
||||||
|
close_fund_prompt = "Вы уверены? Это завершит <b>активный в данный момент сбор</b>!"
|
||||||
|
fund_closed = 'Сбор "<b>{name}</b>" закрыт! Вот его данные:\n\n{fund_text}'
|
||||||
|
not_owner = "Вы не являетесь создателем этого сбора, обратитесь к {owner_name}, если хотите его закрыть"
|
||||||
|
not_set_up = "В группе меценатов нет ни одного участника! Вы точно прописывали /setup и все желающие участвовать в сборах приняли участие?"
|
||||||
|
not_fund_member = "Вы не являетесь участником этого сбора! Пропишите /setup и попросите создать новый сбор!"
|
||||||
|
|
||||||
|
contributed = "Вы отметились!"
|
||||||
|
already_contributed = "Вы уже отмечались ранее. Не забудьте уведомить создателя сбора, если вы решили отказаться от участия!"
|
||||||
|
|||||||
@ -23,6 +23,8 @@ services:
|
|||||||
DB_NAME: db
|
DB_NAME: db
|
||||||
HOST: postgres
|
HOST: postgres
|
||||||
PORT: 5432
|
PORT: 5432
|
||||||
|
volumes:
|
||||||
|
- ./.state-save:/app/.state-save/:rw
|
||||||
depends_on:
|
depends_on:
|
||||||
postgres:
|
postgres:
|
||||||
condition: service_healthy
|
condition: service_healthy
|
||||||
|
|||||||
Reference in New Issue
Block a user