prince1604 commited on
Commit
4371a7d
·
1 Parent(s): 42cddc3

Fix silent JS errors and enable multi-file attachment selection

Browse files
Files changed (2) hide show
  1. app.py +6 -3
  2. templates/campaign.html +43 -6
app.py CHANGED
@@ -55,11 +55,14 @@ def setup_campaign():
55
  sender_password = request.form.get('sender_password')
56
  subject = request.form.get('subject')
57
  body = request.form.get('body')
58
- email_column = request.form.get('email_column', 'RecipientEmail')
59
  contacts_file = request.files.get('contactsFile')
60
 
61
  if not contacts_file or contacts_file.filename == '':
62
  return jsonify({'error': 'Contacts file is required.'}), 400
 
 
 
63
 
64
  # Secure filename and check extension
65
  allowed_extensions = {'.csv', '.xlsx', '.xls'}
@@ -77,7 +80,7 @@ def setup_campaign():
77
 
78
  # Verify SMTP credentials BEFORE starting campaign
79
  try:
80
- server = smtplib.SMTP('smtp.gmail.com', 587)
81
  server.starttls()
82
  server.login(sender_email, sender_password)
83
  server.quit()
@@ -241,7 +244,7 @@ def _send_single_email(s_name, s_email, s_pass, to_email, subj, text, att_paths)
241
  part.add_header('Content-Disposition', f'attachment; filename="{os.path.basename(p)}"')
242
  msg.attach(part)
243
 
244
- server = smtplib.SMTP('smtp.gmail.com', 587)
245
  server.starttls()
246
  server.login(s_email, s_pass)
247
  server.send_message(msg)
 
55
  sender_password = request.form.get('sender_password')
56
  subject = request.form.get('subject')
57
  body = request.form.get('body')
58
+ email_column = request.form.get('email_column', '').strip()
59
  contacts_file = request.files.get('contactsFile')
60
 
61
  if not contacts_file or contacts_file.filename == '':
62
  return jsonify({'error': 'Contacts file is required.'}), 400
63
+
64
+ if not email_column:
65
+ return jsonify({'error': 'Please select an Email Column.'}), 400
66
 
67
  # Secure filename and check extension
68
  allowed_extensions = {'.csv', '.xlsx', '.xls'}
 
80
 
81
  # Verify SMTP credentials BEFORE starting campaign
82
  try:
83
+ server = smtplib.SMTP('smtp.gmail.com', 587, timeout=15)
84
  server.starttls()
85
  server.login(sender_email, sender_password)
86
  server.quit()
 
244
  part.add_header('Content-Disposition', f'attachment; filename="{os.path.basename(p)}"')
245
  msg.attach(part)
246
 
247
+ server = smtplib.SMTP('smtp.gmail.com', 587, timeout=15)
248
  server.starttls()
249
  server.login(s_email, s_pass)
250
  server.send_message(msg)
templates/campaign.html CHANGED
@@ -480,6 +480,8 @@ LinkedIn: {LinkedInURL}`
480
 
481
  // Handle both forms dynamically depending on which is visible
482
  document.querySelectorAll('.campaign-form').forEach(form => {
 
 
483
  const fileInput = form.querySelector('.contactsFileInput');
484
  const fileNameDisp = form.querySelector('.contactFileName');
485
  if (fileInput && fileNameDisp) {
@@ -543,9 +545,20 @@ LinkedIn: {LinkedInURL}`
543
  if (attachInput && attachCountDisp) {
544
  attachInput.addEventListener('change', e => {
545
  if (e.target.files) {
546
- attachCountDisp.textContent = e.target.files.length + " files attached";
 
 
 
 
547
  }
548
  });
 
 
 
 
 
 
 
549
  }
550
 
551
  form.addEventListener('submit', async (e) => {
@@ -563,6 +576,18 @@ LinkedIn: {LinkedInURL}`
563
 
564
  try {
565
  const formData = new FormData(form);
 
 
 
 
 
 
 
 
 
 
 
 
566
  const res = await fetch('/api/setup_campaign', {
567
  method: 'POST',
568
  body: formData
@@ -611,8 +636,14 @@ LinkedIn: {LinkedInURL}`
611
  sendBatch(campaignId);
612
  }
613
  } catch (err) {
614
- if (progressStatus) progressStatus.textContent = "Network Error while sending.";
615
- if (progressTitle) progressTitle.classList.add("text-red-500");
 
 
 
 
 
 
616
  if (submitBtn) submitBtn.disabled = false;
617
  if (btnSpan) btnSpan.textContent = 'Retry Send';
618
  }
@@ -621,10 +652,16 @@ LinkedIn: {LinkedInURL}`
621
  await sendBatch(data.campaign_id);
622
 
623
  } catch (err) {
624
- alert("Error: " + err.message);
 
 
 
 
 
 
 
625
  if (submitBtn) submitBtn.disabled = false;
626
- if (btnSpan) btnSpan.textContent = 'Send Now';
627
- if (progressContainer) progressContainer.classList.add('hidden-forced');
628
  }
629
  });
630
  });
 
480
 
481
  // Handle both forms dynamically depending on which is visible
482
  document.querySelectorAll('.campaign-form').forEach(form => {
483
+ let selectedAttachments = [];
484
+
485
  const fileInput = form.querySelector('.contactsFileInput');
486
  const fileNameDisp = form.querySelector('.contactFileName');
487
  if (fileInput && fileNameDisp) {
 
545
  if (attachInput && attachCountDisp) {
546
  attachInput.addEventListener('change', e => {
547
  if (e.target.files) {
548
+ for(let i=0; i<e.target.files.length; i++) {
549
+ selectedAttachments.push(e.target.files[i]);
550
+ }
551
+ attachCountDisp.textContent = selectedAttachments.length + " files attached (Tap to reset)";
552
+ attachInput.value = ''; // Reset so they can add more
553
  }
554
  });
555
+
556
+ // Allow resetting attachments by clicking the count
557
+ attachCountDisp.style.cursor = 'pointer';
558
+ attachCountDisp.addEventListener('click', () => {
559
+ selectedAttachments = [];
560
+ attachCountDisp.textContent = "0 files attached";
561
+ });
562
  }
563
 
564
  form.addEventListener('submit', async (e) => {
 
576
 
577
  try {
578
  const formData = new FormData(form);
579
+
580
+ // Inject accumulated attachments
581
+ formData.delete('attachments');
582
+ selectedAttachments.forEach(file => {
583
+ formData.append('attachments', file);
584
+ });
585
+
586
+ // Ensure email_column is safely handled
587
+ if (!formData.get('email_column')) {
588
+ throw new Error("Please select an Email Column after uploading your contacts file.");
589
+ }
590
+
591
  const res = await fetch('/api/setup_campaign', {
592
  method: 'POST',
593
  body: formData
 
636
  sendBatch(campaignId);
637
  }
638
  } catch (err) {
639
+ if (progressStatus) {
640
+ progressStatus.textContent = "Network Error while sending: " + err.message;
641
+ progressStatus.classList.add("text-red-600");
642
+ }
643
+ if (progressTitle) {
644
+ progressTitle.textContent = "Error Sending!";
645
+ progressTitle.classList.replace("text-primary", "text-red-600");
646
+ }
647
  if (submitBtn) submitBtn.disabled = false;
648
  if (btnSpan) btnSpan.textContent = 'Retry Send';
649
  }
 
652
  await sendBatch(data.campaign_id);
653
 
654
  } catch (err) {
655
+ if (progressTitle) {
656
+ progressTitle.textContent = "Setup Error";
657
+ progressTitle.classList.replace('text-primary', 'text-red-600');
658
+ }
659
+ if (progressStatus) {
660
+ progressStatus.textContent = err.message;
661
+ progressStatus.classList.add('text-red-600', 'font-bold');
662
+ }
663
  if (submitBtn) submitBtn.disabled = false;
664
+ if (btnSpan) btnSpan.textContent = 'Retry';
 
665
  }
666
  });
667
  });