diff --git a/frontend/src/components/Sidebar.tsx b/frontend/src/components/Sidebar.tsx index 3bbc7b73..9b9eca82 100644 --- a/frontend/src/components/Sidebar.tsx +++ b/frontend/src/components/Sidebar.tsx @@ -138,16 +138,6 @@ const Sidebar: React.FC = ({ business, user, isCollapsed, toggleCo isCollapsed={isCollapsed} /> )} - {hasPermission('can_access_tasks') && ( - } - /> - )} {(isStaff && hasPermission('can_access_my_schedule')) && ( = ({ business, user, isCollapsed, toggleCo )} - {/* Extend Section - Automations */} - {hasPermission('can_access_automations') && ( + {/* Extend Section - Tasks & Automations */} + {(hasPermission('can_access_tasks') || hasPermission('can_access_automations')) && ( - } - /> + {hasPermission('can_access_tasks') && ( + } + /> + )} + {hasPermission('can_access_automations') && ( + } + /> + )} )} diff --git a/frontend/src/hooks/__tests__/usePlanFeatures.test.ts b/frontend/src/hooks/__tests__/usePlanFeatures.test.ts index 256fd938..843fdbfb 100644 --- a/frontend/src/hooks/__tests__/usePlanFeatures.test.ts +++ b/frontend/src/hooks/__tests__/usePlanFeatures.test.ts @@ -231,7 +231,8 @@ describe('usePlanFeatures', () => { custom_domain: true, white_label: true, custom_oauth: true, - plugins: true, + automations: true, + can_create_automations: true, tasks: true, export_data: true, video_conferencing: true, @@ -259,7 +260,7 @@ describe('usePlanFeatures', () => { expect(result.current.canUse('custom_domain')).toBe(true); expect(result.current.canUse('white_label')).toBe(true); expect(result.current.canUse('custom_oauth')).toBe(true); - expect(result.current.canUse('plugins')).toBe(true); + expect(result.current.canUse('automations')).toBe(true); expect(result.current.canUse('tasks')).toBe(true); expect(result.current.canUse('export_data')).toBe(true); expect(result.current.canUse('video_conferencing')).toBe(true); @@ -780,7 +781,8 @@ describe('FEATURE_NAMES', () => { 'custom_domain', 'white_label', 'custom_oauth', - 'plugins', + 'automations', + 'can_create_automations', 'tasks', 'export_data', 'video_conferencing', @@ -805,7 +807,8 @@ describe('FEATURE_NAMES', () => { expect(FEATURE_NAMES.custom_domain).toBe('Custom Domain'); expect(FEATURE_NAMES.white_label).toBe('White Label'); expect(FEATURE_NAMES.custom_oauth).toBe('Custom OAuth'); - expect(FEATURE_NAMES.plugins).toBe('Plugins'); + expect(FEATURE_NAMES.automations).toBe('Automations'); + expect(FEATURE_NAMES.can_create_automations).toBe('Custom Automation Creation'); expect(FEATURE_NAMES.tasks).toBe('Scheduled Tasks'); expect(FEATURE_NAMES.export_data).toBe('Data Export'); expect(FEATURE_NAMES.video_conferencing).toBe('Video Conferencing'); @@ -826,7 +829,8 @@ describe('FEATURE_DESCRIPTIONS', () => { 'custom_domain', 'white_label', 'custom_oauth', - 'plugins', + 'automations', + 'can_create_automations', 'tasks', 'export_data', 'video_conferencing', @@ -851,7 +855,8 @@ describe('FEATURE_DESCRIPTIONS', () => { expect(FEATURE_DESCRIPTIONS.custom_domain).toContain('custom domain'); expect(FEATURE_DESCRIPTIONS.white_label).toContain('branding'); expect(FEATURE_DESCRIPTIONS.custom_oauth).toContain('OAuth'); - expect(FEATURE_DESCRIPTIONS.plugins).toContain('plugin'); + expect(FEATURE_DESCRIPTIONS.automations).toContain('Automate'); + expect(FEATURE_DESCRIPTIONS.can_create_automations).toContain('automations'); expect(FEATURE_DESCRIPTIONS.tasks).toContain('task'); expect(FEATURE_DESCRIPTIONS.export_data).toContain('Export'); expect(FEATURE_DESCRIPTIONS.video_conferencing).toContain('video'); diff --git a/frontend/src/hooks/useBusiness.ts b/frontend/src/hooks/useBusiness.ts index 314bc90c..322040d4 100644 --- a/frontend/src/hooks/useBusiness.ts +++ b/frontend/src/hooks/useBusiness.ts @@ -62,8 +62,8 @@ export const useCurrentBusiness = () => { custom_domain: false, white_label: false, custom_oauth: false, - plugins: false, - can_create_plugins: false, + automations: false, + can_create_automations: false, tasks: false, export_data: false, video_conferencing: false, diff --git a/frontend/src/hooks/usePlanFeatures.ts b/frontend/src/hooks/usePlanFeatures.ts index 09442e7f..3288a1bf 100644 --- a/frontend/src/hooks/usePlanFeatures.ts +++ b/frontend/src/hooks/usePlanFeatures.ts @@ -83,8 +83,8 @@ export const FEATURE_NAMES: Record = { custom_domain: 'Custom Domain', white_label: 'White Label', custom_oauth: 'Custom OAuth', - plugins: 'Plugins', - can_create_plugins: 'Custom Plugin Creation', + automations: 'Automations', + can_create_automations: 'Custom Automation Creation', tasks: 'Scheduled Tasks', export_data: 'Data Export', video_conferencing: 'Video Conferencing', @@ -106,9 +106,9 @@ export const FEATURE_DESCRIPTIONS: Record = { custom_domain: 'Use your own custom domain for your booking site', white_label: 'Remove SmoothSchedule branding and use your own', custom_oauth: 'Configure your own OAuth credentials for social login', - plugins: 'Install and use plugins from the marketplace', - can_create_plugins: 'Create custom plugins tailored to your business needs', - tasks: 'Create scheduled tasks to automate plugin execution', + automations: 'Automate repetitive tasks with custom workflows', + can_create_automations: 'Create custom automations tailored to your business needs', + tasks: 'Create scheduled tasks to automate execution', export_data: 'Export your data to CSV or other formats', video_conferencing: 'Add video conferencing links to appointments', two_factor_auth: 'Require two-factor authentication for enhanced security', diff --git a/frontend/src/types.ts b/frontend/src/types.ts index b4e73534..3e4fc171 100644 --- a/frontend/src/types.ts +++ b/frontend/src/types.ts @@ -38,8 +38,8 @@ export interface PlanPermissions { custom_domain: boolean; white_label: boolean; custom_oauth: boolean; - plugins: boolean; - can_create_plugins: boolean; + automations: boolean; + can_create_automations: boolean; tasks: boolean; export_data: boolean; video_conferencing: boolean; diff --git a/smoothschedule/smoothschedule/billing/management/commands/billing_seed_catalog.py b/smoothschedule/smoothschedule/billing/management/commands/billing_seed_catalog.py index 237eb9c5..f6950d95 100644 --- a/smoothschedule/smoothschedule/billing/management/commands/billing_seed_catalog.py +++ b/smoothschedule/smoothschedule/billing/management/commands/billing_seed_catalog.py @@ -71,10 +71,10 @@ FEATURES = [ {"code": "white_label", "name": "White Label", "description": "Remove all SmoothSchedule branding completely", "feature_type": "boolean", "category": "customization", "tenant_field_name": "can_white_label", "display_order": 50}, {"code": "max_public_pages", "name": "Public Web Pages", "description": "Maximum number of public-facing web pages", "feature_type": "integer", "category": "customization", "tenant_field_name": "max_public_pages", "display_order": 55}, - # --- Plugins & Automation --- - {"code": "can_use_plugins", "name": "Use Plugins", "description": "Install and use marketplace plugins", "feature_type": "boolean", "category": "plugins", "tenant_field_name": "can_use_plugins", "display_order": 10}, - {"code": "can_use_tasks", "name": "Scheduled Tasks", "description": "Create automated scheduled tasks", "feature_type": "boolean", "category": "plugins", "tenant_field_name": "can_use_tasks", "display_order": 20, "depends_on": "can_use_plugins"}, - {"code": "can_create_plugins", "name": "Create Plugins", "description": "Build custom plugins", "feature_type": "boolean", "category": "plugins", "tenant_field_name": "can_create_plugins", "display_order": 30, "depends_on": "can_use_plugins"}, + # --- Automations --- + {"code": "can_use_automations", "name": "Use Automations", "description": "Install and use marketplace automations", "feature_type": "boolean", "category": "automations", "tenant_field_name": "can_use_automations", "display_order": 10}, + {"code": "can_use_tasks", "name": "Scheduled Tasks", "description": "Create automated scheduled tasks", "feature_type": "boolean", "category": "automations", "tenant_field_name": "can_use_tasks", "display_order": 20, "depends_on": "can_use_automations"}, + {"code": "can_create_automations", "name": "Create Automations", "description": "Build custom automations", "feature_type": "boolean", "category": "automations", "tenant_field_name": "can_create_automations", "display_order": 30, "depends_on": "can_use_automations"}, # --- Advanced Features --- {"code": "api_access", "name": "API Access", "description": "Access the public API for integrations", "feature_type": "boolean", "category": "advanced", "tenant_field_name": "can_api_access", "display_order": 10}, @@ -159,7 +159,7 @@ PLANS = [ "payment_processing": True, "mobile_app_access": True, "can_use_email_templates": True, - "can_use_plugins": True, + "can_use_automations": True, "can_process_refunds": True, }, "integer_features": { @@ -200,7 +200,7 @@ PLANS = [ "custom_domain": True, "integrations_enabled": True, "can_use_email_templates": True, - "can_use_plugins": True, + "can_use_automations": True, "can_use_tasks": True, "can_process_refunds": True, "can_use_calendar_sync": True, @@ -252,9 +252,9 @@ PLANS = [ "audit_logs": True, "custom_branding": True, "can_use_email_templates": True, - "can_use_plugins": True, + "can_use_automations": True, "can_use_tasks": True, - "can_create_plugins": True, + "can_create_automations": True, "can_process_refunds": True, "can_use_calendar_sync": True, "can_export_data": True, @@ -313,9 +313,9 @@ PLANS = [ "dedicated_account_manager": True, "sla_guarantee": True, "can_use_email_templates": True, - "can_use_plugins": True, + "can_use_automations": True, "can_use_tasks": True, - "can_create_plugins": True, + "can_create_automations": True, "can_process_refunds": True, "can_use_calendar_sync": True, "can_export_data": True, diff --git a/smoothschedule/smoothschedule/identity/core/permissions.py b/smoothschedule/smoothschedule/identity/core/permissions.py index b5b91aa3..6e1ce677 100644 --- a/smoothschedule/smoothschedule/identity/core/permissions.py +++ b/smoothschedule/smoothschedule/identity/core/permissions.py @@ -372,7 +372,7 @@ def HasFeaturePermission(permission_key): 'can_use_masked_phone_numbers': 'Masked Calling', 'can_use_custom_domain': 'Custom Domains', 'can_white_label': 'White Labeling', - 'can_create_plugins': 'Plugin Creation', + 'can_create_automations': 'Automation Creation', 'can_use_webhooks': 'Webhooks', 'can_accept_payments': 'Payment Processing', 'can_api_access': 'API Access', diff --git a/smoothschedule/smoothschedule/identity/core/tests/test_permissions.py b/smoothschedule/smoothschedule/identity/core/tests/test_permissions.py index 710781c8..fa991424 100644 --- a/smoothschedule/smoothschedule/identity/core/tests/test_permissions.py +++ b/smoothschedule/smoothschedule/identity/core/tests/test_permissions.py @@ -672,7 +672,7 @@ class TestPermissionFactoryConfiguration: 'can_use_masked_phone_numbers', 'can_use_custom_domain', 'can_white_label', - 'can_create_plugins', + 'can_create_automations', 'can_use_webhooks', 'can_accept_payments', 'can_api_access', diff --git a/smoothschedule/smoothschedule/platform/admin/serializers.py b/smoothschedule/smoothschedule/platform/admin/serializers.py index 3fa3f0c1..d41ea525 100644 --- a/smoothschedule/smoothschedule/platform/admin/serializers.py +++ b/smoothschedule/smoothschedule/platform/admin/serializers.py @@ -267,7 +267,7 @@ class TenantSerializer(serializers.ModelSerializer): features = {} feature_keys = [ 'sms_reminders', 'webhooks', 'api_access', 'custom_domain', - 'white_label', 'custom_oauth', 'plugins', 'can_create_plugins', + 'white_label', 'custom_oauth', 'automations', 'can_create_automations', 'tasks', 'export_data', 'video_conferencing', 'two_factor_auth', 'masked_calling', 'pos_system', 'mobile_app', 'contracts', 'multi_location', diff --git a/smoothschedule/smoothschedule/platform/admin/tasks.py b/smoothschedule/smoothschedule/platform/admin/tasks.py index 9e9bd1e1..9c66257b 100644 --- a/smoothschedule/smoothschedule/platform/admin/tasks.py +++ b/smoothschedule/smoothschedule/platform/admin/tasks.py @@ -265,11 +265,11 @@ def sync_subscription_plan_to_tenants(self, plan_id: int): # Advanced features - plan may use short names 'export_data': 'can_export_data', 'can_export_data': 'can_export_data', - 'plugins': 'can_use_plugins', - 'can_use_plugins': 'can_use_plugins', + 'automations': 'can_use_automations', + 'can_use_automations': 'can_use_automations', 'tasks': 'can_use_tasks', 'can_use_tasks': 'can_use_tasks', - 'can_create_plugins': 'can_create_plugins', + 'can_create_automations': 'can_create_automations', 'webhooks': 'can_use_webhooks', 'can_use_webhooks': 'can_use_webhooks', 'calendar_sync': 'can_use_calendar_sync', diff --git a/smoothschedule/smoothschedule/platform/admin/tests/test_tasks.py b/smoothschedule/smoothschedule/platform/admin/tests/test_tasks.py index 8895436c..8433ff8a 100644 --- a/smoothschedule/smoothschedule/platform/admin/tests/test_tasks.py +++ b/smoothschedule/smoothschedule/platform/admin/tests/test_tasks.py @@ -325,14 +325,14 @@ class TestSyncSubscriptionPlanToTenantsTask: mock_plan = Mock( id=1, name='Professional', - permissions={'can_use_plugins': True}, + permissions={'can_use_automations': True}, limits={} ) MockPlan.objects.get.return_value = mock_plan mock_tenant = Mock() mock_tenant.id = 1 - mock_tenant.can_use_plugins = False + mock_tenant.can_use_automations = False mock_tenant.subscription_tier = 'FREE' mock_tenant.save.side_effect = Exception("DB error") diff --git a/smoothschedule/smoothschedule/platform/admin/tests/test_views.py b/smoothschedule/smoothschedule/platform/admin/tests/test_views.py index 58ffe008..495803f6 100644 --- a/smoothschedule/smoothschedule/platform/admin/tests/test_views.py +++ b/smoothschedule/smoothschedule/platform/admin/tests/test_views.py @@ -1478,7 +1478,7 @@ class TestTenantViewSet: mock_tenant = Mock(id=1, schema_name='demo', name='Demo Business') mock_custom_tier = Mock( id=1, - features={'max_users': 100, 'can_use_plugins': True}, + features={'max_users': 100, 'can_use_automations': True}, notes='Custom tier for testing', is_active=True, days_until_expiry=None, @@ -1493,7 +1493,7 @@ class TestTenantViewSet: mock_serializer = Mock() mock_serializer.data = { 'id': 1, - 'features': {'max_users': 100, 'can_use_plugins': True}, + 'features': {'max_users': 100, 'can_use_automations': True}, 'notes': 'Custom tier for testing', 'is_active': True, 'days_until_expiry': None, diff --git a/smoothschedule/smoothschedule/scheduling/automations/views.py b/smoothschedule/smoothschedule/scheduling/automations/views.py index 768a8114..a154a6ba 100644 --- a/smoothschedule/smoothschedule/scheduling/automations/views.py +++ b/smoothschedule/smoothschedule/scheduling/automations/views.py @@ -117,7 +117,7 @@ class AutomationTemplateViewSet(viewsets.ModelViewSet): tenant = getattr(self.request, 'tenant', None) if tenant: # Check for new feature name, fall back to old name for compatibility - return tenant.has_feature('can_use_automations') or tenant.has_feature('can_use_plugins') + return tenant.has_feature('can_use_automations') or tenant.has_feature('can_use_automations') return True # Allow if no tenant context def get_queryset(self): @@ -183,14 +183,14 @@ class AutomationTemplateViewSet(viewsets.ModelViewSet): # Check permission to use automations first tenant = getattr(self.request, 'tenant', None) - if tenant and not (tenant.has_feature('can_use_automations') or tenant.has_feature('can_use_plugins')): + if tenant and not (tenant.has_feature('can_use_automations') or tenant.has_feature('can_use_automations')): raise PermissionDenied( "Your current plan does not include Automation access. " "Please upgrade your subscription to use automations." ) # Check permission to create automations - if tenant and not (tenant.has_feature('can_create_automations') or tenant.has_feature('can_create_plugins')): + if tenant and not (tenant.has_feature('can_create_automations') or tenant.has_feature('can_create_automations')): raise PermissionDenied( "Your current plan does not include Automation Creation. " "Please upgrade your subscription to create custom automations." @@ -269,7 +269,7 @@ class AutomationTemplateViewSet(viewsets.ModelViewSet): """ # Check permission to use automations tenant = getattr(request, 'tenant', None) - if tenant and not (tenant.has_feature('can_use_automations') or tenant.has_feature('can_use_plugins')): + if tenant and not (tenant.has_feature('can_use_automations') or tenant.has_feature('can_use_automations')): return Response( {'error': 'Your current plan does not include Automation access. Please upgrade your subscription to install automations.'}, status=status.HTTP_403_FORBIDDEN @@ -473,7 +473,7 @@ class AutomationInstallationViewSet(viewsets.ModelViewSet): from rest_framework.exceptions import PermissionDenied tenant = getattr(self.request, 'tenant', None) - if tenant and not (tenant.has_feature('can_use_automations') or tenant.has_feature('can_use_plugins')): + if tenant and not (tenant.has_feature('can_use_automations') or tenant.has_feature('can_use_automations')): raise PermissionDenied( "Your current plan does not include Automation access. " "Please upgrade your subscription to use automations." @@ -505,7 +505,7 @@ class AutomationInstallationViewSet(viewsets.ModelViewSet): # Check permission to use automations tenant = getattr(self.request, 'tenant', None) - if tenant and not (tenant.has_feature('can_use_automations') or tenant.has_feature('can_use_plugins')): + if tenant and not (tenant.has_feature('can_use_automations') or tenant.has_feature('can_use_automations')): raise PermissionDenied( "Your current plan does not include Automation access. " "Please upgrade your subscription to use automations." @@ -625,7 +625,7 @@ class EventAutomationViewSet(viewsets.ModelViewSet): from rest_framework.exceptions import PermissionDenied tenant = getattr(self.request, 'tenant', None) - if tenant and not (tenant.has_feature('can_use_automations') or tenant.has_feature('can_use_plugins')): + if tenant and not (tenant.has_feature('can_use_automations') or tenant.has_feature('can_use_automations')): raise PermissionDenied( "Your current plan does not include Automation access. " "Please upgrade your subscription to use automations." @@ -752,7 +752,7 @@ class GlobalEventAutomationViewSet(viewsets.ModelViewSet): from rest_framework.exceptions import PermissionDenied tenant = getattr(self.request, 'tenant', None) - if tenant and not (tenant.has_feature('can_use_automations') or tenant.has_feature('can_use_plugins')): + if tenant and not (tenant.has_feature('can_use_automations') or tenant.has_feature('can_use_automations')): raise PermissionDenied( "Your current plan does not include Automation access. " "Please upgrade your subscription to use automations." diff --git a/smoothschedule/smoothschedule/scheduling/schedule/api_views.py b/smoothschedule/smoothschedule/scheduling/schedule/api_views.py index 0cba3f92..895850aa 100644 --- a/smoothschedule/smoothschedule/scheduling/schedule/api_views.py +++ b/smoothschedule/smoothschedule/scheduling/schedule/api_views.py @@ -171,8 +171,8 @@ def current_business_view(request): 'custom_domain': tenant.has_feature('custom_domain'), 'white_label': tenant.has_feature('white_label'), 'custom_oauth': tenant.has_feature('can_manage_oauth'), - 'plugins': tenant.has_feature('can_use_plugins'), - 'can_create_plugins': tenant.has_feature('can_create_plugins'), + 'automations': tenant.has_feature('can_use_automations'), + 'can_create_automations': tenant.has_feature('can_create_automations'), 'tasks': tenant.has_feature('can_use_tasks'), 'export_data': tenant.has_feature('can_export_data'), 'video_conferencing': tenant.has_feature('can_add_video_conferencing'), diff --git a/smoothschedule/smoothschedule/scheduling/schedule/tests/test_api_views.py b/smoothschedule/smoothschedule/scheduling/schedule/tests/test_api_views.py index 6f87b10e..9deaa8d2 100644 --- a/smoothschedule/smoothschedule/scheduling/schedule/tests/test_api_views.py +++ b/smoothschedule/smoothschedule/scheduling/schedule/tests/test_api_views.py @@ -297,8 +297,8 @@ class TestCurrentBusinessView: 'custom_domain': False, 'white_label': False, 'can_manage_oauth': False, - 'can_use_plugins': True, - 'can_create_plugins': False, + 'can_use_automations': True, + 'can_create_automations': False, 'can_use_tasks': True, 'can_export_data': False, 'can_add_video_conferencing': False, @@ -324,7 +324,7 @@ class TestCurrentBusinessView: assert response.data['subdomain'] == 'demo' assert response.data['plan'] == 'pro' assert response.data['plan_permissions']['sms_reminders'] is True - assert response.data['plan_permissions']['plugins'] is True + assert response.data['plan_permissions']['automations'] is True class TestUpdateBusinessView: @@ -393,8 +393,8 @@ class TestUpdateBusinessView: mock_tenant.can_use_custom_domain = False mock_tenant.can_white_label = False mock_tenant.can_manage_oauth_credentials = False - mock_tenant.can_use_plugins = False - mock_tenant.can_create_plugins = False + mock_tenant.can_use_automations = False + mock_tenant.can_create_automations = False mock_tenant.can_use_tasks = False mock_tenant.can_export_data = False mock_tenant.can_add_video_conferencing = False @@ -456,8 +456,8 @@ class TestUpdateBusinessView: mock_tenant.can_use_custom_domain = False mock_tenant.can_white_label = False mock_tenant.can_manage_oauth_credentials = False - mock_tenant.can_use_plugins = False - mock_tenant.can_create_plugins = False + mock_tenant.can_use_automations = False + mock_tenant.can_create_automations = False mock_tenant.can_use_tasks = False mock_tenant.can_export_data = False mock_tenant.can_add_video_conferencing = False diff --git a/smoothschedule/smoothschedule/scheduling/schedule/views.py b/smoothschedule/smoothschedule/scheduling/schedule/views.py index d138bfc7..5b8602f4 100644 --- a/smoothschedule/smoothschedule/scheduling/schedule/views.py +++ b/smoothschedule/smoothschedule/scheduling/schedule/views.py @@ -921,7 +921,7 @@ class ScheduledTaskViewSet(TaskFeatureRequiredMixin, TenantFilteredQuerySetMixin - Must be authenticated - Only owners/managers can create/update/delete - Subject to MAX_AUTOMATED_TASKS quota (hard block on creation) - - Requires can_use_plugins AND can_use_tasks features + - Requires can_use_automations AND can_use_tasks features Features: - List all scheduled tasks @@ -1117,9 +1117,9 @@ class PluginTemplateViewSet(viewsets.ModelViewSet): Permissions: - Marketplace view: Always accessible (for discovery) - - My Plugins view: Requires can_use_plugins feature - - Install action: Requires can_use_plugins feature - - Create: Requires can_use_plugins AND can_create_plugins features + - My Plugins view: Requires can_use_automations feature + - Install action: Requires can_use_automations feature + - Create: Requires can_use_automations AND can_create_automations features """ queryset = PluginTemplate.objects.all() serializer_class = PluginTemplateSerializer @@ -1132,7 +1132,7 @@ class PluginTemplateViewSet(viewsets.ModelViewSet): """Check if tenant has permission to use plugins.""" tenant = getattr(self.request, 'tenant', None) if tenant: - return tenant.has_feature('can_use_plugins') + return tenant.has_feature('can_use_automations') return True # Allow if no tenant context def get_queryset(self): @@ -1140,7 +1140,7 @@ class PluginTemplateViewSet(viewsets.ModelViewSet): Filter templates based on user permissions. - Marketplace view: Only approved PUBLIC templates (always accessible) - - My Plugins: User's own templates (requires can_use_plugins) + - My Plugins: User's own templates (requires can_use_automations) - Platform admins: All templates """ queryset = super().get_queryset() @@ -1198,14 +1198,14 @@ class PluginTemplateViewSet(viewsets.ModelViewSet): # Check permission to use plugins first tenant = getattr(self.request, 'tenant', None) - if tenant and not tenant.has_feature('can_use_plugins'): + if tenant and not tenant.has_feature('can_use_automations'): raise PermissionDenied( "Your current plan does not include Plugin access. " "Please upgrade your subscription to use plugins." ) - # Check permission to create plugins (requires can_use_plugins) - if tenant and not tenant.has_feature('can_create_plugins'): + # Check permission to create plugins (requires can_use_automations) + if tenant and not tenant.has_feature('can_create_automations'): raise PermissionDenied( "Your current plan does not include Plugin Creation. " "Please upgrade your subscription to create custom plugins." @@ -1284,7 +1284,7 @@ class PluginTemplateViewSet(viewsets.ModelViewSet): """ # Check permission to use plugins tenant = getattr(request, 'tenant', None) - if tenant and not tenant.has_feature('can_use_plugins'): + if tenant and not tenant.has_feature('can_use_automations'): return Response( {'error': 'Your current plan does not include Plugin access. Please upgrade your subscription to install plugins.'}, status=status.HTTP_403_FORBIDDEN @@ -1476,7 +1476,7 @@ class PluginInstallationViewSet(viewsets.ModelViewSet): - Rate and review plugin Permissions: - - Requires can_use_plugins feature for all operations + - Requires can_use_automations feature for all operations """ queryset = PluginInstallation.objects.select_related('template', 'scheduled_task').all() serializer_class = PluginInstallationSerializer @@ -1488,7 +1488,7 @@ class PluginInstallationViewSet(viewsets.ModelViewSet): from rest_framework.exceptions import PermissionDenied tenant = getattr(self.request, 'tenant', None) - if tenant and not tenant.has_feature('can_use_plugins'): + if tenant and not tenant.has_feature('can_use_automations'): raise PermissionDenied( "Your current plan does not include Plugin access. " "Please upgrade your subscription to use plugins." @@ -1520,7 +1520,7 @@ class PluginInstallationViewSet(viewsets.ModelViewSet): # Check permission to use plugins tenant = getattr(self.request, 'tenant', None) - if tenant and not tenant.has_feature('can_use_plugins'): + if tenant and not tenant.has_feature('can_use_automations'): raise PermissionDenied( "Your current plan does not include Plugin access. " "Please upgrade your subscription to use plugins." @@ -1640,7 +1640,7 @@ class EventPluginViewSet(viewsets.ModelViewSet): from rest_framework.exceptions import PermissionDenied tenant = getattr(self.request, 'tenant', None) - if tenant and not tenant.has_feature('can_use_plugins'): + if tenant and not tenant.has_feature('can_use_automations'): raise PermissionDenied( "Your current plan does not include Plugin access. " "Please upgrade your subscription to use plugins." @@ -1767,7 +1767,7 @@ class GlobalEventPluginViewSet(viewsets.ModelViewSet): from rest_framework.exceptions import PermissionDenied tenant = getattr(self.request, 'tenant', None) - if tenant and not tenant.has_feature('can_use_plugins'): + if tenant and not tenant.has_feature('can_use_automations'): raise PermissionDenied( "Your current plan does not include Plugin access. " "Please upgrade your subscription to use plugins."