Merge pull request #2874 from Mikhail5555/HomeAssistantConnector

Home assistant connector
This commit is contained in:
vabene1111
2024-02-26 08:06:50 +01:00
committed by GitHub
32 changed files with 830 additions and 29 deletions

View File

@@ -77,7 +77,7 @@ from cookbook.models import (Automation, BookmarkletImport, CookLog, CustomFilte
ShoppingListEntry, ShoppingListRecipe, Space, Step, Storage,
Supermarket, SupermarketCategory, SupermarketCategoryRelation, Sync,
SyncLog, Unit, UnitConversion, UserFile, UserPreference, UserSpace,
ViewLog)
ViewLog, ConnectorConfig)
from cookbook.provider.dropbox import Dropbox
from cookbook.provider.local import Local
from cookbook.provider.nextcloud import Nextcloud
@@ -104,7 +104,7 @@ from cookbook.serializer import (AccessTokenSerializer, AutomationSerializer,
SyncLogSerializer, SyncSerializer, UnitConversionSerializer,
UnitSerializer, UserFileSerializer, UserPreferenceSerializer,
UserSerializer, UserSpaceSerializer, ViewLogSerializer,
ShoppingListEntryBulkSerializer)
ShoppingListEntryBulkSerializer, ConnectorConfigConfigSerializer)
from cookbook.views.import_export import get_integration
from recipes import settings
from recipes.settings import FDC_API_KEY, DRF_THROTTLE_RECIPE_URL_IMPORT
@@ -464,6 +464,15 @@ class StorageViewSet(viewsets.ModelViewSet):
return self.queryset.filter(space=self.request.space)
class ConnectorConfigConfigViewSet(viewsets.ModelViewSet):
queryset = ConnectorConfig.objects
serializer_class = ConnectorConfigConfigSerializer
permission_classes = [CustomIsAdmin & CustomTokenHasReadWriteScope]
def get_queryset(self):
return self.queryset.filter(space=self.request.space)
class SyncViewSet(viewsets.ModelViewSet):
queryset = Sync.objects
serializer_class = SyncSerializer

View File

@@ -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)
RecipeImport, Space, Storage, Sync, UserSpace, ConnectorConfig)
from cookbook.provider.dropbox import Dropbox
from cookbook.provider.local import Local
from cookbook.provider.nextcloud import Nextcloud
@@ -122,6 +122,18 @@ class StorageDelete(GroupRequiredMixin, DeleteView):
return HttpResponseRedirect(reverse('list_storage'))
class ConnectorConfigDelete(GroupRequiredMixin, DeleteView):
groups_required = ['admin']
template_name = "generic/delete_template.html"
model = ConnectorConfig
success_url = reverse_lazy('list_connector_config')
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context['title'] = _("Connectors Config Backend")
return context
class CommentDelete(OwnerRequiredMixin, DeleteView):
template_name = "generic/delete_template.html"
model = Comment

View File

