Account-centric alternative user model initial implementation
This commit is contained in:
parent
6a52e99d10
commit
833b527361
|
@ -44,9 +44,6 @@ def get_accounts():
|
|||
items.MenuItem(_("Accounts"),
|
||||
reverse('admin:accounts_account_changelist'))
|
||||
]
|
||||
if isinstalled('orchestra.apps.users'):
|
||||
url = reverse('admin:users_user_changelist')
|
||||
childrens.append(items.MenuItem(_("Users"), url))
|
||||
if isinstalled('orchestra.apps.payments'):
|
||||
url = reverse('admin:payments_transactionprocess_changelist')
|
||||
childrens.append(items.MenuItem(_("Transaction processes"), url))
|
||||
|
|
|
@ -2,6 +2,7 @@ from django import forms
|
|||
from django.conf.urls import patterns, url
|
||||
from django.contrib import admin, messages
|
||||
from django.contrib.admin.util import unquote
|
||||
from django.contrib.auth import admin as auth
|
||||
from django.http import HttpResponseRedirect
|
||||
from django.utils.safestring import mark_safe
|
||||
from django.utils.six.moves.urllib.parse import parse_qsl
|
||||
|
@ -17,8 +18,8 @@ from .forms import AccountCreationForm, AccountChangeForm
|
|||
from .models import Account
|
||||
|
||||
|
||||
class AccountAdmin(ExtendedModelAdmin):
|
||||
list_display = ('name', 'user_link', 'type', 'is_active')
|
||||
class AccountAdmin(auth.UserAdmin, ExtendedModelAdmin):
|
||||
list_display = ('name', 'type', 'is_active')
|
||||
list_filter = (
|
||||
'type', 'is_active', HasMainUserListFilter
|
||||
)
|
||||
|
@ -32,23 +33,21 @@ class AccountAdmin(ExtendedModelAdmin):
|
|||
)
|
||||
fieldsets = (
|
||||
(_("User"), {
|
||||
'fields': ('user_link', 'password',),
|
||||
'fields': ('username', 'password',),
|
||||
}),
|
||||
(_("Account info"), {
|
||||
'fields': (('type', 'language'), 'comments'),
|
||||
}),
|
||||
)
|
||||
readonly_fields = ('user_link',)
|
||||
search_fields = ('users__username',)
|
||||
search_fields = ('username',)
|
||||
add_form = AccountCreationForm
|
||||
form = AccountChangeForm
|
||||
filter_horizontal = ()
|
||||
change_form_template = 'admin/accounts/account/change_form.html'
|
||||
|
||||
user_link = admin_link('user', order='user__username')
|
||||
|
||||
def name(self, account):
|
||||
return account.name
|
||||
name.admin_order_field = 'user__username'
|
||||
name.admin_order_field = 'username'
|
||||
|
||||
def formfield_for_dbfield(self, db_field, **kwargs):
|
||||
""" Make value input widget bigger """
|
||||
|
@ -75,20 +74,10 @@ class AccountAdmin(ExtendedModelAdmin):
|
|||
return super(AccountAdmin, self).change_view(request, object_id,
|
||||
form_url=form_url, extra_context=context)
|
||||
|
||||
def save_model(self, request, obj, form, change):
|
||||
""" Save user and account, they are interdependent """
|
||||
if change:
|
||||
return super(AccountAdmin, self).save_model(request, obj, form, change)
|
||||
obj.user.save()
|
||||
obj.user_id = obj.user.pk
|
||||
obj.save()
|
||||
obj.user.account = obj
|
||||
obj.user.save()
|
||||
|
||||
def get_queryset(self, request):
|
||||
""" Select related for performance """
|
||||
qs = super(AccountAdmin, self).get_queryset(request)
|
||||
related = ('user', 'invoicecontact')
|
||||
related = ('invoicecontact',)
|
||||
return qs.select_related(*related)
|
||||
|
||||
|
||||
|
@ -97,10 +86,10 @@ admin.site.register(Account, AccountAdmin)
|
|||
|
||||
class AccountListAdmin(AccountAdmin):
|
||||
""" Account list to allow account selection when creating new services """
|
||||
list_display = ('select_account', 'type', 'user')
|
||||
list_display = ('select_account', 'type', 'username')
|
||||
actions = None
|
||||
search_fields = ['user__username',]
|
||||
ordering = ('user__username',)
|
||||
search_fields = ['username',]
|
||||
ordering = ('username',)
|
||||
|
||||
def select_account(self, instance):
|
||||
# TODO get query string from request.META['QUERY_STRING'] to preserve filters
|
||||
|
@ -111,7 +100,7 @@ class AccountListAdmin(AccountAdmin):
|
|||
return '<a href="%(url)s">%(name)s</a>' % context
|
||||
select_account.short_description = _("account")
|
||||
select_account.allow_tags = True
|
||||
select_account.order_admin_field = 'user__username'
|
||||
select_account.order_admin_field = 'username'
|
||||
|
||||
def changelist_view(self, request, extra_context=None):
|
||||
original_app_label = request.META['PATH_INFO'].split('/')[-5]
|
||||
|
@ -139,7 +128,7 @@ class AccountAdminMixin(object):
|
|||
return '<a href="%s">%s</a>' % (url, str(account))
|
||||
account_link.short_description = _("account")
|
||||
account_link.allow_tags = True
|
||||
account_link.admin_order_field = 'account__user__username'
|
||||
account_link.admin_order_field = 'account__username'
|
||||
|
||||
def get_readonly_fields(self, request, obj=None):
|
||||
""" provide account for filter_by_account_fields """
|
||||
|
@ -150,13 +139,13 @@ class AccountAdminMixin(object):
|
|||
def get_queryset(self, request):
|
||||
""" Select related for performance """
|
||||
qs = super(AccountAdminMixin, self).get_queryset(request)
|
||||
return qs.select_related('account__user')
|
||||
return qs.select_related('account')
|
||||
|
||||
def formfield_for_dbfield(self, db_field, **kwargs):
|
||||
""" Improve performance of account field and filter by account """
|
||||
if db_field.name == 'account':
|
||||
qs = kwargs.get('queryset', db_field.rel.to.objects)
|
||||
kwargs['queryset'] = qs.select_related('user')
|
||||
""" Filter by account """
|
||||
# if db_field.name == 'account':
|
||||
# qs = kwargs.get('queryset', db_field.rel.to.objects)
|
||||
# kwargs['queryset'] = qs.select_related('user')
|
||||
formfield = super(AccountAdminMixin, self).formfield_for_dbfield(db_field, **kwargs)
|
||||
if db_field.name in self.filter_by_account_fields:
|
||||
if hasattr(self, 'account'):
|
||||
|
|
|
@ -9,17 +9,17 @@ from .serializers import AccountSerializer
|
|||
class AccountApiMixin(object):
|
||||
def get_queryset(self):
|
||||
qs = super(AccountApiMixin, self).get_queryset()
|
||||
return qs.filter(account=self.request.user.account_id)
|
||||
return qs.filter(account=self.request.user.pk)
|
||||
|
||||
|
||||
class AccountViewSet(viewsets.ModelViewSet):
|
||||
model = Account
|
||||
serializer_class = AccountSerializer
|
||||
singleton_pk = lambda _,request: request.user.account.pk
|
||||
singleton_pk = lambda _,request: request.user.pk
|
||||
|
||||
def get_queryset(self):
|
||||
qs = super(AccountViewSet, self).get_queryset()
|
||||
return qs.filter(id=self.request.user.account_id)
|
||||
return qs.filter(id=self.request.user)
|
||||
|
||||
|
||||
router.register(r'accounts', AccountViewSet)
|
||||
|
|
|
@ -23,16 +23,12 @@ class AccountCreationForm(auth.forms.UserCreationForm):
|
|||
return username
|
||||
raise forms.ValidationError(self.error_messages['duplicate_username'])
|
||||
|
||||
def save(self, commit=True):
|
||||
account = super(auth.forms.UserCreationForm, self).save(commit=False)
|
||||
user = User(username=self.cleaned_data['username'], is_admin=True)
|
||||
user.set_password(self.cleaned_data['password1'])
|
||||
user.account = account
|
||||
account.user = user
|
||||
if commit:
|
||||
user.save()
|
||||
account.save()
|
||||
return account
|
||||
# def save(self, commit=True):
|
||||
# account = super(auth.forms.UserCreationForm, self).save(commit=False)
|
||||
# account.set_password(self.cleaned_data['password1'])
|
||||
# if commit:
|
||||
# account.save()
|
||||
# return account
|
||||
|
||||
|
||||
class AccountChangeForm(forms.ModelForm):
|
||||
|
@ -45,8 +41,8 @@ class AccountChangeForm(forms.ModelForm):
|
|||
def __init__(self, *args, **kwargs):
|
||||
super(AccountChangeForm, self).__init__(*args, **kwargs)
|
||||
account = kwargs.get('instance')
|
||||
self.fields['username'].widget = ReadOnlyWidget(account.user.username)
|
||||
self.fields['password'].initial = account.user.password
|
||||
self.fields['username'].widget = ReadOnlyWidget(account.username)
|
||||
self.fields['password'].initial = account.password
|
||||
|
||||
def clean_password(self):
|
||||
# Regardless of what the user provides, return the initial value.
|
||||
|
|
|
@ -18,7 +18,7 @@ class Command(BaseCommand):
|
|||
)
|
||||
|
||||
option_list = BaseCommand.option_list
|
||||
help = 'Used to create an initial account and its user.'
|
||||
help = 'Used to create an initial account.'
|
||||
|
||||
@transaction.atomic
|
||||
def handle(self, *args, **options):
|
||||
|
@ -27,5 +27,4 @@ class Command(BaseCommand):
|
|||
email = options.get('email')
|
||||
username = options.get('username')
|
||||
password = options.get('password')
|
||||
account = Account.objects.create()
|
||||
account.users.create_superuser(username, email, password, is_main=True)
|
||||
Account.objects.create_user(username, email=email, password=password)
|
||||
|
|
|
@ -7,6 +7,7 @@ from orchestra.apps.accounts.models import Account
|
|||
class Command(createsuperuser.Command):
|
||||
def handle(self, *args, **options):
|
||||
super(Command, self).handle(*args, **options)
|
||||
raise NotImplementedError
|
||||
users = get_user_model().objects.filter()
|
||||
if len(users) == 1 and not Account.objects.all().exists():
|
||||
user = users[0]
|
||||
|
|
|
@ -1,30 +0,0 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from django.db import models, migrations
|
||||
from django.conf import settings
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.CreateModel(
|
||||
name='Account',
|
||||
fields=[
|
||||
('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
|
||||
('type', models.CharField(default=b'INDIVIDUAL', max_length=32, verbose_name='type', choices=[(b'INDIVIDUAL', 'Individual'), (b'ASSOCIATION', 'Association'), (b'CUSTOMER', 'Customer'), (b'COMPANY', 'Company'), (b'PUBLICBODY', 'Public body')])),
|
||||
('language', models.CharField(default=b'en', max_length=2, verbose_name='language', choices=[(b'en', 'English')])),
|
||||
('register_date', models.DateTimeField(auto_now_add=True, verbose_name='register date')),
|
||||
('comments', models.TextField(max_length=256, verbose_name='comments', blank=True)),
|
||||
('is_active', models.BooleanField(default=True)),
|
||||
('user', models.OneToOneField(related_name=b'accounts', verbose_name='user', to=settings.AUTH_USER_MODEL)),
|
||||
],
|
||||
options={
|
||||
},
|
||||
bases=(models.Model,),
|
||||
),
|
||||
]
|
|
@ -1,20 +0,0 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from django.db import models, migrations
|
||||
from django.conf import settings
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('accounts', '0001_initial'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterField(
|
||||
model_name='account',
|
||||
name='user',
|
||||
field=models.OneToOneField(related_name=b'accounts', null=True, verbose_name='user', to=settings.AUTH_USER_MODEL),
|
||||
),
|
||||
]
|
|
@ -1,25 +0,0 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from django.db import models, migrations
|
||||
import datetime
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('accounts', '0002_auto_20140909_1850'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.RemoveField(
|
||||
model_name='account',
|
||||
name='register_date',
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='account',
|
||||
name='registered_on',
|
||||
field=models.DateField(default=datetime.datetime(2014, 9, 26, 13, 25, 49, 42008), verbose_name='registered', auto_now_add=True),
|
||||
preserve_default=False,
|
||||
),
|
||||
]
|
|
@ -1,5 +1,8 @@
|
|||
from django.contrib.auth import models as auth
|
||||
from django.conf import settings as djsettings
|
||||
from django.core import validators
|
||||
from django.db import models
|
||||
from django.utils import timezone
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
|
||||
from orchestra.core import services
|
||||
|
@ -8,10 +11,11 @@ from orchestra.utils import send_email_template
|
|||
from . import settings
|
||||
|
||||
|
||||
class Account(models.Model):
|
||||
# Users depends on Accounts (think about what should happen when you delete an account)
|
||||
user = models.OneToOneField(djsettings.AUTH_USER_MODEL,
|
||||
verbose_name=_("user"), related_name='accounts', null=True)
|
||||
class Account(auth.AbstractBaseUser):
|
||||
username = models.CharField(_("username"), max_length=64, unique=True,
|
||||
help_text=_("Required. 30 characters or fewer. Letters, digits and ./-/_ only."),
|
||||
validators=[validators.RegexValidator(r'^[\w.-]+$',
|
||||
_("Enter a valid username."), 'invalid')])
|
||||
type = models.CharField(_("type"), choices=settings.ACCOUNTS_TYPES,
|
||||
max_length=32, default=settings.ACCOUNTS_DEFAULT_TYPE)
|
||||
language = models.CharField(_("language"), max_length=2,
|
||||
|
@ -19,24 +23,92 @@ class Account(models.Model):
|
|||
default=settings.ACCOUNTS_DEFAULT_LANGUAGE)
|
||||
registered_on = models.DateField(_("registered"), auto_now_add=True)
|
||||
comments = models.TextField(_("comments"), max_length=256, blank=True)
|
||||
is_active = models.BooleanField(default=True)
|
||||
first_name = models.CharField(_("first name"), max_length=30, blank=True)
|
||||
last_name = models.CharField(_("last name"), max_length=30, blank=True)
|
||||
email = models.EmailField(_('email address'), blank=True)
|
||||
is_active = models.BooleanField(_("active"), default=True,
|
||||
help_text=_("Designates whether this account should be treated as active. "
|
||||
"Unselect this instead of deleting accounts."))
|
||||
date_joined = models.DateTimeField(_("date joined"), default=timezone.now)
|
||||
|
||||
objects = auth.UserManager()
|
||||
|
||||
USERNAME_FIELD = 'username'
|
||||
REQUIRED_FIELDS = ['email']
|
||||
|
||||
def __unicode__(self):
|
||||
return self.name
|
||||
|
||||
@property
|
||||
def name(self):
|
||||
return self.user.username if self.user_id else str(self.pk)
|
||||
return self.username
|
||||
|
||||
@property
|
||||
def is_superuser(self):
|
||||
return self.pk == settings.ACCOUNTS_MAIN_PK
|
||||
|
||||
@property
|
||||
def is_staff(self):
|
||||
return self.is_superuser
|
||||
|
||||
@classmethod
|
||||
def get_main(cls):
|
||||
return cls.objects.get(pk=settings.ACCOUNTS_MAIN_PK)
|
||||
|
||||
def save(self, *args, **kwargs):
|
||||
created = not self.pk
|
||||
super(Account, self).save(*args, **kwargs)
|
||||
if created:
|
||||
self.users.create(username=self.username, password=self.password)
|
||||
|
||||
def send_email(self, template, context, contacts=[], attachments=[], html=None):
|
||||
contacts = self.contacts.filter(email_usages=contacts)
|
||||
email_to = contacts.values_list('email', flat=True)
|
||||
send_email_template(template, context, email_to, html=html,
|
||||
attachments=attachments)
|
||||
|
||||
def get_full_name(self):
|
||||
full_name = '%s %s' % (self.first_name, self.last_name)
|
||||
return full_name.strip() or self.username
|
||||
|
||||
def get_short_name(self):
|
||||
""" Returns the short name for the user """
|
||||
return self.first_name
|
||||
|
||||
def has_perm(self, perm, obj=None):
|
||||
"""
|
||||
Returns True if the user has the specified permission. This method
|
||||
queries all available auth backends, but returns immediately if any
|
||||
backend returns True. Thus, a user who has permission from a single
|
||||
auth backend is assumed to have permission in general. If an object is
|
||||
provided, permissions for this specific object are checked.
|
||||
"""
|
||||
# Active superusers have all permissions.
|
||||
if self.is_active and self.is_superuser:
|
||||
return True
|
||||
# Otherwise we need to check the backends.
|
||||
return auth._user_has_perm(self, perm, obj)
|
||||
|
||||
def has_perms(self, perm_list, obj=None):
|
||||
"""
|
||||
Returns True if the user has each of the specified permissions. If
|
||||
object is passed, it checks if the user has all required perms for this
|
||||
object.
|
||||
"""
|
||||
for perm in perm_list:
|
||||
if not self.has_perm(perm, obj):
|
||||
return False
|
||||
return True
|
||||
|
||||
def has_module_perms(self, app_label):
|
||||
"""
|
||||
Returns True if the user has any permissions in the given app label.
|
||||
Uses pretty much the same logic as has_perm, above.
|
||||
"""
|
||||
# Active superusers have all permissions.
|
||||
if self.is_active and self.is_superuser:
|
||||
return True
|
||||
return auth._user_has_module_perms(self, app_label)
|
||||
|
||||
|
||||
services.register(Account, menu=False)
|
||||
|
|
|
@ -7,7 +7,7 @@ class AccountSerializer(serializers.HyperlinkedModelSerializer):
|
|||
class Meta:
|
||||
model = Account
|
||||
fields = (
|
||||
'url', 'user', 'type', 'language', 'register_date', 'is_active'
|
||||
'url', 'username', 'type', 'language', 'register_date', 'is_active'
|
||||
)
|
||||
|
||||
|
||||
|
|
|
@ -1,126 +0,0 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from django.db import models, migrations
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('accounts', '__first__'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.CreateModel(
|
||||
name='Bill',
|
||||
fields=[
|
||||
('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
|
||||
('number', models.CharField(unique=True, max_length=16, verbose_name='number', blank=True)),
|
||||
('type', models.CharField(max_length=16, verbose_name='type', choices=[(b'INVOICE', 'Invoice'), (b'AMENDMENTINVOICE', 'Amendment invoice'), (b'FEE', 'Fee'), (b'AMENDMENTFEE', 'Amendment Fee'), (b'BUDGET', 'Budget')])),
|
||||
('status', models.CharField(default=b'OPEN', max_length=16, verbose_name='status', choices=[(b'OPEN', 'Open'), (b'CLOSED', 'Closed'), (b'SENT', 'Sent'), (b'PAID', 'Paid'), (b'BAD_DEBT', 'Bad debt')])),
|
||||
('created_on', models.DateTimeField(auto_now_add=True, verbose_name='created on')),
|
||||
('due_on', models.DateField(null=True, verbose_name='due on', blank=True)),
|
||||
('last_modified_on', models.DateTimeField(auto_now=True, verbose_name='last modified on')),
|
||||
('comments', models.TextField(verbose_name='comments', blank=True)),
|
||||
('html', models.TextField(verbose_name='HTML', blank=True)),
|
||||
('account', models.ForeignKey(related_name=b'bill', verbose_name='account', to='accounts.Account')),
|
||||
],
|
||||
options={
|
||||
},
|
||||
bases=(models.Model,),
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='BillLine',
|
||||
fields=[
|
||||
('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
|
||||
('description', models.CharField(max_length=256, verbose_name='description')),
|
||||
('rate', models.DecimalField(null=True, verbose_name='rate', max_digits=12, decimal_places=2, blank=True)),
|
||||
('amount', models.DecimalField(verbose_name='amount', max_digits=12, decimal_places=2)),
|
||||
('total', models.DecimalField(verbose_name='total', max_digits=12, decimal_places=2)),
|
||||
('tax', models.PositiveIntegerField(verbose_name='tax')),
|
||||
('order_id', models.PositiveIntegerField(null=True, blank=True)),
|
||||
('order_last_bill_date', models.DateTimeField(null=True)),
|
||||
('order_billed_until', models.DateTimeField(null=True)),
|
||||
('auto', models.BooleanField(default=False)),
|
||||
('amended_line', models.ForeignKey(related_name=b'amendment_lines', verbose_name='amended line', blank=True, to='bills.BillLine', null=True)),
|
||||
('bill', models.ForeignKey(related_name=b'billlines', verbose_name='bill', to='bills.Bill')),
|
||||
],
|
||||
options={
|
||||
'abstract': False,
|
||||
},
|
||||
bases=(models.Model,),
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='BillSubline',
|
||||
fields=[
|
||||
('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
|
||||
('description', models.CharField(max_length=256, verbose_name='description')),
|
||||
('total', models.DecimalField(max_digits=12, decimal_places=2)),
|
||||
('bill_line', models.ForeignKey(related_name=b'sublines', verbose_name='bill line', to='bills.BillLine')),
|
||||
],
|
||||
options={
|
||||
},
|
||||
bases=(models.Model,),
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='BudgetLine',
|
||||
fields=[
|
||||
('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
|
||||
('description', models.CharField(max_length=256, verbose_name='description')),
|
||||
('rate', models.DecimalField(null=True, verbose_name='rate', max_digits=12, decimal_places=2, blank=True)),
|
||||
('amount', models.DecimalField(verbose_name='amount', max_digits=12, decimal_places=2)),
|
||||
('total', models.DecimalField(verbose_name='total', max_digits=12, decimal_places=2)),
|
||||
('tax', models.PositiveIntegerField(verbose_name='tax')),
|
||||
('bill', models.ForeignKey(related_name=b'budgetlines', verbose_name='bill', to='bills.Bill')),
|
||||
],
|
||||
options={
|
||||
'abstract': False,
|
||||
},
|
||||
bases=(models.Model,),
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='AmendmentFee',
|
||||
fields=[
|
||||
],
|
||||
options={
|
||||
'proxy': True,
|
||||
},
|
||||
bases=('bills.bill',),
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='AmendmentInvoice',
|
||||
fields=[
|
||||
],
|
||||
options={
|
||||
'proxy': True,
|
||||
},
|
||||
bases=('bills.bill',),
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='Budget',
|
||||
fields=[
|
||||
],
|
||||
options={
|
||||
'proxy': True,
|
||||
},
|
||||
bases=('bills.bill',),
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='Fee',
|
||||
fields=[
|
||||
],
|
||||
options={
|
||||
'proxy': True,
|
||||
},
|
||||
bases=('bills.bill',),
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='Invoice',
|
||||
fields=[
|
||||
],
|
||||
options={
|
||||
'proxy': True,
|
||||
},
|
||||
bases=('bills.bill',),
|
||||
),
|
||||
]
|
|
@ -1,20 +0,0 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from django.db import models, migrations
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('bills', '0001_initial'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name='bill',
|
||||
name='closed_on',
|
||||
field=models.DateTimeField(null=True, verbose_name='closed on', blank=True),
|
||||
preserve_default=True,
|
||||
),
|
||||
]
|
|
@ -1,20 +0,0 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from django.db import models, migrations
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('bills', '0002_bill_closed_on'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name='bill',
|
||||
name='total',
|
||||
field=models.DecimalField(default=10, max_digits=12, decimal_places=2),
|
||||
preserve_default=False,
|
||||
),
|
||||
]
|
|
@ -1,19 +0,0 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from django.db import models, migrations
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('bills', '0003_bill_total'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterField(
|
||||
model_name='bill',
|
||||
name='total',
|
||||
field=models.DecimalField(default=0, max_digits=12, decimal_places=2),
|
||||
),
|
||||
]
|
|
@ -1,19 +0,0 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from django.db import models, migrations
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('bills', '0004_auto_20140911_1234'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.RenameField(
|
||||
model_name='billsubline',
|
||||
old_name='bill_line',
|
||||
new_name='line',
|
||||
),
|
||||
]
|
|
@ -1,59 +0,0 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from django.db import models, migrations
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('bills', '0005_auto_20140911_1234'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.RemoveField(
|
||||
model_name='budgetline',
|
||||
name='bill',
|
||||
),
|
||||
migrations.DeleteModel(
|
||||
name='BudgetLine',
|
||||
),
|
||||
migrations.DeleteModel(
|
||||
name='Budget',
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='ProForma',
|
||||
fields=[
|
||||
],
|
||||
options={
|
||||
'proxy': True,
|
||||
},
|
||||
bases=('bills.bill',),
|
||||
),
|
||||
migrations.RemoveField(
|
||||
model_name='billline',
|
||||
name='auto',
|
||||
),
|
||||
migrations.RemoveField(
|
||||
model_name='billline',
|
||||
name='order_billed_until',
|
||||
),
|
||||
migrations.RemoveField(
|
||||
model_name='billline',
|
||||
name='order_id',
|
||||
),
|
||||
migrations.RemoveField(
|
||||
model_name='billline',
|
||||
name='order_last_bill_date',
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='bill',
|
||||
name='type',
|
||||
field=models.CharField(max_length=16, verbose_name='type', choices=[(b'INVOICE', 'Invoice'), (b'AMENDMENTINVOICE', 'Amendment invoice'), (b'FEE', 'Fee'), (b'AMENDMENTFEE', 'Amendment Fee'), (b'PROFORMA', 'Pro forma')]),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='billline',
|
||||
name='bill',
|
||||
field=models.ForeignKey(related_name=b'lines', verbose_name='bill', to='bills.Bill'),
|
||||
),
|
||||
]
|
|
@ -1,50 +0,0 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from django.db import models, migrations
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('bills', '0006_auto_20140911_1238'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.RemoveField(
|
||||
model_name='bill',
|
||||
name='status',
|
||||
),
|
||||
migrations.RemoveField(
|
||||
model_name='billline',
|
||||
name='amount',
|
||||
),
|
||||
migrations.RemoveField(
|
||||
model_name='billline',
|
||||
name='total',
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='bill',
|
||||
name='is_open',
|
||||
field=models.BooleanField(default=True, verbose_name='is open'),
|
||||
preserve_default=True,
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='bill',
|
||||
name='is_sent',
|
||||
field=models.BooleanField(default=False, verbose_name='is sent'),
|
||||
preserve_default=True,
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='billline',
|
||||
name='quantity',
|
||||
field=models.DecimalField(default=10, verbose_name='quantity', max_digits=12, decimal_places=2),
|
||||
preserve_default=False,
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='billline',
|
||||
name='subtotal',
|
||||
field=models.DecimalField(default=20, verbose_name='subtotal', max_digits=12, decimal_places=2),
|
||||
preserve_default=False,
|
||||
),
|
||||
]
|
|
@ -1,18 +0,0 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from django.db import models, migrations
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('bills', '0007_auto_20140918_1454'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterModelOptions(
|
||||
name='bill',
|
||||
options={'get_latest_by': 'id'},
|
||||
),
|
||||
]
|
|
@ -1,46 +0,0 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from django.db import models, migrations
|
||||
import datetime
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('orders', '__first__'),
|
||||
('bills', '0008_auto_20140926_1218'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name='billline',
|
||||
name='created_on',
|
||||
field=models.DateField(default=datetime.datetime(2014, 9, 26, 12, 20, 24, 908200), verbose_name='created', auto_now_add=True),
|
||||
preserve_default=False,
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='billline',
|
||||
name='order_billed_on',
|
||||
field=models.DateField(null=True, verbose_name='order billed', blank=True),
|
||||
preserve_default=True,
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='billline',
|
||||
name='order_billed_until',
|
||||
field=models.DateField(null=True, verbose_name='order billed until', blank=True),
|
||||
preserve_default=True,
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='billline',
|
||||
name='order_id',
|
||||
field=models.ForeignKey(blank=True, to='orders.Order', help_text='Informative link back to the order', null=True),
|
||||
preserve_default=True,
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='billsubline',
|
||||
name='type',
|
||||
field=models.CharField(default=b'OTHER', max_length=16, verbose_name='type', choices=[(b'VOLUME', 'Volume'), (b'COMPENSATION', 'Compensation'), (b'OTHER', 'Other')]),
|
||||
preserve_default=True,
|
||||
),
|
||||
]
|
|
@ -1,29 +0,0 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from django.db import models, migrations
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('bills', '0009_auto_20140926_1220'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterField(
|
||||
model_name='bill',
|
||||
name='closed_on',
|
||||
field=models.DateField(null=True, verbose_name='closed on', blank=True),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='bill',
|
||||
name='created_on',
|
||||
field=models.DateField(auto_now_add=True, verbose_name='created on'),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='bill',
|
||||
name='last_modified_on',
|
||||
field=models.DateField(auto_now=True, verbose_name='last modified on'),
|
||||
),
|
||||
]
|
|
@ -1,25 +0,0 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from django.db import models, migrations
|
||||
import datetime
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('bills', '0010_auto_20140926_1326'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.RemoveField(
|
||||
model_name='bill',
|
||||
name='last_modified_on',
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='bill',
|
||||
name='updated_on',
|
||||
field=models.DateField(default=datetime.date(2014, 9, 26), verbose_name='updated on', auto_now=True),
|
||||
preserve_default=False,
|
||||
),
|
||||
]
|
|
@ -1,19 +0,0 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from django.db import models, migrations
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('bills', '0011_auto_20140926_1334'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.RenameField(
|
||||
model_name='billline',
|
||||
old_name='order_id',
|
||||
new_name='order',
|
||||
),
|
||||
]
|
|
@ -57,7 +57,7 @@ class PermissionInline(AccountAdminMixin, admin.TabularInline):
|
|||
class DatabaseAdmin(SelectAccountAdminMixin, ExtendedModelAdmin):
|
||||
list_display = ('name', 'type', 'account_link')
|
||||
list_filter = ('type',)
|
||||
search_fields = ['name', 'account__user__username']
|
||||
search_fields = ['name', 'account__username']
|
||||
inlines = [UserInline]
|
||||
add_inlines = []
|
||||
change_readonly_fields = ('name', 'type')
|
||||
|
@ -102,7 +102,7 @@ class DatabaseAdmin(SelectAccountAdminMixin, ExtendedModelAdmin):
|
|||
class DatabaseUserAdmin(SelectAccountAdminMixin, ExtendedModelAdmin):
|
||||
list_display = ('username', 'type', 'account_link')
|
||||
list_filter = ('type',)
|
||||
search_fields = ['username', 'account__user__username']
|
||||
search_fields = ['username', 'account__username']
|
||||
form = DatabaseUserChangeForm
|
||||
add_form = DatabaseUserCreationForm
|
||||
change_readonly_fields = ('username', 'type')
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
import re
|
||||
|
||||
from django import forms
|
||||
from django.contrib import admin
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
|
@ -52,7 +54,7 @@ class DomainAdmin(ChangeListDefaultFilter, AccountAdminMixin, ExtendedModelAdmin
|
|||
inlines = [RecordInline, DomainInline]
|
||||
list_filter = [TopDomainListFilter]
|
||||
change_readonly_fields = ('name',)
|
||||
search_fields = ['name', 'account__user__username']
|
||||
search_fields = ['name', 'account__username']
|
||||
default_changelist_filters = (
|
||||
('top_domain', 'True'),
|
||||
)
|
||||
|
@ -91,9 +93,12 @@ class DomainAdmin(ChangeListDefaultFilter, AccountAdminMixin, ExtendedModelAdmin
|
|||
qs = super(DomainAdmin, self).get_queryset(request)
|
||||
qs = qs.select_related('top')
|
||||
# For some reason if we do this we know for sure that join table will be called T4
|
||||
str(qs.query)
|
||||
query = str(qs.query)
|
||||
table = re.findall(r'(T\d+)\."account_id"', query)[0]
|
||||
qs = qs.extra(
|
||||
select={'structured_name': 'CONCAT(T4.name, domains_domain.name)'},
|
||||
select={
|
||||
'structured_name': 'CONCAT({table}.name, domains_domain.name)'.format(table=table)
|
||||
},
|
||||
).order_by('structured_name')
|
||||
if apps.isinstalled('orchestra.apps.websites'):
|
||||
qs = qs.prefetch_related('websites')
|
||||
|
|
|
@ -1,42 +0,0 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from django.db import models, migrations
|
||||
import orchestra.core.validators
|
||||
import orchestra.apps.domains.validators
|
||||
import orchestra.apps.domains.utils
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('accounts', '0002_auto_20140909_1850'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.CreateModel(
|
||||
name='Domain',
|
||||
fields=[
|
||||
('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
|
||||
('name', models.CharField(unique=True, max_length=256, verbose_name='name', validators=[orchestra.core.validators.validate_hostname, orchestra.apps.domains.validators.validate_allowed_domain])),
|
||||
('serial', models.IntegerField(default=orchestra.apps.domains.utils.generate_zone_serial, help_text='Serial number', verbose_name='serial')),
|
||||
('account', models.ForeignKey(related_name=b'domains', verbose_name='Account', blank=True, to='accounts.Account')),
|
||||
('top', models.ForeignKey(related_name=b'subdomains', to='domains.Domain', null=True)),
|
||||
],
|
||||
options={
|
||||
},
|
||||
bases=(models.Model,),
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='Record',
|
||||
fields=[
|
||||
('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
|
||||
('type', models.CharField(max_length=32, verbose_name='type', choices=[(b'MX', b'MX'), (b'NS', b'NS'), (b'CNAME', b'CNAME'), (b'A', 'A (IPv4 address)'), (b'AAAA', 'AAAA (IPv6 address)'), (b'SRV', b'SRV'), (b'TXT', b'TXT'), (b'SOA', b'SOA')])),
|
||||
('value', models.CharField(max_length=256, verbose_name='value')),
|
||||
('domain', models.ForeignKey(related_name=b'records', verbose_name='domain', to='domains.Domain')),
|
||||
],
|
||||
options={
|
||||
},
|
||||
bases=(models.Model,),
|
||||
),
|
||||
]
|
|
@ -1,21 +0,0 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from django.db import models, migrations
|
||||
import orchestra.apps.domains.validators
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('domains', '0001_initial'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name='record',
|
||||
name='ttl',
|
||||
field=models.CharField(default='', validators=[orchestra.apps.domains.validators.validate_zone_interval], max_length=8, blank=True, help_text='Record TTL, defaults to 1h', verbose_name='TTL'),
|
||||
preserve_default=False,
|
||||
),
|
||||
]
|
|
@ -54,7 +54,7 @@ class BillSelectedOrders(object):
|
|||
|
||||
def select_related(self, request):
|
||||
# TODO use changelist ?
|
||||
related = self.queryset.get_related().select_related('account__user', 'service')
|
||||
related = self.queryset.get_related().select_related('account', 'service')
|
||||
if not related:
|
||||
return self.confirmation(request)
|
||||
self.options['related_queryset'] = related
|
||||
|
|
|
@ -73,7 +73,7 @@ class TransactionAdmin(ChangeViewActionsMixin, AccountAdminMixin, admin.ModelAdm
|
|||
|
||||
def get_queryset(self, request):
|
||||
qs = super(TransactionAdmin, self).get_queryset(request)
|
||||
return qs.select_related('source', 'bill__account__user')
|
||||
return qs.select_related('source', 'bill__account')
|
||||
|
||||
def get_change_view_actions(self, obj=None):
|
||||
actions = super(TransactionAdmin, self).get_change_view_actions()
|
||||
|
|
|
@ -1,78 +0,0 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from django.db import models, migrations
|
||||
import orchestra.models.fields
|
||||
import django.core.validators
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('djcelery', '__first__'),
|
||||
('contenttypes', '0001_initial'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.CreateModel(
|
||||
name='MonitorData',
|
||||
fields=[
|
||||
('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
|
||||
('monitor', models.CharField(max_length=256, verbose_name='monitor', choices=[(b'Apache2Backend', 'Apache 2'), (b'Apache2Traffic', 'Apache 2 Traffic'), (b'AutoresponseBackend', 'Mail autoresponse'), (b'AwstatsBackend', 'Awstats'), (b'Bind9MasterDomainBackend', 'Bind9 master domain'), (b'Bind9SlaveDomainBackend', 'Bind9 slave domain'), (b'DokuWikiMuBackend', 'DokuWiki multisite'), (b'DrupalMuBackend', 'Drupal multisite'), (b'FTPTraffic', 'FTP traffic'), (b'MailSystemUserBackend', 'Mail system user'), (b'MaildirDisk', 'Maildir disk usage'), (b'MailmanBackend', b'Mailman'), (b'MailmanTraffic', b'MailmanTraffic'), (b'MySQLDBBackend', b'MySQL database'), (b'MySQLPermissionBackend', b'MySQL permission'), (b'MySQLUserBackend', b'MySQL user'), (b'MysqlDisk', 'MySQL disk'), (b'OpenVZTraffic', b'OpenVZTraffic'), (b'PHPFPMBackend', 'PHP-FPM'), (b'PHPFcgidBackend', 'PHP-Fcgid'), (b'PostfixAddressBackend', 'Postfix address'), (b'ServiceController', b'ServiceController'), (b'ServiceMonitor', b'ServiceMonitor'), (b'StaticBackend', 'Static'), (b'SystemUserBackend', 'System User'), (b'SystemUserDisk', 'System user disk'), (b'WebalizerBackend', 'Webalizer'), (b'WordpressMuBackend', 'Wordpress multisite')])),
|
||||
('object_id', models.PositiveIntegerField()),
|
||||
('date', models.DateTimeField(auto_now_add=True, verbose_name='date')),
|
||||
('value', models.DecimalField(verbose_name='value', max_digits=16, decimal_places=2)),
|
||||
('content_type', models.ForeignKey(to='contenttypes.ContentType')),
|
||||
],
|
||||
options={
|
||||
'get_latest_by': 'id',
|
||||
'verbose_name_plural': 'monitor data',
|
||||
},
|
||||
bases=(models.Model,),
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='Resource',
|
||||
fields=[
|
||||
('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
|
||||
('name', models.CharField(help_text='Required. 32 characters or fewer. Lowercase letters, digits and hyphen only.', max_length=32, verbose_name='name', validators=[django.core.validators.RegexValidator(b'^[a-z0-9_\\-]+$', 'Enter a valid name.', b'invalid')])),
|
||||
('verbose_name', models.CharField(max_length=256, verbose_name='verbose name')),
|
||||
('period', models.CharField(default=b'LAST', help_text='Operation used for aggregating this resource monitoreddata.', max_length=16, verbose_name='period', choices=[(b'LAST', 'Last'), (b'MONTHLY_SUM', 'Monthly Sum'), (b'MONTHLY_AVG', 'Monthly Average')])),
|
||||
('ondemand', models.BooleanField(default=False, help_text='If enabled the resource will not be pre-allocated, but allocated under the application demand', verbose_name='on demand')),
|
||||
('default_allocation', models.PositiveIntegerField(help_text='Default allocation value used when this is not an on demand resource', null=True, verbose_name='default allocation', blank=True)),
|
||||
('unit', models.CharField(help_text='The unit in which this resource is measured. For example GB, KB or subscribers', max_length=16, verbose_name='unit')),
|
||||
('scale', models.PositiveIntegerField(help_text='Scale in which this resource monitoring resoults should be prorcessed to match with unit.', verbose_name='scale')),
|
||||
('disable_trigger', models.BooleanField(default=False, help_text='Disables monitors exeeded and recovery triggers', verbose_name='disable trigger')),
|
||||
('monitors', orchestra.models.fields.MultiSelectField(blank=True, help_text='Monitor backends used for monitoring this resource.', max_length=256, verbose_name='monitors', choices=[(b'Apache2Backend', 'Apache 2'), (b'Apache2Traffic', 'Apache 2 Traffic'), (b'AutoresponseBackend', 'Mail autoresponse'), (b'AwstatsBackend', 'Awstats'), (b'Bind9MasterDomainBackend', 'Bind9 master domain'), (b'Bind9SlaveDomainBackend', 'Bind9 slave domain'), (b'DokuWikiMuBackend', 'DokuWiki multisite'), (b'DrupalMuBackend', 'Drupal multisite'), (b'FTPTraffic', 'FTP traffic'), (b'MailSystemUserBackend', 'Mail system user'), (b'MaildirDisk', 'Maildir disk usage'), (b'MailmanBackend', b'Mailman'), (b'MailmanTraffic', b'MailmanTraffic'), (b'MySQLDBBackend', b'MySQL database'), (b'MySQLPermissionBackend', b'MySQL permission'), (b'MySQLUserBackend', b'MySQL user'), (b'MysqlDisk', 'MySQL disk'), (b'OpenVZTraffic', b'OpenVZTraffic'), (b'PHPFPMBackend', 'PHP-FPM'), (b'PHPFcgidBackend', 'PHP-Fcgid'), (b'PostfixAddressBackend', 'Postfix address'), (b'ServiceController', b'ServiceController'), (b'ServiceMonitor', b'ServiceMonitor'), (b'StaticBackend', 'Static'), (b'SystemUserBackend', 'System User'), (b'SystemUserDisk', 'System user disk'), (b'WebalizerBackend', 'Webalizer'), (b'WordpressMuBackend', 'Wordpress multisite')])),
|
||||
('is_active', models.BooleanField(default=True, verbose_name='is active')),
|
||||
('content_type', models.ForeignKey(help_text='Model where this resource will be hooked.', to='contenttypes.ContentType')),
|
||||
('crontab', models.ForeignKey(blank=True, to='djcelery.CrontabSchedule', help_text='Crontab for periodic execution. Leave it empty to disable periodic monitoring', null=True, verbose_name='crontab')),
|
||||
],
|
||||
options={
|
||||
},
|
||||
bases=(models.Model,),
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='ResourceData',
|
||||
fields=[
|
||||
('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
|
||||
('object_id', models.PositiveIntegerField()),
|
||||
('used', models.PositiveIntegerField(null=True)),
|
||||
('last_update', models.DateTimeField(null=True)),
|
||||
('allocated', models.PositiveIntegerField(null=True, blank=True)),
|
||||
('content_type', models.ForeignKey(to='contenttypes.ContentType')),
|
||||
('resource', models.ForeignKey(related_name=b'dataset', to='resources.Resource')),
|
||||
],
|
||||
options={
|
||||
'verbose_name_plural': 'resource data',
|
||||
},
|
||||
bases=(models.Model,),
|
||||
),
|
||||
migrations.AlterUniqueTogether(
|
||||
name='resourcedata',
|
||||
unique_together=set([('resource', 'content_type', 'object_id')]),
|
||||
),
|
||||
migrations.AlterUniqueTogether(
|
||||
name='resource',
|
||||
unique_together=set([('name', 'content_type'), ('verbose_name', 'content_type')]),
|
||||
),
|
||||
]
|
|
@ -1,19 +0,0 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from django.db import models, migrations
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('resources', '0001_initial'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.RenameField(
|
||||
model_name='resource',
|
||||
old_name='ondemand',
|
||||
new_name='on_demand',
|
||||
),
|
||||
]
|
|
@ -1,70 +0,0 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from django.db import models, migrations
|
||||
import datetime
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('resources', '0002_auto_20140926_1143'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.RemoveField(
|
||||
model_name='monitordata',
|
||||
name='date',
|
||||
),
|
||||
migrations.RemoveField(
|
||||
model_name='resourcedata',
|
||||
name='last_update',
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='monitordata',
|
||||
name='created_at',
|
||||
field=models.DateTimeField(default=datetime.datetime(2014, 9, 26, 13, 25, 33, 290000), verbose_name='created', auto_now_add=True),
|
||||
preserve_default=False,
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='resourcedata',
|
||||
name='updated_at',
|
||||
field=models.DateTimeField(null=True, verbose_name='updated'),
|
||||
preserve_default=True,
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='monitordata',
|
||||
name='content_type',
|
||||
field=models.ForeignKey(verbose_name='content type', to='contenttypes.ContentType'),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='monitordata',
|
||||
name='object_id',
|
||||
field=models.PositiveIntegerField(verbose_name='object id'),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='resourcedata',
|
||||
name='allocated',
|
||||
field=models.PositiveIntegerField(null=True, verbose_name='allocated', blank=True),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='resourcedata',
|
||||
name='content_type',
|
||||
field=models.ForeignKey(verbose_name='content type', to='contenttypes.ContentType'),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='resourcedata',
|
||||
name='object_id',
|
||||
field=models.PositiveIntegerField(verbose_name='object id'),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='resourcedata',
|
||||
name='resource',
|
||||
field=models.ForeignKey(related_name=b'dataset', verbose_name='resource', to='resources.Resource'),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='resourcedata',
|
||||
name='used',
|
||||
field=models.PositiveIntegerField(null=True, verbose_name='used'),
|
||||
),
|
||||
]
|
|
@ -326,7 +326,7 @@ class Service(models.Model):
|
|||
def update_orders(self):
|
||||
order_model = get_model(settings.SERVICES_ORDER_MODEL)
|
||||
related_model = self.content_type.model_class()
|
||||
for instance in related_model.objects.all().select_related('account__user'):
|
||||
for instance in related_model.objects.all().select_related('account'):
|
||||
order_model.update_orders(instance, service=self)
|
||||
|
||||
|
||||
|
|
|
@ -2,7 +2,6 @@ from django.conf.urls import patterns, url
|
|||
from django.core.urlresolvers import reverse
|
||||
from django.contrib import admin
|
||||
from django.contrib.admin.util import unquote
|
||||
from django.contrib.auth import admin as auth
|
||||
from django.utils.translation import ugettext, ugettext_lazy as _
|
||||
|
||||
from orchestra.admin import ExtendedModelAdmin
|
||||
|
@ -14,22 +13,16 @@ from .models import User
|
|||
from .roles.filters import role_list_filter_factory
|
||||
|
||||
|
||||
class UserAdmin(AccountAdminMixin, auth.UserAdmin, ExtendedModelAdmin):
|
||||
class UserAdmin(AccountAdminMixin, ExtendedModelAdmin):
|
||||
list_display = ('username', 'display_is_main')
|
||||
list_filter = ('is_staff', 'is_superuser', 'is_active')
|
||||
list_filter = ('is_active',)
|
||||
fieldsets = (
|
||||
(None, {
|
||||
'fields': ('account', 'username', 'password')
|
||||
'fields': ('account', 'username', 'password', 'is_active')
|
||||
}),
|
||||
(_("Personal info"), {
|
||||
'fields': ('first_name', 'last_name', 'email')
|
||||
}),
|
||||
(_("Permissions"), {
|
||||
'fields': ('is_active', 'is_staff', 'is_superuser', 'display_is_main')
|
||||
}),
|
||||
(_("Important dates"), {
|
||||
'fields': ('last_login', 'date_joined')
|
||||
}),
|
||||
)
|
||||
add_fieldsets = (
|
||||
(None, {
|
||||
|
@ -37,7 +30,7 @@ class UserAdmin(AccountAdminMixin, auth.UserAdmin, ExtendedModelAdmin):
|
|||
'fields': ('username', 'password1', 'password2', 'account'),
|
||||
}),
|
||||
)
|
||||
search_fields = ['username', 'account__user__username']
|
||||
search_fields = ['username', 'account__username']
|
||||
readonly_fields = ('display_is_main', 'account_link')
|
||||
change_readonly_fields = ('username',)
|
||||
filter_horizontal = ()
|
||||
|
@ -101,10 +94,10 @@ class UserAdmin(AccountAdminMixin, auth.UserAdmin, ExtendedModelAdmin):
|
|||
kwargs['extra_context'] = extra_context
|
||||
return super(UserAdmin, self).change_view(request, object_id, **kwargs)
|
||||
|
||||
def get_queryset(self, request):
|
||||
""" Select related for performance """
|
||||
related = ['account__user'] + [ role.name for role in self.roles ]
|
||||
return super(UserAdmin, self).get_queryset(request).select_related(*related)
|
||||
# def get_queryset(self, request):
|
||||
# """ Select related for performance """
|
||||
# related = ['account'] + [ role.name for role in self.roles ]
|
||||
# return super(UserAdmin, self).get_queryset(request).select_related(*related)
|
||||
|
||||
|
||||
admin.site.register(User, UserAdmin)
|
||||
|
|
|
@ -1,45 +1,32 @@
|
|||
from django.contrib.auth import models as auth
|
||||
from django.contrib.auth.hashers import make_password
|
||||
from django.core import validators
|
||||
from django.core.mail import send_mail
|
||||
from django.db import models
|
||||
from django.utils import timezone
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
|
||||
|
||||
from orchestra.core import services
|
||||
|
||||
|
||||
class User(auth.AbstractBaseUser):
|
||||
class User(models.Model):
|
||||
username = models.CharField(_("username"), max_length=64, unique=True,
|
||||
help_text=_("Required. 30 characters or fewer. Letters, digits and "
|
||||
"./-/_ only."),
|
||||
validators=[validators.RegexValidator(r'^[\w.-]+$',
|
||||
_("Enter a valid username."), 'invalid')])
|
||||
password = models.CharField(_("password"), max_length=128)
|
||||
account = models.ForeignKey('accounts.Account', verbose_name=_("Account"),
|
||||
related_name='users')
|
||||
first_name = models.CharField(_("first name"), max_length=30, blank=True)
|
||||
last_name = models.CharField(_("last name"), max_length=30, blank=True)
|
||||
email = models.EmailField(_('email address'), blank=True)
|
||||
is_superuser = models.BooleanField(_("superuser status"), default=False,
|
||||
help_text=_("Designates that this user has all permissions without "
|
||||
"explicitly assigning them."))
|
||||
is_staff = models.BooleanField(_("staff status"), default=False,
|
||||
help_text=_("Designates whether the user can log into this admin "
|
||||
"site."))
|
||||
is_admin = models.BooleanField(_("admin status"), default=False,
|
||||
help_text=_("Designates whether the user can administrate its account."))
|
||||
is_active = models.BooleanField(_("active"), default=True,
|
||||
help_text=_("Designates whether this user should be treated as "
|
||||
"active. Unselect this instead of deleting accounts."))
|
||||
date_joined = models.DateTimeField(_("date joined"), default=timezone.now)
|
||||
|
||||
objects = auth.UserManager()
|
||||
|
||||
USERNAME_FIELD = 'username'
|
||||
REQUIRED_FIELDS = ['email']
|
||||
help_text=_("Designates whether this account should be treated as active. "
|
||||
"Unselect this instead of deleting accounts."))
|
||||
|
||||
@property
|
||||
def is_main(self):
|
||||
return self.account.user == self
|
||||
return self.username == self.account.username
|
||||
|
||||
def get_full_name(self):
|
||||
full_name = '%s %s' % (self.first_name, self.last_name)
|
||||
|
@ -49,44 +36,24 @@ class User(auth.AbstractBaseUser):
|
|||
""" Returns the short name for the user """
|
||||
return self.first_name
|
||||
|
||||
def get_description(self):
|
||||
return "{full_name}, {email}".format(full_name=self.get_full_name(), email=self.email)
|
||||
|
||||
def email_user(self, subject, message, from_email=None, **kwargs):
|
||||
""" Sends an email to this User """
|
||||
send_mail(subject, message, from_email, [self.email], **kwargs)
|
||||
|
||||
def has_perm(self, perm, obj=None):
|
||||
"""
|
||||
Returns True if the user has the specified permission. This method
|
||||
queries all available auth backends, but returns immediately if any
|
||||
backend returns True. Thus, a user who has permission from a single
|
||||
auth backend is assumed to have permission in general. If an object is
|
||||
provided, permissions for this specific object are checked.
|
||||
"""
|
||||
# Active superusers have all permissions.
|
||||
if self.is_active and self.is_superuser:
|
||||
return True
|
||||
# Otherwise we need to check the backends.
|
||||
return auth._user_has_perm(self, perm, obj)
|
||||
def set_password(self, raw_password):
|
||||
self.password = make_password(raw_password)
|
||||
|
||||
def has_perms(self, perm_list, obj=None):
|
||||
def check_password(self, raw_password):
|
||||
"""
|
||||
Returns True if the user has each of the specified permissions. If
|
||||
object is passed, it checks if the user has all required perms for this
|
||||
object.
|
||||
Returns a boolean of whether the raw_password was correct. Handles
|
||||
hashing formats behind the scenes.
|
||||
"""
|
||||
for perm in perm_list:
|
||||
if not self.has_perm(perm, obj):
|
||||
return False
|
||||
return True
|
||||
|
||||
def has_module_perms(self, app_label):
|
||||
"""
|
||||
Returns True if the user has any permissions in the given app label.
|
||||
Uses pretty much the same logic as has_perm, above.
|
||||
"""
|
||||
# Active superusers have all permissions.
|
||||
if self.is_active and self.is_superuser:
|
||||
return True
|
||||
return auth._user_has_module_perms(self, app_label)
|
||||
def setter(raw_password):
|
||||
self.set_password(raw_password)
|
||||
self.save(update_fields=["password"])
|
||||
|
||||
|
||||
services.register(User, menu=False)
|
||||
services.register(User)
|
||||
|
|
|
@ -70,8 +70,8 @@ INSTALLED_APPS = (
|
|||
'orchestra.apps.domains',
|
||||
'orchestra.apps.users',
|
||||
# 'orchestra.apps.users.roles.mail',
|
||||
'orchestra.apps.users.roles.jabber',
|
||||
'orchestra.apps.users.roles.posix',
|
||||
# 'orchestra.apps.users.roles.jabber',
|
||||
# 'orchestra.apps.users.roles.posix',
|
||||
'orchestra.apps.mails',
|
||||
'orchestra.apps.lists',
|
||||
'orchestra.apps.webapps',
|
||||
|
@ -114,7 +114,7 @@ INSTALLED_APPS = (
|
|||
)
|
||||
|
||||
|
||||
AUTH_USER_MODEL = 'users.User'
|
||||
AUTH_USER_MODEL = 'accounts.Account'
|
||||
|
||||
|
||||
AUTHENTICATION_BACKENDS = [
|
||||
|
@ -145,7 +145,6 @@ FLUENT_DASHBOARD_APP_GROUPS = (
|
|||
'models': (
|
||||
'orchestra.apps.accounts.models.Account',
|
||||
'orchestra.apps.contacts.models.Contact',
|
||||
'orchestra.apps.users.models.User',
|
||||
'orchestra.apps.orders.models.Order',
|
||||
'orchestra.apps.services.models.ContractedPlan',
|
||||
'orchestra.apps.bills.models.Bill',
|
||||
|
|
Loading…
Reference in a new issue