diff --git a/cookbook/admin.py b/cookbook/admin.py index 3429e63d..64a03173 100644 --- a/cookbook/admin.py +++ b/cookbook/admin.py @@ -16,7 +16,7 @@ from .models import (BookmarkletImport, Comment, CookLog, Food, ImportLog, Ingre ShoppingList, ShoppingListEntry, ShoppingListRecipe, Space, Step, Storage, Supermarket, SupermarketCategory, SupermarketCategoryRelation, Sync, SyncLog, TelegramBot, Unit, UnitConversion, UserFile, UserPreference, UserSpace, - ViewLog, HomeAssistantConfig) + ViewLog, HomeAssistantConfig, ExampleConfig) class CustomUserAdmin(UserAdmin): @@ -103,6 +103,14 @@ class HomeAssistantConfigAdmin(admin.ModelAdmin): admin.site.register(HomeAssistantConfig, HomeAssistantConfigAdmin) +class ExampleConfigAdmin(admin.ModelAdmin): + list_display = ('id', 'name', 'enabled', 'feed_url') + search_fields = ('name',) + + +admin.site.register(ExampleConfig, ExampleConfigAdmin) + + class SyncAdmin(admin.ModelAdmin): list_display = ('storage', 'path', 'active', 'last_checked') search_fields = ('storage__name', 'path') diff --git a/cookbook/connectors/connector_manager.py b/cookbook/connectors/connector_manager.py index 39919597..178c8efb 100644 --- a/cookbook/connectors/connector_manager.py +++ b/cookbook/connectors/connector_manager.py @@ -12,14 +12,15 @@ from typing import List, Any, Dict, Optional from django_scopes import scope from cookbook.connectors.connector import Connector +from cookbook.connectors.example import Example from cookbook.connectors.homeassistant import HomeAssistant -from cookbook.models import ShoppingListEntry, Recipe, MealPlan, Space, HomeAssistantConfig, ConnectorConfig +from cookbook.models import ShoppingListEntry, Recipe, MealPlan, Space, HomeAssistantConfig, ExampleConfig multiprocessing.set_start_method('fork') # https://code.djangoproject.com/ticket/31169 QUEUE_MAX_SIZE = 25 REGISTERED_CLASSES: UnionType = ShoppingListEntry | Recipe | MealPlan -CONNECTOR_UPDATE_CLASSES: UnionType = HomeAssistantConfig | ConnectorConfig +CONNECTOR_UPDATE_CLASSES: UnionType = HomeAssistantConfig | ExampleConfig class ActionType(Enum): @@ -97,7 +98,10 @@ class ConnectorManager: loop.run_until_complete(close_connectors(connectors)) with scope(space=space): - connectors: List[Connector] = [HomeAssistant(config) for config in space.homeassistantconfig_set.all() if config.enabled] + connectors: List[Connector] = [ + *(HomeAssistant(config) for config in space.homeassistantconfig_set.all() if config.enabled), + *(Example(config) for config in space.exampleconfig_set.all() if config.enabled) + ] _connectors[space.name] = connectors if len(connectors) == 0 or refresh_connector_cache: diff --git a/cookbook/connectors/example.py b/cookbook/connectors/example.py new file mode 100644 index 00000000..ce55f476 --- /dev/null +++ b/cookbook/connectors/example.py @@ -0,0 +1,27 @@ +from cookbook.connectors.connector import Connector +from cookbook.models import ExampleConfig, Space, ShoppingListEntry + + +class Example(Connector): + _config: ExampleConfig + + def __init__(self, config: ExampleConfig): + self._config = config + + async def on_shopping_list_entry_created(self, space: Space, shopping_list_entry: ShoppingListEntry) -> None: + if not self._config.on_shopping_list_entry_created_enabled: + return + pass + + async def on_shopping_list_entry_updated(self, space: Space, shopping_list_entry: ShoppingListEntry) -> None: + if not self._config.on_shopping_list_entry_updated_enabled: + return + pass + + async def on_shopping_list_entry_deleted(self, space: Space, shopping_list_entry: ShoppingListEntry) -> None: + if not self._config.on_shopping_list_entry_deleted_enabled: + return + pass + + async def close(self) -> None: + pass diff --git a/cookbook/forms.py b/cookbook/forms.py index dce4da57..18867958 100644 --- a/cookbook/forms.py +++ b/cookbook/forms.py @@ -10,7 +10,7 @@ from django_scopes.forms import SafeModelChoiceField, SafeModelMultipleChoiceFie from hcaptcha.fields import hCaptchaField from .models import (Comment, Food, InviteLink, Keyword, Recipe, RecipeBook, RecipeBookEntry, - SearchPreference, Space, Storage, Sync, User, UserPreference, HomeAssistantConfig) + SearchPreference, Space, Storage, Sync, User, UserPreference, HomeAssistantConfig, ExampleConfig) class SelectWidget(widgets.Select): @@ -188,12 +188,35 @@ class StorageForm(forms.ModelForm): } -class HomeAssistantConfigForm(forms.ModelForm): - token = forms.CharField( - widget=forms.TextInput( - attrs={'autocomplete': 'new-password', 'type': 'password'} - ), - required=True, +class ConnectorConfigForm(forms.ModelForm): + enabled = forms.BooleanField( + help_text="Is the connector enabled", + required=False, + ) + + on_shopping_list_entry_created_enabled = forms.BooleanField( + help_text="Enable action for ShoppingListEntry created events", + required=False, + ) + + on_shopping_list_entry_updated_enabled = forms.BooleanField( + help_text="Enable action for ShoppingListEntry updated events", + required=False, + ) + + on_shopping_list_entry_deleted_enabled = forms.BooleanField( + help_text="Enable action for ShoppingListEntry deleted events", + required=False, + ) + + class Meta: + fields = ('name', 'enabled', 'on_shopping_list_entry_created_enabled', 'on_shopping_list_entry_updated_enabled', 'on_shopping_list_entry_deleted_enabled') + + +class HomeAssistantConfigForm(ConnectorConfigForm): + update_token = forms.CharField( + widget=forms.TextInput(attrs={'autocomplete': 'update-token', 'type': 'password'}), + required=False, help_text=_('Long Lived Access Token for your HomeAssistant instance') ) @@ -202,11 +225,6 @@ class HomeAssistantConfigForm(forms.ModelForm): help_text=_('Something like http://homeassistant.local:8123/api'), ) - enabled = forms.BooleanField( - help_text="Is the HomeAssistantConnector enabled", - required=False, - ) - on_shopping_list_entry_created_enabled = forms.BooleanField( help_text="Enable syncing ShoppingListEntry to Homeassistant Todo List -- Warning: Might have negative performance impact", required=False, @@ -224,15 +242,24 @@ class HomeAssistantConfigForm(forms.ModelForm): class Meta: model = HomeAssistantConfig - fields = ( - 'name', 'url', 'token', 'todo_entity', 'enabled', 'on_shopping_list_entry_created_enabled', 'on_shopping_list_entry_updated_enabled', - 'on_shopping_list_entry_deleted_enabled') + + fields = ConnectorConfigForm.Meta.fields + ('url', 'todo_entity') help_texts = { 'url': _('http://homeassistant.local:8123/api for example'), } +class ExampleConfigForm(ConnectorConfigForm): + feed_url = forms.URLField( + required=False, + ) + + class Meta: + model = ExampleConfig + fields = ConnectorConfigForm.Meta.fields + ('feed_url',) + + # TODO: Deprecate class RecipeBookEntryForm(forms.ModelForm): prefix = 'bookmark' diff --git a/cookbook/migrations/0208_homeassistantconfig.py b/cookbook/migrations/0208_homeassistantconfig_exampleconfig.py similarity index 58% rename from cookbook/migrations/0208_homeassistantconfig.py rename to cookbook/migrations/0208_homeassistantconfig_exampleconfig.py index f21ff06a..789094c1 100644 --- a/cookbook/migrations/0208_homeassistantconfig.py +++ b/cookbook/migrations/0208_homeassistantconfig_exampleconfig.py @@ -1,4 +1,4 @@ -# Generated by Django 4.2.7 on 2024-01-12 21:01 +# Generated by Django 4.2.7 on 2024-01-14 16:00 import cookbook.models from django.conf import settings @@ -35,4 +35,22 @@ class Migration(migrations.Migration): }, bases=(models.Model, cookbook.models.PermissionModelMixin), ), + migrations.CreateModel( + name='ExampleConfig', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('name', models.CharField(max_length=128, validators=[django.core.validators.MinLengthValidator(1)])), + ('enabled', models.BooleanField(default=True, help_text='Is Connector Enabled')), + ('on_shopping_list_entry_created_enabled', models.BooleanField(default=False)), + ('on_shopping_list_entry_updated_enabled', models.BooleanField(default=False)), + ('on_shopping_list_entry_deleted_enabled', models.BooleanField(default=False)), + ('feed_url', models.URLField(blank=True)), + ('created_by', models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, to=settings.AUTH_USER_MODEL)), + ('space', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='cookbook.space')), + ], + options={ + 'abstract': False, + }, + bases=(models.Model, cookbook.models.PermissionModelMixin), + ), ] diff --git a/cookbook/models.py b/cookbook/models.py index 9d6b9c5a..a41dc37f 100644 --- a/cookbook/models.py +++ b/cookbook/models.py @@ -340,6 +340,7 @@ class Space(ExportModelOperationsMixin('space'), models.Model): Sync.objects.filter(space=self).delete() Storage.objects.filter(space=self).delete() HomeAssistantConfig.objects.filter(space=self).delete() + ExampleConfig.objects.filter(space=self).delete() ShoppingListEntry.objects.filter(shoppinglist__space=self).delete() ShoppingListRecipe.objects.filter(shoppinglist__space=self).delete() @@ -387,6 +388,10 @@ class HomeAssistantConfig(ConnectorConfig): todo_entity = models.CharField(max_length=128, default='todo.shopping_list') +class ExampleConfig(ConnectorConfig): + feed_url = models.URLField(blank=True) + + class UserPreference(models.Model, PermissionModelMixin): # Themes BOOTSTRAP = 'BOOTSTRAP' diff --git a/cookbook/tables.py b/cookbook/tables.py index 4f49690c..ba14fbbe 100644 --- a/cookbook/tables.py +++ b/cookbook/tables.py @@ -1,9 +1,14 @@ +from typing import Any, Dict + import django_tables2 as tables from django.utils.html import format_html from django.utils.translation import gettext as _ +from django.views.generic import TemplateView +from django_tables2 import MultiTableMixin from django_tables2.utils import A -from .models import CookLog, InviteLink, RecipeImport, Storage, Sync, SyncLog, ViewLog, HomeAssistantConfig +from .helper.permission_helper import GroupRequiredMixin +from .models import CookLog, InviteLink, RecipeImport, Storage, Sync, SyncLog, ViewLog, HomeAssistantConfig, ExampleConfig class StorageTable(tables.Table): @@ -15,6 +20,16 @@ class StorageTable(tables.Table): fields = ('id', 'name', 'method') +class ExampleConfigTable(tables.Table): + id = tables.LinkColumn('edit_example_config', args=[A('id')]) + + class Meta: + model = ExampleConfig + template_name = 'generic/table_template.html' + fields = ('id', 'name', 'enabled', 'feed_url') + attrs = {'table_name': "Example Configs", 'create_url': 'new_example_config'} + + class HomeAssistantConfigTable(tables.Table): id = tables.LinkColumn('edit_home_assistant_config', args=[A('id')]) @@ -22,6 +37,30 @@ class HomeAssistantConfigTable(tables.Table): model = HomeAssistantConfig template_name = 'generic/table_template.html' fields = ('id', 'name', 'enabled', 'url') + attrs = {'table_name': "HomeAssistant Configs", 'create_url': 'new_home_assistant_config'} + + +class ConnectorConfigTable(GroupRequiredMixin, MultiTableMixin, TemplateView): + groups_required = ['admin'] + template_name = "list_connectors.html" + + table_pagination = { + "per_page": 25 + } + + def get_context_data(self, **kwargs: Any) -> Dict[str, Any]: + kwargs = super().get_context_data(**kwargs) + kwargs['title'] = _("Connectors") + return kwargs + + def get_tables(self): + example_configs = ExampleConfig.objects.filter(space=self.request.space).all() + home_assistant_configs = HomeAssistantConfig.objects.filter(space=self.request.space).all() + + return [ + ExampleConfigTable(example_configs), + HomeAssistantConfigTable(home_assistant_configs) + ] class ImportLogTable(tables.Table): diff --git a/cookbook/templates/base.html b/cookbook/templates/base.html index d9e2eda1..7fbb14db 100644 --- a/cookbook/templates/base.html +++ b/cookbook/templates/base.html @@ -336,7 +336,7 @@ class="fas fa-server fa-fw"> {% trans 'Space Settings' %} {% endif %} {% if request.user == request.space.created_by or user.is_superuser %} - {% trans 'External Connectors' %} {% endif %} {% if user.is_superuser %} diff --git a/cookbook/templates/list_connectors.html b/cookbook/templates/list_connectors.html new file mode 100644 index 00000000..283f7c31 --- /dev/null +++ b/cookbook/templates/list_connectors.html @@ -0,0 +1,55 @@ +{% extends "base.html" %} +{% load crispy_forms_tags %} +{% load i18n %} +{% load django_tables2 %} + +{% block title %}{% trans 'List' %}{% endblock %} + + +{% block content %} + +{% if request.resolver_match.url_name in 'list_storage,list_recipe_import,list_sync_log' %} + +{% endif %} + +
+ +

