diff --git a/.env.example b/.env.example
deleted file mode 100644
index 15bbe394..00000000
--- a/.env.example
+++ /dev/null
@@ -1,5 +0,0 @@
-SECRET_KEY=k_=*vfue(^campsl63)7w5m&cu9u4o4-!vaw94qzyrymyv0hgg
-DEBUG=True
-ALLOWED_HOSTS=.localhost,127.0.0.1
-DATABASE_URL=postgres://USER:PASSWORD@HOST:PORT/NAME
-STATIC_ROOT=PATH_TO_STATIC_ROOT
diff --git a/INSTALL_RIBAGUIFI_STYLE.md b/INSTALL_RIBAGUIFI_STYLE.md
deleted file mode 100644
index ee821040..00000000
--- a/INSTALL_RIBAGUIFI_STYLE.md
+++ /dev/null
@@ -1,70 +0,0 @@
-We need have python3.6
-
-#Install Packages
-```bash
-apt=(
- bind9utils
- ca-certificates
- gettext
- libcrack2-dev
- libxml2-dev
- libxslt1-dev
- ssh-client
- wget
- xvfb
- zlib1g-dev
- git
- iceweasel
- dnsutils
- postgresql-contrib
-)
-sudo apt-get install --no-install-recommends -y ${apt[@]}
-```
-
-It is necessary install *wkhtmltopdf*
-You can install it from https://wkhtmltopdf.org/downloads.html
-
-Clone this repository
-```bash
-git clone https://github.com/ribaguifi/django-orchestra
-```
-
-Prepare env and install requirements
-```bash
-cd django-orchestra
-python3.6 -m venv env
-source env/bin/activate
-pip3 install --upgrade pip
-pip3 install -r total_requirements.txt
-pip3 install -e .
-```
-
-Configure project using environment file (you can use provided example as quickstart):
-```bash
-cp .env.example .env
-```
-
-Prepare your Postgres database (create database, user and grant permissions):
-```sql
-CREATE DATABASE myproject;
-CREATE USER myuser WITH PASSWORD 'password';
-GRANT ALL PRIVILEGES ON DATABASE myproject TO myuser;
-```
-
-Prepare a new project:
-
-```bash
-django-admin.py startproject PROJECT_NAME --template="orchestra/conf/ribaguifi_template"
-```
-
-Run migrations:
-```bash
-python3 manage.py migrate
-```
-
-(Optional) You can start a Django development server to check that everything is ok.
-```bash
-python3 manage.py runserver
-```
-
-Open [http://127.0.0.1:8000/](http://127.0.0.1:8000/) in your browser.
diff --git a/install_manually.md b/install_manually.md
index 51d8c660..a2747041 100644
--- a/install_manually.md
+++ b/install_manually.md
@@ -93,7 +93,7 @@ Remember create a database for your project and give permitions for the correct
```
psql -U postgres
psql (12.4)
-Digite «help».
+Digite «help» para obtener ayuda.
postgres=# CREATE database orchesta;
postgres=# CREATE USER orchesta WITH PASSWORD 'orquesta';
diff --git a/orchestra/api/serializers.py b/orchestra/api/serializers.py
index 1fd1bb8c..01005771 100644
--- a/orchestra/api/serializers.py
+++ b/orchestra/api/serializers.py
@@ -17,7 +17,7 @@ class SetPasswordSerializer(serializers.Serializer):
class HyperlinkedModelSerializer(serializers.HyperlinkedModelSerializer):
""" support for postonly_fields, fields whose value can only be set on post """
-
+
def validate(self, attrs):
""" calls model.clean() """
attrs = super(HyperlinkedModelSerializer, self).validate(attrs)
@@ -39,7 +39,7 @@ class HyperlinkedModelSerializer(serializers.HyperlinkedModelSerializer):
instance = ModelClass(**validated_data)
instance.clean()
return attrs
-
+
def post_only_cleanning(self, instance, validated_data):
""" removes postonly_fields from attrs """
model_attrs = dict(**validated_data)
@@ -49,12 +49,12 @@ class HyperlinkedModelSerializer(serializers.HyperlinkedModelSerializer):
if attr in post_only_fields:
model_attrs.pop(attr)
return model_attrs
-
+
def update(self, instance, validated_data):
""" removes postonly_fields from attrs when not posting """
model_attrs = self.post_only_cleanning(instance, validated_data)
return super(HyperlinkedModelSerializer, self).update(instance, model_attrs)
-
+
def partial_update(self, instance, validated_data):
""" removes postonly_fields from attrs when not posting """
model_attrs = self.post_only_cleanning(instance, validated_data)
@@ -64,7 +64,10 @@ class HyperlinkedModelSerializer(serializers.HyperlinkedModelSerializer):
class RelatedHyperlinkedModelSerializer(HyperlinkedModelSerializer):
""" returns object on to_internal_value based on URL """
def to_internal_value(self, data):
- url = data.get('url')
+ try:
+ url = data.get('url')
+ except AttributeError:
+ url = None
if not url:
raise ValidationError({
'url': "URL is required."
@@ -80,16 +83,16 @@ class SetPasswordHyperlinkedSerializer(HyperlinkedModelSerializer):
password = serializers.CharField(max_length=128, label=_('Password'),
validators=[validate_password], write_only=True, required=False,
style={'widget': widgets.PasswordInput})
-
- def validate_password(self, attrs, source):
+
+ def validate_password(self, value):
""" POST only password """
if self.instance:
- if 'password' in attrs:
+ if value:
raise serializers.ValidationError(_("Can not set password"))
- elif 'password' not in attrs:
+ elif not value:
raise serializers.ValidationError(_("Password required"))
- return attrs
-
+ return value
+
def validate(self, attrs):
""" remove password in case is not a real model field """
try:
@@ -102,7 +105,7 @@ class SetPasswordHyperlinkedSerializer(HyperlinkedModelSerializer):
if password is not None:
attrs['password'] = password
return attrs
-
+
def create(self, validated_data):
password = validated_data.pop('password')
instance = self.Meta.model(**validated_data)
diff --git a/orchestra/conf/project_template/project_name/settings.py b/orchestra/conf/project_template/project_name/settings.py
index c59610d7..82b244f9 100644
--- a/orchestra/conf/project_template/project_name/settings.py
+++ b/orchestra/conf/project_template/project_name/settings.py
@@ -66,6 +66,7 @@ INSTALLED_APPS = [
'admin_tools.dashboard',
'rest_framework',
'rest_framework.authtoken',
+ 'django_filters',
'passlib.ext.django',
'django_countries',
# 'debug_toolbar',
diff --git a/orchestra/conf/ribaguifi_template/locale/.gitignore b/orchestra/conf/ribaguifi_template/locale/.gitignore
deleted file mode 100644
index e69de29b..00000000
diff --git a/orchestra/conf/ribaguifi_template/manage.py b/orchestra/conf/ribaguifi_template/manage.py
deleted file mode 100755
index ee4b9652..00000000
--- a/orchestra/conf/ribaguifi_template/manage.py
+++ /dev/null
@@ -1,13 +0,0 @@
-#!/usr/bin/env python3
-import os
-import sys
-
-
-if __name__ == "__main__":
- if sys.version_info < (3, 3):
- cmd = ' '.join(sys.argv)
- sys.stderr.write("Sorry, Orchestra requires at least Python 3.3, try with:\n$ python3 %s\n" % cmd)
- sys.exit(1)
- os.environ.setdefault("DJANGO_SETTINGS_MODULE", "{{ project_name }}.settings")
- from django.core.management import execute_from_command_line
- execute_from_command_line(sys.argv)
diff --git a/orchestra/conf/ribaguifi_template/media/.gitignore b/orchestra/conf/ribaguifi_template/media/.gitignore
deleted file mode 100644
index e69de29b..00000000
diff --git a/orchestra/conf/ribaguifi_template/project_name/__init__.py b/orchestra/conf/ribaguifi_template/project_name/__init__.py
deleted file mode 100644
index e69de29b..00000000
diff --git a/orchestra/conf/ribaguifi_template/project_name/settings.py b/orchestra/conf/ribaguifi_template/project_name/settings.py
deleted file mode 100644
index 2fa397a5..00000000
--- a/orchestra/conf/ribaguifi_template/project_name/settings.py
+++ /dev/null
@@ -1,257 +0,0 @@
-"""
-Django settings for {{ project_name }} project.
-
-Generated by 'django-admin startproject' using Django {{ django_version }}.
-
-For more information on this file, see
-https://docs.djangoproject.com/en/{{ docs_version }}/topics/settings/
-
-For the full list of settings and their values, see
-https://docs.djangoproject.com/en/{{ docs_version }}/ref/settings/
-"""
-
-import os
-from decouple import config, Csv
-from dj_database_url import parse as db_url
-
-# Build paths inside the project like this: os.path.join(BASE_DIR, ...)
-BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
-
-
-# Quick-start development settings - unsuitable for production
-# See https://docs.djangoproject.com/en/{{ docs_version }}/howto/deployment/checklist/
-
-# SECURITY WARNING: keep the secret key used in production secret!
-SECRET_KEY = '{{ secret_key }}'
-# SECRET_KEY = config('SECRET_KEY')
-
-# SECURITY WARNING: don't run with debug turned on in production!
-DEBUG = config('DEBUG', default=False, cast=bool)
-ALLOWED_HOSTS = config('ALLOWED_HOSTS', default=[], cast=Csv())
-
-
-# Application definition
-
-INSTALLED_APPS = [
- # django-orchestra apps
- 'orchestra',
- 'orchestra.contrib.accounts',
- 'orchestra.contrib.systemusers',
- 'orchestra.contrib.contacts',
- 'orchestra.contrib.orchestration',
- 'orchestra.contrib.bills',
- 'orchestra.contrib.payments',
- 'orchestra.contrib.tasks',
- 'orchestra.contrib.mailer',
- 'orchestra.contrib.history',
- 'orchestra.contrib.issues',
- 'orchestra.contrib.services',
- 'orchestra.contrib.plans',
- 'orchestra.contrib.orders',
- 'orchestra.contrib.domains',
- 'orchestra.contrib.mailboxes',
- 'orchestra.contrib.lists',
- 'orchestra.contrib.webapps',
- 'orchestra.contrib.websites',
- 'orchestra.contrib.letsencrypt',
- 'orchestra.contrib.databases',
- 'orchestra.contrib.vps',
- 'orchestra.contrib.saas',
- 'orchestra.contrib.miscellaneous',
-
- # Third-party apps
- 'django_extensions',
- 'djcelery',
- 'fluent_dashboard',
- 'admin_tools',
- 'admin_tools.theming',
- 'admin_tools.menu',
- 'admin_tools.dashboard',
- 'rest_framework',
- 'rest_framework.authtoken',
- 'passlib.ext.django',
- 'django_countries',
-# 'debug_toolbar',
-
- # Django.contrib
- 'django.contrib.auth',
- 'django.contrib.contenttypes',
- 'django.contrib.sessions',
- 'django.contrib.messages',
- 'django.contrib.staticfiles',
- 'django.contrib.admin.apps.SimpleAdminConfig',
-
- # Last to load
- 'orchestra.contrib.resources',
- 'orchestra.contrib.settings',
-# 'django_nose',
-]
-
-
-ROOT_URLCONF = '{{ project_name }}.urls'
-
-TEMPLATES = [
- {
- 'BACKEND': 'django.template.backends.django.DjangoTemplates',
- 'DIRS': [],
- 'OPTIONS': {
- 'context_processors': [
- 'django.template.context_processors.debug',
- 'django.template.context_processors.request',
- 'django.contrib.auth.context_processors.auth',
- 'django.contrib.messages.context_processors.messages',
- 'orchestra.core.context_processors.site',
- ],
- 'loaders': [
- 'admin_tools.template_loaders.Loader',
- 'django.template.loaders.filesystem.Loader',
- 'django.template.loaders.app_directories.Loader',
- ],
- },
- },
-]
-
-
-WSGI_APPLICATION = '{{ project_name }}.wsgi.application'
-
-
-# Database
-# https://docs.djangoproject.com/en/{{ docs_version }}/ref/settings/#databases
-
-DATABASES = {
- 'default': config(
- 'DATABASE_URL',
- default='sqlite:///' + os.path.join(BASE_DIR, 'db.sqlite3'),
- cast=db_url
- )
-}
-
-
-# Internationalization
-# https://docs.djangoproject.com/en/{{ docs_version }}/topics/i18n/
-
-LANGUAGE_CODE = 'en-us'
-
-
-try:
- TIME_ZONE = open('/etc/timezone', 'r').read().strip()
-except IOError:
- TIME_ZONE = 'UTC'
-
-USE_I18N = True
-
-USE_L10N = True
-
-USE_TZ = True
-
-# Static files (CSS, JavaScript, Images)
-# https://docs.djangoproject.com/en/{{ docs_version }}/howto/static-files/
-
-STATIC_URL = '/static/'
-
-
-# Absolute path to the directory static files should be collected to.
-# Don't put anything in this directory yourself; store your static files
-# in apps' "static/" subdirectories and in STATICFILES_DIRS.
-# Example: "/home/media/media.lawrence.com/static/"
-STATIC_ROOT = os.path.join(BASE_DIR, 'static')
-
-# Absolute filesystem path to the directory that will hold user-uploaded files.
-MEDIA_ROOT = os.path.join(BASE_DIR, 'media')
-
-
-# Path used for database translations files
-LOCALE_PATHS = (
- os.path.join(BASE_DIR, 'locale'),
-)
-
-ORCHESTRA_SITE_NAME = '{{ project_name }}'
-
-
-MIDDLEWARE_CLASSES = (
- 'django.contrib.sessions.middleware.SessionMiddleware',
- 'django.middleware.common.CommonMiddleware',
- 'django.middleware.csrf.CsrfViewMiddleware',
- 'django.contrib.auth.middleware.AuthenticationMiddleware',
- 'django.contrib.auth.middleware.SessionAuthenticationMiddleware',
- # 'django.middleware.locale.LocaleMiddleware'
- 'django.contrib.messages.middleware.MessageMiddleware',
- 'django.middleware.clickjacking.XFrameOptionsMiddleware',
- 'django.middleware.security.SecurityMiddleware',
- 'orchestra.core.caches.RequestCacheMiddleware',
- # also handles transations, ATOMIC_REQUESTS does not wrap middlewares
- 'orchestra.contrib.orchestration.middlewares.OperationsMiddleware',
-)
-
-
-AUTH_USER_MODEL = 'accounts.Account'
-
-
-AUTHENTICATION_BACKENDS = [
- 'orchestra.permissions.auth.OrchestraPermissionBackend',
- 'django.contrib.auth.backends.ModelBackend',
-]
-
-
-EMAIL_BACKEND = 'orchestra.contrib.mailer.backends.EmailBackend'
-
-
-# Needed for Bulk operations
-DATA_UPLOAD_MAX_NUMBER_FIELDS = None
-
-
-#################################
-## 3RD PARTY APPS CONIGURATION ##
-#################################
-
-# Admin Tools
-ADMIN_TOOLS_MENU = 'orchestra.admin.menu.OrchestraMenu'
-
-# Fluent dashboard
-ADMIN_TOOLS_INDEX_DASHBOARD = 'orchestra.admin.dashboard.OrchestraIndexDashboard'
-FLUENT_DASHBOARD_ICON_THEME = '../orchestra/icons'
-
-
-# Django-celery
-import djcelery
-djcelery.setup_loader()
-CELERYBEAT_SCHEDULER = 'djcelery.schedulers.DatabaseScheduler'
-
-
-# rest_framework
-REST_FRAMEWORK = {
- 'DEFAULT_PERMISSION_CLASSES': (
- 'orchestra.permissions.api.OrchestraPermissionBackend',
- ),
- 'DEFAULT_AUTHENTICATION_CLASSES': (
- 'rest_framework.authentication.SessionAuthentication',
- 'rest_framework.authentication.TokenAuthentication',
- ),
- 'DEFAULT_FILTER_BACKENDS': (
- ('django_filters.rest_framework.DjangoFilterBackend',)
- ),
-}
-
-
-# Use a UNIX compatible hash
-PASSLIB_CONFIG = (
- "[passlib]\n"
- "schemes = sha512_crypt, django_pbkdf2_sha256, django_pbkdf2_sha1, "
- " django_bcrypt, django_bcrypt_sha256, django_salted_sha1, des_crypt, "
- " django_salted_md5, django_des_crypt, hex_md5, bcrypt, phpass\n"
- "default = sha512_crypt\n"
- "deprecated = django_pbkdf2_sha1, django_salted_sha1, django_salted_md5, "
- " django_des_crypt, des_crypt, hex_md5\n"
- "all__vary_rounds = 0.05\n"
- "django_pbkdf2_sha256__min_rounds = 10000\n"
- "sha512_crypt__min_rounds = 80000\n"
- "staff__django_pbkdf2_sha256__default_rounds = 12500\n"
- "staff__sha512_crypt__default_rounds = 100000\n"
- "superuser__django_pbkdf2_sha256__default_rounds = 15000\n"
- "superuser__sha512_crypt__default_rounds = 120000\n"
-)
-
-
-SHELL_PLUS_PRE_IMPORTS = (
- ('orchestra.contrib.orchestration.managers', ('orchestrate',)),
-)
diff --git a/orchestra/conf/ribaguifi_template/project_name/urls.py b/orchestra/conf/ribaguifi_template/project_name/urls.py
deleted file mode 100644
index 3ae27421..00000000
--- a/orchestra/conf/ribaguifi_template/project_name/urls.py
+++ /dev/null
@@ -1,6 +0,0 @@
-from django.conf.urls import include, url
-
-
-urlpatterns = [
- url(r'', include('orchestra.urls')),
-]
diff --git a/orchestra/conf/ribaguifi_template/project_name/wsgi.py b/orchestra/conf/ribaguifi_template/project_name/wsgi.py
deleted file mode 100644
index 94d60c8c..00000000
--- a/orchestra/conf/ribaguifi_template/project_name/wsgi.py
+++ /dev/null
@@ -1,14 +0,0 @@
-"""
-WSGI config for {{ project_name }} project.
-
-It exposes the WSGI callable as a module-level variable named ``application``.
-
-For more information on this file, see
-https://docs.djangoproject.com/en/{{ docs_version }}/howto/deployment/wsgi/
-"""
-
-import os
-os.environ.setdefault("DJANGO_SETTINGS_MODULE", "{{ project_name }}.settings")
-
-from django.core.wsgi import get_wsgi_application
-application = get_wsgi_application()
diff --git a/orchestra/contrib/mailboxes/admin.py b/orchestra/contrib/mailboxes/admin.py
index f1b54feb..3314b1db 100644
--- a/orchestra/contrib/mailboxes/admin.py
+++ b/orchestra/contrib/mailboxes/admin.py
@@ -252,7 +252,7 @@ class AddressAdmin(SelectAccountAdminMixin, ExtendedModelAdmin):
def display_mailboxes(self, address):
boxes = address.mailboxes.all()
return format_html_join(
- '
', '{}',
+ mark_safe('
'), '{}',
[(change_url(mailbox), mailbox.name) for mailbox in boxes]
)
display_mailboxes.short_description = _("Mailboxes")
@@ -261,7 +261,7 @@ class AddressAdmin(SelectAccountAdminMixin, ExtendedModelAdmin):
def display_all_mailboxes(self, address):
boxes = address.get_mailboxes()
return format_html_join(
- '
', '{}',
+ mark_safe('
'), '{}',
[(change_url(mailbox), mailbox.name) for mailbox in boxes]
)
display_all_mailboxes.short_description = _("Mailboxes links")
diff --git a/orchestra/contrib/mailboxes/api.py b/orchestra/contrib/mailboxes/api.py
index 16d926d3..e17b68dc 100644
--- a/orchestra/contrib/mailboxes/api.py
+++ b/orchestra/contrib/mailboxes/api.py
@@ -4,7 +4,7 @@ from orchestra.api import router, SetPasswordApiMixin, LogApiMixin
from orchestra.contrib.accounts.api import AccountApiMixin
from .models import Address, Mailbox
-from .serializers import AddressSerializer, MailboxSerializer
+from .serializers import AddressSerializer, MailboxSerializer, MailboxWritableSerializer
class AddressViewSet(LogApiMixin, AccountApiMixin, viewsets.ModelViewSet):
@@ -17,6 +17,12 @@ class MailboxViewSet(LogApiMixin, SetPasswordApiMixin, AccountApiMixin, viewsets
queryset = Mailbox.objects.prefetch_related('addresses__domain').all()
serializer_class = MailboxSerializer
+ def get_serializer_class(self):
+ if self.request.method == 'GET':
+ return self.serializer_class
+
+ return MailboxWritableSerializer
+
router.register(r'mailboxes', MailboxViewSet)
router.register(r'addresses', AddressViewSet)
diff --git a/orchestra/contrib/mailboxes/serializers.py b/orchestra/contrib/mailboxes/serializers.py
index 264afac8..1608a6ce 100644
--- a/orchestra/contrib/mailboxes/serializers.py
+++ b/orchestra/contrib/mailboxes/serializers.py
@@ -1,3 +1,4 @@
+from django.db import transaction
from rest_framework import serializers
from orchestra.api.serializers import SetPasswordHyperlinkedSerializer, RelatedHyperlinkedModelSerializer
@@ -8,7 +9,7 @@ from .models import Mailbox, Address
class RelatedDomainSerializer(AccountSerializerMixin, RelatedHyperlinkedModelSerializer):
class Meta:
- model = Address.domain.field.model
+ model = Address.domain.field.related_model
fields = ('url', 'id', 'name')
@@ -35,6 +36,41 @@ class MailboxSerializer(AccountSerializerMixin, SetPasswordHyperlinkedSerializer
postonly_fields = ('name', 'password')
+class AddressRelatedField(serializers.HyperlinkedRelatedField):
+ # Filter addresses by account (user)
+ def get_queryset(self):
+ qs = super().get_queryset()
+ return qs.filter(account=self.context['account'])
+
+
+class MailboxWritableSerializer(AccountSerializerMixin, SetPasswordHyperlinkedSerializer):
+ addresses = AddressRelatedField(many=True, view_name='address-detail', queryset=Address.objects.all())
+
+ class Meta:
+ model = Mailbox
+ fields = (
+ 'url', 'id', 'name', 'password', 'filtering', 'custom_filtering', 'addresses', 'is_active'
+ )
+ postonly_fields = ('name', 'password')
+
+ def __init__(self, *args, **kwargs):
+ super().__init__(*args, **kwargs)
+ self.fields['addresses'].context['account'] = self.account
+
+ @transaction.atomic
+ def create(self, validated_data):
+ addresses = validated_data.pop('addresses', [])
+ instance = super().create(validated_data)
+ instance.addresses.set(addresses)
+ return instance
+
+ @transaction.atomic
+ def update(self, instance, validated_data):
+ addresses = validated_data.pop('addresses', [])
+ instance.addresses.set(addresses)
+ return super().update(instance, validated_data)
+
+
class RelatedMailboxSerializer(AccountSerializerMixin, RelatedHyperlinkedModelSerializer):
class Meta:
model = Mailbox
@@ -43,7 +79,7 @@ class RelatedMailboxSerializer(AccountSerializerMixin, RelatedHyperlinkedModelSe
class AddressSerializer(AccountSerializerMixin, serializers.HyperlinkedModelSerializer):
domain = RelatedDomainSerializer()
- mailboxes = RelatedMailboxSerializer(many=True, required=False) #allow_add_remove=True
+ mailboxes = RelatedMailboxSerializer(many=True, required=False)
class Meta:
model = Address
@@ -51,6 +87,21 @@ class AddressSerializer(AccountSerializerMixin, serializers.HyperlinkedModelSeri
def validate(self, attrs):
attrs = super(AddressSerializer, self).validate(attrs)
- if not attrs['mailboxes'] and not attrs['forward']:
+ mailboxes = attrs.get('mailboxes', [])
+ forward = attrs.get('forward', '')
+ if not mailboxes and not forward:
raise serializers.ValidationError("A mailbox or forward address should be provided.")
return attrs
+
+ @transaction.atomic
+ def create(self, validated_data):
+ mailboxes = validated_data.pop('mailboxes', [])
+ obj = super().create(validated_data)
+ obj.mailboxes.set(mailboxes)
+ return obj
+
+ @transaction.atomic
+ def update(self, instance, validated_data):
+ mailboxes = validated_data.pop('mailboxes', [])
+ instance.mailboxes.set(mailboxes)
+ return super().update(instance, validated_data)
diff --git a/orchestra/contrib/payments/serializers.py b/orchestra/contrib/payments/serializers.py
index e423abbb..93ae9f78 100644
--- a/orchestra/contrib/payments/serializers.py
+++ b/orchestra/contrib/payments/serializers.py
@@ -10,7 +10,7 @@ class PaymentSourceSerializer(AccountSerializerMixin, serializers.HyperlinkedMod
class Meta:
model = PaymentSource
fields = ('url', 'id', 'method', 'data', 'is_active')
-
+
def validate(self, data):
""" validate data according to method """
data = super(PaymentSourceSerializer, self).validate(data)
@@ -20,7 +20,7 @@ class PaymentSourceSerializer(AccountSerializerMixin, serializers.HyperlinkedMod
if not serializer.is_valid():
raise serializers.ValidationError(serializer.errors)
return data
-
+
def transform_data(self, obj, value):
if not obj:
return {}
@@ -29,7 +29,7 @@ class PaymentSourceSerializer(AccountSerializerMixin, serializers.HyperlinkedMod
serializer_class = plugin().get_serializer()
return serializer_class().to_native(obj.data)
return obj.data
-
+
# TODO
def metadata(self):
meta = super(PaymentSourceSerializer, self).metadata()
@@ -43,3 +43,4 @@ class PaymentSourceSerializer(AccountSerializerMixin, serializers.HyperlinkedMod
class TransactionSerializer(AccountSerializerMixin, serializers.HyperlinkedModelSerializer):
class Meta:
model = Transaction
+ exclude = ('process',)
diff --git a/total_requirements.txt b/total_requirements.txt
deleted file mode 100644
index f360a3ef..00000000
--- a/total_requirements.txt
+++ /dev/null
@@ -1,39 +0,0 @@
-Django==1.10.5
-django-fluent-dashboard==0.6.1
-django-admin-tools==0.8.0
-django-extensions==1.7.4
-django-celery==3.1.17
-celery==3.1.23
-kombu==3.0.35
-billiard==3.3.0.23
-Markdown==2.4
-djangorestframework==3.4.7
-ecdsa==0.11
-Pygments==1.6
-django-filter==0.15.2
-jsonfield==0.9.22
-python-dateutil==2.2
-django-iban==0.3.0
-requests
-phonenumbers
-django-countries
-django-localflavor
-amqp
-anyjson
-pytz
-cracklib
-lxml==3.3.5
-selenium
-xvfbwrapper
-freezegun==0.3.14
-coverage
-flake8
-django-debug-toolbar==1.3.0
-django-nose==1.4.4
-sqlparse
-pyinotify
-PyMySQL
-dj_database_url==0.5.0
-psycopg2-binary
-python-decouple
-https://github.com/glic3rinu/passlib/archive/master.zip