/nearby, subscriptions check, geocoding #2

Merged
profitroll merged 30 commits from dev into master 2023-01-02 12:16:38 +02:00
6 changed files with 65 additions and 14 deletions
Showing only changes of commit 22011829a5 - Show all commits

5
classes/errors/geo.py Normal file
View File

@ -0,0 +1,5 @@
class PlaceNotFoundError(Exception):
"""Query provided did not lead to any city or populated area"""
def __init__(self, query):
self.query = query
super().__init__(f"Could not find any place on geonames.org of feature classes A and P by query '{self.query}'")

View File

@ -8,9 +8,10 @@ from typing import Any, List, Literal, Union
from pyrogram.types import User, ChatMember, ChatPrivileges, Chat, Message, Photo, Video, Document, Animation, Voice, ForceReply, ReplyKeyboardMarkup from pyrogram.types import User, ChatMember, ChatPrivileges, Chat, Message, Photo, Video, Document, Animation, Voice, ForceReply, ReplyKeyboardMarkup
from pyrogram.errors import bad_request_400 from pyrogram.errors import bad_request_400
from dateutil.relativedelta import relativedelta from dateutil.relativedelta import relativedelta
from classes.errors.geo import PlaceNotFoundError
from modules.database import col_tmp, col_users, col_context, col_warnings, col_applications, col_sponsorships, col_messages from modules.database import col_tmp, col_users, col_context, col_warnings, col_applications, col_sponsorships, col_messages
from modules.logging import logWrite from modules.logging import logWrite
from modules.utils import configGet, locale, should_quote from modules.utils import configGet, find_location, locale, should_quote
class DefaultApplicationTemp(dict): class DefaultApplicationTemp(dict):
def __init__(self, user: int, reapply: bool = False): def __init__(self, user: int, reapply: bool = False):
@ -350,6 +351,10 @@ class HoloUser():
) )
progress = col_tmp.find_one({"user": self.id, "type": "application"}) progress = col_tmp.find_one({"user": self.id, "type": "application"})
if progress is None:
return
stage = progress["stage"] stage = progress["stage"]
if self.sponsorship_state()[0] == "fill": if self.sponsorship_state()[0] == "fill":
@ -385,13 +390,16 @@ class HoloUser():
elif stage == 3: elif stage == 3:
try: try:
result = (get(f"http://api.geonames.org/searchJSON?q={query}&maxRows=1&countryBias=UA&lang=uk&orderby=relevance&featureClass=P&featureClass=A&username={configGet('username', 'geocoding')}")).json() progress["application"][str(stage)] = find_location(query)
progress["application"][str(stage)] = result["geonames"][0] if ("lat" in progress["application"][str(stage)] and "lng" in progress["application"][str(stage)]):
progress["application"][str(stage)]["loc"] = [progress["application"][str(stage)]["lng"], progress["application"][str(stage)]["lat"]]
del progress["application"][str(stage)]["lat"]
del progress["application"][str(stage)]["lng"]
col_tmp.update_one({"user": {"$eq": self.id}, "type": {"$eq": "application"}}, {"$set": {"application": progress["application"], "stage": progress["stage"]+1}}) col_tmp.update_one({"user": {"$eq": self.id}, "type": {"$eq": "application"}}, {"$set": {"application": progress["application"], "stage": progress["stage"]+1}})
await msg.reply_text(locale(f"question3_found", "message", locale=self.locale).format(result["geonames"][0]["name"], result["geonames"][0]["adminName1"])) await msg.reply_text(locale("question3_found", "message", locale=self.locale).format(progress["application"][str(stage)]["name"], progress["application"][str(stage)]["adminName1"]))
await msg.reply_text(locale(f"question{stage+1}", "message", locale=self.locale), reply_markup=ForceReply(placeholder=str(locale(f"question{stage+1}", "force_reply", locale=self.locale)))) await msg.reply_text(locale(f"question{stage+1}", "message", locale=self.locale), reply_markup=ForceReply(placeholder=str(locale(f"question{stage+1}", "force_reply", locale=self.locale))))
except (ValueError, KeyError, IndexError): except PlaceNotFoundError:
await msg.reply_text(locale(f"question3_invalid", "message", locale=self.locale), reply_markup=ForceReply(placeholder=str(locale(f"question{stage}", "force_reply", locale=self.locale)))) await msg.reply_text(locale("question3_invalid", "message", locale=self.locale), reply_markup=ForceReply(placeholder=str(locale(f"question{stage}", "force_reply", locale=self.locale))))
return return
except Exception as exp: except Exception as exp:
await msg.reply_text(locale("question3_error", "message", locale=self.locale), reply_markup=ForceReply(placeholder=str(locale(f"question{stage}", "force_reply", locale=self.locale)))) await msg.reply_text(locale("question3_error", "message", locale=self.locale), reply_markup=ForceReply(placeholder=str(locale(f"question{stage}", "force_reply", locale=self.locale))))
@ -470,6 +478,10 @@ class HoloUser():
if col_tmp.find_one({"user": self.id, "type": "sponsorship"}) is not None: if col_tmp.find_one({"user": self.id, "type": "sponsorship"}) is not None:
progress = col_tmp.find_one({"user": self.id, "type": "sponsorship"}) progress = col_tmp.find_one({"user": self.id, "type": "sponsorship"})
if progress is None:
return
stage = progress["stage"] stage = progress["stage"]
if progress["state"] == "fill" and progress["sent"] is False: if progress["state"] == "fill" and progress["sent"] is False:

View File

