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"),
|
items.MenuItem(_("Accounts"),
|
||||||
reverse('admin:accounts_account_changelist'))
|
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'):
|
if isinstalled('orchestra.apps.payments'):
|
||||||
url = reverse('admin:payments_transactionprocess_changelist')
|
url = reverse('admin:payments_transactionprocess_changelist')
|
||||||
childrens.append(items.MenuItem(_("Transaction processes"), url))
|
childrens.append(items.MenuItem(_("Transaction processes"), url))
|
||||||
|
|
|
@ -2,6 +2,7 @@ from django import forms
|
||||||
from django.conf.urls import patterns, url
|
from django.conf.urls import patterns, url
|
||||||
from django.contrib import admin, messages
|
from django.contrib import admin, messages
|
||||||
from django.contrib.admin.util import unquote
|
from django.contrib.admin.util import unquote
|
||||||
|
from django.contrib.auth import admin as auth
|
||||||
from django.http import HttpResponseRedirect
|
from django.http import HttpResponseRedirect
|
||||||
from django.utils.safestring import mark_safe
|
from django.utils.safestring import mark_safe
|
||||||
from django.utils.six.moves.urllib.parse import parse_qsl
|
from django.utils.six.moves.urllib.parse import parse_qsl
|
||||||
|
@ -17,8 +18,8 @@ from .forms import AccountCreationForm, AccountChangeForm
|
||||||
from .models import Account
|
from .models import Account
|
||||||
|
|
||||||
|
|
||||||
class AccountAdmin(ExtendedModelAdmin):
|
class AccountAdmin(auth.UserAdmin, ExtendedModelAdmin):
|
||||||
list_display = ('name', 'user_link', 'type', 'is_active')
|
list_display = ('name', 'type', 'is_active')
|
||||||
list_filter = (
|
list_filter = (
|
||||||
'type', 'is_active', HasMainUserListFilter
|
'type', 'is_active', HasMainUserListFilter
|
||||||
)
|
)
|
||||||
|
@ -32,23 +33,21 @@ class AccountAdmin(ExtendedModelAdmin):
|
||||||
)
|
)
|
||||||
fieldsets = (
|
fieldsets = (
|
||||||
(_("User"), {
|
(_("User"), {
|
||||||
'fields': ('user_link', 'password',),
|
'fields': ('username', 'password',),
|
||||||
}),
|
}),
|
||||||
(_("Account info"), {
|
(_("Account info"), {
|
||||||
'fields': (('type', 'language'), 'comments'),
|
'fields': (('type', 'language'), 'comments'),
|
||||||
}),
|
}),
|
||||||
)
|
)
|
||||||
readonly_fields = ('user_link',)
|
search_fields = ('username',)
|
||||||
search_fields = ('users__username',)
|
|
||||||
add_form = AccountCreationForm
|
add_form = AccountCreationForm
|
||||||
form = AccountChangeForm
|
form = AccountChangeForm
|
||||||
|
filter_horizontal = ()
|
||||||
change_form_template = 'admin/accounts/account/change_form.html'
|
change_form_template = 'admin/accounts/account/change_form.html'
|
||||||
|
|
||||||
user_link = admin_link('user', order='user__username')
|
|
||||||
|
|
||||||
def name(self, account):
|
def name(self, account):
|
||||||
return account.name
|
return account.name
|
||||||
name.admin_order_field = 'user__username'
|
name.admin_order_field = 'username'
|
||||||
|
|
||||||
def formfield_for_dbfield(self, db_field, **kwargs):
|
def formfield_for_dbfield(self, db_field, **kwargs):
|
||||||
""" Make value input widget bigger """
|
""" Make value input widget bigger """
|
||||||
|
@ -75,20 +74,10 @@ class AccountAdmin(ExtendedModelAdmin):
|
||||||
return super(AccountAdmin, self).change_view(request, object_id,
|
return super(AccountAdmin, self).change_view(request, object_id,
|
||||||
form_url=form_url, extra_context=context)
|
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):
|
def get_queryset(self, request):
|
||||||
""" Select related for performance """
|
""" Select related for performance """
|
||||||
qs = super(AccountAdmin, self).get_queryset(request)
|
qs = super(AccountAdmin, self).get_queryset(request)
|
||||||
related = ('user', 'invoicecontact')
|
related = ('invoicecontact',)
|
||||||
return qs.select_related(*related)
|
return qs.select_related(*related)
|
||||||
|
|
||||||
|
|
||||||
|
@ -97,10 +86,10 @@ admin.site.register(Account, AccountAdmin)
|
||||||
|
|
||||||
class AccountListAdmin(AccountAdmin):
|
class AccountListAdmin(AccountAdmin):
|
||||||
""" Account list to allow account selection when creating new services """
|
""" Account list to allow account selection when creating new services """
|
||||||
list_display = ('select_account', 'type', 'user')
|
list_display = ('select_account', 'type', 'username')
|
||||||
actions = None
|
actions = None
|
||||||
search_fields = ['user__username',]
|
search_fields = ['username',]
|
||||||
ordering = ('user__username',)
|
ordering = ('username',)
|
||||||
|
|
||||||
def select_account(self, instance):
|
def select_account(self, instance):
|
||||||
# TODO get query string from request.META['QUERY_STRING'] to preserve filters
|
# 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
|
return '<a href="%(url)s">%(name)s</a>' % context
|
||||||
select_account.short_description = _("account")
|
select_account.short_description = _("account")
|
||||||
select_account.allow_tags = True
|
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):
|
def changelist_view(self, request, extra_context=None):
|
||||||
original_app_label = request.META['PATH_INFO'].split('/')[-5]
|
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))
|
return '<a href="%s">%s</a>' % (url, str(account))
|
||||||
account_link.short_description = _("account")
|
account_link.short_description = _("account")
|
||||||
account_link.allow_tags = True
|
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):
|
def get_readonly_fields(self, request, obj=None):
|
||||||
""" provide account for filter_by_account_fields """
|
""" provide account for filter_by_account_fields """
|
||||||
|
@ -150,13 +139,13 @@ class AccountAdminMixin(object):
|
||||||
def get_queryset(self, request):
|
def get_queryset(self, request):
|
||||||
""" Select related for performance """
|
""" Select related for performance """
|
||||||
qs = super(AccountAdminMixin, self).get_queryset(request)
|
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):
|
def formfield_for_dbfield(self, db_field, **kwargs):
|
||||||
""" Improve performance of account field and filter by account """
|
""" Filter by account """
|
||||||
if db_field.name == 'account':
|
# if db_field.name == 'account':
|
||||||
qs = kwargs.get('queryset', db_field.rel.to.objects)
|
# qs = kwargs.get('queryset', db_field.rel.to.objects)
|
||||||
kwargs['queryset'] = qs.select_related('user')
|
# kwargs['queryset'] = qs.select_related('user')
|
||||||
formfield = super(AccountAdminMixin, self).formfield_for_dbfield(db_field, **kwargs)
|
formfield = super(AccountAdminMixin, self).formfield_for_dbfield(db_field, **kwargs)
|
||||||
if db_field.name in self.filter_by_account_fields:
|
if db_field.name in self.filter_by_account_fields:
|
||||||
if hasattr(self, 'account'):
|
if hasattr(self, 'account'):
|
||||||
|
|
|
@ -9,17 +9,17 @@ from .serializers import AccountSerializer
|
||||||
class AccountApiMixin(object):
|
class AccountApiMixin(object):
|
||||||
def get_queryset(self):
|
def get_queryset(self):
|
||||||
qs = super(AccountApiMixin, self).get_queryset()
|
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):
|
class AccountViewSet(viewsets.ModelViewSet):
|
||||||
model = Account
|
model = Account
|
||||||
serializer_class = AccountSerializer
|
serializer_class = AccountSerializer
|
||||||
singleton_pk = lambda _,request: request.user.account.pk
|
singleton_pk = lambda _,request: request.user.pk
|
||||||
|
|
||||||
def get_queryset(self):
|
def get_queryset(self):
|
||||||
qs = super(AccountViewSet, self).get_queryset()
|
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)
|
router.register(r'accounts', AccountViewSet)
|
||||||
|
|
|
@ -23,16 +23,12 @@ class AccountCreationForm(auth.forms.UserCreationForm):
|
||||||
return username
|
return username
|
||||||
raise forms.ValidationError(self.error_messages['duplicate_username'])
|
raise forms.ValidationError(self.error_messages['duplicate_username'])
|
||||||
|
|
||||||
def save(self, commit=True):
|
# def save(self, commit=True):
|
||||||
account = super(auth.forms.UserCreationForm, self).save(commit=False)
|
# account = super(auth.forms.UserCreationForm, self).save(commit=False)
|
||||||
user = User(username=self.cleaned_data['username'], is_admin=True)
|
# account.set_password(self.cleaned_data['password1'])
|
||||||
user.set_password(self.cleaned_data['password1'])
|
# if commit:
|
||||||
user.account = account
|
# account.save()
|
||||||
account.user = user
|
# return account
|
||||||
if commit:
|
|
||||||
user.save()
|
|
||||||
account.save()
|
|
||||||
return account
|
|
||||||
|
|
||||||
|
|
||||||
class AccountChangeForm(forms.ModelForm):
|
class AccountChangeForm(forms.ModelForm):
|
||||||
|
@ -45,8 +41,8 @@ class AccountChangeForm(forms.ModelForm):
|
||||||
def __init__(self, *args, **kwargs):
|
def __init__(self, *args, **kwargs):
|
||||||
super(AccountChangeForm, self).__init__(*args, **kwargs)
|
super(AccountChangeForm, self).__init__(*args, **kwargs)
|
||||||
account = kwargs.get('instance')
|
account = kwargs.get('instance')
|
||||||
self.fields['username'].widget = ReadOnlyWidget(account.user.username)
|
self.fields['username'].widget = ReadOnlyWidget(account.username)
|
||||||
self.fields['password'].initial = account.user.password
|
self.fields['password'].initial = account.password
|
||||||
|
|
||||||
def clean_password(self):
|
def clean_password(self):
|
||||||
# Regardless of what the user provides, return the initial value.
|
# Regardless of what the user provides, return the initial value.
|
||||||
|
|
|
@ -18,7 +18,7 @@ class Command(BaseCommand):
|
||||||
)
|
)
|
||||||
|
|
||||||
option_list = BaseCommand.option_list
|
option_list = BaseCommand.option_list
|
||||||
help = 'Used to create an initial account and its user.'
|
help = 'Used to create an initial account.'
|
||||||
|
|
||||||
@transaction.atomic
|
@transaction.atomic
|
||||||
def handle(self, *args, **options):
|
def handle(self, *args, **options):
|
||||||
|
@ -27,5 +27,4 @@ class Command(BaseCommand):
|
||||||
email = options.get('email')
|
email = options.get('email')
|
||||||
username = options.get('username')
|
username = options.get('username')
|
||||||
password = options.get('password')
|
password = options.get('password')
|
||||||
account = Account.objects.create()
|
Account.objects.create_user(username, email=email, password=password)
|
||||||
account.users.create_superuser(username, email, password, is_main=True)
|
|
||||||
|
|
|
@ -7,6 +7,7 @@ from orchestra.apps.accounts.models import Account
|
||||||
class Command(createsuperuser.Command):
|
class Command(createsuperuser.Command):
|
||||||
def handle(self, *args, **options):
|
def handle(self, *args, **options):
|
||||||
super(Command, self).handle(*args, **options)
|
super(Command, self).handle(*args, **options)
|
||||||
|
raise NotImplementedError
|
||||||
users = get_user_model().objects.filter()
|
users = get_user_model().objects.filter()
|
||||||
if len(users) == 1 and not Account.objects.all().exists():
|
if len(users) == 1 and not Account.objects.all().exists():
|
||||||
user = users[0]
|
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.conf import settings as djsettings
|
||||||
|
from django.core import validators
|
||||||
from django.db import models
|
from django.db import models
|
||||||
|
from django.utils import timezone
|
||||||
from django.utils.translation import ugettext_lazy as _
|
from django.utils.translation import ugettext_lazy as _
|
||||||
|
|
||||||
from orchestra.core import services
|
from orchestra.core import services
|
||||||
|
@ -8,10 +11,11 @@ from orchestra.utils import send_email_template
|
||||||
from . import settings
|
from . import settings
|
||||||
|
|
||||||
|
|
||||||
class Account(models.Model):
|
class Account(auth.AbstractBaseUser):
|
||||||
# Users depends on Accounts (think about what should happen when you delete an account)
|
username = models.CharField(_("username"), max_length=64, unique=True,
|
||||||
user = models.OneToOneField(djsettings.AUTH_USER_MODEL,
|
help_text=_("Required. 30 characters or fewer. Letters, digits and ./-/_ only."),
|
||||||
verbose_name=_("user"), related_name='accounts', null=True)
|
validators=[validators.RegexValidator(r'^[\w.-]+$',
|
||||||
|
_("Enter a valid username."), 'invalid')])
|
||||||
type = models.CharField(_("type"), choices=settings.ACCOUNTS_TYPES,
|
type = models.CharField(_("type"), choices=settings.ACCOUNTS_TYPES,
|
||||||
max_length=32, default=settings.ACCOUNTS_DEFAULT_TYPE)
|
max_length=32, default=settings.ACCOUNTS_DEFAULT_TYPE)
|
||||||
language = models.CharField(_("language"), max_length=2,
|
language = models.CharField(_("language"), max_length=2,
|
||||||
|
@ -19,24 +23,92 @@ class Account(models.Model):
|
||||||
default=settings.ACCOUNTS_DEFAULT_LANGUAGE)
|
default=settings.ACCOUNTS_DEFAULT_LANGUAGE)
|
||||||
registered_on = models.DateField(_("registered"), auto_now_add=True)
|
registered_on = models.DateField(_("registered"), auto_now_add=True)
|
||||||
comments = models.TextField(_("comments"), max_length=256, blank=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):
|
def __unicode__(self):
|
||||||
return self.name
|
return self.name
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def name(self):
|
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
|
@classmethod
|
||||||
def get_main(cls):
|
def get_main(cls):
|
||||||
return cls.objects.get(pk=settings.ACCOUNTS_MAIN_PK)
|
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):
|
def send_email(self, template, context, contacts=[], attachments=[], html=None):
|
||||||
contacts = self.contacts.filter(email_usages=contacts)
|
contacts = self.contacts.filter(email_usages=contacts)
|
||||||
email_to = contacts.values_list('email', flat=True)
|
email_to = contacts.values_list('email', flat=True)
|
||||||
send_email_template(template, context, email_to, html=html,
|
send_email_template(template, context, email_to, html=html,
|
||||||
attachments=attachments)
|
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)
|
services.register(Account, menu=False)
|
||||||
|
|
|
@ -7,7 +7,7 @@ class AccountSerializer(serializers.HyperlinkedModelSerializer):
|
||||||
class Meta:
|
class Meta:
|
||||||
model = Account
|
model = Account
|
||||||
fields = (
|
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):
|
class DatabaseAdmin(SelectAccountAdminMixin, ExtendedModelAdmin):
|
||||||
list_display = ('name', 'type', 'account_link')
|
list_display = ('name', 'type', 'account_link')
|
||||||
list_filter = ('type',)
|
list_filter = ('type',)
|
||||||
search_fields = ['name', 'account__user__username']
|
search_fields = ['name', 'account__username']
|
||||||
inlines = [UserInline]
|
inlines = [UserInline]
|
||||||
add_inlines = []
|
add_inlines = []
|
||||||
change_readonly_fields = ('name', 'type')
|
change_readonly_fields = ('name', 'type')
|
||||||
|
@ -102,7 +102,7 @@ class DatabaseAdmin(SelectAccountAdminMixin, ExtendedModelAdmin):
|
||||||
class DatabaseUserAdmin(SelectAccountAdminMixin, ExtendedModelAdmin):
|
class DatabaseUserAdmin(SelectAccountAdminMixin, ExtendedModelAdmin):
|
||||||
list_display = ('username', 'type', 'account_link')
|
list_display = ('username', 'type', 'account_link')
|
||||||
list_filter = ('type',)
|
list_filter = ('type',)
|
||||||
search_fields = ['username', 'account__user__username']
|
search_fields = ['username', 'account__username']
|
||||||
form = DatabaseUserChangeForm
|
form = DatabaseUserChangeForm
|
||||||
add_form = DatabaseUserCreationForm
|
add_form = DatabaseUserCreationForm
|
||||||
change_readonly_fields = ('username', 'type')
|
change_readonly_fields = ('username', 'type')
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
|
import re
|
||||||
|
|
||||||
from django import forms
|
from django import forms
|
||||||
from django.contrib import admin
|
from django.contrib import admin
|
||||||
from django.utils.translation import ugettext_lazy as _
|
from django.utils.translation import ugettext_lazy as _
|
||||||
|
@ -52,7 +54,7 @@ class DomainAdmin(ChangeListDefaultFilter, AccountAdminMixin, ExtendedModelAdmin
|
||||||
inlines = [RecordInline, DomainInline]
|
inlines = [RecordInline, DomainInline]
|
||||||
list_filter = [TopDomainListFilter]
|
list_filter = [TopDomainListFilter]
|
||||||
change_readonly_fields = ('name',)
|
change_readonly_fields = ('name',)
|
||||||
search_fields = ['name', 'account__user__username']
|
search_fields = ['name', 'account__username']
|
||||||
default_changelist_filters = (
|
default_changelist_filters = (
|
||||||
('top_domain', 'True'),
|
('top_domain', 'True'),
|
||||||
)
|
)
|
||||||
|
@ -91,9 +93,12 @@ class DomainAdmin(ChangeListDefaultFilter, AccountAdminMixin, ExtendedModelAdmin
|
||||||
qs = super(DomainAdmin, self).get_queryset(request)
|
qs = super(DomainAdmin, self).get_queryset(request)
|
||||||
qs = qs.select_related('top')
|
qs = qs.select_related('top')
|
||||||
# For some reason if we do this we know for sure that join table will be called T4
|
# 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(
|
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')
|
).order_by('structured_name')
|
||||||
if apps.isinstalled('orchestra.apps.websites'):
|
if apps.isinstalled('orchestra.apps.websites'):
|
||||||
qs = qs.prefetch_related('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):
|
def select_related(self, request):
|
||||||
# TODO use changelist ?
|
# 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:
|
if not related:
|
||||||
return self.confirmation(request)
|
return self.confirmation(request)
|
||||||
self.options['related_queryset'] = related
|
self.options['related_queryset'] = related
|
||||||
|
|
|
@ -73,7 +73,7 @@ class TransactionAdmin(ChangeViewActionsMixin, AccountAdminMixin, admin.ModelAdm
|
||||||
|
|
||||||
def get_queryset(self, request):
|
def get_queryset(self, request):
|
||||||
qs = super(TransactionAdmin, self).get_queryset(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):
|
def get_change_view_actions(self, obj=None):
|
||||||
actions = super(TransactionAdmin, self).get_change_view_actions()
|
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):
|
def update_orders(self):
|
||||||
order_model = get_model(settings.SERVICES_ORDER_MODEL)
|
order_model = get_model(settings.SERVICES_ORDER_MODEL)
|
||||||
related_model = self.content_type.model_class()
|
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)
|
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.core.urlresolvers import reverse
|
||||||
from django.contrib import admin
|
from django.contrib import admin
|
||||||
from django.contrib.admin.util import unquote
|
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 django.utils.translation import ugettext, ugettext_lazy as _
|
||||||
|
|
||||||
from orchestra.admin import ExtendedModelAdmin
|
from orchestra.admin import ExtendedModelAdmin
|
||||||
|
@ -14,22 +13,16 @@ from .models import User
|
||||||
from .roles.filters import role_list_filter_factory
|
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_display = ('username', 'display_is_main')
|
||||||
list_filter = ('is_staff', 'is_superuser', 'is_active')
|
list_filter = ('is_active',)
|
||||||
fieldsets = (
|
fieldsets = (
|
||||||
(None, {
|
(None, {
|
||||||
'fields': ('account', 'username', 'password')
|
'fields': ('account', 'username', 'password', 'is_active')
|
||||||
}),
|
}),
|
||||||
(_("Personal info"), {
|
(_("Personal info"), {
|
||||||
'fields': ('first_name', 'last_name', 'email')
|
'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 = (
|
add_fieldsets = (
|
||||||
(None, {
|
(None, {
|
||||||
|
@ -37,7 +30,7 @@ class UserAdmin(AccountAdminMixin, auth.UserAdmin, ExtendedModelAdmin):
|
||||||
'fields': ('username', 'password1', 'password2', 'account'),
|
'fields': ('username', 'password1', 'password2', 'account'),
|
||||||
}),
|
}),
|
||||||
)
|
)
|
||||||
search_fields = ['username', 'account__user__username']
|
search_fields = ['username', 'account__username']
|
||||||
readonly_fields = ('display_is_main', 'account_link')
|
readonly_fields = ('display_is_main', 'account_link')
|
||||||
change_readonly_fields = ('username',)
|
change_readonly_fields = ('username',)
|
||||||
filter_horizontal = ()
|
filter_horizontal = ()
|
||||||
|
@ -101,10 +94,10 @@ class UserAdmin(AccountAdminMixin, auth.UserAdmin, ExtendedModelAdmin):
|
||||||
kwargs['extra_context'] = extra_context
|
kwargs['extra_context'] = extra_context
|
||||||
return super(UserAdmin, self).change_view(request, object_id, **kwargs)
|
return super(UserAdmin, self).change_view(request, object_id, **kwargs)
|
||||||
|
|
||||||
def get_queryset(self, request):
|
# def get_queryset(self, request):
|
||||||
""" Select related for performance """
|
# """ Select related for performance """
|
||||||
related = ['account__user'] + [ role.name for role in self.roles ]
|
# related = ['account'] + [ role.name for role in self.roles ]
|
||||||
return super(UserAdmin, self).get_queryset(request).select_related(*related)
|
# return super(UserAdmin, self).get_queryset(request).select_related(*related)
|
||||||
|
|
||||||
|
|
||||||
admin.site.register(User, UserAdmin)
|
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 import validators
|
||||||
from django.core.mail import send_mail
|
from django.core.mail import send_mail
|
||||||
from django.db import models
|
from django.db import models
|
||||||
from django.utils import timezone
|
|
||||||
from django.utils.translation import ugettext_lazy as _
|
from django.utils.translation import ugettext_lazy as _
|
||||||
|
|
||||||
|
|
||||||
from orchestra.core import services
|
from orchestra.core import services
|
||||||
|
|
||||||
|
|
||||||
class User(auth.AbstractBaseUser):
|
class User(models.Model):
|
||||||
username = models.CharField(_("username"), max_length=64, unique=True,
|
username = models.CharField(_("username"), max_length=64, unique=True,
|
||||||
help_text=_("Required. 30 characters or fewer. Letters, digits and "
|
help_text=_("Required. 30 characters or fewer. Letters, digits and "
|
||||||
"./-/_ only."),
|
"./-/_ only."),
|
||||||
validators=[validators.RegexValidator(r'^[\w.-]+$',
|
validators=[validators.RegexValidator(r'^[\w.-]+$',
|
||||||
_("Enter a valid username."), 'invalid')])
|
_("Enter a valid username."), 'invalid')])
|
||||||
|
password = models.CharField(_("password"), max_length=128)
|
||||||
account = models.ForeignKey('accounts.Account', verbose_name=_("Account"),
|
account = models.ForeignKey('accounts.Account', verbose_name=_("Account"),
|
||||||
related_name='users')
|
related_name='users')
|
||||||
first_name = models.CharField(_("first name"), max_length=30, blank=True)
|
first_name = models.CharField(_("first name"), max_length=30, blank=True)
|
||||||
last_name = models.CharField(_("last name"), max_length=30, blank=True)
|
last_name = models.CharField(_("last name"), max_length=30, blank=True)
|
||||||
email = models.EmailField(_('email address'), 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,
|
is_active = models.BooleanField(_("active"), default=True,
|
||||||
help_text=_("Designates whether this user should be treated as "
|
help_text=_("Designates whether this account should be treated as active. "
|
||||||
"active. Unselect this instead of deleting accounts."))
|
"Unselect this instead of deleting accounts."))
|
||||||
date_joined = models.DateTimeField(_("date joined"), default=timezone.now)
|
|
||||||
|
|
||||||
objects = auth.UserManager()
|
|
||||||
|
|
||||||
USERNAME_FIELD = 'username'
|
|
||||||
REQUIRED_FIELDS = ['email']
|
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def is_main(self):
|
def is_main(self):
|
||||||
return self.account.user == self
|
return self.username == self.account.username
|
||||||
|
|
||||||
def get_full_name(self):
|
def get_full_name(self):
|
||||||
full_name = '%s %s' % (self.first_name, self.last_name)
|
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 """
|
""" Returns the short name for the user """
|
||||||
return self.first_name
|
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):
|
def email_user(self, subject, message, from_email=None, **kwargs):
|
||||||
""" Sends an email to this User """
|
""" Sends an email to this User """
|
||||||
send_mail(subject, message, from_email, [self.email], **kwargs)
|
send_mail(subject, message, from_email, [self.email], **kwargs)
|
||||||
|
|
||||||
def has_perm(self, perm, obj=None):
|
def set_password(self, raw_password):
|
||||||
"""
|
self.password = make_password(raw_password)
|
||||||
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):
|
def check_password(self, raw_password):
|
||||||
"""
|
"""
|
||||||
Returns True if the user has each of the specified permissions. If
|
Returns a boolean of whether the raw_password was correct. Handles
|
||||||
object is passed, it checks if the user has all required perms for this
|
hashing formats behind the scenes.
|
||||||
object.
|
|
||||||
"""
|
"""
|
||||||
for perm in perm_list:
|
def setter(raw_password):
|
||||||
if not self.has_perm(perm, obj):
|
self.set_password(raw_password)
|
||||||
return False
|
self.save(update_fields=["password"])
|
||||||
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(User, menu=False)
|
services.register(User)
|
||||||
|
|
|
@ -70,8 +70,8 @@ INSTALLED_APPS = (
|
||||||
'orchestra.apps.domains',
|
'orchestra.apps.domains',
|
||||||
'orchestra.apps.users',
|
'orchestra.apps.users',
|
||||||
# 'orchestra.apps.users.roles.mail',
|
# 'orchestra.apps.users.roles.mail',
|
||||||
'orchestra.apps.users.roles.jabber',
|
# 'orchestra.apps.users.roles.jabber',
|
||||||
'orchestra.apps.users.roles.posix',
|
# 'orchestra.apps.users.roles.posix',
|
||||||
'orchestra.apps.mails',
|
'orchestra.apps.mails',
|
||||||
'orchestra.apps.lists',
|
'orchestra.apps.lists',
|
||||||
'orchestra.apps.webapps',
|
'orchestra.apps.webapps',
|
||||||
|
@ -114,7 +114,7 @@ INSTALLED_APPS = (
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
AUTH_USER_MODEL = 'users.User'
|
AUTH_USER_MODEL = 'accounts.Account'
|
||||||
|
|
||||||
|
|
||||||
AUTHENTICATION_BACKENDS = [
|
AUTHENTICATION_BACKENDS = [
|
||||||
|
@ -145,7 +145,6 @@ FLUENT_DASHBOARD_APP_GROUPS = (
|
||||||
'models': (
|
'models': (
|
||||||
'orchestra.apps.accounts.models.Account',
|
'orchestra.apps.accounts.models.Account',
|
||||||
'orchestra.apps.contacts.models.Contact',
|
'orchestra.apps.contacts.models.Contact',
|
||||||
'orchestra.apps.users.models.User',
|
|
||||||
'orchestra.apps.orders.models.Order',
|
'orchestra.apps.orders.models.Order',
|
||||||
'orchestra.apps.services.models.ContractedPlan',
|
'orchestra.apps.services.models.ContractedPlan',
|
||||||
'orchestra.apps.bills.models.Bill',
|
'orchestra.apps.bills.models.Bill',
|
||||||
|
|
Loading…
Reference in New Issue