# -*- 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 enumfields
from django import forms
from django.apps import apps
from django.core.exceptions import ObjectDoesNotExist
from django.core.validators import validate_email
from django.utils.text import camel_case_to_spaces
from django.utils.translation import ugettext_lazy as _
[docs]class MultiEmailField(forms.Field):
"""
From https://docs.djangoproject.com/en/1.11/ref/forms/validation/#form-field-default-cleaning
"""
[docs] def validate(self, value):
"""Check if value consists only of valid emails."""
# Use the parent's handling of required fields, etc.
super().validate(value)
if value:
for email in value.split(","):
if email:
validate_email(email)
[docs]class Type(object):
name = None
identifier = None
[docs] def get_field(self, **kwargs):
"""
Get a Django form field for this type.
The kwargs are passed directly to the field
constructor.
:param kwargs: Kwargs for field constructor.
:type kwargs: dict
:return: Form field.
:rtype: django.forms.Field
"""
return forms.CharField(**kwargs)
[docs] def unserialize(self, value):
return self.get_field().to_python(value)
[docs] def validate(self, value):
return self.get_field().validate(value)
[docs] def is_coercible_from(self, other_type):
return self.identifier == other_type.identifier
class _String(Type):
pass
class _Number(Type):
pass
[docs]class Boolean(Type):
name = _("Boolean")
identifier = "boolean"
[docs] def get_field(self, **kwargs):
return forms.BooleanField(**kwargs)
[docs]class Integer(_Number):
name = _("Integer Number")
identifier = "integer"
[docs] def get_field(self, **kwargs):
return forms.IntegerField(**kwargs)
[docs]class Decimal(_Number):
name = _("Decimal Number")
identifier = "decimal"
[docs] def get_field(self, **kwargs):
return forms.DecimalField(**kwargs)
[docs]class Text(_String):
name = _("Text")
identifier = "text"
[docs] def is_coercible_from(self, other_type):
# All variables can be used as raw text
return True
[docs]class Language(_String):
name = _("Language")
identifier = "language"
[docs]class Email(_String):
name = _("Email Address")
identifier = "email"
[docs] def get_field(self, **kwargs):
return MultiEmailField(**kwargs)
[docs]class URL(_String):
name = _("URL Address")
identifier = "url"
[docs] def get_field(self, **kwargs):
return forms.URLField(**kwargs)
[docs]class Phone(_String):
name = _("Phone Number")
identifier = "phone"
[docs]class Model(Type):
model_label = None
identifier = "model"
@property
def name(self):
return self.get_model()._meta.verbose_name
def __init__(self, model_label):
"""
:param model_label: Model label in Django `app.Model` format (e.g. `shuup.Order`).
:type model_label: str
"""
self.model_label = model_label
[docs] def unserialize(self, value):
if isinstance(value, self.get_model()):
return value
try:
return self.get_model().objects.get(pk=value)
except ObjectDoesNotExist:
return None
[docs] def is_coercible_from(self, other_type):
return isinstance(other_type, Model) and self.get_model() == other_type.get_model()
[docs] def get_model(self):
"""
:rtype: django.db.models.Model
"""
return apps.get_model(self.model_label)
[docs] def get_field(self, **kwargs):
kwargs.setdefault("queryset", self.get_model().objects.all())
return forms.ModelChoiceField(**kwargs)
[docs]class Enum(Type):
enum_class = None
identifier = "enum"
@property
def name(self):
if self.enum_class:
return camel_case_to_spaces(self.enum_class.__class__.__name__)
return "<Invalid Enum>"
def __init__(self, enum_class):
self.enum_class = enum_class
assert issubclass(enum_class, enumfields.Enum), "%r is not an enum" % enum_class
[docs] def unserialize(self, value):
if isinstance(value, self.enum_class):
return value
try:
return self.enum_class(value)
except ValueError:
try:
return self.enum_class(int(value))
except ValueError:
pass
return None
[docs] def get_field(self, **kwargs):
return enumfields.EnumField(self.enum_class).formfield(**kwargs)