CoolFace
Apppublic

Bishall10/ipo

sourceHugging Faceupdated 3mo agoView on Hugging Face
0likes
run_github_automation.py214 linesDownload Raw Back to root
1import os2import psycopg23import datetime4import time5import re6from playwright.sync_api import sync_playwright7from main import login, apply_ipo, handle_password_reset, check_allotment_results8from expiry_handler import handle_expired_account9 10# ── Firebase setup ──────────────────────────────────────────────────11import firebase_admin12from firebase_admin import credentials, messaging13 14def _init_firebase():15    if not firebase_admin._apps:16        cred_path = os.path.join(os.path.dirname(__file__), "config", "firebase_vcc.json")17        if os.path.exists(cred_path):18            cred = credentials.Certificate(cred_path)19        else:20            import base64, json21            b64 = os.environ.get("FIREBASE_CREDENTIALS_B64", "")22            if not b64:23                print("  ⚠️  Firebase credentials not found. Skipping notifications.")24                return False25            cred_json = json.loads(base64.b64decode(b64).decode())26            cred = credentials.Certificate(cred_json)27        firebase_admin.initialize_app(cred)28    return True29 30def send_push_notification(fcm_tokens: list, title: str, body: str):31    if not fcm_tokens:32        return33    if not _init_firebase():34        return35    android_config = messaging.AndroidConfig(36        priority='high',37        notification=messaging.AndroidNotification(38            channel_id='high_importance_channel',39            sticky=True,40            default_vibrate_timings=True,41            default_sound=True,42        )43    )44    message = messaging.MulticastMessage(45        notification=messaging.Notification(title=title, body=body),46        tokens=fcm_tokens,47        android=android_config,48    )49    try:50        response = messaging.send_each_for_multicast(message)51        print(f"  FCM: {response.success_count} sent, {response.failure_count} failed.")52    except Exception as e:53        print(f"  FCM error: {e}")54 55# ── Database connection ─────────────────────────────────────────────56DB_URL = os.environ.get("DATABASE_URL")57 58# ── Encryption ─────────────────────────────────────────────────────59from cryptography.fernet import Fernet60_ENCRYPTION_KEY = os.environ.get("ENCRYPTION_KEY", "").encode()61 62def decrypt(token: str) -> str:63    if not token:64        return token65    if not _ENCRYPTION_KEY:66        return token67    if not token.startswith('gAAAAA'):68        return token69    try:70        return Fernet(_ENCRYPTION_KEY).decrypt(token.encode()).decode()71    except Exception as e:72        print(f"  ⚠️  Decryption failed: {e}")73        return token74 75# ── Main automation ─────────────────────────────────────────────────76 77def run_automation():78    if not DB_URL:79        print("Error: DATABASE_URL not set.")80        return81 82    try:83        # 1. Fetch active accounts84        conn = psycopg2.connect(DB_URL)85        cur = conn.cursor()86        cur.execute("""87            SELECT a.id, a.meroshare_user, a.meroshare_pass, a.dp_name,88                   a.crn, a.tpin, a.bank_name, a.kitta, a.owner_id89            FROM automation_account a90            WHERE a.is_active = True;91        """)92        columns = [desc[0] for desc in cur.description]93        accounts = [dict(zip(columns, row)) for row in cur.fetchall()]94        cur.close()95        conn.close()96 97        if not accounts:98            print("No active accounts found.")99            return100 101        print(f"Found {len(accounts)} active accounts. Starting automation...")102 103        with sync_playwright() as p:104            browser = p.chromium.launch(105                headless=True,106                args=['--disable-blink-features=AutomationControlled', '--no-sandbox']107            )108            context = browser.new_context(109                user_agent="Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/122.0.0.0 Safari/537.36",110                viewport={"width": 1280, "height": 720},111                permissions=['geolocation'],112                geolocation={'latitude': 27.7172, 'longitude': 85.3240}113            )114 115            for acc in accounts:116                print(f"\n{'='*50}\nProcessing: {acc['meroshare_user']}")117                notification_sent = False118                status = "Error"119                remark = "Unknown error"120                ipo_name = "Auto-Check"121                page = context.new_page()122                try:123                    decrypted_pass = decrypt(acc['meroshare_pass'])124                    if decrypted_pass.startswith('gAAAAA'):125                        print(f"  ⚠️  WARNING: Password for {acc['meroshare_user']} still looks ENCRYPTED. Check your ENCRYPTION_KEY.")126                    else:127                        print(f"  🔑 Password Decrypted. Length: {len(decrypted_pass)} chars.")128 129                    account_data = {130                        'ID': acc['id'],131                        'MEROSHARE_USER': acc['meroshare_user'],132                        'MEROSHARE_PASS': decrypted_pass,133                        'DP_NAME': acc['dp_name'],134                        'CRN': acc['crn'],135                        'TPIN': acc['tpin'],136                        'BANK_NAME': acc['bank_name'],137                        'KITTA': str(acc['kitta']),138                        'owner_id': acc.get('owner_id'),139                    }140 141                    page.goto("https://meroshare.cdsc.com.np", timeout=60000)142                    login_result = login(page, account_data['MEROSHARE_USER'], account_data['MEROSHARE_PASS'], account_data['DP_NAME'])143 144                    if login_result is True:145                        print(f"  ✅ Login OK. Applying IPO...")146                        success, result_detail = apply_ipo(page, account_data)147                        if success:148                            status = "Success"149                            ipo_name = result_detail150                            remark = f"{ipo_name} applied successfully."151                        else:152                            status = "Failed"153                            remark = result_detail154                        155                        # Call allotment result check after applying156                        print(f"  Checking allotment status in MeroShare dashboard...")157                        try:158                            check_allotment_results(page, account_data)159                        except Exception as ar_e:160                            print(f"  ⚠️ Error checking allotment results: {ar_e}")161                    elif login_result == "EXPIRED":162                        print(f"  [{acc['meroshare_user']}] Password expired. Handling reset...")163                        if handle_password_reset(page, account_data):164                            status = "Success"165                            remark = "Password reset successfully. Re-run required."166                        else:167                            status = "Failed"168                            remark = "Password expired and reset failed."169                    else:170                        print(f"  ❌ MeroShare Login failed for {acc['meroshare_user']}.")171                        status = "Failed"172                        remark = "MeroShare login failed"173 174                except Exception as e:175                    print(f"  ❌ Inner Exception: {e}")176                    remark = str(e)177                finally:178                    # 3. Final Logging and Notification179                    try:180                        conn = psycopg2.connect(DB_URL)181                        cur = conn.cursor()182                        # Skip logging for: no IPO found, and Block Amount Status updates (these are noise)183                        remark_lower = remark.lower()184                        skip_log = (185                            remark == "No ordinary shares found" or186                            "block amount status" in remark_lower187                        )188                        if not skip_log:189                            cur.execute("""190                                INSERT INTO automation_applicationlog191                                    (account_id, company_name, status, remark, timestamp, is_read, is_listed)192                                VALUES (%s, %s, %s, %s, %s, %s, %s)193                            """, (acc['id'], ipo_name, status, remark, datetime.datetime.now(datetime.timezone.utc), False, False))194                            conn.commit()195                        else:196                            print(f"  ℹ️  Skipping database log for: {remark}")197 198                        cur.close()199                        conn.close()200                    except Exception as fatal:201                        print(f"  ⚠️  Fatal Logging Error: {fatal}")202 203                    try: page.close()204                    except: pass205 206            browser.close()207        print("\nAutomation run completed.")208 209    except Exception as e:210        print(f"Global Error: {e}")211 212if __name__ == "__main__":213    run_automation()214