Compare commits
4 Commits
v0.1.3
...
9b35b4892a
Author | SHA1 | Date | |
---|---|---|---|
9b35b4892a
|
|||
1b0870fca9
|
|||
acd1746344
|
|||
89050dbb6b
|
@@ -10,7 +10,7 @@ class CallbackLanguage:
|
|||||||
language: str
|
language: str
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def from_callback(cls, callback: CallbackQuery) -> "CallbackLanguage":
|
def from_callback(cls, callback: CallbackQuery):
|
||||||
"""Parse callback query and extract language data from it.
|
"""Parse callback query and extract language data from it.
|
||||||
|
|
||||||
### Args:
|
### Args:
|
||||||
|
@@ -23,7 +23,7 @@ class GarbageEntry:
|
|||||||
date: datetime
|
date: datetime
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
async def from_dict(cls, data: Mapping[str, Any]) -> "GarbageEntry":
|
async def from_dict(cls, data: Mapping[str, Any]):
|
||||||
"""Generate GarbageEntry object from the mapping provided
|
"""Generate GarbageEntry object from the mapping provided
|
||||||
|
|
||||||
### Args:
|
### Args:
|
||||||
@@ -60,7 +60,7 @@ class GarbageEntry:
|
|||||||
)
|
)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
async def from_record(cls, data: Mapping[str, Any]) -> "GarbageEntry":
|
async def from_record(cls, data: Mapping[str, Any]):
|
||||||
locations = [
|
locations = [
|
||||||
await Location.get(location_id) for location_id in data["locations"]
|
await Location.get(location_id) for location_id in data["locations"]
|
||||||
]
|
]
|
||||||
|
@@ -28,7 +28,7 @@ class Location:
|
|||||||
timezone: Union[BaseTzInfo, DstTzInfo]
|
timezone: Union[BaseTzInfo, DstTzInfo]
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
async def get(cls, id: int) -> "Location":
|
async def get(cls, id: int):
|
||||||
db_entry = await col_locations.find_one({"id": id})
|
db_entry = await col_locations.find_one({"id": id})
|
||||||
|
|
||||||
if db_entry is None:
|
if db_entry is None:
|
||||||
@@ -40,7 +40,7 @@ class Location:
|
|||||||
return cls(**db_entry)
|
return cls(**db_entry)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
async def find(cls, name: str) -> "Location":
|
async def find(cls, name: str):
|
||||||
db_entry = await col_locations.find_one({"name": {"$regex": name}})
|
db_entry = await col_locations.find_one({"name": {"$regex": name}})
|
||||||
|
|
||||||
if db_entry is None:
|
if db_entry is None:
|
||||||
@@ -52,7 +52,7 @@ class Location:
|
|||||||
return cls(**db_entry)
|
return cls(**db_entry)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
async def nearby(cls, lat: float, lon: float) -> "Location":
|
async def nearby(cls, lat: float, lon: float):
|
||||||
db_entry = await col_locations.find_one({"location": {"$near": [lon, lat]}})
|
db_entry = await col_locations.find_one({"location": {"$near": [lon, lat]}})
|
||||||
|
|
||||||
if db_entry is None:
|
if db_entry is None:
|
||||||
|
@@ -19,11 +19,11 @@ logger = logging.getLogger(__name__)
|
|||||||
|
|
||||||
class PyroClient(LibPyroClient):
|
class PyroClient(LibPyroClient):
|
||||||
def __init__(self, **kwargs):
|
def __init__(self, **kwargs):
|
||||||
self.__version__ = (0, 1, 3)
|
self.__version__ = (0, 1, 2)
|
||||||
|
|
||||||
super().__init__(**kwargs)
|
super().__init__(**kwargs)
|
||||||
|
|
||||||
self.updater = Updater()
|
self.updater = Updater(ClientSession())
|
||||||
self.contexts = []
|
self.contexts = []
|
||||||
|
|
||||||
if self.scheduler is not None:
|
if self.scheduler is not None:
|
||||||
@@ -91,7 +91,6 @@ class PyroClient(LibPyroClient):
|
|||||||
]
|
]
|
||||||
|
|
||||||
async def check_updates(self) -> None:
|
async def check_updates(self) -> None:
|
||||||
"""Check for updates and send a message to the owner if newer version was found"""
|
|
||||||
if await self.updater.check_updates(
|
if await self.updater.check_updates(
|
||||||
self.__version__, self.config["strings"]["url_updater"]
|
self.__version__, self.config["strings"]["url_updater"]
|
||||||
):
|
):
|
||||||
|
@@ -1,9 +1,8 @@
|
|||||||
import logging
|
import logging
|
||||||
from dataclasses import dataclass
|
from dataclasses import dataclass
|
||||||
from datetime import datetime, timedelta
|
from datetime import datetime, timedelta, timezone
|
||||||
from typing import Any, Mapping, Tuple, Union
|
from typing import Any, Union
|
||||||
|
|
||||||
import pytz
|
|
||||||
from bson import ObjectId
|
from bson import ObjectId
|
||||||
|
|
||||||
from classes.location import Location
|
from classes.location import Location
|
||||||
@@ -46,7 +45,7 @@ class PyroUser:
|
|||||||
offset: int = 1,
|
offset: int = 1,
|
||||||
time_hour: int = 16,
|
time_hour: int = 16,
|
||||||
time_minute: int = 0,
|
time_minute: int = 0,
|
||||||
) -> "PyroUser":
|
):
|
||||||
db_entry = await col_users.find_one({"id": id})
|
db_entry = await col_users.find_one({"id": id})
|
||||||
|
|
||||||
if db_entry is None:
|
if db_entry is None:
|
||||||
@@ -74,7 +73,7 @@ class PyroUser:
|
|||||||
return cls(**db_entry)
|
return cls(**db_entry)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
async def from_dict(cls, **kwargs) -> "PyroUser":
|
async def from_dict(cls, **kwargs):
|
||||||
if "location" in kwargs:
|
if "location" in kwargs:
|
||||||
try:
|
try:
|
||||||
kwargs["location"] = await Location.get(kwargs["location"]) # type: ignore
|
kwargs["location"] = await Location.get(kwargs["location"]) # type: ignore
|
||||||
@@ -82,134 +81,52 @@ class PyroUser:
|
|||||||
kwargs["location"] = None # type: ignore
|
kwargs["location"] = None # type: ignore
|
||||||
return cls(**kwargs)
|
return cls(**kwargs)
|
||||||
|
|
||||||
async def update_locale(self, locale: Union[str, None]) -> Union[str, None]:
|
async def update_locale(self, locale: Union[str, None]) -> None:
|
||||||
"""Change user's locale stored in the database.
|
"""Change user's locale stored in the database.
|
||||||
|
|
||||||
### Args:
|
### Args:
|
||||||
* locale (`Union[str, None]`): New locale to be set.
|
* locale (`Union[str, None]`): New locale to be set.
|
||||||
"""
|
"""
|
||||||
logger.info("%s's locale has been set to %s", self.id, locale)
|
logger.debug("%s's locale has been set to %s", self.id, locale)
|
||||||
|
|
||||||
await col_users.update_one({"_id": self._id}, {"$set": {"locale": locale}})
|
await col_users.update_one({"_id": self._id}, {"$set": {"locale": locale}})
|
||||||
|
|
||||||
self.locale = locale
|
self.locale = locale
|
||||||
|
|
||||||
return self.locale
|
async def update_state(self, enabled: bool = False) -> None:
|
||||||
|
logger.debug("%s's state has been set to %s", self.id, enabled)
|
||||||
async def update_state(self, enabled: bool = False) -> bool:
|
|
||||||
"""Update user's state (enabled/disabled)
|
|
||||||
|
|
||||||
### Args:
|
|
||||||
* enabled (`bool`, *optional*): Whether the user is enabled. Defaults to `False`.
|
|
||||||
|
|
||||||
### Returns:
|
|
||||||
* `bool`: User's current state
|
|
||||||
"""
|
|
||||||
logger.info("%s's state has been set to %s", self.id, enabled)
|
|
||||||
|
|
||||||
await col_users.update_one({"_id": self._id}, {"$set": {"enabled": enabled}})
|
await col_users.update_one({"_id": self._id}, {"$set": {"enabled": enabled}})
|
||||||
|
|
||||||
self.enabled = enabled
|
self.enabled = enabled
|
||||||
|
|
||||||
return self.enabled
|
async def update_location(self, location_id: int = 0) -> None:
|
||||||
|
logger.debug("%s's location has been set to %s", self.id, location_id)
|
||||||
async def update_location(self, location_id: int) -> Location:
|
|
||||||
"""Update user's location and move their time to the new timezone (if the user had a location set previously)
|
|
||||||
|
|
||||||
### Args:
|
|
||||||
* location_id (`int`): ID of the location
|
|
||||||
|
|
||||||
### Returns:
|
|
||||||
`Location`: New location
|
|
||||||
"""
|
|
||||||
logger.info("%s's location has been set to %s", self.id, location_id)
|
|
||||||
|
|
||||||
await col_users.update_one(
|
await col_users.update_one(
|
||||||
{"_id": self._id}, {"$set": {"location": location_id}}
|
{"_id": self._id}, {"$set": {"location": location_id}}
|
||||||
)
|
)
|
||||||
|
self.location = await Location.get(location_id)
|
||||||
|
|
||||||
location = await Location.get(location_id)
|
async def update_offset(self, offset: int = 1) -> None:
|
||||||
|
logger.debug("%s's offset has been set to %s", self.id, offset)
|
||||||
# Execute if timezones of old and new locations are different
|
|
||||||
if self.location and (self.location.timezone.zone != location.timezone.zone):
|
|
||||||
# Get UTC time for selected reminder time
|
|
||||||
now_utc = datetime.now(pytz.utc).replace(
|
|
||||||
hour=self.time_hour, minute=self.time_minute, second=0, microsecond=0
|
|
||||||
)
|
|
||||||
|
|
||||||
# Get the time for the reminder time of old and new location
|
|
||||||
local_old = now_utc.astimezone(self.location.timezone)
|
|
||||||
local_new = (
|
|
||||||
location.timezone.localize(local_old.replace(tzinfo=None))
|
|
||||||
).astimezone(pytz.utc)
|
|
||||||
|
|
||||||
# Update the time to match the new timezone
|
|
||||||
await self.update_time(hour=local_new.hour, minute=local_new.minute)
|
|
||||||
|
|
||||||
self.location = location
|
|
||||||
|
|
||||||
return self.location
|
|
||||||
|
|
||||||
async def update_offset(self, offset: int = 1) -> int:
|
|
||||||
"""Update the offset of the reminder (in days)
|
|
||||||
|
|
||||||
### Args:
|
|
||||||
* offset (`int`, *optional*): Offset in days. Defaults to `1`.
|
|
||||||
|
|
||||||
### Returns:
|
|
||||||
* `int`: Offset in days
|
|
||||||
"""
|
|
||||||
logger.info("%s's offset has been set to %s", self.id, offset)
|
|
||||||
|
|
||||||
await col_users.update_one({"_id": self._id}, {"$set": {"offset": offset}})
|
await col_users.update_one({"_id": self._id}, {"$set": {"offset": offset}})
|
||||||
|
|
||||||
self.offset = offset
|
self.offset = offset
|
||||||
|
|
||||||
return offset
|
async def update_time(self, hour: int = 16, minute: int = 0) -> None:
|
||||||
|
logger.debug("%s's time has been set to %s h. %s m.", self.id, hour, minute)
|
||||||
async def update_time(self, hour: int = 16, minute: int = 0) -> Tuple[int, int]:
|
|
||||||
"""Update the time of the reminder (hour and minute, for UTC timezone)
|
|
||||||
|
|
||||||
### Args:
|
|
||||||
* hour (`int`, *optional*): Hour of the reminder. Defaults to `16`.
|
|
||||||
* minute (`int`, *optional*): Minute of the reminder. Defaults to `0`.
|
|
||||||
|
|
||||||
### Returns:
|
|
||||||
* `Tuple[int, int]`: Hour and minute of the reminder
|
|
||||||
"""
|
|
||||||
logger.info("%s's time has been set to %s h. %s m.", self.id, hour, minute)
|
|
||||||
|
|
||||||
await col_users.update_one(
|
await col_users.update_one(
|
||||||
{"_id": self._id}, {"$set": {"time_hour": hour, "time_minute": minute}}
|
{"_id": self._id}, {"$set": {"time_hour": hour, "time_minute": minute}}
|
||||||
)
|
)
|
||||||
|
|
||||||
self.time_hour = hour
|
self.time_hour = hour
|
||||||
self.time_minute = minute
|
self.time_minute = minute
|
||||||
|
|
||||||
return self.time_hour, self.time_minute
|
|
||||||
|
|
||||||
async def delete(self) -> None:
|
async def delete(self) -> None:
|
||||||
"""Delete the database record of the user"""
|
logger.debug("%s's data has been deleted", self.id)
|
||||||
logger.info("%s's data has been deleted", self.id)
|
|
||||||
|
|
||||||
await col_users.delete_one({"_id": self._id})
|
await col_users.delete_one({"_id": self._id})
|
||||||
|
|
||||||
async def checkout(self) -> Mapping[str, Any]:
|
async def checkout(self) -> Any:
|
||||||
"""Checkout the user's database record
|
logger.debug("%s's data has been checked out", self.id)
|
||||||
|
|
||||||
### Raises:
|
|
||||||
* `KeyError`: Database record of the user was not found
|
|
||||||
|
|
||||||
### Returns:
|
|
||||||
* `Mapping[str, Any]`: Database record
|
|
||||||
"""
|
|
||||||
logger.info("%s's data has been checked out", self.id)
|
|
||||||
|
|
||||||
db_entry = await col_users.find_one({"_id": self._id})
|
db_entry = await col_users.find_one({"_id": self._id})
|
||||||
|
|
||||||
if db_entry is None:
|
if db_entry is None:
|
||||||
raise KeyError(
|
raise KeyError(
|
||||||
f"DB record with id {self._id} of user {self.id} was not found"
|
f"DB record with id {self._id} of user {self.id} is not found"
|
||||||
)
|
)
|
||||||
|
|
||||||
del db_entry["_id"] # type: ignore
|
del db_entry["_id"] # type: ignore
|
||||||
@@ -238,7 +155,7 @@ class PyroUser:
|
|||||||
logger.warning("Location %s does not have a timezone set", self.location.id)
|
logger.warning("Location %s does not have a timezone set", self.location.id)
|
||||||
|
|
||||||
return (
|
return (
|
||||||
datetime.now(self.location.timezone or pytz.utc) + timedelta(days=1)
|
datetime.now(self.location.timezone or timezone.utc) + timedelta(days=1)
|
||||||
).replace(hour=0, minute=0, second=0, microsecond=0)
|
).replace(hour=0, minute=0, second=0, microsecond=0)
|
||||||
|
|
||||||
def get_reminder_time(self) -> datetime:
|
def get_reminder_time(self) -> datetime:
|
||||||
@@ -263,12 +180,12 @@ class PyroUser:
|
|||||||
logger.warning("Location %s does not have a timezone set", self.location.id)
|
logger.warning("Location %s does not have a timezone set", self.location.id)
|
||||||
|
|
||||||
return (
|
return (
|
||||||
datetime.now(pytz.utc)
|
datetime.now(timezone.utc)
|
||||||
.replace(
|
.replace(
|
||||||
hour=self.time_hour,
|
hour=self.time_hour,
|
||||||
minute=self.time_minute,
|
minute=self.time_minute,
|
||||||
second=0,
|
second=0,
|
||||||
microsecond=0,
|
microsecond=0,
|
||||||
)
|
)
|
||||||
.astimezone(self.location.timezone or pytz.utc)
|
.astimezone(self.location.timezone or timezone.utc)
|
||||||
)
|
)
|
||||||
|
@@ -1,5 +1,5 @@
|
|||||||
import logging
|
import logging
|
||||||
from typing import Any, Dict, Tuple, Union
|
from typing import Any, Dict, Tuple
|
||||||
|
|
||||||
from aiohttp import ClientSession
|
from aiohttp import ClientSession
|
||||||
|
|
||||||
@@ -7,15 +7,12 @@ logger = logging.getLogger(__name__)
|
|||||||
|
|
||||||
|
|
||||||
class Updater:
|
class Updater:
|
||||||
def __init__(self, client_session: Union[ClientSession, None] = None) -> None:
|
def __init__(self, client_session: ClientSession) -> None:
|
||||||
self.client_session: Union[ClientSession, None] = client_session
|
self.client_session: ClientSession = client_session
|
||||||
|
|
||||||
async def check_updates(
|
async def check_updates(
|
||||||
self, version_current: Tuple[int, int, int], api_url: str
|
self, version_current: Tuple[int, int, int], api_url: str
|
||||||
) -> bool:
|
) -> bool:
|
||||||
if not self.client_session:
|
|
||||||
self.client_session = ClientSession()
|
|
||||||
|
|
||||||
response = await self.client_session.get(api_url)
|
response = await self.client_session.get(api_url)
|
||||||
|
|
||||||
if response.status != 200:
|
if response.status != 200:
|
||||||
@@ -33,9 +30,6 @@ class Updater:
|
|||||||
)
|
)
|
||||||
|
|
||||||
async def get_latest_release(self, api_url: str) -> Dict[str, Any]:
|
async def get_latest_release(self, api_url: str) -> Dict[str, Any]:
|
||||||
if not self.client_session:
|
|
||||||
self.client_session = ClientSession()
|
|
||||||
|
|
||||||
response = await self.client_session.get(api_url)
|
response = await self.client_session.get(api_url)
|
||||||
|
|
||||||
if response.status != 200:
|
if response.status != 200:
|
||||||
|
@@ -8,7 +8,7 @@
|
|||||||
},
|
},
|
||||||
"bot": {
|
"bot": {
|
||||||
"name": "Garbage Reminder",
|
"name": "Garbage Reminder",
|
||||||
"about": "Nie wieder Müllabfuhrtermin verpassen. Mehr erfahren: https://garbagebot.eu",
|
"about": "Nie wieder Müllabfuhrtermin verpassen. Quellcode: https://garbagebot.eu",
|
||||||
"description": "Sie können Erinnerungen an die Müllabfuhr für Orte Ihrer Wahl erhalten.\n\nVerwenden Sie /help, um die Funktionsweise des Bots besser zu verstehen, oder verwenden Sie /setup, um Ihre Erinnerungen zu konfigurieren."
|
"description": "Sie können Erinnerungen an die Müllabfuhr für Orte Ihrer Wahl erhalten.\n\nVerwenden Sie /help, um die Funktionsweise des Bots besser zu verstehen, oder verwenden Sie /setup, um Ihre Erinnerungen zu konfigurieren."
|
||||||
},
|
},
|
||||||
"formats": {
|
"formats": {
|
||||||
|
@@ -8,7 +8,7 @@
|
|||||||
},
|
},
|
||||||
"bot": {
|
"bot": {
|
||||||
"name": "Garbage Reminder",
|
"name": "Garbage Reminder",
|
||||||
"about": "Never forget about garbage collection again. Learn more: https://garbagebot.eu",
|
"about": "Never forget about garbage collection again. Source code: https://garbagebot.eu",
|
||||||
"description": "You can receive reminders about garbage collection for locations of your choice.\n\nUse /help to better understand how the bot works or use /setup to configure your reminders."
|
"description": "You can receive reminders about garbage collection for locations of your choice.\n\nUse /help to better understand how the bot works or use /setup to configure your reminders."
|
||||||
},
|
},
|
||||||
"formats": {
|
"formats": {
|
||||||
|
@@ -8,7 +8,7 @@
|
|||||||
},
|
},
|
||||||
"bot": {
|
"bot": {
|
||||||
"name": "Garbage Reminder 🇺🇦",
|
"name": "Garbage Reminder 🇺🇦",
|
||||||
"about": "Більше ніколи не забувайте про вивезення сміття. Дізнатись більше: https://garbagebot.eu",
|
"about": "Більше ніколи не забувайте про вивезення сміття. Вихідний код: https://garbagebot.eu",
|
||||||
"description": "Ви можете отримувати нагадування про вивезення сміття для обраних вами місць.\n\nВикористовуйте /help, щоб краще зрозуміти, як працює бот, або /setup, щоб налаштувати нагадування."
|
"description": "Ви можете отримувати нагадування про вивезення сміття для обраних вами місць.\n\nВикористовуйте /help, щоб краще зрозуміти, як працює бот, або /setup, щоб налаштувати нагадування."
|
||||||
},
|
},
|
||||||
"formats": {
|
"formats": {
|
||||||
|
@@ -8,7 +8,7 @@
|
|||||||
},
|
},
|
||||||
"bot": {
|
"bot": {
|
||||||
"name": "Garbage Reminder 🇺🇦",
|
"name": "Garbage Reminder 🇺🇦",
|
||||||
"about": "Більше ніколи не забувайте про вивезення сміття. Дізнатись більше: https://garbagebot.eu",
|
"about": "Більше ніколи не забувайте про вивезення сміття. Вихідний код: https://garbagebot.eu",
|
||||||
"description": "Ви можете отримувати нагадування про вивезення сміття для обраних вами місць.\n\nВикористовуйте /help, щоб краще зрозуміти, як працює бот, або /setup, щоб налаштувати нагадування."
|
"description": "Ви можете отримувати нагадування про вивезення сміття для обраних вами місць.\n\nВикористовуйте /help, щоб краще зрозуміти, як працює бот, або /setup, щоб налаштувати нагадування."
|
||||||
},
|
},
|
||||||
"formats": {
|
"formats": {
|
||||||
|
4
main.py
4
main.py
@@ -4,7 +4,6 @@ from argparse import ArgumentParser
|
|||||||
from os import getpid
|
from os import getpid
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
|
||||||
from aiohttp import ClientSession
|
|
||||||
from convopyro import Conversation
|
from convopyro import Conversation
|
||||||
from libbot import sync
|
from libbot import sync
|
||||||
|
|
||||||
@@ -42,8 +41,7 @@ def main():
|
|||||||
exit()
|
exit()
|
||||||
|
|
||||||
client = PyroClient(
|
client = PyroClient(
|
||||||
scheduler=scheduler,
|
scheduler=scheduler, commands_source=sync.json_read(Path("commands.json"))
|
||||||
commands_source=sync.json_read(Path("commands.json")),
|
|
||||||
)
|
)
|
||||||
Conversation(client)
|
Conversation(client)
|
||||||
|
|
||||||
|
@@ -13,4 +13,4 @@ class Migration(BaseMigration):
|
|||||||
|
|
||||||
def downgrade(self):
|
def downgrade(self):
|
||||||
sync.config_delete("update_checker", missing_ok=True)
|
sync.config_delete("update_checker", missing_ok=True)
|
||||||
sync.config_delete("url_updater", "strings", missing_ok=True)
|
sync.config_delete("url_updater", "strings")
|
||||||
|
@@ -1,7 +1,6 @@
|
|||||||
import logging
|
import logging
|
||||||
from datetime import datetime
|
from datetime import datetime, timezone
|
||||||
|
|
||||||
import pytz
|
|
||||||
from bson import json_util
|
from bson import json_util
|
||||||
from libbot.pyrogram.classes import PyroClient
|
from libbot.pyrogram.classes import PyroClient
|
||||||
|
|
||||||
@@ -15,7 +14,7 @@ logger = logging.getLogger(__name__)
|
|||||||
|
|
||||||
|
|
||||||
async def remind(app: PyroClient) -> None:
|
async def remind(app: PyroClient) -> None:
|
||||||
utcnow = datetime.now(pytz.utc)
|
utcnow = datetime.now(timezone.utc)
|
||||||
|
|
||||||
logger.debug("Performing reminder lookup for %s (UTCNOW)", utcnow)
|
logger.debug("Performing reminder lookup for %s (UTCNOW)", utcnow)
|
||||||
|
|
||||||
@@ -43,7 +42,13 @@ async def remind(app: PyroClient) -> None:
|
|||||||
logger.warning("Skipping reminder for %s due to invalid location", user.id)
|
logger.warning("Skipping reminder for %s due to invalid location", user.id)
|
||||||
continue
|
continue
|
||||||
|
|
||||||
user_date = user.get_reminder_date().replace(tzinfo=None)
|
try:
|
||||||
|
user_date = user.get_reminder_date()
|
||||||
|
except AttributeError:
|
||||||
|
logger.warning(
|
||||||
|
"Skipping reminder for %s due to missing attributes", user.id
|
||||||
|
)
|
||||||
|
continue
|
||||||
|
|
||||||
entries = await col_entries.find(
|
entries = await col_entries.find(
|
||||||
{
|
{
|
||||||
|
@@ -1,7 +1,8 @@
|
|||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
from typing import Union
|
from typing import Union
|
||||||
|
|
||||||
import pytz
|
from pytz import UTC
|
||||||
|
from pytz import timezone as pytz_timezone
|
||||||
|
|
||||||
|
|
||||||
def to_utc(date: datetime, timezone: Union[str, None] = None) -> datetime:
|
def to_utc(date: datetime, timezone: Union[str, None] = None) -> datetime:
|
||||||
@@ -17,9 +18,7 @@ def to_utc(date: datetime, timezone: Union[str, None] = None) -> datetime:
|
|||||||
* `datetime`: Timezone unaware datetime in UTC with timezone's offset applied to it.
|
* `datetime`: Timezone unaware datetime in UTC with timezone's offset applied to it.
|
||||||
"""
|
"""
|
||||||
timezone = "UTC" if timezone is None else timezone
|
timezone = "UTC" if timezone is None else timezone
|
||||||
return (
|
return pytz_timezone(timezone).localize(date).astimezone(UTC).replace(tzinfo=None)
|
||||||
pytz.timezone(timezone).localize(date).astimezone(pytz.utc).replace(tzinfo=None)
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
def from_utc(date: datetime, timezone: Union[str, None] = None) -> datetime:
|
def from_utc(date: datetime, timezone: Union[str, None] = None) -> datetime:
|
||||||
@@ -36,5 +35,8 @@ def from_utc(date: datetime, timezone: Union[str, None] = None) -> datetime:
|
|||||||
"""
|
"""
|
||||||
timezone = "UTC" if timezone is None else timezone
|
timezone = "UTC" if timezone is None else timezone
|
||||||
return (
|
return (
|
||||||
pytz.utc.localize(date).astimezone(pytz.timezone(timezone)).replace(tzinfo=None)
|
pytz_timezone("UTC")
|
||||||
|
.localize(date)
|
||||||
|
.astimezone(pytz_timezone(timezone))
|
||||||
|
.replace(tzinfo=None)
|
||||||
)
|
)
|
||||||
|
@@ -1,7 +1,6 @@
|
|||||||
import logging
|
import logging
|
||||||
from datetime import datetime
|
from datetime import datetime, timezone
|
||||||
|
|
||||||
import pytz
|
|
||||||
from convopyro import listen_message
|
from convopyro import listen_message
|
||||||
from pyrogram import filters
|
from pyrogram import filters
|
||||||
from pyrogram.types import ForceReply, Message, ReplyKeyboardRemove
|
from pyrogram.types import ForceReply, Message, ReplyKeyboardRemove
|
||||||
@@ -66,9 +65,9 @@ async def command_set_offset(app: PyroClient, message: Message):
|
|||||||
logger.info("User %s has set offset to %s", user.id, offset)
|
logger.info("User %s has set offset to %s", user.id, offset)
|
||||||
|
|
||||||
garbage_time = (
|
garbage_time = (
|
||||||
datetime.now(pytz.utc)
|
datetime.now(timezone.utc)
|
||||||
.replace(hour=user.time_hour, minute=user.time_minute)
|
.replace(hour=user.time_hour, minute=user.time_minute)
|
||||||
.astimezone(user.location.timezone or pytz.utc)
|
.astimezone(user.location.timezone or timezone.utc)
|
||||||
)
|
)
|
||||||
|
|
||||||
await answer.reply_text(
|
await answer.reply_text(
|
||||||
|
@@ -1,7 +1,6 @@
|
|||||||
import logging
|
import logging
|
||||||
from datetime import datetime
|
from datetime import datetime, timezone
|
||||||
|
|
||||||
import pytz
|
|
||||||
from convopyro import listen_message
|
from convopyro import listen_message
|
||||||
from pyrogram import filters
|
from pyrogram import filters
|
||||||
from pyrogram.types import ForceReply, Message, ReplyKeyboardRemove
|
from pyrogram.types import ForceReply, Message, ReplyKeyboardRemove
|
||||||
@@ -55,30 +54,34 @@ async def command_set_time(app: PyroClient, message: Message):
|
|||||||
|
|
||||||
break
|
break
|
||||||
|
|
||||||
# Time we got from the user
|
now = datetime.now()
|
||||||
parsed_time = datetime.strptime(answer.text, "%H:%M")
|
|
||||||
|
|
||||||
# Datetime user means in their timezone
|
parsed_time = datetime.strptime(answer.text, "%H:%M").replace(
|
||||||
user_time = datetime.now(user.location.timezone).replace(
|
year=now.year,
|
||||||
hour=parsed_time.hour, minute=parsed_time.minute, second=0, microsecond=0
|
month=now.month,
|
||||||
|
day=now.day,
|
||||||
|
second=0,
|
||||||
|
microsecond=0,
|
||||||
|
tzinfo=timezone.utc,
|
||||||
)
|
)
|
||||||
|
|
||||||
# Datetime in user's timezone moved to UTC timezone
|
user_time = parsed_time.astimezone(user.location.timezone or timezone.utc)
|
||||||
utc_time = user_time.astimezone(pytz.utc)
|
|
||||||
|
|
||||||
await user.update_time(hour=utc_time.hour, minute=utc_time.minute)
|
await user.update_time(hour=user_time.hour, minute=user_time.minute)
|
||||||
|
|
||||||
logger.info(
|
logger.info(
|
||||||
"User %s has selected notification time of %s (%s UTC)",
|
"User %s has selected notification time of %s (%s UTC)",
|
||||||
user.id,
|
user.id,
|
||||||
|
parsed_time.strftime("%H:%M"),
|
||||||
user_time.strftime("%H:%M"),
|
user_time.strftime("%H:%M"),
|
||||||
utc_time.strftime("%H:%M"),
|
|
||||||
)
|
)
|
||||||
|
|
||||||
|
garbage_time = parsed_time.strftime(app._("time", "formats", locale=user.locale))
|
||||||
|
|
||||||
await answer.reply_text(
|
await answer.reply_text(
|
||||||
app._("set_time_finished", "messages", locale=user.locale).format(
|
app._("set_time_finished", "messages", locale=user.locale).format(
|
||||||
offset=user.offset,
|
offset=user.offset,
|
||||||
time=user_time.strftime(app._("time", "formats", locale=user.locale)),
|
time=garbage_time,
|
||||||
toggle_notice=(
|
toggle_notice=(
|
||||||
"" if user.enabled else app._("toggle", "messages", locale=user.locale)
|
"" if user.enabled else app._("toggle", "messages", locale=user.locale)
|
||||||
),
|
),
|
||||||
|
@@ -72,9 +72,12 @@ async def command_setup(app: PyroClient, message: Message):
|
|||||||
|
|
||||||
await user.update_location(location.id)
|
await user.update_location(location.id)
|
||||||
|
|
||||||
|
try:
|
||||||
user_time = user.get_reminder_time().strftime(
|
user_time = user.get_reminder_time().strftime(
|
||||||
app._("time", "formats", locale=user.locale)
|
app._("time", "formats", locale=user.locale)
|
||||||
)
|
)
|
||||||
|
except AttributeError:
|
||||||
|
user_time = "N/A"
|
||||||
|
|
||||||
await message.reply_text(
|
await message.reply_text(
|
||||||
app._("setup_finished", "messages", locale=user.locale).format(
|
app._("setup_finished", "messages", locale=user.locale).format(
|
||||||
|
@@ -88,9 +88,12 @@ async def command_start(app: PyroClient, message: Message):
|
|||||||
|
|
||||||
await user.update_location(location.id)
|
await user.update_location(location.id)
|
||||||
|
|
||||||
|
try:
|
||||||
user_time = user.get_reminder_time().strftime(
|
user_time = user.get_reminder_time().strftime(
|
||||||
app._("time", "formats", locale=user.locale)
|
app._("time", "formats", locale=user.locale)
|
||||||
)
|
)
|
||||||
|
except AttributeError:
|
||||||
|
user_time = "N/A"
|
||||||
|
|
||||||
await answer.reply_text(
|
await answer.reply_text(
|
||||||
app._("start_selection_yes", "messages", locale=user.locale).format(
|
app._("start_selection_yes", "messages", locale=user.locale).format(
|
||||||
|
@@ -13,7 +13,7 @@ async def command_toggle(app: PyroClient, message: Message):
|
|||||||
|
|
||||||
await user.update_state(not user.enabled)
|
await user.update_state(not user.enabled)
|
||||||
|
|
||||||
if not user.enabled:
|
if user.enabled:
|
||||||
await message.reply_text(
|
await message.reply_text(
|
||||||
app._("toggle_disabled", "messages", locale=user.locale)
|
app._("toggle_disabled", "messages", locale=user.locale)
|
||||||
)
|
)
|
||||||
|
@@ -1,6 +1,5 @@
|
|||||||
from datetime import datetime, timedelta
|
from datetime import datetime, timedelta, timezone
|
||||||
|
|
||||||
import pytz
|
|
||||||
from pyrogram import filters
|
from pyrogram import filters
|
||||||
from pyrogram.types import Message
|
from pyrogram.types import Message
|
||||||
|
|
||||||
@@ -24,11 +23,11 @@ async def command_upcoming(app: PyroClient, message: Message):
|
|||||||
|
|
||||||
date_min = (
|
date_min = (
|
||||||
datetime.now(user.location.timezone).replace(second=0, microsecond=0)
|
datetime.now(user.location.timezone).replace(second=0, microsecond=0)
|
||||||
).replace(tzinfo=pytz.utc)
|
).replace(tzinfo=timezone.utc)
|
||||||
date_max = (
|
date_max = (
|
||||||
datetime.now(user.location.timezone).replace(second=0, microsecond=0)
|
datetime.now(user.location.timezone).replace(second=0, microsecond=0)
|
||||||
+ timedelta(days=30)
|
+ timedelta(days=30)
|
||||||
).replace(tzinfo=pytz.utc)
|
).replace(tzinfo=timezone.utc)
|
||||||
|
|
||||||
entries = [
|
entries = [
|
||||||
await GarbageEntry.from_record(entry)
|
await GarbageEntry.from_record(entry)
|
||||||
|
@@ -1,12 +1,12 @@
|
|||||||
aiohttp~=3.10.2
|
aiohttp~=3.9.5
|
||||||
apscheduler~=3.10.4
|
apscheduler~=3.10.4
|
||||||
async_pymongo==0.1.9
|
|
||||||
convopyro==0.5
|
convopyro==0.5
|
||||||
mongodb-migrations==1.3.1
|
mongodb-migrations==1.3.1
|
||||||
pytz>=2024.1
|
pytz<=2023.2
|
||||||
tgcrypto==1.2.5
|
tgcrypto==1.2.5
|
||||||
ujson>=5.0.0
|
ujson>=5.0.0
|
||||||
uvloop==0.20.0
|
uvloop==0.19.0
|
||||||
--extra-index-url https://git.end-play.xyz/api/packages/profitroll/pypi/simple
|
--extra-index-url https://git.end-play.xyz/api/packages/profitroll/pypi/simple
|
||||||
libbot[speed,pyrogram]==3.2.3
|
async_pymongo==0.1.4
|
||||||
|
libbot[speed,pyrogram]==3.2.2
|
||||||
pykeyboard==0.1.7
|
pykeyboard==0.1.7
|
Reference in New Issue
Block a user