@ -92,6 +92,8 @@
"label_too_long": "Довжина назви ролі не повинна перевищувати 16 символів", "label_too_long": "Довжина назви ролі не повинна перевищувати 16 символів",
"finish_sponsorship": "❌ **Дія неможлива**\nПерш ніж заповнювати анкету, треба завершити заповнення форми спонсора.", "finish_sponsorship": "❌ **Дія неможлива**\nПерш ніж заповнювати анкету, треба завершити заповнення форми спонсора.",
"finish_application": "❌ **Дія неможлива**\nПерш ніж заповнювати форму спонсора, треба завершити заповнення анкети.", "finish_application": "❌ **Дія неможлива**\nПерш ніж заповнювати форму спонсора, треба завершити заповнення анкети.",
"nearby_invalid": "",
"nearby_error": "",
"voice_message": [ "voice_message": [
"why are u gae", "why are u gae",
"руки відірвало? пиши як людина", "руки відірвало? пиши як людина",

View File

@ -4,25 +4,35 @@ from pyrogram.types import Message
from pyrogram.client import Client from pyrogram.client import Client
from classes.holo_user import HoloUser from classes.holo_user import HoloUser
from modules import custom_filters from modules import custom_filters
from modules.utils import configGet, should_quote from modules.utils import configGet, locale, should_quote, find_location
from modules.database import col_applications from modules.database import col_applications
from classes.errors.geo import PlaceNotFoundError
# Nearby command =============================================================================================================== # Nearby command ===============================================================================================================
@app.on_message(~ filters.scheduled & (custom_filters.allowed | custom_filters.admin) & (filters.private | (filters.chat(configGet("admin_group")) | filters.chat(configGet("destination_group")))) & filters.command(["nearby"], prefixes=["/"])) @app.on_message(~ filters.scheduled & (custom_filters.allowed | custom_filters.admin) & (filters.private | (filters.chat(configGet("admin_group")) | filters.chat(configGet("destination_group")))) & filters.command(["nearby"], prefixes=["/"]))
async def cmd_nearby(app: Client, msg: Message): async def cmd_nearby(app: Client, msg: Message):
if len(msg.command) < 1: holo_user = HoloUser(msg.from_user)
if len(msg.command) < 2:
application = col_applications.find_one({"user": msg.from_user}) application = col_applications.find_one({"user": msg.from_user})
if application is None: if application is None:
await msg.reply_text("You have no application") await msg.reply_text(locale("nearby_user_empty", "message", locale=holo_user.locale))
return return
location = application["application"]["3"]["loc"][0], application["application"]["3"]["loc"][1] location = application["application"]["3"]["loc"][0], application["application"]["3"]["loc"][1]
else: else:
# find location try:
location = "result" location_coordinates = find_location(" ".join(msg.command[2:]))
location = location_coordinates["lng"], location_coordinates["lat"]
except PlaceNotFoundError:
await msg.reply_text(locale("nearby_invalid", "message", locale=holo_user.locale), quote=should_quote(msg))
return
except Exception as exp:
await msg.reply_text(locale("nearby_error", "message", locale=holo_user.locale), quote=should_quote(msg))
return
output = [] output = []
users_nearby = col_applications.find( {"application": {"loc": { "$within": { "$center": [[location], 5] } }}} ) users_nearby = col_applications.find( {"application.loc": {"$near": { "$geometry": { "type": "Point", "coordinates": location }, "$maxDistance": 30000 }} } )
for user in users_nearby: for user in users_nearby:
output.append(user) output.append(user)

View File

@ -1,4 +1,4 @@
from pymongo import MongoClient from pymongo import MongoClient, GEO2D
from ujson import loads from ujson import loads
with open("config.json", "r", encoding="utf-8") as f: with open("config.json", "r", encoding="utf-8") as f:
@ -36,3 +36,5 @@ col_messages = db.get_collection("messages")
col_warnings = db.get_collection("warnings") col_warnings = db.get_collection("warnings")
col_applications = db.get_collection("applications") col_applications = db.get_collection("applications")
col_sponsorships = db.get_collection("sponsorships") col_sponsorships = db.get_collection("sponsorships")
col_applications.create_index([("application.3.loc", GEO2D)])

View File

@ -1,4 +1,5 @@
from typing import Any, Union from typing import Any, Union
from requests import get
from pyrogram.enums.chat_type import ChatType from pyrogram.enums.chat_type import ChatType
from pyrogram.types import User from pyrogram.types import User
from pyrogram.client import Client from pyrogram.client import Client
@ -10,6 +11,7 @@ from sys import exit
from os import kill, listdir, sep from os import kill, listdir, sep
from os import name as osname from os import name as osname
from traceback import print_exc from traceback import print_exc
from classes.errors.geo import PlaceNotFoundError
from modules.logging import logWrite from modules.logging import logWrite
@ -171,6 +173,24 @@ def all_locales(key: str, *args: str) -> list:
return output return output
def find_location(query: str) -> dict:
"""Find location on geonames.org by query. Search is made with feature classes A and P.
### Args:
* query (`str`): Some city/village/state name
### Raises:
* PlaceNotFoundError: Exception is raised when API result is empty
### Returns:
* `dict`: One instance of geonames response
"""
try:
result = (get(f"http://api.geonames.org/searchJSON?q={query}&maxRows=1&countryBias=UA&lang=uk&orderby=relevance&featureClass=P&featureClass=A&username={configGet('username', 'geocoding')}")).json()
return result["geonames"][0]
except (ValueError, KeyError, IndexError):
raise PlaceNotFoundError(query)
try: try:
from psutil import Process from psutil import Process
except ModuleNotFoundError: except ModuleNotFoundError: