From 3fa43432d59f30a02b387ceaf9d8c8484178a33a Mon Sep 17 00:00:00 2001 From: Bryce Date: Mon, 4 Aug 2025 12:26:52 -0700 Subject: [PATCH 1/3] improvements --- .env | 10 +++++++--- tests/test_imap_routes.py | 10 +++++----- 2 files changed, 12 insertions(+), 8 deletions(-) diff --git a/.env b/.env index 619eb86..f12cda8 100644 --- a/.env +++ b/.env @@ -1,5 +1,9 @@ SECRET_KEY=your-secret-key-here DATABASE_URL=postgresql://postgres:password@localhost:5432/email_organizer_dev -OPENAI_API_KEY=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 -OPENAI_BASE_URL=https://openrouter.ai/api/v1 -OPENAI_MODEL=qwen/qwen3-coder +# OPENAI_API_KEY=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 +# OPENAI_BASE_URL=https://openrouter.ai/api/v1 +# OPENAI_MODEL=qwen/qwen3-coder +# +OPENAI_API_KEY=aaoeu +OPENAI_BASE_URL=http://localhost:8082/v1 +OPENAI_MODEL= diff --git a/tests/test_imap_routes.py b/tests/test_imap_routes.py index ea4fc3e..80abe3d 100644 --- a/tests/test_imap_routes.py +++ b/tests/test_imap_routes.py @@ -34,10 +34,10 @@ class TestIMAPRoutes: response = client.post('/api/imap/test', data={ 'server': 'test.com', - 'port': '993', - 'username': 'test@test.com', - 'password': 'testpass', - 'use_ssl': 'on' + 'port': '5153', + 'username': 'user1@example.com', + 'password': 'password1', + 'use_ssl': 'off' }) assert response.status_code == 200 @@ -60,4 +60,4 @@ class TestIMAPRoutes: response = client.post('/api/imap/sync') # Should fail without real IMAP server but return proper response - assert response.status_code in [200, 400] \ No newline at end of file + assert response.status_code in [200, 400] From 8bf00e9a3bd8941378e2dcea6be76334579646b8 Mon Sep 17 00:00:00 2001 From: Bryce Date: Mon, 4 Aug 2025 16:35:13 -0700 Subject: [PATCH 2/3] supports syncing of folders. --- app/imap_service.py | 54 +++++++++++++++--------- app/routes.py | 22 +++++++--- app/templates/index.html | 49 ++++++++++++++++++++- app/templates/partials/folders_list.html | 8 +++- docker-compose.yml | 1 + 5 files changed, 106 insertions(+), 28 deletions(-) diff --git a/app/imap_service.py b/app/imap_service.py index bb124b5..c0bc3e9 100644 --- a/app/imap_service.py +++ b/app/imap_service.py @@ -12,20 +12,29 @@ class IMAPService: self.config = user.imap_config or {} self.connection = None + def _connect(self): + """Create an IMAP connection based on configuration.""" + server = self.config.get('server', 'imap.gmail.com') + port = self.config.get('port', 993) + use_ssl = self.config.get('use_ssl', True) + + if use_ssl: + # Create SSL context + context = ssl.create_default_context() + # Connect using SSL + self.connection = imaplib.IMAP4_SSL(server, port) + else: + # Connect without SSL + self.connection = imaplib.IMAP4(server, port) + def test_connection(self) -> Tuple[bool, str]: """Test IMAP connection with current configuration.""" try: if not self.config: return False, "No IMAP configuration found" - # Create SSL context - context = ssl.create_default_context() - # Connect to IMAP server - self.connection = imaplib.IMAP4_SSL( - self.config.get('server', 'imap.gmail.com'), - self.config.get('port', 993) - ) + self._connect() # Login self.connection.login( @@ -34,17 +43,27 @@ class IMAPService: ) # Select inbox to verify connection - self.connection.select('INBOX') + resp_code, content = self.connection.select('INBOX') + print(resp_code, content) - # Close connection + # Close the folder, not the connection self.connection.close() + + # Logout self.connection.logout() + self.connection = None return True, "Connection successful" except imaplib.IMAP4.error as e: + print(e) + import traceback + traceback.print_exc() return False, f"IMAP connection error: {str(e)}" except Exception as e: + print(e) + import traceback + traceback.print_exc() return False, f"Connection error: {str(e)}" finally: if self.connection: @@ -59,14 +78,8 @@ class IMAPService: if not self.config: return [] - # Create SSL context - context = ssl.create_default_context() - # Connect to IMAP server - self.connection = imaplib.IMAP4_SSL( - self.config.get('server', 'imap.gmail.com'), - self.config.get('port', 993) - ) + self._connect() # Login self.connection.login( @@ -79,6 +92,8 @@ class IMAPService: if status != 'OK': return [] + + print(folder_data) folders = [] for folder_item in folder_data: @@ -101,8 +116,6 @@ class IMAPService: 'full_path': folder_name }) - # Close connection - self.connection.close() self.connection.logout() return folders @@ -163,5 +176,8 @@ class IMAPService: return True, f"Successfully synced {synced_count} folders" except Exception as e: + import traceback + traceback.print_exc() + print(e) db.session.rollback() - return False, f"Sync error: {str(e)}" \ No newline at end of file + return False, f"Sync error: {str(e)}" diff --git a/app/routes.py b/app/routes.py index de74468..731d2d6 100644 --- a/app/routes.py +++ b/app/routes.py @@ -205,7 +205,12 @@ def update_folder(folder_id): @login_required def imap_config_modal(): """Return the IMAP configuration modal.""" - response = make_response(render_template('partials/imap_config_modal.html')) + # Pass existing IMAP config to the template if it exists + response = make_response(render_template('partials/imap_config_modal.html', + server=current_user.imap_config.get('server') if current_user.imap_config else None, + port=current_user.imap_config.get('port') if current_user.imap_config else None, + username=current_user.imap_config.get('username') if current_user.imap_config else None, + use_ssl=current_user.imap_config.get('use_ssl', True) if current_user.imap_config else True)) response.headers['HX-Trigger'] = 'open-modal' return response @@ -213,6 +218,7 @@ def imap_config_modal(): @login_required def test_imap_connection(): """Test IMAP connection with provided configuration.""" + print("HELLO") try: # Get form data server = request.form.get('server') @@ -235,7 +241,7 @@ def test_imap_connection(): errors['password'] = 'Password is required' if errors: - response = make_response(render_template('partials/imap_config_modal.html', errors=errors)) + response = make_response(render_template('partials/imap_config_modal.html', errors=errors, server=server, port=port, username=username, use_ssl=use_ssl)) response.headers['HX-Retarget'] = '#imap-modal' response.headers['HX-Reswap'] = 'outerHTML' return response @@ -246,7 +252,7 @@ def test_imap_connection(): 'port': int(port), 'username': username, 'password': password, - 'use_ssl': use_ssl, + 'use_ssl': False, 'use_tls': False, 'connection_timeout': 30 } @@ -254,6 +260,7 @@ def test_imap_connection(): # Test connection temp_user = type('User', (), {'imap_config': test_config})() imap_service = IMAPService(temp_user) + print(temp_user, test_config) success, message = imap_service.test_connection() if success: @@ -266,8 +273,9 @@ def test_imap_connection(): response.headers['HX-Retarget'] = '#imap-modal' response.headers['HX-Reswap'] = 'outerHTML' else: + print(message) response = make_response(render_template('partials/imap_config_modal.html', - errors={'general': message})) + errors={'general': message}, server=server, port=port, username=username, use_ssl=use_ssl)) response.headers['HX-Retarget'] = '#imap-modal' response.headers['HX-Reswap'] = 'outerHTML' @@ -275,8 +283,9 @@ def test_imap_connection(): except Exception as e: logging.exception("Error testing IMAP connection: %s", e) + print(e) errors = {'general': 'An unexpected error occurred. Please try again.'} - response = make_response(render_template('partials/imap_config_modal.html', errors=errors)) + response = make_response(render_template('partials/imap_config_modal.html', errors=errors, server=server, port=port, username=username, use_ssl=use_ssl)) response.headers['HX-Retarget'] = '#imap-modal' response.headers['HX-Reswap'] = 'outerHTML' return response @@ -302,4 +311,5 @@ def sync_imap_folders(): except Exception as e: logging.exception("Error syncing IMAP folders: %s", e) - return jsonify({'error': 'An unexpected error occurred. Please try again.'}), 500 \ No newline at end of file + print(e) + return jsonify({'error': 'An unexpected error occurred. Please try again.'}), 500 diff --git a/app/templates/index.html b/app/templates/index.html index 6dcd7d4..8862713 100644 --- a/app/templates/index.html +++ b/app/templates/index.html @@ -28,6 +28,53 @@ + +
+

