diff --git a/orchestra/admin/menu.py b/orchestra/admin/menu.py index 67a34a53..b330de2f 100644 --- a/orchestra/admin/menu.py +++ b/orchestra/admin/menu.py @@ -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)) diff --git a/orchestra/apps/accounts/admin.py b/orchestra/apps/accounts/admin.py index 70bdb23d..189ed31e 100644 --- a/orchestra/apps/accounts/admin.py +++ b/orchestra/apps/accounts/admin.py @@ -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 '%(name)s' % 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 '%s' % (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'): diff --git a/orchestra/apps/accounts/api.py b/orchestra/apps/accounts/api.py index e1b363d4..7165be20 100644 --- a/orchestra/apps/accounts/api.py +++ b/orchestra/apps/accounts/api.py @@ -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) diff --git a/orchestra/apps/accounts/forms.py b/orchestra/apps/accounts/forms.py index bb3eabad..e59a574f 100644 --- a/orchestra/apps/accounts/forms.py +++ b/orchestra/apps/accounts/forms.py @@ -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. diff --git a/orchestra/apps/accounts/management/commands/createinitialaccount.py b/orchestra/apps/accounts/management/commands/createinitialaccount.py index 8e5b1bc5..2e1cfa37 100644 --- a/orchestra/apps/accounts/management/commands/createinitialaccount.py +++ b/orchestra/apps/accounts/management/commands/createinitialaccount.py @@ -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) diff --git a/orchestra/apps/accounts/management/commands/createsuperuser.py b/orchestra/apps/accounts/management/commands/createsuperuser.py index 20d05244..abd4d26e 100644 --- a/orchestra/apps/accounts/management/commands/createsuperuser.py +++ b/orchestra/apps/accounts/management/commands/createsuperuser.py @@ -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] diff --git a/orchestra/apps/accounts/migrations/0001_initial.py b/orchestra/apps/accounts/migrations/0001_initial.py deleted file mode 100644 index 759b6e70..00000000 --- a/orchestra/apps/accounts/migrations/0001_initial.py +++ /dev/null @@ -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,), - ), - ] diff --git a/orchestra/apps/accounts/migrations/0002_auto_20140909_1850.py b/orchestra/apps/accounts/migrations/0002_auto_20140909_1850.py deleted file mode 100644 index c7f11cde..00000000 --- a/orchestra/apps/accounts/migrations/0002_auto_20140909_1850.py +++ /dev/null @@ -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), - ), - ] diff --git a/orchestra/apps/accounts/migrations/0003_auto_20140926_1325.py b/orchestra/apps/accounts/migrations/0003_auto_20140926_1325.py deleted file mode 100644 index 735351a3..00000000 --- a/orchestra/apps/accounts/migrations/0003_auto_20140926_1325.py +++ /dev/null @@ -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, - ), - ] diff --git a/orchestra/apps/accounts/migrations/__init__.py b/orchestra/apps/accounts/migrations/__init__.py deleted file mode 100644 index e69de29b..00000000 diff --git a/orchestra/apps/accounts/models.py b/orchestra/apps/accounts/models.py index 08f10d74..c8b4b3d1 100644 --- a/orchestra/apps/accounts/models.py +++ b/orchestra/apps/accounts/models.py @@ -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) diff --git a/orchestra/apps/accounts/serializers.py b/orchestra/apps/accounts/serializers.py index 8da396ba..01256647 100644 --- a/orchestra/apps/accounts/serializers.py +++ b/orchestra/apps/accounts/serializers.py @@ -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' ) diff --git a/orchestra/apps/bills/migrations/0001_initial.py b/orchestra/apps/bills/migrations/0001_initial.py deleted file mode 100644 index f14e385c..00000000 --- a/orchestra/apps/bills/migrations/0001_initial.py +++ /dev/null @@ -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',), - ), - ] diff --git a/orchestra/apps/bills/migrations/0002_bill_closed_on.py b/orchestra/apps/bills/migrations/0002_bill_closed_on.py deleted file mode 100644 index 5ab0d042..00000000 --- a/orchestra/apps/bills/migrations/0002_bill_closed_on.py +++ /dev/null @@ -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, - ), - ] diff --git a/orchestra/apps/bills/migrations/0003_bill_total.py b/orchestra/apps/bills/migrations/0003_bill_total.py deleted file mode 100644 index 6f51c303..00000000 --- a/orchestra/apps/bills/migrations/0003_bill_total.py +++ /dev/null @@ -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, - ), - ] diff --git a/orchestra/apps/bills/migrations/0004_auto_20140911_1234.py b/orchestra/apps/bills/migrations/0004_auto_20140911_1234.py deleted file mode 100644 index ae41b309..00000000 --- a/orchestra/apps/bills/migrations/0004_auto_20140911_1234.py +++ /dev/null @@ -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), - ), - ] diff --git a/orchestra/apps/bills/migrations/0005_auto_20140911_1234.py b/orchestra/apps/bills/migrations/0005_auto_20140911_1234.py deleted file mode 100644 index bff6b210..00000000 --- a/orchestra/apps/bills/migrations/0005_auto_20140911_1234.py +++ /dev/null @@ -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', - ), - ] diff --git a/orchestra/apps/bills/migrations/0006_auto_20140911_1238.py b/orchestra/apps/bills/migrations/0006_auto_20140911_1238.py deleted file mode 100644 index 018be2b3..00000000 --- a/orchestra/apps/bills/migrations/0006_auto_20140911_1238.py +++ /dev/null @@ -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'), - ), - ] diff --git a/orchestra/apps/bills/migrations/0007_auto_20140918_1454.py b/orchestra/apps/bills/migrations/0007_auto_20140918_1454.py deleted file mode 100644 index 43dff9f6..00000000 --- a/orchestra/apps/bills/migrations/0007_auto_20140918_1454.py +++ /dev/null @@ -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, - ), - ] diff --git a/orchestra/apps/bills/migrations/0008_auto_20140926_1218.py b/orchestra/apps/bills/migrations/0008_auto_20140926_1218.py deleted file mode 100644 index 561885ee..00000000 --- a/orchestra/apps/bills/migrations/0008_auto_20140926_1218.py +++ /dev/null @@ -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'}, - ), - ] diff --git a/orchestra/apps/bills/migrations/0009_auto_20140926_1220.py b/orchestra/apps/bills/migrations/0009_auto_20140926_1220.py deleted file mode 100644 index 1382c851..00000000 --- a/orchestra/apps/bills/migrations/0009_auto_20140926_1220.py +++ /dev/null @@ -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, - ), - ] diff --git a/orchestra/apps/bills/migrations/0010_auto_20140926_1326.py b/orchestra/apps/bills/migrations/0010_auto_20140926_1326.py deleted file mode 100644 index e4b5c90e..00000000 --- a/orchestra/apps/bills/migrations/0010_auto_20140926_1326.py +++ /dev/null @@ -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'), - ), - ] diff --git a/orchestra/apps/bills/migrations/0011_auto_20140926_1334.py b/orchestra/apps/bills/migrations/0011_auto_20140926_1334.py deleted file mode 100644 index a31d489e..00000000 --- a/orchestra/apps/bills/migrations/0011_auto_20140926_1334.py +++ /dev/null @@ -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, - ), - ] diff --git a/orchestra/apps/bills/migrations/0012_auto_20140926_1458.py b/orchestra/apps/bills/migrations/0012_auto_20140926_1458.py deleted file mode 100644 index 321a4086..00000000 --- a/orchestra/apps/bills/migrations/0012_auto_20140926_1458.py +++ /dev/null @@ -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', - ), - ] diff --git a/orchestra/apps/bills/migrations/__init__.py b/orchestra/apps/bills/migrations/__init__.py deleted file mode 100644 index e69de29b..00000000 diff --git a/orchestra/apps/databases/admin.py b/orchestra/apps/databases/admin.py index c54a9bfe..94d171b5 100644 --- a/orchestra/apps/databases/admin.py +++ b/orchestra/apps/databases/admin.py @@ -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') diff --git a/orchestra/apps/domains/admin.py b/orchestra/apps/domains/admin.py index 0ee63fac..bc0498bd 100644 --- a/orchestra/apps/domains/admin.py +++ b/orchestra/apps/domains/admin.py @@ -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') diff --git a/orchestra/apps/domains/migrations/0001_initial.py b/orchestra/apps/domains/migrations/0001_initial.py deleted file mode 100644 index 5fb4bd30..00000000 --- a/orchestra/apps/domains/migrations/0001_initial.py +++ /dev/null @@ -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,), - ), - ] diff --git a/orchestra/apps/domains/migrations/0002_record_ttl.py b/orchestra/apps/domains/migrations/0002_record_ttl.py deleted file mode 100644 index 8ce4f8ff..00000000 --- a/orchestra/apps/domains/migrations/0002_record_ttl.py +++ /dev/null @@ -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, - ), - ] diff --git a/orchestra/apps/domains/migrations/__init__.py b/orchestra/apps/domains/migrations/__init__.py deleted file mode 100644 index e69de29b..00000000 diff --git a/orchestra/apps/orders/actions.py b/orchestra/apps/orders/actions.py index 8b031ce8..4f8fe13b 100644 --- a/orchestra/apps/orders/actions.py +++ b/orchestra/apps/orders/actions.py @@ -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 diff --git a/orchestra/apps/payments/admin.py b/orchestra/apps/payments/admin.py index 4ce329b0..f58818d5 100644 --- a/orchestra/apps/payments/admin.py +++ b/orchestra/apps/payments/admin.py @@ -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() diff --git a/orchestra/apps/resources/migrations/0001_initial.py b/orchestra/apps/resources/migrations/0001_initial.py deleted file mode 100644 index 17be9bb7..00000000 --- a/orchestra/apps/resources/migrations/0001_initial.py +++ /dev/null @@ -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')]), - ), - ] diff --git a/orchestra/apps/resources/migrations/0002_auto_20140926_1143.py b/orchestra/apps/resources/migrations/0002_auto_20140926_1143.py deleted file mode 100644 index 5e2bc3f6..00000000 --- a/orchestra/apps/resources/migrations/0002_auto_20140926_1143.py +++ /dev/null @@ -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', - ), - ] diff --git a/orchestra/apps/resources/migrations/0003_auto_20140926_1325.py b/orchestra/apps/resources/migrations/0003_auto_20140926_1325.py deleted file mode 100644 index ee2eab56..00000000 --- a/orchestra/apps/resources/migrations/0003_auto_20140926_1325.py +++ /dev/null @@ -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'), - ), - ] diff --git a/orchestra/apps/resources/migrations/__init__.py b/orchestra/apps/resources/migrations/__init__.py deleted file mode 100644 index e69de29b..00000000 diff --git a/orchestra/apps/services/models.py b/orchestra/apps/services/models.py index c9174c72..a53bcc78 100644 --- a/orchestra/apps/services/models.py +++ b/orchestra/apps/services/models.py @@ -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) diff --git a/orchestra/apps/users/admin.py b/orchestra/apps/users/admin.py index 6451d0af..6f049fd5 100644 --- a/orchestra/apps/users/admin.py +++ b/orchestra/apps/users/admin.py @@ -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) diff --git a/orchestra/apps/users/models.py b/orchestra/apps/users/models.py index b91b72aa..6eea5e24 100644 --- a/orchestra/apps/users/models.py +++ b/orchestra/apps/users/models.py @@ -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) diff --git a/orchestra/conf/base_settings.py b/orchestra/conf/base_settings.py index f9e67fe4..28470f5c 100644 --- a/orchestra/conf/base_settings.py +++ b/orchestra/conf/base_settings.py @@ -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',