Skip to content
Merged

merge #134

Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
38 commits
Select commit Hold shift + click to select a range
6b71c03
Revert "Merge branch 'InboxSearchBar' into main"
S-Shahla May 20, 2025
f37a46d
Refactor main API structure for consistent logging and dependency man…
mads-jm May 25, 2025
1c9be25
Refactor API structure and enhance logging and dependencies across se…
j-mads Jun 11, 2025
515a623
delete by google id..
j-mads Jun 11, 2025
a90d922
Merge pull request #124 from EmailEssence/122-api-refactor
riteshsamal-ship Jun 11, 2025
7baaffa
fixing issue with client import error
emmamelkumian May 29, 2025
2d9bd73
created a logout function
emmamelkumian May 30, 2025
b569dbc
Css for logout
emmamelkumian May 31, 2025
7a4c73b
changed logout button to a button div
emmamelkumian Jun 1, 2025
7b12a6e
shifted things, created an empty delete account button
emmamelkumian Jun 1, 2025
6121c29
the css for the button
emmamelkumian Jun 1, 2025
049d27a
still needs testing with a temp account and verifying
emmamelkumian Jun 9, 2025
60087e0
fixs to the API functions; replaced " with ` and added const token
emmamelkumian Jun 9, 2025
17928eb
Update HandleDeleteAccount
riteshsamal-ship Jun 11, 2025
0991563
edit wording
emmamelkumian Jun 11, 2025
a31a4ef
Deletion of Emails
riteshsamal-ship Jun 14, 2025
85b3389
Deletion of Summaries
riteshsamal-ship Jun 14, 2025
1dd44fe
error handling for deletion
riteshsamal-ship Jun 14, 2025
0fc5765
Merge pull request #129 from EmailEssence/UserDeletion
riteshsamal-ship Jun 14, 2025
5a96cac
updated homepage
emmamelkumian Jun 14, 2025
0736e0e
Merge branch 'main' of https://github.com/EmailEssence/EmailEssence.g…
emmamelkumian Jun 14, 2025
640018e
auto scrolls to top of page when you go to terms, privacy, or contact us
emmamelkumian Jun 14, 2025
4460b9c
Added Min and Max Pooling
riteshsamal-ship Jun 3, 2025
d4bf78a
Connection Pooling
riteshsamal-ship Jun 14, 2025
77ff866
Update connection.py
riteshsamal-ship Jun 14, 2025
9ee0f24
OpenRouter - Initial Implementation
mads-jm May 7, 2025
3d216ce
Add OpenRouter model configurations and update settings
mads-jm May 7, 2025
da3a4e2
Add OpenRouter summarization support
mads-jm Jun 14, 2025
f9ade77
Add OpenRouter API key to MockSettings
mads-jm Jun 14, 2025
7936d8f
Add OpenRouter API key to test settings
mads-jm Jun 14, 2025
b5cf8df
Update Settings class to make API keys optional and add validation
mads-jm Jun 14, 2025
7d17349
Add OpenRouter API key to Docker workflow
mads-jm Jun 14, 2025
4c3e99f
Update Docker workflow to use updated secret names for environment va…
mads-jm Jun 14, 2025
a57db50
Refactor environment variable names in Docker workflow for consistency
mads-jm Jun 14, 2025
7b2bc47
README reality
mads-jm Jun 14, 2025
9523d4f
Merge branch 'main' of https://github.com/EmailEssence/EmailEssence.g…
mads-jm Jun 14, 2025
a506d93
Comments (#133)
emmamelkumian Jun 14, 2025
1ce18f8
Merge branch 'InboxSearchBar-BatchFetch' into NEUDemo
S-Shahla Jun 17, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 9 additions & 8 deletions .github/workflows/docker-image.yml
Original file line number Diff line number Diff line change
Expand Up @@ -44,14 +44,15 @@ jobs:
which pytest
python -m pytest --maxfail=2
env:
TEST_EMAIL_ACCOUNT: ${{ secrets.TEST_EMAIL_ACCOUNT }}
TEST_GOOGLE_CLIENT_ID: ${{ secrets.TEST_GOOGLE_CLIENT_ID }}
TEST_GOOGLE_CLIENT_SECRET: ${{ secrets.TEST_GOOGLE_CLIENT_SECRET }}
TEST_MONGO_URI: ${{ secrets.TEST_MONGO_URI }}
TEST_OPENAI_API_KEY: ${{ secrets.TEST_OPENAI_API_KEY }}
TEST_DEEPSEEK_API_KEY: ${{ secrets.TEST_DEEPSEEK_API_KEY }}
TEST_GOOGLE_API_KEY: ${{ secrets.TEST_GEMINI_API_KEY }}
TEST_SUMMARIZER_PROVIDER: ${{ secrets.TEST_SUMMARIZER_PROVIDER || 'openai' }}
EMAIL_ACCOUNT: ${{ secrets.TEST_EMAIL_ACCOUNT }}
GOOGLE_CLIENT_ID: ${{ secrets.TEST_GOOGLE_CLIENT_ID }}
GOOGLE_CLIENT_SECRET: ${{ secrets.TEST_GOOGLE_CLIENT_SECRET }}
MONGO_URI: ${{ secrets.TEST_MONGO_URI }}
OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }}
OPENROUTER_API_KEY: ${{ secrets.OPENROUTER_API_KEY }}
DEEPSEEK_API_KEY: ${{ secrets.DEEPSEEK_API_KEY }}
GOOGLE_API_KEY: ${{ secrets.GEMINI_API_KEY }}
SUMMARIZER_PROVIDER: ${{ secrets.SUMMARIZER_PROVIDER || 'openrouter' }}

