DinoPLayZ commited on
Commit
c28ddc7
·
verified ·
1 Parent(s): 9bb4423

Broke the Intervals

Browse files
Files changed (1) hide show
  1. main.py +73 -50
main.py CHANGED
@@ -47,8 +47,8 @@ WARNING_EMAIL_RECIPIENT = os.getenv("WARNING_EMAIL_RECIPIENT", os.getenv("EMAIL_
47
  EMAIL_PASSWORD = os.getenv("EMAIL_PASSWORD", "")
48
  BREVO_API_KEY = os.getenv("BREVO_API_KEY", "")
49
 
50
- # App check interval in seconds (default 60 secs = 1 min)
51
- # Read dynamically inside the loop via os.getenv("CHECK_INTERVAL_SECONDS", "60")
52
 
53
  BIP_API = "https://bip.bitsathy.ac.in/nova-api/student-activity-masters"
54
  HEADERS = {
@@ -67,6 +67,7 @@ STATE_FILE = "state.txt"
67
  LAST_EVENT_ID = None
68
  LAST_EVENT_CODE = None
69
  SESSION_EXPIRED = False
 
70
 
71
  # ==============================================================================
72
  # STATE MANAGEMENT (Task 1)
@@ -184,6 +185,13 @@ def send_event_alerts(events):
184
  if not events:
185
  return
186
 
 
 
 
 
 
 
 
187
  msg = """
188
  <div style="font-family: Arial, sans-serif; background-color: #f4f6f9; padding: 20px;">
189
  <div style="max-width: 600px; margin: 0 auto; background: #ffffff; border-radius: 8px;
@@ -201,32 +209,29 @@ def send_event_alerts(events):
201
 
202
  for i, ev in enumerate(events, 1):
203
 
204
- # Date formatting
205
- from datetime import datetime
206
-
207
- def format_date(date_str):
208
- try:
209
- dt = datetime.strptime(date_str, "%Y-%m-%d")
210
- return f"<span style='font-weight:bold;'>{dt.strftime('%d-%m')}</span>-{dt.strftime('%Y')}"
211
- except:
212
- return date_str
213
-
214
  start = format_date(ev.get("start_date", "")) if ev.get("start_date") else ""
215
  end = format_date(ev.get("end_date", "")) if ev.get("end_date") else ""
216
 
217
  date_str = f"{start} to {end}" if start and end else (start or end or "-")
218
 
219
- # Highlight last 3 digits of code
220
  code = ev.get("event_code", "-")
221
- if len(code) >= 3:
222
- highlighted_code = code[:-3] + f"<span style='font-weight:bold; color:#dc3545;'>{code[-3:]}</span>"
223
- else:
224
- highlighted_code = code
225
 
226
- # Count values
227
- max_count = ev.get("max_count", 0)
228
- applied = ev.get("applied_count", 0)
229
- balance = max_count - applied
 
 
 
 
 
 
 
 
 
 
 
230
 
231
  msg += f"""
232
  <table style="width: 100%; border-collapse: collapse;
@@ -236,7 +241,7 @@ def send_event_alerts(events):
236
  <tr>
237
  <td style="padding: 8px 0; font-weight: bold; width: 35%;">Code</td>
238
  <td style="padding: 8px 0; width: 5%;">:</td>
239
- <td style="padding: 8px 0; width: 60%;">{highlighted_code}</td>
240
  </tr>
241
 
242
  <tr>
@@ -263,16 +268,6 @@ def send_event_alerts(events):
263
  <td style="padding: 8px 0;">{ev.get('location', '-')}</td>
264
  </tr>
265
 
266
- <tr>
267
- <td style="padding: 12px 0; font-weight: bold;">Count</td>
268
- <td style="padding: 12px 0;">:</td>
269
- <td style="padding: 12px 0;">
270
- Max: <b>{max_count}</b> |
271
- Balance: <b>{balance}</b> |
272
- Applied: <b>{applied}</b>
273
- </td>
274
- </tr>
275
-
276
  <tr>
277
  <td style="padding: 8px 0; font-weight: bold;">Logger URL</td>
278
  <td style="padding: 8px 0;">:</td>
@@ -295,6 +290,16 @@ def send_event_alerts(events):
295
  </td>
296
  </tr>
297
 
 
 
 
 
 
 
 
 
 
 
298
  </table>
299
  """
300
 
@@ -410,8 +415,25 @@ def check_new_events(last_id, xsrf_token, bip_session):
410
  # ==============================================================================
411
  # SCHEDULER ENGINE
412
  # ==============================================================================
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
413
  def process_tick():
414
- global LAST_EVENT_ID, LAST_EVENT_CODE
415
  logger.debug("--- process_tick starting ---")
416
 
417
  try:
@@ -451,6 +473,9 @@ def process_tick():
451
  raise SystemExit(1)
452
 
453
  if new_events:
 
 
 
454
  # If LAST_EVENT_ID is None, it's the very first startup run. Set ID without alerting.
455
  if LAST_EVENT_ID is None:
456
  LAST_EVENT_ID = new_events[0]["id"]
@@ -584,23 +609,24 @@ def test_real_event_alert():
584
  logger.info("✅ Real latest event alert sent successfully!")
585
 
586
  def start_loop():
 
587
  logger.info("🚀 BIP CLI Notifier Started")
588
 
589
  sleep_notified = False
590
 
591
  try:
592
  while True:
593
- now_ist = datetime.now(IST)
594
- current_hour = now_ist.hour
595
 
596
- if 8 <= current_hour < 15:
597
- check_interval = 120
598
- sleep_notified = False
599
- elif 15 <= current_hour < 17:
600
- check_interval = 60
601
  sleep_notified = False
602
  else:
603
  # Sleep until next 8 AM
 
 
604
  next_8am = now_ist.replace(hour=8, minute=0, second=0, microsecond=0)
605
  if current_hour >= 17:
606
  next_8am += timedelta(days=1)
@@ -621,6 +647,7 @@ def start_loop():
621
  )
622
  sleep_notified = True
623
 
 
624
  time.sleep(sleep_seconds)
625
  continue
626
 
@@ -717,17 +744,13 @@ async def root():
717
  async def internal_assistant():
718
  load_dotenv(override=True)
719
 
720
- now_ist = datetime.now(IST)
721
- current_hour = now_ist.hour
722
-
723
- if 8 <= current_hour < 15:
724
- current_interval = 120
725
- status_msg = "running"
726
- elif 15 <= current_hour < 17:
727
- current_interval = 60
728
  status_msg = "running"
729
  else:
730
- current_interval = 0
731
  status_msg = "paused (inactive hours)"
732
 
733
  return {
@@ -774,4 +797,4 @@ if __name__ == "__main__":
774
  else:
775
  # Default behavior: run FastAPI
776
  port = int(os.getenv("PORT", 7860))
777
- uvicorn.run(app, host="0.0.0.0", port=port, log_level="warning")
 
47
  EMAIL_PASSWORD = os.getenv("EMAIL_PASSWORD", "")
48
  BREVO_API_KEY = os.getenv("BREVO_API_KEY", "")
49
 
50
+ # App check intervals in seconds
51
+ # Read dynamically via os.getenv for NORMAL_INTERVAL, FAST_INTERVAL, FAST_DURATION
52
 
53
  BIP_API = "https://bip.bitsathy.ac.in/nova-api/student-activity-masters"
54
  HEADERS = {
 
67
  LAST_EVENT_ID = None
68
  LAST_EVENT_CODE = None
69
  SESSION_EXPIRED = False
70
+ FAST_MODE_UNTIL = 0
71
 
72
  # ==============================================================================
73
  # STATE MANAGEMENT (Task 1)
 
185
  if not events:
186
  return
187
 
188
+ def format_date(date_str):
189
+ try:
190
+ dt = datetime.strptime(date_str, "%Y-%m-%d")
191
+ return dt.strftime('%d-%m-%Y')
192
+ except:
193
+ return date_str
194
+
195
  msg = """
196
  <div style="font-family: Arial, sans-serif; background-color: #f4f6f9; padding: 20px;">
197
  <div style="max-width: 600px; margin: 0 auto; background: #ffffff; border-radius: 8px;
 
209
 
210
  for i, ev in enumerate(events, 1):
211
 
 
 
 
 
 
 
 
 
 
 
212
  start = format_date(ev.get("start_date", "")) if ev.get("start_date") else ""
213
  end = format_date(ev.get("end_date", "")) if ev.get("end_date") else ""
214
 
215
  date_str = f"{start} to {end}" if start and end else (start or end or "-")
216
 
217
+ # Code formatting without highlight
218
  code = ev.get("event_code", "-")
 
 
 
 
219
 
220
+ # Count values (convert to ints to ensure accurate calculation)
221
+ try:
222
+ max_count = int(ev.get("maximum_count", 0))
223
+ except (ValueError, TypeError):
224
+ max_count = 0
225
+
226
+ try:
227
+ applied = int(ev.get("applied_count", 0))
228
+ except (ValueError, TypeError):
229
+ applied = 0
230
+
231
+ try:
232
+ balance = int(ev.get("ComputedField", 0))
233
+ except (ValueError, TypeError):
234
+ balance = 0
235
 
236
  msg += f"""
237
  <table style="width: 100%; border-collapse: collapse;
 
241
  <tr>
242
  <td style="padding: 8px 0; font-weight: bold; width: 35%;">Code</td>
243
  <td style="padding: 8px 0; width: 5%;">:</td>
244
+ <td style="padding: 8px 0; width: 60%; font-weight: bold;">{code}</td>
245
  </tr>
246
 
247
  <tr>
 
268
  <td style="padding: 8px 0;">{ev.get('location', '-')}</td>
269
  </tr>
270
 
 
 
 
 
 
 
 
 
 
 
271
  <tr>
272
  <td style="padding: 8px 0; font-weight: bold;">Logger URL</td>
273
  <td style="padding: 8px 0;">:</td>
 
290
  </td>
291
  </tr>
292
 
293
+ <tr>
294
+ <td style="padding: 12px 0; font-weight: bold;">Count</td>
295
+ <td style="padding: 12px 0;">:</td>
296
+ <td style="padding: 12px 0;">
297
+ Max: <b>{max_count}</b> |
298
+ Balance: <b>{balance}</b> |
299
+ Applied: <b>{applied}</b>
300
+ </td>
301
+ </tr>
302
+
303
  </table>
304
  """
305
 
 
415
  # ==============================================================================
416
  # SCHEDULER ENGINE
417
  # ==============================================================================
418
+ def get_current_interval():
419
+ """Returns the polling interval in seconds, or 0 if in inactive hours."""
420
+ global FAST_MODE_UNTIL
421
+
422
+ fast_interval = int(os.getenv("FAST_INTERVAL", "30"))
423
+ normal_interval = int(os.getenv("NORMAL_INTERVAL", "120"))
424
+
425
+ now_ist = datetime.now(IST)
426
+ current_hour = now_ist.hour
427
+
428
+ if 8 <= current_hour < 17:
429
+ if time.time() < FAST_MODE_UNTIL:
430
+ return fast_interval
431
+ else:
432
+ return normal_interval
433
+ return 0
434
+
435
  def process_tick():
436
+ global LAST_EVENT_ID, LAST_EVENT_CODE, FAST_MODE_UNTIL
437
  logger.debug("--- process_tick starting ---")
438
 
439
  try:
 
473
  raise SystemExit(1)
474
 
475
  if new_events:
476
+ fast_duration = int(os.getenv("FAST_DURATION", "120"))
477
+ FAST_MODE_UNTIL = time.time() + fast_duration
478
+
479
  # If LAST_EVENT_ID is None, it's the very first startup run. Set ID without alerting.
480
  if LAST_EVENT_ID is None:
481
  LAST_EVENT_ID = new_events[0]["id"]
 
609
  logger.info("✅ Real latest event alert sent successfully!")
610
 
611
  def start_loop():
612
+ global FAST_MODE_UNTIL
613
  logger.info("🚀 BIP CLI Notifier Started")
614
 
615
  sleep_notified = False
616
 
617
  try:
618
  while True:
619
+ check_interval = get_current_interval()
 
620
 
621
+ if check_interval > 0:
622
+ fast_interval = int(os.getenv("FAST_INTERVAL", "30"))
623
+ if check_interval == fast_interval:
624
+ logger.info(f"⚡ Fast Mode Active ({fast_interval}s interval)")
 
625
  sleep_notified = False
626
  else:
627
  # Sleep until next 8 AM
628
+ now_ist = datetime.now(IST)
629
+ current_hour = now_ist.hour
630
  next_8am = now_ist.replace(hour=8, minute=0, second=0, microsecond=0)
631
  if current_hour >= 17:
632
  next_8am += timedelta(days=1)
 
647
  )
648
  sleep_notified = True
649
 
650
+ FAST_MODE_UNTIL = 0
651
  time.sleep(sleep_seconds)
652
  continue
653
 
 
744
  async def internal_assistant():
745
  load_dotenv(override=True)
746
 
747
+ current_interval = get_current_interval()
748
+ fast_interval = int(os.getenv("FAST_INTERVAL", "30"))
749
+ if current_interval == fast_interval:
750
+ status_msg = "running (fast mode)"
751
+ elif current_interval > 0:
 
 
 
752
  status_msg = "running"
753
  else:
 
754
  status_msg = "paused (inactive hours)"
755
 
756
  return {
 
797
  else:
798
  # Default behavior: run FastAPI
799
  port = int(os.getenv("PORT", 7860))
800
+ uvicorn.run(app, host="0.0.0.0", port=port, log_level="warning")