basically.... yea
This commit is contained in:
parent
35fbb4b695
commit
08c231209c
File diff suppressed because it is too large
Load Diff
161
bot/main.py
161
bot/main.py
|
|
@ -1,5 +1,156 @@
|
||||||
- get chats page
|
import asyncio
|
||||||
- for each
|
import aiohttp
|
||||||
- if seen_at is less than latest[created_at]
|
import os
|
||||||
- get token url from api
|
import sys
|
||||||
- respond to that user
|
import json
|
||||||
|
from typing import Optional, Dict, Any
|
||||||
|
from dotenv import load_dotenv
|
||||||
|
import urllib.parse
|
||||||
|
import re
|
||||||
|
|
||||||
|
load_dotenv()
|
||||||
|
|
||||||
|
SKETCHERS_UNITED_SESSION = os.environ.get('SKETCHERS_UNITED_SESSION')
|
||||||
|
REMEMBER_WEB = os.environ.get('REMEMBER_WEB')
|
||||||
|
TARGET_URL = 'https://sketchersunited.org/chats'
|
||||||
|
API_PASSWORD = os.environ.get('API_PASSWORD')
|
||||||
|
XSRF_TOKEN = os.environ.get('XSRF_TOKEN')
|
||||||
|
|
||||||
|
def get_session_cookie_header() -> Optional[Dict[str, str]]:
|
||||||
|
if not SKETCHERS_UNITED_SESSION or not REMEMBER_WEB:
|
||||||
|
print("Missing required session or remember_web environment variables.", file=sys.stderr)
|
||||||
|
return None
|
||||||
|
|
||||||
|
cookies_to_send = []
|
||||||
|
cookies_to_send.append(f"sketchers_united_session={SKETCHERS_UNITED_SESSION}")
|
||||||
|
cookies_to_send.append(f"remember_web_59ba36addc2b2f9401580f014c7f58ea4e30989d={REMEMBER_WEB}")
|
||||||
|
|
||||||
|
if XSRF_TOKEN:
|
||||||
|
cookies_to_send.append(f"XSRF-TOKEN={XSRF_TOKEN}")
|
||||||
|
|
||||||
|
cookie_header = "; ".join(cookies_to_send)
|
||||||
|
|
||||||
|
return {
|
||||||
|
'Cookie': cookie_header,
|
||||||
|
'Accept': 'application/json',
|
||||||
|
'User-Agent': 'usernames chat checking bot',
|
||||||
|
'Content-Type': 'application/json',
|
||||||
|
}
|
||||||
|
|
||||||
|
def get_post_headers(xsrf_token: str) -> Dict[str, str]:
|
||||||
|
return {
|
||||||
|
'User-Agent': 'Mozilla/5.0 (X11; Linux x86_64; rv:133.0) Gecko/20100101 Firefox/133.0',
|
||||||
|
'Accept': 'application/json, text/plain, */*',
|
||||||
|
'Accept-Language': 'en-US,en;q=0.5',
|
||||||
|
'X-XSRF-TOKEN': xsrf_token,
|
||||||
|
'Sec-GPC': '1',
|
||||||
|
'Sec-Fetch-Dest': 'empty',
|
||||||
|
'Sec-Fetch-Mode': 'cors',
|
||||||
|
'Sec-Fetch-Site': 'same-origin',
|
||||||
|
'Priority': 'u=0',
|
||||||
|
}
|
||||||
|
|
||||||
|
async def make_new_json_request(user_id: int):
|
||||||
|
url = f'http://localhost/api/token/{user_id}'
|
||||||
|
data = {
|
||||||
|
'password': API_PASSWORD
|
||||||
|
}
|
||||||
|
|
||||||
|
headers = {
|
||||||
|
'Content-Type': 'application/json',
|
||||||
|
'Accept': 'application/json',
|
||||||
|
}
|
||||||
|
|
||||||
|
async with aiohttp.ClientSession() as session:
|
||||||
|
async with session.post(url, json=data, headers=headers) as response:
|
||||||
|
response_text = await response.text()
|
||||||
|
return response_text
|
||||||
|
|
||||||
|
async def post_chat_update(session: aiohttp.ClientSession, chat_object: Dict[str, Any], xsrf_token: str):
|
||||||
|
pattern = r'/(\d+)/'
|
||||||
|
match = re.search(pattern, chat_object.get('icon_url'))
|
||||||
|
|
||||||
|
token = await make_new_json_request(match.group(1))
|
||||||
|
|
||||||
|
form_data = aiohttp.FormData()
|
||||||
|
form_data.add_field('text', f"""You've signed up for the Secret Sketchers event, your link is http://localhost/profile/{token} - it is private and should only be used by you.
|
||||||
|
\nDon't want to be in it anymore? Go to http://localhost/withdraw/{token} - note that withdrawing is permanent and you cannot re-enter the event.""")
|
||||||
|
|
||||||
|
headers = get_post_headers(xsrf_token)
|
||||||
|
|
||||||
|
try:
|
||||||
|
cookie_headers = get_session_cookie_header()
|
||||||
|
if cookie_headers:
|
||||||
|
headers['Cookie'] = cookie_headers['Cookie']
|
||||||
|
|
||||||
|
async with session.post(
|
||||||
|
f"{TARGET_URL}/{chat_object.get('id')}/messages",
|
||||||
|
data=form_data,
|
||||||
|
headers=headers
|
||||||
|
) as response:
|
||||||
|
if response.status not in [200, 201]:
|
||||||
|
text = await response.text()
|
||||||
|
print(f" Status: {response.status}. Response: {text}", file=sys.stderr)
|
||||||
|
except aiohttp.ClientError as e:
|
||||||
|
print(f"-> POST ERROR: Client error during update for chat ID {chat_object.get('id', 'N/A')}: {e}", file=sys.stderr)
|
||||||
|
except Exception as e:
|
||||||
|
print(f"-> POST ERROR: Unexpected error during update for chat ID {chat_object.get('id', 'N/A')}: {e}", file=sys.stderr)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
async def process_chats():
|
||||||
|
global XSRF_TOKEN
|
||||||
|
|
||||||
|
async with aiohttp.ClientSession() as session:
|
||||||
|
headers = get_session_cookie_header()
|
||||||
|
if not headers:
|
||||||
|
return
|
||||||
|
|
||||||
|
async with session.get(TARGET_URL, headers=headers) as response:
|
||||||
|
if response.status != 200:
|
||||||
|
print(f"failed: {response.status}", file=sys.stderr)
|
||||||
|
return
|
||||||
|
|
||||||
|
try:
|
||||||
|
chat_data_array = await response.json()
|
||||||
|
if not isinstance(chat_data_array, list):
|
||||||
|
print("not json", file=sys.stderr)
|
||||||
|
return
|
||||||
|
|
||||||
|
except aiohttp.ContentTypeError:
|
||||||
|
print("also not json", file=sys.stderr)
|
||||||
|
return
|
||||||
|
|
||||||
|
fresh_xsrf_token = None
|
||||||
|
for cookie in session.cookie_jar:
|
||||||
|
if cookie.key == "XSRF-TOKEN":
|
||||||
|
fresh_xsrf_token = urllib.parse.unquote(cookie.value)
|
||||||
|
break
|
||||||
|
|
||||||
|
XSRF_TOKEN = fresh_xsrf_token
|
||||||
|
|
||||||
|
for index, chat_object in enumerate(chat_data_array):
|
||||||
|
if(chat_object.get('type') == 'private'):
|
||||||
|
seen_at_value = chat_object.get('seen_at')
|
||||||
|
is_unread = False
|
||||||
|
|
||||||
|
try:
|
||||||
|
if isinstance(seen_at_value, dict):
|
||||||
|
is_unread = True
|
||||||
|
# print(f"Chat {index}: Status: DICT (New Chat) -> Unread: True")
|
||||||
|
else:
|
||||||
|
latest_created_at = chat_object.get('latest', {}).get('created_at', 0)
|
||||||
|
seen_at_int = int(seen_at_value) if seen_at_value is not None else 0
|
||||||
|
|
||||||
|
is_unread = seen_at_int < latest_created_at
|
||||||
|
# print(f"Chat {index}: Seen at ({seen_at_int}) < Latest message ({latest_created_at}) -> Unread: {is_unread}")
|
||||||
|
|
||||||
|
except (AttributeError, TypeError, ValueError) as e:
|
||||||
|
is_unread = False
|
||||||
|
|
||||||
|
if is_unread:
|
||||||
|
await post_chat_update(session, chat_object, fresh_xsrf_token)
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
asyncio.run(process_chats())
|
||||||
|
|
|
||||||
|
|
@ -204,14 +204,17 @@ $cancelEditingSubmission = function ()
|
||||||
@elseif($participant->desperate)
|
@elseif($participant->desperate)
|
||||||
<p>You're in a bind!</p>
|
<p>You're in a bind!</p>
|
||||||
@else
|
@else
|
||||||
<p>You haven't been assigned anyone.</p>
|
<p>You haven't been assigned anyone yet. Assignments will be made on DATE</p>
|
||||||
@endif
|
@endif
|
||||||
</div>
|
</div>
|
||||||
|
<div class="other-content">
|
||||||
<a
|
<a
|
||||||
href="/withdraw/{{$token}}"
|
href="/withdraw/{{$token}}"
|
||||||
>
|
>
|
||||||
Withdraw from Secret Sketchers...
|
Withdraw from Secret Sketchers...?
|
||||||
</a>
|
</a>
|
||||||
|
</div>
|
||||||
|
|
||||||
@endif
|
@endif
|
||||||
|
|
||||||
<style>
|
<style>
|
||||||
|
|
|
||||||
|
|
@ -45,6 +45,7 @@ $withdraw = function ()
|
||||||
|
|
||||||
<div>
|
<div>
|
||||||
<h1>Withdraw from the event?</h1>
|
<h1>Withdraw from the event?</h1>
|
||||||
|
<p>Withdrawing is permanent, once you withdraw you cannot rejoin.</p>
|
||||||
<button
|
<button
|
||||||
wire:click="confirmWithdrawal"
|
wire:click="confirmWithdrawal"
|
||||||
class=""
|
class=""
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue