Files
smoothschedule/smoothschedule/CUSTOM_SCRIPTING_GUIDE.md
poduck 3fef0d5749 feat: Add comprehensive plugin documentation and advanced template system
Added complete plugin documentation with visual mockups and expanded template
variable system with CONTEXT, DATE helpers, and default values.

Backend Changes:
- Extended template_parser.py to support all new template types
- Added PROMPT with default values: {{PROMPT:var|desc|default}}
- Added CONTEXT variables: {{CONTEXT:business_name}}, {{CONTEXT:owner_email}}
- Added DATE helpers: {{DATE:today}}, {{DATE:+7d}}, {{DATE:monday}}
- Implemented date expression evaluation for relative dates
- Updated compile_template to handle all template types
- Added context parameter for business data auto-fill

Frontend Changes:
- Created comprehensive HelpPluginDocs.tsx with Stripe-style API docs
- Added visual mockup of plugin configuration form
- Documented all template types with examples and benefits
- Added Command Reference section with allowed/blocked Python commands
- Documented all HTTP methods (GET, POST, PUT, PATCH, DELETE)
- Added URL whitelisting requirements and approval process
- Created Platform Staff management page with edit modal
- Added can_approve_plugins and can_whitelist_urls permissions

Platform Staff Features:
- List all platform_manager and platform_support users
- Edit user details with role-based permissions
- Superusers can edit anyone
- Platform managers can only edit platform_support users
- Permission cascade: users can only grant permissions they have
- Real-time updates via React Query cache invalidation

Documentation Highlights:
- 4 template types: PROMPT, CONTEXT, DATE, and automatic validation
- Visual form mockup showing exactly what users see
- All allowed control flow (if/elif/else, for, while, try/except, etc.)
- All allowed built-in functions (len, range, min, max, etc.)
- All blocked operations (import, exec, eval, class/function defs)
- Complete HTTP API reference with examples
- URL whitelisting process: contact pluginaccess@smoothschedule.com

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-28 20:54:07 -05:00

662 lines
15 KiB
Markdown

# Custom Scripting Guide
Create your own automations with safe, powerful scripting! Write Python-like code with if/else statements, loops, and variables to automate your business processes.
## 🎯 What You Can Do
- **Access Your Data**: Get appointments, customers, and more
- **Write Logic**: Use if/else, loops, and variables
- **Send Emails**: Contact customers automatically
- **Create Reports**: Generate custom analytics
- **Call APIs**: Integrate with external services (approved domains)
## 🔒 Safety Features
We protect your data and our servers with:
- **No Infinite Loops**: Automatically stopped after 10,000 iterations
- **Execution Timeout**: Scripts limited to 30 seconds
- **API Rate Limits**: Maximum 50 API calls per execution
- **Memory Limits**: 50MB maximum
- **No File Access**: Can't read/write files
- **No Code Injection**: Can't use eval, exec, or import
- **Sandboxed**: Runs in isolated environment
## 📚 Available API Methods
### `api.get_appointments(**filters)`
Get appointments for your business.
**Parameters:**
- `status` - Filter by status ('SCHEDULED', 'COMPLETED', 'CANCELED')
- `start_date` - Filter by start date ('YYYY-MM-DD')
- `end_date` - Filter by end date ('YYYY-MM-DD')
- `limit` - Maximum results (default: 100, max: 1000)
**Returns:** List of appointment dictionaries
**Example:**
```python
# Get all scheduled appointments
appointments = api.get_appointments(status='SCHEDULED')
# Get appointments from last week
from datetime import datetime, timedelta
start = (datetime.now() - timedelta(days=7)).strftime('%Y-%m-%d')
recent = api.get_appointments(start_date=start, limit=50)
```
### `api.get_customers(**filters)`
Get customers for your business.
**Parameters:**
- `limit` - Maximum results (default: 100, max: 1000)
- `has_email` - Only customers with email addresses (True/False)
**Returns:** List of customer dictionaries
**Example:**
```python
# Get all customers with emails
customers = api.get_customers(has_email=True)
# Get first 50 customers
top_customers = api.get_customers(limit=50)
```
### `api.send_email(to, subject, body)`
Send an email to a customer.
**Parameters:**
- `to` - Email address or customer ID
- `subject` - Email subject (max 200 characters)
- `body` - Email body (max 10,000 characters)
**Returns:** True if sent successfully
**Example:**
```python
# Send to email address
api.send_email(
to='customer@example.com',
subject='Special Offer',
body='Hello! Here is a special offer just for you...'
)
# Send to customer by ID
api.send_email(
to=123,
subject='Appointment Reminder',
body='Your appointment is tomorrow at 2 PM'
)
```
### `api.create_appointment(title, start_time, end_time, **kwargs)`
Create a new appointment.
**Parameters:**
- `title` - Appointment title
- `start_time` - Start datetime (ISO format: '2025-01-15T10:00:00')
- `end_time` - End datetime (ISO format: '2025-01-15T11:00:00')
- `notes` - Optional notes
**Returns:** Created appointment dictionary
**Example:**
```python
apt = api.create_appointment(
title='Follow-up Consultation',
start_time='2025-01-20T14:00:00',
end_time='2025-01-20T15:00:00',
notes='Automated follow-up'
)
```
### `api.log(message)`
Log a message for debugging.
**Example:**
```python
api.log('Script started')
api.log(f'Found {len(appointments)} appointments')
```
### `api.http_get(url, headers=None)`
Make HTTP GET request to approved domains.
**Parameters:**
- `url` - URL to fetch (must be approved)
- `headers` - Optional headers dictionary
**Returns:** Response text
**Example:**
```python
# Call Slack webhook
response = api.http_get(
'https://hooks.slack.com/services/YOUR/WEBHOOK/URL'
)
```
### Helper Methods
```python
# Count items
count = api.count(appointments)
# Sum numbers
total = api.sum([10, 20, 30])
# Filter with condition
active = api.filter(customers, lambda c: c['email'] != '')
```
## 📝 Script Examples
### Example 1: Simple Appointment Count
```python
# Get all appointments
appointments = api.get_appointments(limit=500)
# Count by status
scheduled = 0
completed = 0
for apt in appointments:
if apt['status'] == 'SCHEDULED':
scheduled += 1
elif apt['status'] == 'COMPLETED':
completed += 1
# Log results
api.log(f"Scheduled: {scheduled}, Completed: {completed}")
# Return result
result = {
'scheduled': scheduled,
'completed': completed,
'total': len(appointments)
}
```
### Example 2: Conditional Email Campaign
```python
# Get customers
customers = api.get_customers(has_email=True, limit=100)
# Get recent appointments
from datetime import datetime, timedelta
cutoff = (datetime.now() - timedelta(days=30)).strftime('%Y-%m-%d')
recent_apts = api.get_appointments(start_date=cutoff)
# Find customers who booked recently
recent_customer_ids = set()
for apt in recent_apts:
# In real usage, you'd extract customer ID from appointment
pass
# Send emails to inactive customers
sent = 0
for customer in customers:
# If customer hasn't booked recently
if customer['id'] not in recent_customer_ids:
success = api.send_email(
to=customer['email'],
subject='We Miss You!',
body=f"Hi {customer['name']},\n\nIt's been a while! Come back and get 15% off."
)
if success:
sent += 1
result = {'emails_sent': sent}
```
### Example 3: Weekly Summary Report
```python
# Get appointments from last 7 days
from datetime import datetime, timedelta
end_date = datetime.now().strftime('%Y-%m-%d')
start_date = (datetime.now() - timedelta(days=7)).strftime('%Y-%m-%d')
appointments = api.get_appointments(
start_date=start_date,
end_date=end_date,
limit=500
)
# Group by day
daily_counts = {}
for apt in appointments:
# Extract date from ISO timestamp
date = apt['start_time'].split('T')[0]
daily_counts[date] = daily_counts.get(date, 0) + 1
# Build report
report = "Weekly Appointment Summary\n\n"
for date in sorted(daily_counts.keys()):
report += f"{date}: {daily_counts[date]} appointments\n"
report += f"\nTotal: {len(appointments)}"
# Send report
api.send_email(
to='manager@business.com',
subject='Weekly Summary',
body=report
)
result = {'total_appointments': len(appointments)}
```
### Example 4: Smart Customer Segmentation
```python
# Get all customers
customers = api.get_customers(has_email=True, limit=500)
# Get all appointments
appointments = api.get_appointments(limit=1000)
# Count visits per customer (simplified)
visit_counts = {}
for apt in appointments:
# In real usage, extract customer ID
customer_id = 'placeholder'
visit_counts[customer_id] = visit_counts.get(customer_id, 0) + 1
# Segment customers
new_customers = []
loyal_customers = []
for customer in customers:
visits = visit_counts.get(customer['id'], 0)
if visits == 1:
new_customers.append(customer)
elif visits >= 5:
loyal_customers.append(customer)
# Send different messages to each segment
for customer in new_customers:
api.send_email(
to=customer['email'],
subject='Welcome!',
body=f"Hi {customer['name']}, thanks for trying us! Here's 20% off your next visit."
)
for customer in loyal_customers:
api.send_email(
to=customer['email'],
subject='VIP Offer',
body=f"Hi {customer['name']}, you're a valued customer! Exclusive offer inside..."
)
result = {
'new_customers': len(new_customers),
'loyal_customers': len(loyal_customers)
}
```
### Example 5: Dynamic Pricing Alert
```python
# Get upcoming appointments
from datetime import datetime, timedelta
today = datetime.now().strftime('%Y-%m-%d')
next_week = (datetime.now() + timedelta(days=7)).strftime('%Y-%m-%d')
upcoming = api.get_appointments(
start_date=today,
end_date=next_week,
status='SCHEDULED'
)
# Count by day
daily_bookings = {}
for apt in upcoming:
date = apt['start_time'].split('T')[0]
daily_bookings[date] = daily_bookings.get(date, 0) + 1
# Find slow days (less than 3 bookings)
slow_days = []
for date, count in daily_bookings.items():
if count < 3:
slow_days.append(date)
# Alert manager
if slow_days:
message = f"Slow booking days detected:\n\n"
for date in slow_days:
count = daily_bookings[date]
message += f"{date}: only {count} booking(s)\n"
message += "\nConsider running a promotion!"
api.send_email(
to='manager@business.com',
subject='⚠️ Low Booking Alert',
body=message
)
result = {'slow_days': slow_days}
```
## 🎨 Using Script Templates
Pre-built templates make it even easier! Just fill in the parameters.
### Example: Conditional Email Template
```bash
curl -X POST http://lvh.me:8000/api/scheduled-tasks/ \
-H "Content-Type: application/json" \
-d '{
"name": "VIP Customer Campaign",
"plugin_name": "script_template",
"plugin_config": {
"template": "conditional_email",
"parameters": {
"condition_field": "visits",
"condition_value": "5",
"email_subject": "You are a VIP!",
"email_body": "Hi {name}, you are one of our best customers!"
}
},
"schedule_type": "CRON",
"cron_expression": "0 10 * * 1"
}'
```
## 🚀 Creating a Scheduled Script
### Via API
```bash
curl -X POST http://lvh.me:8000/api/scheduled-tasks/ \
-H "Content-Type: application/json" \
-d '{
"name": "My Custom Automation",
"description": "Weekly customer re-engagement",
"plugin_name": "custom_script",
"plugin_config": {
"script": "# Your Python code here\nappointments = api.get_appointments()\napi.log(f\"Found {len(appointments)} appointments\")\nresult = len(appointments)",
"description": "Counts appointments and logs the result"
},
"schedule_type": "CRON",
"cron_expression": "0 9 * * 1",
"status": "ACTIVE"
}'
```
### Schedule Types
**Every Monday at 9 AM:**
```json
{
"schedule_type": "CRON",
"cron_expression": "0 9 * * 1"
}
```
**Every Hour:**
```json
{
"schedule_type": "INTERVAL",
"interval_minutes": 60
}
```
**One-Time on Specific Date:**
```json
{
"schedule_type": "ONE_TIME",
"run_at": "2025-02-01T10:00:00Z"
}
```
## 📖 Built-in Functions
You can use these Python built-ins:
```python
# Math
len([1, 2, 3]) # Length
min([1, 2, 3]) # Minimum
max([1, 2, 3]) # Maximum
sum([1, 2, 3]) # Sum
abs(-5) # Absolute value
round(3.14159, 2) # Round to 2 decimals
# Type conversion
int('42') # Convert to integer
float('3.14') # Convert to float
str(123) # Convert to string
bool(1) # Convert to boolean
# Collections
list((1, 2, 3)) # Create list
dict(a=1, b=2) # Create dictionary
range(10) # Number sequence
sorted([3, 1, 2]) # Sort list
reversed([1, 2, 3]) # Reverse list
# Iteration
enumerate(['a', 'b']) # Index and value
zip([1, 2], ['a', 'b']) # Combine lists
any([True, False]) # Any true?
all([True, True]) # All true?
```
## ❌ What's NOT Allowed
```python
# ❌ Import statements
import os # Error!
# ❌ Eval/exec
eval('1 + 1') # Error!
# ❌ Function definitions (for now)
def my_function(): # Error!
pass
# ❌ Class definitions
class MyClass: # Error!
pass
# ❌ File operations
open('file.txt') # No file access!
# ❌ Network (except approved APIs)
requests.get('http://example.com') # Error!
```
## 🐛 Debugging Tips
### Use Logging
```python
api.log('Script started')
customers = api.get_customers()
api.log(f'Found {len(customers)} customers')
for customer in customers:
api.log(f'Processing {customer["name"]}')
# ... do something
api.log('Script finished')
```
### Check Execution Logs
```bash
# Get logs for task #1
curl http://lvh.me:8000/api/scheduled-tasks/1/logs/
# Filter by status
curl http://lvh.me:8000/api/task-logs/?status=FAILED
```
### Test Scripts Manually
```bash
# Execute task immediately (don't wait for schedule)
curl -X POST http://lvh.me:8000/api/scheduled-tasks/1/execute/
```
## ⚡ Performance Tips
### 1. Limit Data Fetching
```python
# ❌ Bad: Fetch everything
appointments = api.get_appointments(limit=1000)
# ✅ Good: Fetch only what you need
appointments = api.get_appointments(
status='SCHEDULED',
start_date='2025-01-01',
limit=50
)
```
### 2. Use Efficient Loops
```python
# ❌ Bad: Nested loops
for customer in customers:
for apt in appointments:
if apt['customer_id'] == customer['id']:
# ...
# ✅ Good: Build lookup first
customer_apts = {}
for apt in appointments:
cid = apt['customer_id']
if cid not in customer_apts:
customer_apts[cid] = []
customer_apts[cid].append(apt)
for customer in customers:
apts = customer_apts.get(customer['id'], [])
# Much faster!
```
### 3. Batch Operations
```python
# ❌ Bad: Individual calls
for customer in customers:
api.send_email(customer['email'], 'Subject', 'Body')
# ✅ Good: Filter first, then send
active_customers = [c for c in customers if c['status'] == 'active']
for customer in active_customers:
api.send_email(customer['email'], 'Subject', 'Body')
```
## 💡 Common Use Cases
### 1. Abandoned Cart Recovery
```python
# Find customers with unpaid appointments
unpaid = api.get_appointments(status='SCHEDULED')
# Send reminder emails
```
### 2. Birthday Campaigns
```python
# Get customers with birthdays this week
# Send birthday wishes with discount code
```
### 3. Review Requests
```python
# Get completed appointments from yesterday
# Send review request emails
```
### 4. Capacity Alerts
```python
# Count upcoming appointments
# Alert if fully booked or too empty
```
### 5. Customer Lifecycle
```python
# Identify customer segments (new, active, at-risk)
# Send targeted campaigns
```
## 🔐 Security Best Practices
1. **Never hardcode secrets** in scripts
- Use environment variables or settings
- Don't put API keys in code
2. **Validate input data**
```python
email = customer.get('email', '')
if '@' in email:
api.send_email(email, 'Subject', 'Body')
```
3. **Limit batch sizes**
```python
# Don't spam - send max 50 emails per run
customers = api.get_customers(limit=50)
```
4. **Handle errors gracefully**
```python
success = api.send_email(email, subject, body)
if not success:
api.log(f'Failed to send to {email}')
```
## 📊 Script Result Format
Your script should set a `result` variable with execution results:
```python
# Your script logic here
appointments = api.get_appointments()
# Set result variable
result = {
'total': len(appointments),
'scheduled': 10,
'completed': 25,
'message': 'Processing completed successfully'
}
```
This result is stored in the execution log and can be used for tracking and analytics.
## 🆘 Getting Help
- **Execution Failed?** Check the error message in logs
- **Need More API Methods?** Contact support to request new features
- **Performance Issues?** Review the performance tips above
- **Template Request?** Suggest new templates to add
## 📈 Pricing
| Plan | Custom Scripts | Executions/Month | Support |
|------|----------------|------------------|---------|
| Free | 1 active | 100 | Community |
| Pro | 5 active | 1,000 | Email |
| Business | Unlimited | Unlimited | Priority |
Start automating your business today! 🚀