Welcome to Email Organizer!

+

Organize your emails automatically with AI-powered rules. Create folders and set up rules to categorize incoming emails.

+
+ + +
+
+ + +
+
+
{{ folders|length }}
+
Total Folders
+
+
+
0
+
Emails Processed
+
+
+
0
+
Active Rules
+
+
+ + +
+
+ + +
+
+ + + +
+
+
{% include 'partials/folders_list.html' %}
@@ -38,4 +85,4 @@ {% block modal %} {% include "partials/modal_holder.html" %} -{% endblock %} \ No newline at end of file +{% endblock %} diff --git a/app/templates/partials/folders_list.html b/app/templates/partials/folders_list.html index 7170c8e..c416aa8 100644 --- a/app/templates/partials/folders_list.html +++ b/app/templates/partials/folders_list.html @@ -1,6 +1,6 @@
{% for folder in folders %} -
+

{{ folder.name }}

@@ -39,7 +39,7 @@
{% else %} -
+
@@ -53,6 +53,10 @@ Create Folder +
+

Need help setting up your first folder?

+ View tutorial +
{% endfor %}
diff --git a/docker-compose.yml b/docker-compose.yml index b28af40..c8847dd 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -30,3 +30,4 @@ services: tmpfs: - /tmp - /run + user: "0:0" From b4f64b3b764c11155474614b5109fef184a03008 Mon Sep 17 00:00:00 2001 From: Bryce Date: Tue, 5 Aug 2025 05:22:45 -0700 Subject: [PATCH 3/3] Minor change --- app/templates/index.html | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/app/templates/index.html b/app/templates/index.html index 8862713..21ba158 100644 --- a/app/templates/index.html +++ b/app/templates/index.html @@ -38,11 +38,23 @@ Create Your First Folder + {% if current_user.imap_config %} + + + {% else %} + {% endif %}