mirror of
https://github.com/Xtao-Labs/misskey2telegram.git
synced 2024-11-22 13:55:53 +00:00
feat: fcm push
This commit is contained in:
parent
2408824848
commit
4fc4951390
30
alembic/versions/fcdaa7ac5975_fcm.py
Normal file
30
alembic/versions/fcdaa7ac5975_fcm.py
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
"""fcm
|
||||||
|
|
||||||
|
Revision ID: fcdaa7ac5975
|
||||||
|
Revises: a89b6e618441
|
||||||
|
Create Date: 2023-08-03 16:45:44.084709
|
||||||
|
|
||||||
|
"""
|
||||||
|
from alembic import op
|
||||||
|
import sqlalchemy as sa
|
||||||
|
|
||||||
|
|
||||||
|
# revision identifiers, used by Alembic.
|
||||||
|
revision = "fcdaa7ac5975"
|
||||||
|
down_revision = "a89b6e618441"
|
||||||
|
branch_labels = None
|
||||||
|
depends_on = None
|
||||||
|
|
||||||
|
|
||||||
|
def upgrade() -> None:
|
||||||
|
# ### commands auto generated by Alembic - please adjust! ###
|
||||||
|
op.add_column(
|
||||||
|
"user", sa.Column("fcm_token", sa.String(), nullable=True, default="")
|
||||||
|
)
|
||||||
|
# ### end Alembic commands ###
|
||||||
|
|
||||||
|
|
||||||
|
def downgrade() -> None:
|
||||||
|
# ### commands auto generated by Alembic - please adjust! ###
|
||||||
|
op.drop_column("user", "fcm_token")
|
||||||
|
# ### end Alembic commands ###
|
160
defs/chat.py
160
defs/chat.py
@ -1,160 +0,0 @@
|
|||||||
from typing import Optional
|
|
||||||
|
|
||||||
from mipac import ChatMessage, File
|
|
||||||
from mipac.models.lite import LiteUser
|
|
||||||
from pyrogram.errors import MediaEmpty
|
|
||||||
from pyrogram.types import InlineKeyboardMarkup, InlineKeyboardButton
|
|
||||||
|
|
||||||
from init import bot, request
|
|
||||||
from models.services.scheduler import add_delete_file_job, delete_file
|
|
||||||
|
|
||||||
|
|
||||||
def get_user_link(host: str, user: LiteUser) -> str:
|
|
||||||
if user.host:
|
|
||||||
return f"https://{host}/@{user.username}@{user.host}"
|
|
||||||
return f"https://{host}/@{user.username}"
|
|
||||||
|
|
||||||
|
|
||||||
def get_source_link(host: str, message: ChatMessage) -> str:
|
|
||||||
return (
|
|
||||||
f"https://{host}/my/messaging/{message.user.username}?cid={message.user.id}"
|
|
||||||
if not message.group and message.user
|
|
||||||
else f"https://{host}/my/messaging/group/{message.group.id}"
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
def gen_button(host: str, message: ChatMessage):
|
|
||||||
author = get_user_link(host, message.user)
|
|
||||||
source = get_source_link(host, message)
|
|
||||||
first_line = [
|
|
||||||
InlineKeyboardButton(text="Chat", url=source),
|
|
||||||
InlineKeyboardButton(text="Author", url=author),
|
|
||||||
]
|
|
||||||
return InlineKeyboardMarkup([first_line])
|
|
||||||
|
|
||||||
|
|
||||||
def get_content(host: str, message: ChatMessage) -> str:
|
|
||||||
content = message.text or ""
|
|
||||||
content = content[:768]
|
|
||||||
user = f'<a href="{get_user_link(host, message.user)}">{message.user.nickname}</a>'
|
|
||||||
if message.group:
|
|
||||||
group = f'<a href="{get_source_link(host, message)}">{message.group.name}</a>'
|
|
||||||
user += f" ( {group} )"
|
|
||||||
return f"""<b>Misskey Message</b>
|
|
||||||
|
|
||||||
{user}: <code>{content}</code>"""
|
|
||||||
|
|
||||||
|
|
||||||
async def send_text(
|
|
||||||
host: str, cid: int, message: ChatMessage, reply_to_message_id: int
|
|
||||||
):
|
|
||||||
await bot.send_message(
|
|
||||||
cid,
|
|
||||||
get_content(host, message),
|
|
||||||
reply_to_message_id=reply_to_message_id,
|
|
||||||
reply_markup=gen_button(host, message),
|
|
||||||
disable_web_page_preview=True,
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
def deprecated_to_text(func):
|
|
||||||
async def wrapper(*args, **kwargs):
|
|
||||||
try:
|
|
||||||
return await func(*args, **kwargs)
|
|
||||||
except MediaEmpty:
|
|
||||||
return await send_text(args[0], args[1], args[3], args[4])
|
|
||||||
|
|
||||||
return wrapper
|
|
||||||
|
|
||||||
|
|
||||||
@deprecated_to_text
|
|
||||||
async def send_photo(
|
|
||||||
host: str, cid: int, url: str, message: ChatMessage, reply_to_message_id: int
|
|
||||||
):
|
|
||||||
if not url:
|
|
||||||
return await send_text(host, cid, message, reply_to_message_id)
|
|
||||||
await bot.send_photo(
|
|
||||||
cid,
|
|
||||||
url,
|
|
||||||
reply_to_message_id=reply_to_message_id,
|
|
||||||
caption=get_content(host, message),
|
|
||||||
reply_markup=gen_button(host, message),
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
@deprecated_to_text
|
|
||||||
async def send_video(
|
|
||||||
host: str, cid: int, url: str, message: ChatMessage, reply_to_message_id: int
|
|
||||||
):
|
|
||||||
if not url:
|
|
||||||
return await send_text(host, cid, message, reply_to_message_id)
|
|
||||||
await bot.send_video(
|
|
||||||
cid,
|
|
||||||
url,
|
|
||||||
reply_to_message_id=reply_to_message_id,
|
|
||||||
caption=get_content(host, message),
|
|
||||||
reply_markup=gen_button(host, message),
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
@deprecated_to_text
|
|
||||||
async def send_audio(
|
|
||||||
host: str, cid: int, url: str, message: ChatMessage, reply_to_message_id: int
|
|
||||||
):
|
|
||||||
if not url:
|
|
||||||
return await send_text(host, cid, message, reply_to_message_id)
|
|
||||||
await bot.send_audio(
|
|
||||||
cid,
|
|
||||||
url,
|
|
||||||
reply_to_message_id=reply_to_message_id,
|
|
||||||
caption=get_content(host, message),
|
|
||||||
reply_markup=gen_button(host, message),
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
async def fetch_document(file: File) -> Optional[str]:
|
|
||||||
file_name = f"downloads/{file.name}"
|
|
||||||
file_url = file.url
|
|
||||||
if file.size > 10 * 1024 * 1024:
|
|
||||||
return file_url
|
|
||||||
if not file_url:
|
|
||||||
return file_url
|
|
||||||
req = await request.get(file_url)
|
|
||||||
if req.status_code != 200:
|
|
||||||
return file_url
|
|
||||||
with open(file_name, "wb") as f:
|
|
||||||
f.write(req.content)
|
|
||||||
add_delete_file_job(file_name)
|
|
||||||
return file_name
|
|
||||||
|
|
||||||
|
|
||||||
@deprecated_to_text
|
|
||||||
async def send_document(
|
|
||||||
host: str, cid: int, file: File, message: ChatMessage, reply_to_message_id: int
|
|
||||||
):
|
|
||||||
file = await fetch_document(file)
|
|
||||||
if not file:
|
|
||||||
return await send_text(host, cid, message, reply_to_message_id)
|
|
||||||
await bot.send_document(
|
|
||||||
cid,
|
|
||||||
file,
|
|
||||||
reply_to_message_id=reply_to_message_id,
|
|
||||||
caption=get_content(host, message),
|
|
||||||
reply_markup=gen_button(host, message),
|
|
||||||
)
|
|
||||||
await delete_file(file)
|
|
||||||
|
|
||||||
|
|
||||||
async def send_chat_message(host: str, cid: int, message: ChatMessage, topic_id: int):
|
|
||||||
if not message.file:
|
|
||||||
return await send_text(host, cid, message, topic_id)
|
|
||||||
file_url = message.file.url
|
|
||||||
file_type = message.file.type
|
|
||||||
if file_type.startswith("image"):
|
|
||||||
await send_photo(host, cid, file_url, message, topic_id)
|
|
||||||
elif file_type.startswith("video"):
|
|
||||||
await send_video(host, cid, file_url, message, topic_id)
|
|
||||||
elif file_type.startswith("audio"):
|
|
||||||
await send_audio(host, cid, file_url, message, topic_id)
|
|
||||||
else:
|
|
||||||
await send_document(host, cid, message.file, message, topic_id)
|
|
139
defs/fcm_notice.py
Normal file
139
defs/fcm_notice.py
Normal file
@ -0,0 +1,139 @@
|
|||||||
|
from firebase_admin import messaging
|
||||||
|
from mipac import (
|
||||||
|
NotificationAchievement,
|
||||||
|
NotificationFollowRequest,
|
||||||
|
NotificationFollow,
|
||||||
|
NotificationReaction,
|
||||||
|
Note,
|
||||||
|
NotificationNote,
|
||||||
|
)
|
||||||
|
|
||||||
|
from defs.notice import achievement_map
|
||||||
|
from glover import web_domain
|
||||||
|
|
||||||
|
from fcm_init import google_app
|
||||||
|
|
||||||
|
|
||||||
|
def check_fcm_token(token: str) -> bool:
|
||||||
|
message = messaging.Message(
|
||||||
|
notification=messaging.Notification(
|
||||||
|
title="Misskey Telegram Bridge",
|
||||||
|
body="FCM Test",
|
||||||
|
),
|
||||||
|
token=token,
|
||||||
|
)
|
||||||
|
try:
|
||||||
|
messaging.send(message, app=google_app)
|
||||||
|
return True
|
||||||
|
except Exception:
|
||||||
|
return False
|
||||||
|
|
||||||
|
|
||||||
|
def send_fcm_message(token: str, title: str, body: str, img: str = None):
|
||||||
|
message = messaging.Message(
|
||||||
|
notification=messaging.Notification(
|
||||||
|
title=title,
|
||||||
|
body=body,
|
||||||
|
image=img,
|
||||||
|
),
|
||||||
|
token=token,
|
||||||
|
)
|
||||||
|
messaging.send(message, app=google_app)
|
||||||
|
|
||||||
|
|
||||||
|
def gen_image_url(url: str) -> str:
|
||||||
|
return f"https://{web_domain}/1.jpg?url={url}"
|
||||||
|
|
||||||
|
|
||||||
|
def send_fcm_user_followed(token: str, notice: NotificationFollow):
|
||||||
|
title = notice.user.nickname
|
||||||
|
body = "关注了你"
|
||||||
|
image = gen_image_url(notice.user.avatar_url)
|
||||||
|
send_fcm_message(token, title, body, image)
|
||||||
|
|
||||||
|
|
||||||
|
def send_fcm_follow_request(token: str, notice: NotificationFollowRequest):
|
||||||
|
title = notice.user.nickname
|
||||||
|
body = "请求关注你"
|
||||||
|
image = gen_image_url(notice.user.avatar_url)
|
||||||
|
send_fcm_message(token, title, body, image)
|
||||||
|
|
||||||
|
|
||||||
|
def send_fcm_follow_request_accept(token: str, notice: NotificationFollowRequest):
|
||||||
|
title = notice.user.nickname
|
||||||
|
body = "接受了你的关注请求"
|
||||||
|
image = gen_image_url(notice.user.avatar_url)
|
||||||
|
send_fcm_message(token, title, body, image)
|
||||||
|
|
||||||
|
|
||||||
|
def send_fcm_achievement_earned(
|
||||||
|
token: str,
|
||||||
|
notice: NotificationAchievement,
|
||||||
|
):
|
||||||
|
name, desc, note = achievement_map.get(notice.achievement, ("", "", ""))
|
||||||
|
title = "你获得了新成就!"
|
||||||
|
body = f"{name}:{desc} {f'- {note}' if note else ''}"
|
||||||
|
send_fcm_message(token, title, body)
|
||||||
|
|
||||||
|
|
||||||
|
def format_notice_note(note: Note):
|
||||||
|
text = ""
|
||||||
|
if note.content:
|
||||||
|
text = note.content
|
||||||
|
if note.reply:
|
||||||
|
text += f" RE: {note.reply.content}"
|
||||||
|
if note.renote:
|
||||||
|
text += f" QT: {note.renote.content}"
|
||||||
|
if len(text) >= 100:
|
||||||
|
text = text[:100] + "..."
|
||||||
|
return text.strip()
|
||||||
|
|
||||||
|
|
||||||
|
def send_fcm_reaction(
|
||||||
|
token: str,
|
||||||
|
notice: NotificationReaction,
|
||||||
|
):
|
||||||
|
title = notice.user.nickname
|
||||||
|
body = f"{notice.reaction} 了你的推文\n{format_notice_note(notice.note)}"
|
||||||
|
image = gen_image_url(notice.user.avatar_url)
|
||||||
|
send_fcm_message(token, title, body, image)
|
||||||
|
|
||||||
|
|
||||||
|
def send_fcm_mention(
|
||||||
|
token: str,
|
||||||
|
notice: NotificationNote,
|
||||||
|
):
|
||||||
|
title = notice.user.nickname
|
||||||
|
body = f"提到了你\n{format_notice_note(notice.note)}"
|
||||||
|
image = gen_image_url(notice.user.avatar_url)
|
||||||
|
send_fcm_message(token, title, body, image)
|
||||||
|
|
||||||
|
|
||||||
|
def send_fcm_reply(
|
||||||
|
token: str,
|
||||||
|
notice: NotificationNote,
|
||||||
|
):
|
||||||
|
title = notice.user.nickname
|
||||||
|
body = f"回复了你\n{format_notice_note(notice.note)}"
|
||||||
|
image = gen_image_url(notice.user.avatar_url)
|
||||||
|
send_fcm_message(token, title, body, image)
|
||||||
|
|
||||||
|
|
||||||
|
def send_fcm_renote(
|
||||||
|
token: str,
|
||||||
|
notice: NotificationNote,
|
||||||
|
):
|
||||||
|
title = notice.user.nickname
|
||||||
|
body = f"转发了你的推文\n{format_notice_note(notice.note)}"
|
||||||
|
image = gen_image_url(notice.user.avatar_url)
|
||||||
|
send_fcm_message(token, title, body, image)
|
||||||
|
|
||||||
|
|
||||||
|
def send_fcm_quote(
|
||||||
|
token: str,
|
||||||
|
notice: NotificationNote,
|
||||||
|
):
|
||||||
|
title = notice.user.nickname
|
||||||
|
body = f"引用了你的推文\n{format_notice_note(notice.note)}"
|
||||||
|
image = gen_image_url(notice.user.avatar_url)
|
||||||
|
send_fcm_message(token, title, body, image)
|
5
fcm_init.py
Normal file
5
fcm_init.py
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
import firebase_admin
|
||||||
|
from firebase_admin import credentials
|
||||||
|
|
||||||
|
cred = credentials.Certificate("data/google.json")
|
||||||
|
google_app = firebase_admin.initialize_app(cred)
|
2
main.py
2
main.py
@ -5,6 +5,6 @@ from init import logs, bot
|
|||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
logs.info("Bot 开始运行")
|
logs.info("Bot 开始运行")
|
||||||
bot.start()
|
bot.start()
|
||||||
logs.info("Bot 启动成功!")
|
logs.info(f"Bot 启动成功!@{bot.me.username}")
|
||||||
idle()
|
idle()
|
||||||
bot.stop()
|
bot.stop()
|
||||||
|
108
misskey_init.py
108
misskey_init.py
@ -1,8 +1,12 @@
|
|||||||
|
import asyncio
|
||||||
import contextlib
|
import contextlib
|
||||||
from asyncio import sleep, Lock
|
from asyncio import sleep, Lock
|
||||||
|
from builtins import function
|
||||||
|
from concurrent.futures import ThreadPoolExecutor
|
||||||
from typing import Optional, Union
|
from typing import Optional, Union
|
||||||
|
|
||||||
from aiohttp import ClientConnectorError
|
from aiohttp import ClientConnectorError
|
||||||
|
from firebase_admin.exceptions import InvalidArgumentError
|
||||||
from mipa.exception import WebSocketNotConnected
|
from mipa.exception import WebSocketNotConnected
|
||||||
from mipa.ext import commands
|
from mipa.ext import commands
|
||||||
from mipa.router import Router
|
from mipa.router import Router
|
||||||
@ -10,13 +14,24 @@ from mipac import (
|
|||||||
Note,
|
Note,
|
||||||
NotificationFollow,
|
NotificationFollow,
|
||||||
NotificationFollowRequest,
|
NotificationFollowRequest,
|
||||||
ChatMessage,
|
|
||||||
NotificationAchievement,
|
NotificationAchievement,
|
||||||
NoteDeleted,
|
NoteDeleted,
|
||||||
|
NotificationReaction,
|
||||||
|
NotificationNote,
|
||||||
)
|
)
|
||||||
from mipac.client import Client as MisskeyClient
|
from mipac.client import Client as MisskeyClient
|
||||||
|
|
||||||
from defs.chat import send_chat_message
|
from defs.fcm_notice import (
|
||||||
|
send_fcm_user_followed,
|
||||||
|
send_fcm_follow_request,
|
||||||
|
send_fcm_follow_request_accept,
|
||||||
|
send_fcm_achievement_earned,
|
||||||
|
send_fcm_reaction,
|
||||||
|
send_fcm_mention,
|
||||||
|
send_fcm_reply,
|
||||||
|
send_fcm_renote,
|
||||||
|
send_fcm_quote,
|
||||||
|
)
|
||||||
from defs.misskey import send_update
|
from defs.misskey import send_update
|
||||||
from defs.notice import (
|
from defs.notice import (
|
||||||
send_user_followed,
|
send_user_followed,
|
||||||
@ -95,45 +110,70 @@ class MisskeyBot(commands.Bot):
|
|||||||
await RevokeAction.process_delete_note(self.tg_user.user_id, note.note_id)
|
await RevokeAction.process_delete_note(self.tg_user.user_id, note.note_id)
|
||||||
logs.info(f"{self.tg_user.user_id} 处理 note 删除 {note.note_id} 完成")
|
logs.info(f"{self.tg_user.user_id} 处理 note 删除 {note.note_id} 完成")
|
||||||
|
|
||||||
|
async def send_fcm(self, func: function, notice):
|
||||||
|
logs.info(f"{self.tg_user.user_id} 发送 FCM 通知 {func.__name__}")
|
||||||
|
loop = asyncio.get_event_loop()
|
||||||
|
try:
|
||||||
|
with ThreadPoolExecutor() as executor:
|
||||||
|
await loop.run_in_executor(
|
||||||
|
executor, func, self.tg_user.fcm_token, notice
|
||||||
|
)
|
||||||
|
except InvalidArgumentError:
|
||||||
|
logs.error(f"{self.tg_user.user_id} 无效的 FCM Token")
|
||||||
|
except Exception as e:
|
||||||
|
logs.error(e)
|
||||||
|
|
||||||
async def on_user_followed(self, notice: NotificationFollow):
|
async def on_user_followed(self, notice: NotificationFollow):
|
||||||
if self.tg_user.chat_id == 0 or self.tg_user.notice_topic == 0:
|
if self.tg_user.chat_id != 0 and self.tg_user.notice_topic != 0:
|
||||||
return
|
await send_user_followed(
|
||||||
await send_user_followed(
|
self.tg_user.chat_id, notice, self.tg_user.notice_topic
|
||||||
self.tg_user.chat_id, notice, self.tg_user.notice_topic
|
)
|
||||||
)
|
if self.tg_user.fcm_token:
|
||||||
|
await self.send_fcm(send_fcm_user_followed, notice)
|
||||||
|
|
||||||
async def on_follow_request(self, notice: NotificationFollowRequest):
|
async def on_follow_request(self, notice: NotificationFollowRequest):
|
||||||
if self.tg_user.chat_id == 0 or self.tg_user.notice_topic == 0:
|
if self.tg_user.chat_id != 0 and self.tg_user.notice_topic != 0:
|
||||||
return
|
await send_follow_request(
|
||||||
await send_follow_request(
|
self.tg_user.chat_id, notice, self.tg_user.notice_topic
|
||||||
self.tg_user.chat_id, notice, self.tg_user.notice_topic
|
)
|
||||||
)
|
if self.tg_user.fcm_token:
|
||||||
|
await self.send_fcm(send_fcm_follow_request, notice)
|
||||||
|
|
||||||
async def on_follow_request_accept(self, notice: NotificationFollowRequest):
|
async def on_follow_request_accept(self, notice: NotificationFollowRequest):
|
||||||
if self.tg_user.chat_id == 0 or self.tg_user.notice_topic == 0:
|
if self.tg_user.chat_id != 0 and self.tg_user.notice_topic != 0:
|
||||||
return
|
await send_follow_request_accept(
|
||||||
await send_follow_request_accept(
|
self.tg_user.chat_id, notice, self.tg_user.notice_topic
|
||||||
self.tg_user.chat_id, notice, self.tg_user.notice_topic
|
)
|
||||||
)
|
if self.tg_user.fcm_token:
|
||||||
|
await self.send_fcm(send_fcm_follow_request_accept, notice)
|
||||||
async def on_chat(self, message: ChatMessage):
|
|
||||||
if self.tg_user.chat_id == 0 or self.tg_user.notice_topic == 0:
|
|
||||||
return
|
|
||||||
await send_chat_message(
|
|
||||||
self.tg_user.host, self.tg_user.chat_id, message, self.tg_user.notice_topic
|
|
||||||
)
|
|
||||||
|
|
||||||
async def on_chat_unread_message(self, message: ChatMessage):
|
|
||||||
if self.tg_user.chat_id == 0 or self.tg_user.notice_topic == 0:
|
|
||||||
return
|
|
||||||
await message.api.read()
|
|
||||||
|
|
||||||
async def on_achievement_earned(self, notice: NotificationAchievement):
|
async def on_achievement_earned(self, notice: NotificationAchievement):
|
||||||
if self.tg_user.chat_id == 0 or self.tg_user.notice_topic == 0:
|
if self.tg_user.chat_id != 0 and self.tg_user.notice_topic != 0:
|
||||||
return
|
await send_achievement_earned(
|
||||||
await send_achievement_earned(
|
self.tg_user.chat_id, notice, self.tg_user.notice_topic
|
||||||
self.tg_user.chat_id, notice, self.tg_user.notice_topic
|
)
|
||||||
)
|
if self.tg_user.fcm_token:
|
||||||
|
await self.send_fcm(send_fcm_achievement_earned, notice)
|
||||||
|
|
||||||
|
async def on_reaction(self, notice: NotificationReaction):
|
||||||
|
if self.tg_user.fcm_token:
|
||||||
|
await self.send_fcm(send_fcm_reaction, notice)
|
||||||
|
|
||||||
|
async def on_mention(self, notice: NotificationNote):
|
||||||
|
if self.tg_user.fcm_token:
|
||||||
|
await self.send_fcm(send_fcm_mention, notice)
|
||||||
|
|
||||||
|
async def on_reply(self, notice: NotificationNote):
|
||||||
|
if self.tg_user.fcm_token:
|
||||||
|
await self.send_fcm(send_fcm_reply, notice)
|
||||||
|
|
||||||
|
async def on_renote(self, notice: NotificationNote):
|
||||||
|
if self.tg_user.fcm_token:
|
||||||
|
await self.send_fcm(send_fcm_renote, notice)
|
||||||
|
|
||||||
|
async def on_quote(self, notice: NotificationNote):
|
||||||
|
if self.tg_user.fcm_token:
|
||||||
|
await self.send_fcm(send_fcm_quote, notice)
|
||||||
|
|
||||||
|
|
||||||
misskey_bot_map: dict[int, MisskeyBot] = {}
|
misskey_bot_map: dict[int, MisskeyBot] = {}
|
||||||
|
@ -20,3 +20,4 @@ class User(SQLModel, table=True):
|
|||||||
notice_topic: int = Field(default=0)
|
notice_topic: int = Field(default=0)
|
||||||
instance_user_id: str = Field(default="")
|
instance_user_id: str = Field(default="")
|
||||||
push_chat_id: int = Field(default=0, sa_column=Column(sa.BigInteger))
|
push_chat_id: int = Field(default=0, sa_column=Column(sa.BigInteger))
|
||||||
|
fcm_token: str = Field(sa_column=Column(sa.String, nullable=True, default=""))
|
||||||
|
@ -158,3 +158,14 @@ class UserAction:
|
|||||||
user.push_chat_id = push_chat_id
|
user.push_chat_id = push_chat_id
|
||||||
await UserAction.update_user(user)
|
await UserAction.update_user(user)
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
async def change_user_fcm_token(user_id: int, fcm_token: str) -> bool:
|
||||||
|
user = await UserAction.get_user_by_id(user_id)
|
||||||
|
if not user:
|
||||||
|
return False
|
||||||
|
if user.fcm_token == fcm_token:
|
||||||
|
return False
|
||||||
|
user.fcm_token = fcm_token
|
||||||
|
await UserAction.update_user(user)
|
||||||
|
return True
|
||||||
|
35
modules/fcm.py
Normal file
35
modules/fcm.py
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
import asyncio
|
||||||
|
from concurrent.futures import ThreadPoolExecutor
|
||||||
|
|
||||||
|
from pyrogram import Client, filters
|
||||||
|
from pyrogram.types import Message
|
||||||
|
|
||||||
|
from defs.fcm_notice import check_fcm_token
|
||||||
|
from misskey_init import rerun_misskey_bot
|
||||||
|
from models.services.user import UserAction
|
||||||
|
|
||||||
|
|
||||||
|
async def finish_check(message: Message):
|
||||||
|
if await rerun_misskey_bot(message.from_user.id):
|
||||||
|
await message.reply("设置完成,开始链接。", quote=True)
|
||||||
|
|
||||||
|
|
||||||
|
@Client.on_message(filters.incoming & filters.private & filters.command(["fcm"]))
|
||||||
|
async def bind_fcm_token_command(_: Client, message: Message):
|
||||||
|
user = await UserAction.get_user_if_ok(message.from_user.id)
|
||||||
|
if not user:
|
||||||
|
await message.reply("请先私聊我绑定 Misskey 账号。", quote=True)
|
||||||
|
return
|
||||||
|
if len(message.command) == 2:
|
||||||
|
fcm_token = message.command[1]
|
||||||
|
loop = asyncio.get_event_loop()
|
||||||
|
with ThreadPoolExecutor() as executor:
|
||||||
|
success = await loop.run_in_executor(executor, check_fcm_token, fcm_token)
|
||||||
|
if success:
|
||||||
|
await UserAction.change_user_fcm_token(message.from_user.id, fcm_token)
|
||||||
|
await message.reply("FCM Token 绑定成功。", quote=True)
|
||||||
|
await finish_check(message)
|
||||||
|
else:
|
||||||
|
await message.reply("FCM Token 无效,请尝试重新获取。", quote=True)
|
||||||
|
else:
|
||||||
|
await message.reply("请提供 FCM Token,APP 请联系实例管理员索要。", quote=True)
|
@ -10,3 +10,4 @@ aiofiles==23.1.0
|
|||||||
pillow==10.0.0
|
pillow==10.0.0
|
||||||
cashews==6.2.0
|
cashews==6.2.0
|
||||||
alembic==1.11.1
|
alembic==1.11.1
|
||||||
|
firebase-admin==6.2.0
|
||||||
|
Loading…
Reference in New Issue
Block a user