# -*- coding: utf-8 -*-
# This file is part of Shuup.
#
# Copyright (c) 2012-2021, Shuup Commerce Inc. All rights reserved.
#
# This source code is licensed under the OSL-3.0 license found in the
# LICENSE file in the root directory of this source tree.
from __future__ import unicode_literals
import six
from django.conf import settings
from django.contrib import messages
from django.core.exceptions import ImproperlyConfigured, ValidationError
from django.db.transaction import atomic
from django.forms import BaseFormSet
from django.http import HttpResponseRedirect
from django.utils.translation import ugettext_lazy as _
from django.views.generic import ListView, UpdateView
from shuup.admin.modules.settings.view_settings import ViewSettings
from shuup.admin.signals import object_created, object_saved, view_form_valid
from shuup.admin.toolbar import NewActionButton, SettingsActionButton, Toolbar, get_default_edit_toolbar
from shuup.admin.utils.forms import add_form_errors_as_messages, get_possible_name_fields_for_model
from shuup.admin.utils.picotable import Column, PicotableViewMixin
from shuup.admin.utils.urls import NoModelUrl, get_model_front_url, get_model_url
from shuup.core.settings_provider import ShuupSettings
from shuup.utils.django_compat import force_text
from shuup.utils.excs import Problem
from shuup.utils.form_group import FormGroup
from shuup.utils.multilanguage_model_form import MultiLanguageModelForm
[docs]class CreateOrUpdateView(UpdateView):
add_form_errors_as_messages = False
[docs] def get_object(self, queryset=None):
if not self.kwargs.get(self.pk_url_kwarg):
return self.model()
return super(CreateOrUpdateView, self).get_object(queryset)
[docs] def get_context_data(self, **kwargs):
context = super(CreateOrUpdateView, self).get_context_data(**kwargs)
context["is_new"] = not self.object.pk
context["front_url"] = get_model_front_url(self.request, self.object)
context["title"] = get_create_or_change_title(self.request, self.object)
context["save_form_id"] = self.get_save_form_id()
context["toolbar"] = self.get_toolbar()
context["iframe_mode"] = bool(self.request.GET.get("mode", "") == "iframe")
if context["iframe_mode"] and self.object and self.object.id is not None:
name = None
for field in get_possible_name_fields_for_model(self.object.__class__):
name = getattr(self.object, field, None)
if name:
break
context["iframe_close"] = bool(self.request.GET.get("iframe_close"))
context["quick_add_target"] = self.request.GET.get("quick_add_target", "")
context["quick_add_callback"] = self.request.GET.get("quick_add_callback", "")
context["quick_add_option_id"] = self.object.id
context["quick_add_option_name"] = name if name else _("Unnamed")
return context
[docs] def get_return_url(self):
return get_model_url(self.object, kind="list", shop=self.request.shop)
[docs] def get_new_url(self):
return get_model_url(self.object, kind="new", shop=self.request.shop)
[docs] def get_success_url(self): # noqa (C901)
if self.request.GET.get("mode", "") == "iframe":
params = ["mode=iframe", "iframe_close=yes"]
quick_add_target = self.request.GET.get("quick_add_target")
if quick_add_target:
params.append("quick_add_target=%s" % quick_add_target)
quick_add_callback = self.request.GET.get("quick_add_callback")
if quick_add_callback:
params.append("quick_add_callback=%s" % quick_add_callback)
return "%s?%s" % (get_model_url(self.object, shop=self.request.shop), "&".join(params))
next = self.request.POST.get("__next")
try:
if next == "return":
return self.get_return_url()
elif next == "new":
return self.get_new_url()
except NoModelUrl:
pass
try:
return super(CreateOrUpdateView, self).get_success_url()
except ImproperlyConfigured:
pass
try:
return get_model_url(self.object, shop=self.request.shop)
except NoModelUrl:
pass
@atomic()
def _add_create_or_change_message(self, request, object, is_new):
add_create_or_change_message(request, object, is_new)
[docs]def add_create_or_change_message(request, instance, is_new):
if instance:
msg = instance._meta.verbose_name if is_new else instance._meta.verbose_name.title()
else:
msg = _("Item") # instance is not always present. For example when saving configurations.
if is_new:
msg = _("New %s was created.") % msg
else:
msg = _("%s was edited.") % msg
messages.success(request, msg)
[docs]def get_create_or_change_title(request, instance, name_field=None):
"""
Get a title suitable for an create-or-update view.
:param request: Request.
:type request: HttpRequest
:param instance: Model instance.
:type instance: django.db.models.Model
:param name_field: Which property to try to read the name from. If None, use `str`.
:type name_field: str
:return: Title.
:rtype: str
"""
if not instance.pk:
return _("New %s") % instance._meta.verbose_name
if name_field:
name = getattr(instance, name_field, None)
else:
name = "%s" % instance
if name:
return force_text(name)
return _("Unnamed %s") % instance._meta.verbose_name
[docs]def check_and_raise_if_only_one_allowed(setting_name, obj):
if ShuupSettings.get_setting(setting_name):
return
if not obj.pk and obj.__class__.objects.count() >= 1:
raise Problem(_("Only one %(model)s permitted.") % {"model": obj._meta.verbose_name})
[docs]class PicotableListView(PicotableViewMixin, ListView):
def __init__(self):
super(PicotableListView, self).__init__()
if self.mass_actions:
self.default_columns = [
Column("select", "", display="", sortable=False, linked=False, class_name="text-center"),
] + self.default_columns
self.settings = ViewSettings(self.model, self.default_columns, view_context=self)
if self.mass_actions:
if self.settings.columns:
# settings.columns never have selects
self.columns = [
Column("select", "", display="", sortable=False, linked=False, class_name="text-center"),
] + self.settings.columns
else:
self.columns = self.default_columns
else:
self.columns = self.settings.columns or self.default_columns
[docs] def get_context_data(self, **kwargs):
context = super(PicotableListView, self).get_context_data(**kwargs)
context["toolbar"] = self.get_toolbar()
return context
[docs] def get_object_abstract(self, instance, item):
return [
{"text": "%s" % instance, "class": "header"},
]
[docs]class MassEditMixin(object):
template_name = "shuup/admin/mass_action/mass_edit.jinja"
title = _("Mass Edit")
[docs] def dispatch(self, request, *args, **kwargs):
self.ids = request.session["mass_action_ids"]
return super(MassEditMixin, self).dispatch(request, *args, **kwargs)
[docs] def get_context_data(self, **kwargs):
context = super(MassEditMixin, self).get_context_data(**kwargs)
context["form"] = self.get_form()
context["edit_title"] = self.title
context["is_all_selected"] = bool(isinstance(self.ids, six.string_types) and self.ids == "all")
if not context["is_all_selected"]:
context["item_count"] = len(self.ids)
return context