# Add a placeholder job that will always run when tests are disabled
test-skipped:
Expand Down
12 changes: 6 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,28 +18,28 @@ EmailEssence is a sophisticated email management solution that leverages artific
### Feature Complete (FC) Features
- 🎨 Customizable dashboard with modular components
- 🔍 Advanced keyword analysis and topic identification
- 💻 Cross-platform desktop support via Electron
- 🔄 Incremental email fetching for large inboxes
- 🎯 Smart email prioritization
- 🛠️ Enhanced user preferences and settings

### Future Features
- 💻 Cross-platform desktop support via Electron

## Technical Stack

### Frontend
- React - Modern UI framework
- Remix - Full-stack web framework
- Electron - Desktop application framework
- JavaScript - Type-safe development
- Vite - Frontend tooling and build server
- JavaScript - Core language for the frontend

### Backend
- Python - Core backend services
- FastAPI - High-performance API framework
- MongoDB - Flexible document database
- Redis - High-performance caching
- OpenRouter - AI-powered email processing
- Flexible AI provider support (OpenAI, Google, OpenRouter)

### Infrastructure
- Express.js - Web server and middleware
- OAuth 2.0 - Secure authentication
- IMAP - Email protocol support

Expand Down
5 changes: 3 additions & 2 deletions backend/.env.example
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,10 @@ GOOGLE_CLIENT_SECRET=google_client_secret
MONGO_URI=mongodb+srv://<u>:<p>@emailsummarization.1coye.mongodb.net/?retryWrites=true&w=majority&appName=EmailSummarization

# API keys
OPENAI_API_KEY=openai_api_key
OPEN_ROUTER_API_KEY=openrouter_api_key
#OPENAI_API_KEY=openai_api_key
#DEEPSEEK_API_KEY=deepseek_api_key
GOOGLE_API_KEY=google_api_key
#GOOGLE_API_KEY=google_api_key

# Summarizer Settings
# SUMMARIZER_PROVIDER=openai
Expand Down
9 changes: 3 additions & 6 deletions backend/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,9 +23,9 @@ For local development without Docker, use one of the provided setup scripts:

#### On Windows:

