Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
47 commits
Select commit Hold shift + click to select a range
8c28893
fix(area): improve error handling for incompatible action-reaction co…
maelemiel Nov 2, 2025
ea1da54
fix(validators): update Gmail reaction schemas to require message_id …
maelemiel Nov 2, 2025
c9fe2ce
Merge branch 'main' of github.com:My-Epitech-Organisation/Area into f…
Arkteus Nov 2, 2025
130ace1
chore(env): enhance environment variable templates for clarity and se…
Arkteus Nov 2, 2025
a5d726c
fix(docker-compose): update frontend port variable for consistency
Arkteus Nov 2, 2025
7a02fc1
fix(dashboard): enhance service activation logic to include internal …
Arkteus Nov 2, 2025
caca540
feat(email): implement email sending functionality using Django's ema…
Arkteus Nov 2, 2025
6ea05d4
feat(email): add configuration schema for send_email action
Arkteus Nov 2, 2025
f473c76
feat(dashboard): map service names to OAuth provider names for improv…
Arkteus Nov 2, 2025
d517e0c
feat(init_services): remove webhook service integration from initiali…
Arkteus Nov 2, 2025
2b0536d
fix(dashboard): remove webhook service from internal defaults
Arkteus Nov 2, 2025
c335d7b
fix(services): remove webhook service from internal service check
Arkteus Nov 2, 2025
003f65c
fix(dashboard): update service to provider mapping for Google Calendar
Arkteus Nov 2, 2025
62cdb45
fix(dashboard): normalize Google Calendar service name in provider ma…
Arkteus Nov 2, 2025
dded664
fix(dashboard): manage activeServices through useEffect for accurate …
Arkteus Nov 2, 2025
79bd91b
fix(dashboard): remove unused random active services generation function
Arkteus Nov 2, 2025
ff786e4
chore(env): clean up email configuration section in .env.example
Arkteus Nov 2, 2025
59f8da3
fix(dashboard): remove unnecessary whitespace in Dashboard component
Arkteus Nov 2, 2025
bd1639c
fix(dashboard): map service names to OAuth provider names for accurat…
Arkteus Nov 2, 2025
7fe469d
fix(dashboard): enhance NotionWebhookSection UI for better user exper…
Arkteus Nov 2, 2025
d14d417
feat(readme): add available services and API documentation for enhanc…
Arkteus Nov 2, 2025
6a8fd0f
feat(howto): add class diagrams and service implementation examples f…
Arkteus Nov 2, 2025
23e08de
fix(tasks): improve email sending logic and error logging for better …
Arkteus Nov 2, 2025
7e5fecb
fix(notion-webhook): improve UI layout and enhance webhook configurat…
Arkteus Nov 2, 2025
7b5d70e
fix(dashboard): normalize service names in provider mapping for consi…
Arkteus Nov 2, 2025
e6a8253
feat(tests): add comprehensive Django test runner script with coverag…
Arkteus Nov 2, 2025
652cf7d
fix(coverage): update source configuration to include current directo…
Arkteus Nov 2, 2025
0b73c12
fix(tests): enhance virtual environment activation and dependency che…
Arkteus Nov 2, 2025
0fedc59
fix(tests): update expected services and actions in init_services com…
Arkteus Nov 2, 2025
e47c17d
refactor(tests): remove redundant test for JSON data storage in Execu…
Arkteus Nov 2, 2025
f26c4ce
refactor(tests): replace webhook service with email service in timer …
Arkteus Nov 2, 2025
ce8dd36
refactor(tests): replace webhook service with email service in MatchW…
Arkteus Nov 2, 2025
ccf571a
fix(tests): temporarily disable check_timer_actions_idempotency test …
Arkteus Nov 2, 2025
42887a8
chore(gitignore): add htmlcov to ignored files
Arkteus Nov 2, 2025
3fb5318
fix(tests): update patch target in CheckTimerActionsTest to execute_r…
Arkteus Nov 2, 2025
ee53201
fix(tests): update execute_reaction patch to execute_reaction_task in…
Arkteus Nov 2, 2025
24bb12a
fix(tests): remove unnecessary blank lines in coverage report section…
Arkteus Nov 2, 2025
bbe1408
test(email): add tests for send_email reaction execution
Arkteus Nov 2, 2025
e54e41d
test(github): add tests for GitHub reaction execution logic
Arkteus Nov 2, 2025
575da0b
test(gmail): add tests for Gmail reaction execution logic
Arkteus Nov 2, 2025
d2f6581
test(notion): add tests for Notion reaction execution logic
Arkteus Nov 2, 2025
5a7942a
test(slack): add tests for Slack reaction execution logic
Arkteus Nov 2, 2025
6be340e
test(spotify): add tests for Spotify reaction execution logic
Arkteus Nov 2, 2025
b043484
test(slack): refactor test_slack_send_message_default_message for rea…
Arkteus Nov 2, 2025
c820be6
test(notion): improve readability of UUID extraction patching
Arkteus Nov 2, 2025
fd36131
test(github): simplify assertion for GitHub authentication failure
Arkteus Nov 2, 2025
77f8612
test(spotify): remove unnecessary variable assignment in reaction log…
Arkteus Nov 2, 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
413 changes: 254 additions & 159 deletions .env.example

Large diffs are not rendered by default.

438 changes: 304 additions & 134 deletions .env.production

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
*.ref
my_refs(do_not_delete)
backend/staticfiles/
*htmlcov*

node_modules/

Expand Down
342 changes: 341 additions & 1 deletion HOWTOCONTRIBUTE.md
Original file line number Diff line number Diff line change
Expand Up @@ -121,14 +121,118 @@ sequenceDiagram

### 1.4 Core Models

#### Class Diagram

```mermaid
classDiagram
class User {
+Integer id
+String username
+String email
+Boolean email_verified
+DateTime created_at
+DateTime updated_at
+list~Area~ areas
+list~ServiceToken~ tokens
}

class Service {
+Integer id
+String name
+String description
+Status status
+list~Action~ actions
+list~Reaction~ reactions
}

class Action {
+Integer id
+String name
+String description
+JSONField config_schema
+ForeignKey service
}

class Reaction {
+Integer id
+String name
+String description
+JSONField config_schema
+ForeignKey service
}

class Area {
+Integer id
+String name
+JSONField action_config
+JSONField reaction_config
+Status status
+DateTime created_at
+ForeignKey owner
+ForeignKey action
+ForeignKey reaction
+list~Execution~ executions
}

class Execution {
+Integer id
+String external_event_id
+Status status
+JSONField trigger_data
+JSONField result_data
+String error_message
+DateTime created_at
+DateTime started_at
+DateTime completed_at
+Integer retry_count
+ForeignKey area
}

class ServiceToken {
+Integer id
+String access_token
+String refresh_token
+DateTime expires_at
+Boolean is_expired
+DateTime last_used_at
+DateTime created_at
+ForeignKey user
+ForeignKey service
}

class ActionState {
+Integer id
+DateTime last_checked_at
+String last_event_id
+JSONField metadata
+OneToOneField area
}

User "1" --> "*" Area : owns
User "1" --> "*" ServiceToken : has
Service "1" --> "*" Action : provides
Service "1" --> "*" Reaction : provides
Service "1" --> "*" ServiceToken : authenticates
Area "*" --> "1" Action : triggers_on
Area "*" --> "1" Reaction : executes
Area "1" --> "*" Execution : creates
Area "1" --> "1" ActionState : tracks_state
Execution "*" --> "1" Area : belongs_to
ServiceToken "*" --> "1" User : belongs_to
ServiceToken "*" --> "1" Service : for_service
```

#### Model Relationships Summary

```python
# Simplified model relationships
Service (name, description, status)
├── Actions (1-to-many)
└── Reactions (1-to-many)

Area (user, name, action, reaction, configs, status)
└── Executions (1-to-many, with idempotency key)
├── Executions (1-to-many, with idempotency key)
└── ActionState (1-to-1, for polling state)

User
├── Areas (1-to-many)
Expand Down Expand Up @@ -438,6 +542,242 @@ curl http://localhost:8080/api/services/ | jq '.results[] | select(.name=="githu
- [ ] Service accessible via API
- [ ] Documentation updated

### 3.3 Service Implementation Examples

Understanding service complexity helps you choose the right implementation approach:

#### Example 1: Simple Service (No OAuth) - Weather

**Complexity**: ⭐ Low

```python
{
"name": "weather",
"description": "Weather data and alerts integration",
"status": Service.Status.ACTIVE,
"actions": [
{
"name": "weather_rain_detected",
"description": "Triggered when rain is detected",
"config_schema": {
"location": {
"type": "string",
"label": "Location",
"required": True,
"placeholder": "Paris, France"
}
}
}
],
"reactions": []
}
```

**Key Points:**
- ❌ No OAuth required (uses API key in settings)
- ✅ Actions only (monitoring)
- ✅ Polling-based (Celery Beat task every 15 minutes)
- ✅ Simple external API (OpenWeatherMap)

#### Example 2: Medium Service (OAuth + Webhooks) - Notion

**Complexity**: ⭐⭐ Medium

```python
{
"name": "notion",
"description": "Note-taking and database management",
"status": Service.Status.ACTIVE,
"actions": [
{
"name": "notion_page_created",
"description": "Triggered when new page is created",
"config_schema": {}
},
{
"name": "notion_database_item_added",
"description": "Triggered when item added to database",
"config_schema": {
"database_id": {
"type": "string",
"label": "Database ID",
"required": True
}
}
}
],
"reactions": [
{
"name": "notion_create_page",
"description": "Create a new page in Notion",
"config_schema": {
"parent_page_id": {"type": "string", "required": True},
"title": {"type": "string", "required": True},
"content": {"type": "text", "required": False}
}
}
]
}
```

**Key Points:**
- ✅ OAuth2 required (user authorization)
- ✅ Webhook support (real-time notifications)
- ✅ Both actions and reactions
- ⚠️ Requires webhook configuration in Notion dashboard
- 📚 Implementation: `backend/users/oauth/notion.py`

#### Example 3: Complex Service (OAuth + EventSub) - Twitch

**Complexity**: ⭐⭐⭐ High

```python
{
"name": "twitch",
"description": "Live streaming platform integration",
"status": Service.Status.ACTIVE,
"actions": [
{
"name": "twitch_stream_online",
"description": "Triggered when stream goes live",
"config_schema": {
"broadcaster_username": {
"type": "string",
"label": "Streamer Username",
"required": True
}
}
},
{
"name": "twitch_new_follower",
"description": "Triggered when channel gets new follower"
}
],
"reactions": [
{
"name": "twitch_send_chat_message",
"description": "Send message to chat",
"config_schema": {
"broadcaster_username": {"type": "string", "required": True},
"message": {"type": "string", "required": True}
}
},
{
"name": "twitch_create_clip",
"description": "Create a clip of current stream"
}
]
}
```

**Key Points:**
- ✅ OAuth2 with specific scopes (chat:read, clips:edit, etc.)
- ✅ EventSub webhooks (Twitch's webhook system)
- ⚠️ Requires external subscription management
- ⚠️ Webhook URL must be HTTPS and publicly accessible
- 🔧 Complex: needs `WebhookSubscription` model tracking
- 📚 Implementation: `backend/users/oauth/twitch.py` + `backend/automations/webhooks.py`

**EventSub Subscription Flow:**

```python
# When user connects Twitch OAuth
1. User authorizes → Get access token
2. Backend creates EventSub subscriptions:
- POST https://api.twitch.tv/helix/eventsub/subscriptions
- For each event type (stream.online, channel.follow, etc.)
3. Twitch sends verification challenge
4. Backend responds with challenge
5. Subscription becomes active
6. Events sent to: https://areaction.app/webhooks/twitch/
```

#### Example 4: API-Only Service (OAuth, No Webhooks) - Spotify

**Complexity**: ⭐⭐ Medium

```python
{
"name": "spotify",
"description": "Music streaming and playback control",
"status": Service.Status.ACTIVE,
"actions": [], # No actions - reactions only
"reactions": [
{
"name": "spotify_play_track",
"description": "Play a specific track",
"config_schema": {
"track_uri": {
"type": "string",
"label": "Track URI",
"required": True,
"placeholder": "spotify:track:6rqhFgbbKwnb9MLmUQDhG6"
}
}
},
{
"name": "spotify_create_playlist",
"description": "Create a new playlist",
"config_schema": {
"name": {"type": "string", "required": True},
"description": {"type": "string", "required": False},
"public": {"type": "boolean", "default": False}
}
}
]
}
```

**Key Points:**
- ✅ OAuth2 with refresh tokens
- ❌ No webhooks (Spotify doesn't provide real-time events)
- ✅ Reactions only (control playback, manage library)
- ✅ Token refresh handled automatically by `OAuthManager`
- 📚 Implementation: `backend/users/oauth/spotify.py`

**Why no actions?** Spotify's API doesn't provide webhook notifications for events like "song played" or "playlist updated". For user activity monitoring, you'd need to poll the API repeatedly, which is rate-limited and inefficient.

#### Example 5: Google Multi-Service (OAuth + PubSub) - Gmail/Calendar/YouTube

**Complexity**: ⭐⭐⭐ High

```python
# Single OAuth, multiple services
GOOGLE_OAUTH → gmail, google_calendar, youtube

# Gmail: Push notifications via Google Cloud Pub/Sub
{
"name": "gmail",
"actions": [
{"name": "gmail_new_email", "description": "Any new email"},
{"name": "gmail_new_from_sender", "config": {"sender": "..."}}
],
"reactions": [
{"name": "gmail_send_email", "config": {"to": "...", "subject": "..."}}
]
}

# YouTube: PubSubHubbub (WebSub protocol)
{
"name": "youtube",
"actions": [
{"name": "youtube_new_video", "description": "New upload detected"}
],
"reactions": [
{"name": "youtube_post_comment", "config": {"video_id": "...", "text": "..."}}
]
}
```

**Key Points:**
- ✅ Single OAuth grants access to all Google services
- ✅ Gmail: Cloud Pub/Sub webhooks (watch API)
- ✅ YouTube: PubSubHubbub (WebSub standard)
- ✅ Calendar: Calendar API push notifications
- ⚠️ Complex setup (GCP project, webhook URLs)
- 🔧 Watch renewal required (Gmail watches expire after 7 days)
- 📚 Implementation: `backend/automations/google_webhook_views.py`

---

## 4. Adding an Action
Expand Down
Loading
Loading