Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Simplify the User database model by dropping unused columns #2944

Merged
merged 2 commits into from
May 29, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions .ci/setup_profiles.sh
Original file line number Diff line number Diff line change
Expand Up @@ -16,14 +16,14 @@ then

# Setup the main profile
verdi setup --profile $TEST_AIIDA_BACKEND \
--email="aiida@localhost" --first-name=AiiDA --last-name=test --institution="AiiDA Team" --password 'secret' \
--email="aiida@localhost" --first-name=AiiDA --last-name=test --institution="AiiDA Team" \
--db-engine 'postgresql_psycopg2' --db-backend=$TEST_AIIDA_BACKEND --db-host="localhost" --db-port=5432 \
--db-name="$TEST_AIIDA_BACKEND" --db-username=postgres --db-password='' \
--repository="/tmp/repository_${TEST_AIIDA_BACKEND}/" --non-interactive

# Setup the test profile
verdi setup --profile test_$TEST_AIIDA_BACKEND \
--email="aiida@localhost" --first-name=AiiDA --last-name=test --institution="AiiDA Team" --password 'secret' \
--email="aiida@localhost" --first-name=AiiDA --last-name=test --institution="AiiDA Team" \
--db-engine 'postgresql_psycopg2' --db-backend=$TEST_AIIDA_BACKEND --db-host="localhost" --db-port=5432 \
--db-name="test_$TEST_AIIDA_BACKEND" --db-username=postgres --db-password='' \
--repository="/tmp/test_repository_test_${TEST_AIIDA_BACKEND}/" --non-interactive
Expand Down
1 change: 0 additions & 1 deletion .pre-commit-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,6 @@
aiida/backends/djsite/queries.py|
aiida/backends/profile.py|
aiida/backends/general/abstractqueries.py|
aiida/backends/sqlalchemy/alembic_manage.py|
aiida/backends/sqlalchemy/globalsettings.py|
aiida/backends/sqlalchemy/__init__.py|
aiida/backends/sqlalchemy/migrations/env.py|
Expand Down
14 changes: 7 additions & 7 deletions aiida/backends/djsite/db/migrations/0001_initial.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@
from django.db import models, migrations
import django.db.models.deletion
import django.utils.timezone
from django.conf import settings

from aiida.backends.djsite.db.migrations import upgrade_schema_version

Expand All @@ -25,6 +24,7 @@


class Migration(migrations.Migration):