```bash
```ps1
# Run the setup script to create a virtual environment and install dependencies
.\setup.bat
.\\setup.ps1
```

These scripts will:
Expand Down Expand Up @@ -134,7 +134,7 @@ For Render deployments, environment variables are configured through the Render
- `google_client_secret`
- `email_account`
- `mongo_uri`
- `openai_api_key`
- `openrouter_api_key`
- Any optional variables you wish to override

This separates your development environment configuration from your production deployment, following security best practices.
Expand All @@ -152,9 +152,6 @@ For CI/CD environments, use the CI setup scripts:
```bash
# Unix/Linux/macOS
./setup-ci.sh

# Windows
.\setup-ci.bat
```

## Troubleshooting
Expand Down
130 changes: 130 additions & 0 deletions backend/app/dependencies.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,130 @@
"""
Common dependencies for Email Essence FastAPI application.

This module centralizes shared dependencies including authentication schemes,
logging configuration, and common helper functions used across routers and services.
"""

import logging
from typing import Dict, Any

from fastapi import Depends, HTTPException, status
from fastapi.security import OAuth2PasswordBearer

# Internal imports
from app.models.user_models import UserSchema
from app.services.auth_service import AuthService
from app.services.user_service import UserService
from app.services.database.factories import get_auth_service, get_user_service
from app.utils.helpers import get_logger, configure_module_logging, standardize_error_response, log_operation

# -------------------------------------------------------------------------
# Authentication Dependencies
# -------------------------------------------------------------------------

# Centralized OAuth2 scheme
oauth2_scheme = OAuth2PasswordBearer(
tokenUrl="/auth/token",
description="Enter the token you received from the login flow (without Bearer prefix)"
)

async def get_current_user_email(
token: str = Depends(oauth2_scheme),
auth_service: AuthService = Depends(get_auth_service)
) -> str:
"""
Dependency to extract user email from valid token.

Args:
token: JWT token from OAuth2 authentication
auth_service: Auth service instance

Returns:
str: User's email address

Raises:
HTTPException: 401 error if token is invalid
"""
try:
user_data = await auth_service.get_credentials_from_token(token)
return user_data['email']
except Exception as e:
raise HTTPException(
status_code=status.HTTP_401_UNAUTHORIZED,
detail="Invalid authentication credentials",
headers={"WWW-Authenticate": "Bearer"},
)

async def get_current_user_info(
token: str = Depends(oauth2_scheme),
auth_service: AuthService = Depends(get_auth_service)
) -> Dict[str, Any]:
"""
Validates token and returns user information.

Args:
token: JWT token from OAuth2 authentication
auth_service: Auth service instance

Returns:
dict: User information and credentials

Raises:
HTTPException: 401 error if token is invalid
"""
try:
user_data = await auth_service.get_credentials_from_token(token)
return user_data
except Exception as e:
raise HTTPException(
status_code=status.HTTP_401_UNAUTHORIZED,
detail=f"Invalid authentication: {str(e)}"
)

async def get_current_user(
user_data: Dict[str, Any] = Depends(get_current_user_info),
user_service: UserService = Depends(get_user_service)
) -> UserSchema:
"""
Retrieve user details or create user if they don't exist.

Args:
user_data: User information and credentials from token validation
user_service: User service instance

Returns:
UserSchema: User profile information

Raises:
HTTPException: If user retrieval fails
"""
try:
user_info = user_data['user_info']
user_email = user_info.get('email')
google_id = user_info.get('google_id')

# Try to get existing user
user = await user_service.get_user_by_email(user_email)

# If user doesn't exist, create new user
if not user:
user = await user_service.create_user({
"email": user_email,
"name": user_info.get("name", ""),
"picture": user_info.get("picture", ""),
"google_id": google_id
})
else:
# Update google_id if it's missing
user_dict = user.model_dump()
if not user_dict.get('google_id'):
await user_service.update_user(user_dict['_id'], {"google_id": google_id})

return user
except Exception as e:
raise HTTPException(
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
detail=f"Failed to retrieve user: {str(e)}"
)


Loading