{{ title }} {% trans 'List' %}

+
+ + {% if filter %} +
+
+
+ {% csrf_token %} + {{ filter.form|crispy }} + +
+ {% endif %} + + {% if import_btn %} + {% trans 'Import all' %} +
+
+ {% endif %} + + {% for table in tables %} + +

{{ table.attrs.table_name }} {% trans 'List' %} + {% if table.attrs.create_url %} + + {% endif %} +

+
+ + {% render_table table %} + {% endfor %} + +
+ +{% endblock content %} \ No newline at end of file diff --git a/cookbook/urls.py b/cookbook/urls.py index 96735037..e85cfbaf 100644 --- a/cookbook/urls.py +++ b/cookbook/urls.py @@ -12,7 +12,8 @@ from recipes.settings import DEBUG, PLUGINS from .models import (Automation, Comment, CustomFilter, Food, InviteLink, Keyword, PropertyType, Recipe, RecipeBook, RecipeBookEntry, RecipeImport, ShoppingList, Space, Step, Storage, Supermarket, SupermarketCategory, Sync, SyncLog, Unit, UnitConversion, - UserFile, UserSpace, get_model_name, HomeAssistantConfig) + UserFile, UserSpace, get_model_name, HomeAssistantConfig, ExampleConfig) +from .tables import ConnectorConfigTable from .views import api, data, delete, edit, import_export, lists, new, telegram, views from .views.api import CustomAuthToken, ImportOpenData @@ -115,7 +116,7 @@ urlpatterns = [ path('edit/recipe/convert//', edit.convert_recipe, name='edit_convert_recipe'), path('edit/storage//', edit.edit_storage, name='edit_storage'), - path('edit/home-assistant-config//', edit.edit_home_assistant_config, name='edit_home_assistant_config'), + path('list/connectors', ConnectorConfigTable.as_view(), name='list_connectors'), path('delete/recipe-source//', delete.delete_recipe_source, name='delete_recipe_source'), @@ -168,7 +169,7 @@ urlpatterns = [ ] generic_models = ( - Recipe, RecipeImport, Storage, HomeAssistantConfig, RecipeBook, SyncLog, Sync, + Recipe, RecipeImport, Storage, HomeAssistantConfig, ExampleConfig, RecipeBook, SyncLog, Sync, Comment, RecipeBookEntry, ShoppingList, InviteLink, UserSpace, Space ) diff --git a/cookbook/views/delete.py b/cookbook/views/delete.py index b6cf857b..bbdc98ee 100644 --- a/cookbook/views/delete.py +++ b/cookbook/views/delete.py @@ -9,7 +9,7 @@ from django.views.generic import DeleteView from cookbook.helper.permission_helper import GroupRequiredMixin, OwnerRequiredMixin, group_required from cookbook.models import (Comment, InviteLink, MealPlan, Recipe, RecipeBook, RecipeBookEntry, - RecipeImport, Space, Storage, Sync, UserSpace, HomeAssistantConfig) + RecipeImport, Space, Storage, Sync, UserSpace, HomeAssistantConfig, ExampleConfig) from cookbook.provider.dropbox import Dropbox from cookbook.provider.local import Local from cookbook.provider.nextcloud import Nextcloud @@ -126,23 +126,24 @@ class HomeAssistantConfigDelete(GroupRequiredMixin, DeleteView): groups_required = ['admin'] template_name = "generic/delete_template.html" model = HomeAssistantConfig - success_url = reverse_lazy('list_storage') + success_url = reverse_lazy('list_connectors') def get_context_data(self, **kwargs): - context = super(HomeAssistantConfigDelete, self).get_context_data(**kwargs) + context = super().get_context_data(**kwargs) context['title'] = _("HomeAssistant Config Backend") return context - def post(self, request, *args, **kwargs): - try: - return self.delete(request, *args, **kwargs) - except ProtectedError: - messages.add_message( - request, - messages.WARNING, - _('Could not delete this storage backend as it is used in at least one monitor.') # noqa: E501 - ) - return HttpResponseRedirect(reverse('list_storage')) + +class ExampleConfigDelete(GroupRequiredMixin, DeleteView): + groups_required = ['admin'] + template_name = "generic/delete_template.html" + model = ExampleConfig + success_url = reverse_lazy('list_connectors') + + def get_context_data(self, **kwargs): + context = super().get_context_data(**kwargs) + context['title'] = _("Example Config Backend") + return context class CommentDelete(OwnerRequiredMixin, DeleteView): diff --git a/cookbook/views/edit.py b/cookbook/views/edit.py index deb9654b..2f99216b 100644 --- a/cookbook/views/edit.py +++ b/cookbook/views/edit.py @@ -9,10 +9,10 @@ from django.utils.translation import gettext as _ from django.views.generic import UpdateView from django.views.generic.edit import FormMixin -from cookbook.forms import CommentForm, ExternalRecipeForm, StorageForm, SyncForm, HomeAssistantConfigForm +from cookbook.forms import CommentForm, ExternalRecipeForm, StorageForm, SyncForm, HomeAssistantConfigForm, ExampleConfigForm from cookbook.helper.permission_helper import (GroupRequiredMixin, OwnerRequiredMixin, above_space_limit, group_required) -from cookbook.models import Comment, Recipe, RecipeImport, Storage, Sync, HomeAssistantConfig +from cookbook.models import Comment, Recipe, RecipeImport, Storage, Sync, HomeAssistantConfig, ExampleConfig from cookbook.provider.dropbox import Dropbox from cookbook.provider.local import Local from cookbook.provider.nextcloud import Nextcloud @@ -128,46 +128,49 @@ def edit_storage(request, pk): ) -@group_required('admin') -def edit_home_assistant_config(request, pk): - instance: HomeAssistantConfig = get_object_or_404(HomeAssistantConfig, pk=pk, space=request.space) +class HomeAssistantConfigUpdate(GroupRequiredMixin, UpdateView): + groups_required = ['admin'] + template_name = "generic/edit_template.html" + model = HomeAssistantConfig + form_class = HomeAssistantConfigForm - if not (instance.created_by == request.user or request.user.is_superuser): - messages.add_message(request, messages.ERROR, _('You cannot edit this homeassistant config!')) - return HttpResponseRedirect(reverse('edit_home_assistant_config')) + def get_form_kwargs(self): + kwargs = super().get_form_kwargs() + kwargs['initial']['update_token'] = VALUE_NOT_CHANGED + return kwargs - if request.space.demo or settings.HOSTED: - messages.add_message(request, messages.ERROR, _('This feature is not yet available in the hosted version of tandoor!')) - return redirect('index') + def form_valid(self, form): + if form.cleaned_data['update_token'] != VALUE_NOT_CHANGED and form.cleaned_data['update_token'] != "": + form.instance.token = form.cleaned_data['update_token'] + messages.add_message(self.request, messages.SUCCESS, _('Config saved!')) + return super(HomeAssistantConfigUpdate, self).form_valid(form) - if request.method == "POST": - form = HomeAssistantConfigForm(request.POST, instance=copy.deepcopy(instance)) - if form.is_valid(): - instance.name = form.cleaned_data['name'] - instance.url = form.cleaned_data['url'] - instance.todo_entity = form.cleaned_data['todo_entity'] - instance.enabled = form.cleaned_data['enabled'] - instance.on_shopping_list_entry_created_enabled = form.cleaned_data['on_shopping_list_entry_created_enabled'] - instance.on_shopping_list_entry_updated_enabled = form.cleaned_data['on_shopping_list_entry_updated_enabled'] - instance.on_shopping_list_entry_deleted_enabled = form.cleaned_data['on_shopping_list_entry_deleted_enabled'] + def get_success_url(self): + return reverse('edit_home_assistant_config', kwargs={'pk': self.object.pk}) - if form.cleaned_data['token'] != VALUE_NOT_CHANGED: - instance.token = form.cleaned_data['token'] + def get_context_data(self, **kwargs): + context = super().get_context_data(**kwargs) + context['title'] = _("HomeAssistantConfig") + return context - instance.save() - messages.add_message(request, messages.SUCCESS, _('HomeAssistant config saved!')) - else: - messages.add_message(request, messages.ERROR, _('There was an error updating this config!')) - else: - instance.token = VALUE_NOT_CHANGED - form = HomeAssistantConfigForm(instance=instance) +class ExampleConfigUpdate(GroupRequiredMixin, UpdateView): + groups_required = ['admin'] + template_name = "generic/edit_template.html" + model = ExampleConfig + form_class = ExampleConfigForm - return render( - request, - 'generic/edit_template.html', - {'form': form, 'title': _('HomeAssistantConfig')} - ) + def form_valid(self, form): + messages.add_message(self.request, messages.SUCCESS, _('Config saved!')) + return super().form_valid(form) + + def get_success_url(self): + return reverse('edit_example_config', kwargs={'pk': self.object.pk}) + + def get_context_data(self, **kwargs): + context = super().get_context_data(**kwargs) + context['title'] = _("ExampleConfig") + return context class CommentUpdate(OwnerRequiredMixin, UpdateView): diff --git a/cookbook/views/lists.py b/cookbook/views/lists.py index 20dbb73c..ed43c143 100644 --- a/cookbook/views/lists.py +++ b/cookbook/views/lists.py @@ -6,8 +6,8 @@ from django.utils.translation import gettext as _ from django_tables2 import RequestConfig from cookbook.helper.permission_helper import group_required -from cookbook.models import InviteLink, RecipeImport, Storage, SyncLog, UserFile, HomeAssistantConfig -from cookbook.tables import ImportLogTable, InviteLinkTable, RecipeImportTable, StorageTable, HomeAssistantConfigTable +from cookbook.models import InviteLink, RecipeImport, Storage, SyncLog, UserFile +from cookbook.tables import ImportLogTable, InviteLinkTable, RecipeImportTable, StorageTable @group_required('admin') @@ -65,19 +65,6 @@ def storage(request): ) -@group_required('admin') -def home_assistant_config(request): - table = HomeAssistantConfigTable(HomeAssistantConfig.objects.filter(space=request.space).all()) - RequestConfig(request, paginate={'per_page': 25}).configure(table) - - return render( - request, 'generic/list_template.html', { - 'title': _("HomeAssistant Config Backend"), - 'table': table, - 'create_url': 'new_home_assistant_config' - }) - - @group_required('admin') def invite_link(request): table = InviteLinkTable( diff --git a/cookbook/views/new.py b/cookbook/views/new.py index 263dca09..22bfbc84 100644 --- a/cookbook/views/new.py +++ b/cookbook/views/new.py @@ -5,9 +5,9 @@ from django.urls import reverse, reverse_lazy from django.utils.translation import gettext as _ from django.views.generic import CreateView -from cookbook.forms import ImportRecipeForm, Storage, StorageForm, HomeAssistantConfigForm +from cookbook.forms import ImportRecipeForm, Storage, StorageForm, HomeAssistantConfigForm, ExampleConfigForm from cookbook.helper.permission_helper import GroupRequiredMixin, above_space_limit, group_required -from cookbook.models import Recipe, RecipeImport, ShareLink, Step, HomeAssistantConfig +from cookbook.models import Recipe, RecipeImport, ShareLink, Step, HomeAssistantConfig, ExampleConfig from recipes import settings @@ -77,6 +77,40 @@ class HomeAssistantConfigCreate(GroupRequiredMixin, CreateView): form_class = HomeAssistantConfigForm success_url = reverse_lazy('list_home_assistant_config') + def get_form_class(self): + form_class = super().get_form_class() + + if self.request.method == 'GET': + update_token_field = form_class.base_fields['update_token'] + update_token_field.required = True + + return form_class + + def form_valid(self, form): + if self.request.space.demo or settings.HOSTED: + messages.add_message(self.request, messages.ERROR, _('This feature is not yet available in the hosted version of tandoor!')) + return redirect('index') + + obj = form.save(commit=False) + obj.token = form.cleaned_data['update_token'] + obj.created_by = self.request.user + obj.space = self.request.space + obj.save() + return HttpResponseRedirect(reverse('edit_home_assistant_config', kwargs={'pk': obj.pk})) + + def get_context_data(self, **kwargs): + context = super().get_context_data(**kwargs) + context['title'] = _("HomeAssistant Config Backend") + return context + + +class ExampleConfigCreate(GroupRequiredMixin, CreateView): + groups_required = ['admin'] + template_name = "generic/new_template.html" + model = ExampleConfig + form_class = ExampleConfigForm + success_url = reverse_lazy('list_connectors') + def form_valid(self, form): if self.request.space.demo or settings.HOSTED: messages.add_message(self.request, messages.ERROR, _('This feature is not yet available in the hosted version of tandoor!')) @@ -86,11 +120,11 @@ class HomeAssistantConfigCreate(GroupRequiredMixin, CreateView): obj.created_by = self.request.user obj.space = self.request.space obj.save() - return HttpResponseRedirect(reverse('edit_home_assistant_config', kwargs={'pk': obj.pk})) + return HttpResponseRedirect(reverse('edit_example_config', kwargs={'pk': obj.pk})) def get_context_data(self, **kwargs): - context = super(HomeAssistantConfigCreate, self).get_context_data(**kwargs) - context['title'] = _("HomeAssistant Config Backend") + context = super().get_context_data(**kwargs) + context['title'] = _("Example Config Backend") return context