dependencies = [
('auth', '0001_initial'),
]
Expand Down Expand Up @@ -89,7 +89,7 @@ class Migration(migrations.Migration):
('auth_params', models.TextField(default=u'{}')),
('metadata', models.TextField(default=u'{}')),
('enabled', models.BooleanField(default=True)),
('aiidauser', models.ForeignKey(to=settings.AUTH_USER_MODEL)),
('aiidauser', models.ForeignKey(to='db.DbUser')),
],
options={
},
Expand Down Expand Up @@ -291,7 +291,7 @@ class Migration(migrations.Migration):
('module_class', models.TextField()),
('script_path', models.TextField()),
('script_md5', models.CharField(max_length=255)),
('user', models.ForeignKey(to=settings.AUTH_USER_MODEL, on_delete=django.db.models.deletion.PROTECT)),
('user', models.ForeignKey(to='db.DbUser', on_delete=django.db.models.deletion.PROTECT)),
],
options={
},
Expand Down Expand Up @@ -326,7 +326,7 @@ class Migration(migrations.Migration):
('calculations', models.ManyToManyField(related_name='workflow_step', to='db.DbNode')),
('parent', models.ForeignKey(related_name='steps', to='db.DbWorkflow')),
('sub_workflows', models.ManyToManyField(related_name='parent_workflow_step', to='db.DbWorkflow')),
('user', models.ForeignKey(to=settings.AUTH_USER_MODEL, on_delete=django.db.models.deletion.PROTECT)),
('user', models.ForeignKey(to='db.DbUser', on_delete=django.db.models.deletion.PROTECT)),
],
options={
},
Expand Down Expand Up @@ -367,7 +367,7 @@ class Migration(migrations.Migration):
model_name='dbnode',
name='user',
field=models.ForeignKey(related_name='dbnodes', on_delete=django.db.models.deletion.PROTECT,
to=settings.AUTH_USER_MODEL),
to='db.DbUser'),
preserve_default=True,
),
migrations.AddField(
Expand Down Expand Up @@ -396,7 +396,7 @@ class Migration(migrations.Migration):
migrations.AddField(
model_name='dbgroup',
name='user',
field=models.ForeignKey(related_name='dbgroups', to=settings.AUTH_USER_MODEL),
field=models.ForeignKey(related_name='dbgroups', to='db.DbUser'),
preserve_default=True,
),
migrations.AlterUniqueTogether(
Expand All @@ -422,7 +422,7 @@ class Migration(migrations.Migration):
migrations.AddField(
model_name='dbcomment',
name='user',
field=models.ForeignKey(to=settings.AUTH_USER_MODEL),
field=models.ForeignKey(to='db.DbUser'),
preserve_default=True,
),
migrations.AddField(
Expand Down
68 changes: 68 additions & 0 deletions aiida/backends/djsite/db/migrations/0035_simplify_user_model.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
# -*- coding: utf-8 -*-
###########################################################################
# Copyright (c), The AiiDA team. All rights reserved. #
# This file is part of the AiiDA code. #
# #
# The code is hosted on GitHub at https://github.com/aiidateam/aiida_core #
# For further information on the license, see the LICENSE.txt file #
# For further information please visit http://www.aiida.net #
###########################################################################
# pylint: disable=invalid-name,too-few-public-methods
"""Simplify the `DbUser` model."""
from __future__ import division
from __future__ import print_function
from __future__ import unicode_literals
from __future__ import absolute_import

# Remove when https://github.com/PyCQA/pylint/issues/1931 is fixed
# pylint: disable=no-name-in-module,import-error,no-member
from django.db import migrations

from aiida.backends.djsite.db.migrations import upgrade_schema_version

REVISION = '1.0.35'
DOWN_REVISION = '1.0.34'


class Migration(migrations.Migration):
"""Simplify the `DbUser` model by dropping unused columns."""

dependencies = [
('db', '0034_drop_node_columns_nodeversion_public'),
]

operations = [
migrations.RemoveField(
model_name='dbuser',
name='password',
),
migrations.RemoveField(
model_name='dbuser',
name='date_joined',
),
migrations.RemoveField(
model_name='dbuser',
name='groups',
),
migrations.RemoveField(
model_name='dbuser',
name='is_active',
),
migrations.RemoveField(
model_name='dbuser',
name='is_staff',
),
migrations.RemoveField(
model_name='dbuser',
name='is_superuser',
),
migrations.RemoveField(
model_name='dbuser',
name='last_login',
),
migrations.RemoveField(
model_name='dbuser',
name='user_permissions',
),
upgrade_schema_version(REVISION, DOWN_REVISION)
]
2 changes: 1 addition & 1 deletion aiida/backends/djsite/db/migrations/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ class DeserializationException(AiidaException):
pass


LATEST_MIGRATION = '0034_drop_node_columns_nodeversion_public'
LATEST_MIGRATION = '0035_simplify_user_model'


def _update_schema_version(version, apps, schema_editor):
Expand Down
67 changes: 15 additions & 52 deletions aiida/backends/djsite/db/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,19 +13,16 @@

import contextlib
import six
from six.moves import zip, range
from six.moves import range
from django.db import models as m
from django.contrib.auth.models import (
AbstractBaseUser, BaseUserManager, PermissionsMixin)
from django.contrib.postgres.fields import JSONField
from django.utils.encoding import python_2_unicode_compatible
from django.core.exceptions import ObjectDoesNotExist
from django.db.models.query import QuerySet

from aiida.common import timezone
from aiida.common.utils import get_new_uuid
from aiida.common.exceptions import (ConfigurationError, DbContentError)
from aiida.backends.djsite.settings import AUTH_USER_MODEL
from aiida.common.exceptions import DbContentError
import aiida.backends.djsite.db.migrations as migrations
from aiida.backends.utils import AIIDA_ATTRIBUTE_SEP

Expand Down Expand Up @@ -70,55 +67,21 @@ def get_queryset(self):
return AiidaQuerySet(self.model, using=self._db)


class DbUserManager(BaseUserManager):
def create_user(self, email, password=None, **extra_fields):
"""
Creates and saves a User with the given email (that is the
username) and password.
"""
now = timezone.now()
if not email:
raise ValueError('The given email must be set')
email = BaseUserManager.normalize_email(email)
user = self.model(email=email,
is_staff=False, is_active=True, is_superuser=False,
last_login=now, date_joined=now, **extra_fields)

user.set_password(password)
user.save(using=self._db)
return user

def create_superuser(self, email, password, **extra_fields):
u = self.create_user(email, password, **extra_fields)
u.is_staff = True
u.is_active = True
u.is_superuser = True
u.save(using=self._db)
return u


class DbUser(AbstractBaseUser, PermissionsMixin):
"""
This class replaces the default User class of Django
"""
class DbUser(m.Model):
"""Class that represents a user as the owner of a specific Node."""

is_anonymous = False
is_authenticated = True

USERNAME_FIELD = 'email'
REQUIRED_FIELDS = ()

# Set unique email field
email = m.EmailField(unique=True, db_index=True)
first_name = m.CharField(max_length=254, blank=True)
last_name = m.CharField(max_length=254, blank=True)
institution = m.CharField(max_length=254, blank=True)

is_staff = m.BooleanField(default=False,
help_text='Designates whether the user can log into this admin '
'site.')
is_active = m.BooleanField(default=True,
help_text='Designates whether this user should be treated as '
'active. Unselect this instead of deleting accounts.')
date_joined = m.DateTimeField(default=timezone.now)

USERNAME_FIELD = 'email'

objects = DbUserManager()


@python_2_unicode_compatible
class DbNode(m.Model):
Expand Down Expand Up @@ -156,7 +119,7 @@ class DbNode(m.Model):
ctime = m.DateTimeField(default=timezone.now, db_index=True, editable=False)
mtime = m.DateTimeField(auto_now=True, db_index=True, editable=False)
# Cannot delete a user if something is associated to it
user = m.ForeignKey(AUTH_USER_MODEL, on_delete=m.PROTECT, related_name='dbnodes')
user = m.ForeignKey(DbUser, on_delete=m.PROTECT, related_name='dbnodes')

# Direct links
outputs = m.ManyToManyField('self', symmetrical=False,
Expand Down Expand Up @@ -1243,7 +1206,7 @@ class DbGroup(m.Model):
# The owner of the group, not of the calculations
# On user deletion, remove his/her groups too (not the calcuations, only
# the groups
user = m.ForeignKey(AUTH_USER_MODEL, on_delete=m.CASCADE,
user = m.ForeignKey(DbUser, on_delete=m.CASCADE,
related_name='dbgroups')

class Meta:
Expand Down Expand Up @@ -1307,7 +1270,7 @@ class DbAuthInfo(m.Model):
information.
"""
# Delete the DbAuthInfo if either the user or the computer are removed
aiidauser = m.ForeignKey(AUTH_USER_MODEL, on_delete=m.CASCADE)
aiidauser = m.ForeignKey(DbUser, on_delete=m.CASCADE)
dbcomputer = m.ForeignKey(DbComputer, on_delete=m.CASCADE)
auth_params = JSONField(default=dict) # contains mainly the remoteuser and the private_key

Expand Down Expand Up @@ -1336,7 +1299,7 @@ class DbComment(m.Model):
ctime = m.DateTimeField(default=timezone.now, editable=False)
mtime = m.DateTimeField(auto_now=True, editable=False)
# Delete the comments of a deleted user (TODO: check if this is a good policy)
user = m.ForeignKey(AUTH_USER_MODEL, on_delete=m.CASCADE)
user = m.ForeignKey(DbUser, on_delete=m.CASCADE)
content = m.TextField(blank=True)

def __str__(self):
Expand Down
43 changes: 21 additions & 22 deletions aiida/backends/djsite/manage.py
100644 → 100755
Original file line number Diff line number Diff line change
Expand Up @@ -11,33 +11,32 @@
from __future__ import division
from __future__ import print_function
from __future__ import absolute_import
import sys

import click

if __name__ == "__main__":
from django.core.management import execute_from_command_line

# Copy sys.argv
actual_argv = sys.argv[:]
from aiida.cmdline.params import options

# Check if there is also a cmdline option is --aiida-profile=PROFILENAME
try:
first_cmdline_option = sys.argv[1]
except IndexError:
first_cmdline_option = None

profile_name = None # Use the default profile if not specified
if first_cmdline_option is not None:
cmdprefix = "--aiida-profile="
if first_cmdline_option.startswith(cmdprefix):
profile_name = first_cmdline_option[len(cmdprefix):]
# I remove the argument I just read
actual_argv = [actual_argv[0]] + actual_argv[2:]
@click.command()
@options.PROFILE(required=True)
@click.argument('command', nargs=-1)
def main(profile, command):
"""Simple wrapper around the Django command line tool that first loads an AiiDA profile."""
from django.core.management import execute_from_command_line

# Load the profile
# Load the general load_dbenv.
from aiida.manage.configuration import load_profile
from aiida.manage.manager import get_manager
load_profile(profile_name)
get_manager().get_backend()

execute_from_command_line(actual_argv)
load_profile(profile=profile.name)
manager = get_manager()
manager._load_backend(schema_check=False)

# The `execute_from_command` expects a list of command line arguments where the first is the program name that one
# would normally call directly. Since this is now replaced by our `click` command we just spoof a random name.
argv = ['basename'] + list(command)
execute_from_command_line(argv)


if __name__ == '__main__':
main()
4 changes: 0 additions & 4 deletions aiida/backends/djsite/settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,6 @@
'context_processors': [
'django.template.context_processors.debug',
'django.template.context_processors.request',
'django.contrib.auth.context_processors.auth',
'django.contrib.messages.context_processors.messages',
],
'debug':
Expand All @@ -113,8 +112,5 @@
INSTALLED_APPS = [
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'aiida.backends.djsite.db',
]
Loading