fb43306571
Dockerfile fixes: - edu_master/phpsessid-bot: add --no-install-recommends, pin pip versions - edu_master/webinar-checker: pin pip versions with --no-cache-dir - userbot: add SHELL with pipefail for pipe operations Ruff fixes (173 → 0): - W293/W291/W292: whitespace clean via ruff format - N806: camelCase → snake_case (anilist, safone, hearts, flux, etc.) - ARG001/ARG002: prefix unused params with _ - SIM115: use context managers for file I/O - SIM117: combine nested with statements - S608: noqa on SQL f-strings (module name is validated) - E402/N812/N817: import fixes - B023: pass loop variable as argument - I001: auto-sorted imports - syntax: fixed = vs == in dtek_notif/main.py
133 lines
4.6 KiB
Python
133 lines
4.6 KiB
Python
import logging
|
|
import os
|
|
import time
|
|
from datetime import datetime
|
|
|
|
import redis
|
|
import requests
|
|
|
|
# Configure logging
|
|
logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s')
|
|
logger = logging.getLogger(__name__)
|
|
|
|
|
|
# Load configuration (adapted to .env keys)
|
|
def _env(key, default=None):
|
|
v = os.getenv(key, default)
|
|
if isinstance(v, str) and len(v) >= 2 and ((v[0] == '"' and v[-1] == '"') or (v[0] == "'" and v[-1] == "'")):
|
|
return v[1:-1]
|
|
return v
|
|
|
|
|
|
LOGIN = _env('KEEPER_LOGIN')
|
|
PASSWORD = _env('KEEPER_PASSWORD')
|
|
|
|
EDU_BASE = _env('EDU_URL_BASE', 'https://edu.edu.vn.ua')
|
|
EDU_LOGIN_PATH = _env('EDU_URL_LOGIN', '/user/login')
|
|
EDU_COURSES_PATH = _env('EDU_URL_COURSES', '/course/userlist')
|
|
URL_LOGIN = f'{EDU_BASE.rstrip("/")}/{EDU_LOGIN_PATH.lstrip("/")}'
|
|
URL_VERIFY = f'{EDU_BASE.rstrip("/")}/{EDU_COURSES_PATH.lstrip("/")}'
|
|
|
|
INTERVAL = int(_env('KEEPER_INTERVAL', 10))
|
|
USER_AGENT = _env(
|
|
'USER_AGENT',
|
|
'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36',
|
|
)
|
|
REDIS_HOST = _env('REDIS_HOST', 'redis')
|
|
REDIS_PORT = int(_env('REDIS_PORT', 6379))
|
|
|
|
SUCCESS_FILE = '/tmp/last_success' # noqa: S108
|
|
|
|
|
|
def touch_success_file():
|
|
"""Updates the timestamp of the success file for healthchecks."""
|
|
try:
|
|
with open(SUCCESS_FILE, 'w') as f:
|
|
f.write(str(datetime.now().timestamp()))
|
|
except Exception as e:
|
|
logger.error(f'Failed to touch success file: {e}')
|
|
|
|
|
|
def main():
|
|
logger.info('Starting Session Keeper Bot')
|
|
|
|
# Connect to Redis
|
|
try:
|
|
redis_client = redis.Redis(host=REDIS_HOST, port=REDIS_PORT, decode_responses=True)
|
|
redis_client.ping()
|
|
logger.info(f'Connected to Redis at {REDIS_HOST}:{REDIS_PORT}')
|
|
except Exception as e:
|
|
logger.error(f'Failed to connect to Redis: {e}')
|
|
return
|
|
|
|
session = requests.Session()
|
|
|
|
# Set headers
|
|
headers = {
|
|
'User-Agent': USER_AGENT,
|
|
'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7',
|
|
'Accept-Language': 'en-US,en;q=0.9',
|
|
'Cache-Control': 'max-age=0',
|
|
'Upgrade-Insecure-Requests': '1',
|
|
'Sec-Fetch-Site': 'same-origin',
|
|
'Sec-Fetch-Mode': 'navigate',
|
|
'Sec-Fetch-User': '?1',
|
|
'Sec-Fetch-Dest': 'document',
|
|
'Sec-Ch-Ua': '"Not_A Brand";v="99", "Chromium";v="142"',
|
|
'Sec-Ch-Ua-Mobile': '?0',
|
|
'Sec-Ch-Ua-Platform': '"Linux"',
|
|
'Accept-Encoding': 'gzip, deflate, br',
|
|
'Priority': 'u=0, i',
|
|
}
|
|
session.headers.update(headers)
|
|
|
|
while True:
|
|
try:
|
|
logger.info('Attempting login...')
|
|
|
|
# Login payload
|
|
payload = {'login': LOGIN, 'password': PASSWORD}
|
|
|
|
# Perform Login
|
|
# Note: The user request shows a POST to /user/login with form data
|
|
# We need to make sure we handle the PHPSESSID correctly.
|
|
# If we already have a PHPSESSID, requests will send it.
|
|
|
|
login_response = session.post(URL_LOGIN, data=payload, allow_redirects=True)
|
|
|
|
logger.info(f'Login Response Status: {login_response.status_code}')
|
|
logger.info(f'Cookies after login: {session.cookies.get_dict()}')
|
|
|
|
# Verify Session
|
|
logger.info('Verifying session...')
|
|
verify_response = session.get(URL_VERIFY, allow_redirects=False)
|
|
|
|
logger.info(f'Verify Response Status: {verify_response.status_code}')
|
|
|
|
if verify_response.status_code == 200:
|
|
logger.info('Session verification SUCCESS (200 OK).')
|
|
touch_success_file()
|
|
|
|
# Save PHPSESSID to Redis
|
|
phpsessid = session.cookies.get('PHPSESSID')
|
|
if phpsessid:
|
|
try:
|
|
redis_client.set('EDU_PHPSESSID', phpsessid)
|
|
logger.info(f'Saved PHPSESSID to Redis: {phpsessid}')
|
|
except Exception as e:
|
|
logger.error(f'Failed to save PHPSESSID to Redis: {e}')
|
|
elif verify_response.status_code == 302:
|
|
logger.warning('Session verification FAILED (302 Redirect). Session might be invalid.')
|
|
else:
|
|
logger.warning(f'Session verification returned unexpected status: {verify_response.status_code}')
|
|
|
|
except Exception as e:
|
|
logger.error(f'An error occurred: {e}')
|
|
|
|
logger.info(f'Sleeping for {INTERVAL} minutes...')
|
|
time.sleep(INTERVAL * 60)
|
|
|
|
|
|
if __name__ == '__main__':
|
|
main()
|