@@ -1,3 +1,4 @@
import copy
import os
from django.contrib import messages
@@ -8,14 +9,16 @@ 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
from cookbook.forms import CommentForm, ExternalRecipeForm, StorageForm, SyncForm, ConnectorConfigForm
from cookbook.helper.permission_helper import GroupRequiredMixin, OwnerRequiredMixin, above_space_limit, group_required
from cookbook.models import Comment, Recipe, RecipeImport, Storage, Sync
from cookbook.models import Comment, Recipe, RecipeImport, Storage, Sync, ConnectorConfig
from cookbook.provider.dropbox import Dropbox
from cookbook.provider.local import Local
from cookbook.provider.nextcloud import Nextcloud
from recipes import settings
VALUE_NOT_CHANGED = '__NO__CHANGE__'
@group_required('guest')
def switch_recipe(request, pk):
@@ -75,7 +78,7 @@ class SyncUpdate(GroupRequiredMixin, UpdateView, SpaceFormMixing):
@group_required('admin')
def edit_storage(request, pk):
instance = get_object_or_404(Storage, pk=pk, space=request.space)
instance: Storage = get_object_or_404(Storage, pk=pk, space=request.space)
if not (instance.created_by == request.user or request.user.is_superuser):
messages.add_message(request, messages.ERROR, _('You cannot edit this storage!'))
@@ -86,17 +89,18 @@ def edit_storage(request, pk):
return redirect('index')
if request.method == "POST":
form = StorageForm(request.POST, instance=instance)
form = StorageForm(request.POST, instance=copy.deepcopy(instance))
if form.is_valid():
instance.name = form.cleaned_data['name']
instance.method = form.cleaned_data['method']
instance.username = form.cleaned_data['username']
instance.url = form.cleaned_data['url']
instance.path = form.cleaned_data['path']
if form.cleaned_data['password'] != '__NO__CHANGE__':
if form.cleaned_data['password'] != VALUE_NOT_CHANGED:
instance.password = form.cleaned_data['password']
if form.cleaned_data['token'] != '__NO__CHANGE__':
if form.cleaned_data['token'] != VALUE_NOT_CHANGED:
instance.token = form.cleaned_data['token']
instance.save()
@@ -106,13 +110,39 @@ def edit_storage(request, pk):
messages.add_message(request, messages.ERROR, _('There was an error updating this storage backend!'))
else:
pseudo_instance = instance
pseudo_instance.password = '__NO__CHANGE__'
pseudo_instance.token = '__NO__CHANGE__'
pseudo_instance.password = VALUE_NOT_CHANGED
pseudo_instance.token = VALUE_NOT_CHANGED
form = StorageForm(instance=pseudo_instance)
return render(request, 'generic/edit_template.html', {'form': form, 'title': _('Storage')})
class ConnectorConfigUpdate(GroupRequiredMixin, UpdateView):
groups_required = ['admin']
template_name = "generic/edit_template.html"
model = ConnectorConfig
form_class = ConnectorConfigForm
def get_form_kwargs(self):
kwargs = super().get_form_kwargs()
kwargs['initial']['update_token'] = VALUE_NOT_CHANGED
return kwargs
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(ConnectorConfigUpdate, self).form_valid(form)
def get_success_url(self):
return reverse('edit_connector_config', kwargs={'pk': self.object.pk})
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context['title'] = _("ConnectorConfig")
return context
class CommentUpdate(OwnerRequiredMixin, UpdateView):
template_name = "generic/edit_template.html"
model = Comment

View File

@@ -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
from cookbook.tables import ImportLogTable, InviteLinkTable, RecipeImportTable, StorageTable
from cookbook.models import InviteLink, RecipeImport, Storage, SyncLog, UserFile, ConnectorConfig
from cookbook.tables import ImportLogTable, InviteLinkTable, RecipeImportTable, StorageTable, ConnectorConfigTable
@group_required('admin')
@@ -65,6 +65,22 @@ def storage(request):
)
@group_required('admin')
def connector_config(request):
table = ConnectorConfigTable(ConnectorConfig.objects.filter(space=request.space).all())
RequestConfig(request, paginate={'per_page': 25}).configure(table)
return render(
request,
'generic/list_template.html',
{
'title': _("Connector Config Backend"),
'table': table,
'create_url': 'new_connector_config'
}
)
@group_required('admin')
def invite_link(request):
table = InviteLinkTable(

View File

@@ -1,4 +1,3 @@
from django.contrib import messages
from django.http import HttpResponseRedirect
from django.shortcuts import get_object_or_404, redirect, render
@@ -6,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
from cookbook.forms import ImportRecipeForm, Storage, StorageForm, ConnectorConfigForm
from cookbook.helper.permission_helper import GroupRequiredMixin, above_space_limit, group_required
from cookbook.models import Recipe, RecipeImport, ShareLink, Step
from cookbook.models import Recipe, RecipeImport, ShareLink, Step, ConnectorConfig
from recipes import settings
@@ -71,6 +70,35 @@ class StorageCreate(GroupRequiredMixin, CreateView):
return context
class ConnectorConfigCreate(GroupRequiredMixin, CreateView):
groups_required = ['admin']
template_name = "generic/new_template.html"
model = ConnectorConfig
form_class = ConnectorConfigForm
success_url = reverse_lazy('list_connector_config')
def form_valid(self, form):
if self.request.space.demo:
messages.add_message(self.request, messages.ERROR, _('This feature is not yet available in the hosted version of tandoor!'))
return redirect('index')
if settings.DISABLE_EXTERNAL_CONNECTORS:
messages.add_message(self.request, messages.ERROR, _('This feature is not enabled by the server admin!'))
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_connector_config', kwargs={'pk': obj.pk}))
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context['title'] = _("Connector Config Backend")
return context
@group_required('user')
def create_new_external_recipe(request, import_id):
if request.method == "POST":