Skip to content
This repository has been archived by the owner on Apr 28, 2020. It is now read-only.

Commit

Permalink
Remove org and team from email and phone (#232) (#263)
Browse files Browse the repository at this point in the history
Partially satisfies #232 and reverses #125.
  • Loading branch information
jace authored Sep 27, 2018
1 parent 9ecf4fb commit 72265c3
Show file tree
Hide file tree
Showing 8 changed files with 123 additions and 168 deletions.
124 changes: 14 additions & 110 deletions lastuser_core/models/user.py
Original file line number Diff line number Diff line change
Expand Up @@ -595,61 +595,18 @@ def get(cls, buid=None):

# -- User/Org/Team email/phone and misc

class OwnerMixin(object):
"""
Provides the :attr:`owner` property for UserEmail, UserEmailClaim,
UserPhone and UserPhoneClaim.
"""
@property
def owner(self):
"""The owner of this object"""
return self.user or self.org or self.team

@owner.setter
def owner(self, value):
if isinstance(value, User):
self.user = value
self.org = None
self.team = None
elif isinstance(value, Organization):
self.user = None
self.org = value
self.team = None
elif isinstance(value, Team):
self.user = None
self.org = None
self.team = value
else:
raise ValueError(value)


class UserEmail(OwnerMixin, BaseMixin, db.Model):
class UserEmail(BaseMixin, db.Model):
__tablename__ = 'useremail'
user_id = db.Column(None, db.ForeignKey('user.id'), nullable=True)
user_id = db.Column(None, db.ForeignKey('user.id'), nullable=False)
user = db.relationship(User, primaryjoin=user_id == User.id,
backref=db.backref('emails', cascade='all, delete-orphan'))

org_id = db.Column(None, db.ForeignKey('organization.id'), nullable=True)
org = db.relationship(Organization, primaryjoin=org_id == Organization.id,
backref=db.backref('emails', cascade='all, delete-orphan'))

team_id = db.Column(None, db.ForeignKey('team.id'), nullable=True)
team = db.relationship(Team, primaryjoin=team_id == Team.id,
backref=db.backref('emails', cascade='all, delete-orphan'))

_email = db.Column('email', db.Unicode(254), unique=True, nullable=False)
md5sum = db.Column(db.String(32), unique=True, nullable=False)
domain = db.Column(db.Unicode(253), nullable=False, index=True)

private = db.Column(db.Boolean, nullable=False, default=False)
type = db.Column(db.Unicode(30), nullable=True)

__table_args__ = (db.CheckConstraint(
db.case([(user_id != None, 1)], else_=0) +
db.case([(org_id != None, 1)], else_=0) +
db.case([(team_id != None, 1)], else_=0) == 1, # NOQA
name='useremail_user_id_or_org_id_or_team_id'),)

def __init__(self, email, **kwargs):
super(UserEmail, self).__init__(**kwargs)
self._email = email.lower()
Expand All @@ -666,8 +623,8 @@ def email(self):
email = db.synonym('_email', descriptor=email)

def __repr__(self):
return '<UserEmail {email} of {owner}>'.format(
email=self.email, owner=repr(self.owner)[1:-1])
return '<UserEmail {email} of {user}>'.format(
email=self.email, user=repr(self.user)[1:-1])

def __unicode__(self):
return unicode(self.email)
Expand Down Expand Up @@ -712,20 +669,11 @@ def get(cls, email=None, md5sum=None):
DDL('DROP INDEX ix_useremail_email_lower').execute_if(dialect='postgresql'))


class UserEmailClaim(OwnerMixin, BaseMixin, db.Model):
class UserEmailClaim(BaseMixin, db.Model):
__tablename__ = 'useremailclaim'
user_id = db.Column(None, db.ForeignKey('user.id'), nullable=True)
user_id = db.Column(None, db.ForeignKey('user.id'), nullable=False)
user = db.relationship(User, primaryjoin=user_id == User.id,
backref=db.backref('emailclaims', cascade='all, delete-orphan'))

org_id = db.Column(None, db.ForeignKey('organization.id'), nullable=True)
org = db.relationship(Organization, primaryjoin=org_id == Organization.id,
backref=db.backref('emailclaims', cascade='all, delete-orphan'))

team_id = db.Column(None, db.ForeignKey('team.id'), nullable=True)
team = db.relationship(Team, primaryjoin=team_id == Team.id,
backref=db.backref('emailclaims', cascade='all, delete-orphan'))

_email = db.Column('email', db.Unicode(254), nullable=True, index=True)
verification_code = db.Column(db.String(44), nullable=False, default=newsecret)
md5sum = db.Column(db.String(32), nullable=False, index=True)
Expand All @@ -734,17 +682,7 @@ class UserEmailClaim(OwnerMixin, BaseMixin, db.Model):
private = db.Column(db.Boolean, nullable=False, default=False)
type = db.Column(db.Unicode(30), nullable=True)

__table_args__ = (
# Only one of these three unique constraints will apply as null values
# in the *_id columns are ignored for unique constraints
db.UniqueConstraint('user_id', 'email'),
db.UniqueConstraint('org_id', 'email'),
db.UniqueConstraint('team_id', 'email'),
db.CheckConstraint(
db.case([(user_id != None, 1)], else_=0) +
db.case([(org_id != None, 1)], else_=0) +
db.case([(team_id != None, 1)], else_=0) == 1, # NOQA
name='useremailclaim_user_id_or_org_id_or_team_id'))
__table_args__ = (db.UniqueConstraint('user_id', 'email'),)

def __init__(self, email, **kwargs):
super(UserEmailClaim, self).__init__(**kwargs)
Expand All @@ -761,8 +699,8 @@ def email(self):
email = db.synonym('_email', descriptor=email)

def __repr__(self):
return '<UserEmailClaim {email} of {owner}>'.format(
email=self.email, owner=repr(self.owner)[1:-1])
return '<UserEmailClaim {email} of {user}>'.format(
email=self.email, user=repr(self.user)[1:-1])

def __unicode__(self):
return unicode(self.email)
Expand Down Expand Up @@ -796,32 +734,17 @@ def all(cls, email):
return cls.query.filter(UserEmailClaim.email.in_([email, email.lower()])).order_by(cls.user_id).all()


class UserPhone(OwnerMixin, BaseMixin, db.Model):
class UserPhone(BaseMixin, db.Model):
__tablename__ = 'userphone'
user_id = db.Column(None, db.ForeignKey('user.id'), nullable=True)
user_id = db.Column(None, db.ForeignKey('user.id'), nullable=False)
user = db.relationship(User, primaryjoin=user_id == User.id,
backref=db.backref('phones', cascade='all, delete-orphan'))

org_id = db.Column(None, db.ForeignKey('organization.id'), nullable=True)
org = db.relationship(Organization, primaryjoin=org_id == Organization.id,
backref=db.backref('phones', cascade='all, delete-orphan'))

team_id = db.Column(None, db.ForeignKey('team.id'), nullable=True)
team = db.relationship(Team, primaryjoin=team_id == Team.id,
backref=db.backref('phones', cascade='all, delete-orphan'))

_phone = db.Column('phone', db.Unicode(16), unique=True, nullable=False)
gets_text = db.Column(db.Boolean, nullable=False, default=True)

private = db.Column(db.Boolean, nullable=False, default=False)
type = db.Column(db.Unicode(30), nullable=True)

__table_args__ = (db.CheckConstraint(
db.case([(user_id != None, 1)], else_=0) +
db.case([(org_id != None, 1)], else_=0) +
db.case([(team_id != None, 1)], else_=0) == 1, # NOQA
name='userphone_user_id_or_org_id_or_team_id'),)

def __init__(self, phone, **kwargs):
super(UserPhone, self).__init__(**kwargs)
self._phone = phone
Expand Down Expand Up @@ -870,20 +793,11 @@ def get(cls, phone):
return cls.query.filter_by(phone=phone).one_or_none()


class UserPhoneClaim(OwnerMixin, BaseMixin, db.Model):
class UserPhoneClaim(BaseMixin, db.Model):
__tablename__ = 'userphoneclaim'
user_id = db.Column(None, db.ForeignKey('user.id'), nullable=True)
user_id = db.Column(None, db.ForeignKey('user.id'), nullable=False)
user = db.relationship(User, primaryjoin=user_id == User.id,
backref=db.backref('phoneclaims', cascade='all, delete-orphan'))

org_id = db.Column(None, db.ForeignKey('organization.id'), nullable=True)
org = db.relationship(Organization, primaryjoin=org_id == Organization.id,
backref=db.backref('phoneclaims', cascade='all, delete-orphan'))

team_id = db.Column(None, db.ForeignKey('team.id'), nullable=True)
team = db.relationship(Team, primaryjoin=team_id == Team.id,
backref=db.backref('phoneclaims', cascade='all, delete-orphan'))

_phone = db.Column('phone', db.Unicode(16), nullable=False, index=True)
gets_text = db.Column(db.Boolean, nullable=False, default=True)
verification_code = db.Column(db.Unicode(4), nullable=False, default=newpin)
Expand All @@ -892,17 +806,7 @@ class UserPhoneClaim(OwnerMixin, BaseMixin, db.Model):
private = db.Column(db.Boolean, nullable=False, default=False)
type = db.Column(db.Unicode(30), nullable=True)

__table_args__ = (
# Only one of these three unique constraints will apply as null values
# in the *_id columns are ignored for unique constraints
db.UniqueConstraint('user_id', 'phone'),
db.UniqueConstraint('org_id', 'phone'),
db.UniqueConstraint('team_id', 'phone'),
db.CheckConstraint(
db.case([(user_id != None, 1)], else_=0) +
db.case([(org_id != None, 1)], else_=0) +
db.case([(team_id != None, 1)], else_=0) == 1, # NOQA
name='userphoneclaim_user_id_or_org_id_or_team_id'))
__table_args__ = (db.UniqueConstraint('user_id', 'phone'),)

def __init__(self, phone, **kwargs):
super(UserPhoneClaim, self).__init__(**kwargs)
Expand Down
2 changes: 1 addition & 1 deletion lastuser_oauth/templates/emailverify.html.jinja2
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,6 @@
<link itemprop="url" href="{{ request.url_root }}"/>
</div>
</div>
<p>Hello {{ useremail.owner.title }},</p>
<p>Hello {{ useremail.user.fullname }},</p>
<p><a href="{{ url_for('lastuser_oauth.confirm_email', _external=True, md5sum=useremail.md5sum, secret=useremail.verification_code) }}">Click here to confirm your email address</a></p>
<p>If you did not sign up, you may safely ignore this email.</p>
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
"""Remove org and team ownership of email and phone
Revision ID: c446b9bc0691
Revises: f1185c3c4505
Create Date: 2018-09-27 15:58:24.149115
"""
from alembic import op
import sqlalchemy as sa
from sqlalchemy.sql import column


# revision identifiers, used by Alembic.
revision = 'c446b9bc0691'
down_revision = 'f1185c3c4505'
branch_labels = None
depends_on = None


def upgrade():
op.alter_column('useremail', 'user_id', existing_type=sa.INTEGER(), nullable=False)
op.drop_constraint(u'useremail_team_id_fkey', 'useremail', type_='foreignkey')
op.drop_constraint(u'useremail_org_id_fkey', 'useremail', type_='foreignkey')
op.drop_column('useremail', 'team_id')
op.drop_column('useremail', 'org_id')

op.alter_column('useremailclaim', 'user_id', existing_type=sa.INTEGER(), nullable=False)
op.drop_constraint(u'useremailclaim_org_id_email_key', 'useremailclaim', type_='unique')
op.drop_constraint(u'useremailclaim_team_id_email_key', 'useremailclaim', type_='unique')
op.drop_constraint(u'useremailclaim_team_id_fkey', 'useremailclaim', type_='foreignkey')
op.drop_constraint(u'useremailclaim_org_id_fkey', 'useremailclaim', type_='foreignkey')
op.drop_column('useremailclaim', 'team_id')
op.drop_column('useremailclaim', 'org_id')

op.alter_column('userphone', 'user_id', existing_type=sa.INTEGER(), nullable=False)
op.drop_constraint(u'userphone_org_id_fkey', 'userphone', type_='foreignkey')
op.drop_constraint(u'userphone_team_id_fkey', 'userphone', type_='foreignkey')
op.drop_column('userphone', 'team_id')
op.drop_column('userphone', 'org_id')

op.alter_column('userphoneclaim', 'user_id', existing_type=sa.INTEGER(), nullable=False)
op.drop_constraint(u'userphoneclaim_org_id_phone_key', 'userphoneclaim', type_='unique')
op.drop_constraint(u'userphoneclaim_team_id_phone_key', 'userphoneclaim', type_='unique')
op.drop_constraint(u'userphoneclaim_team_id_fkey', 'userphoneclaim', type_='foreignkey')
op.drop_constraint(u'userphoneclaim_org_id_fkey', 'userphoneclaim', type_='foreignkey')
op.drop_column('userphoneclaim', 'team_id')
op.drop_column('userphoneclaim', 'org_id')


def downgrade():
op.add_column('userphoneclaim', sa.Column('org_id', sa.INTEGER(), autoincrement=False, nullable=True))
op.add_column('userphoneclaim', sa.Column('team_id', sa.INTEGER(), autoincrement=False, nullable=True))
op.create_foreign_key(u'userphoneclaim_org_id_fkey', 'userphoneclaim', 'organization', ['org_id'], ['id'])
op.create_foreign_key(u'userphoneclaim_team_id_fkey', 'userphoneclaim', 'team', ['team_id'], ['id'])
op.create_unique_constraint(u'userphoneclaim_team_id_phone_key', 'userphoneclaim', ['team_id', 'phone'])
op.create_unique_constraint(u'userphoneclaim_org_id_phone_key', 'userphoneclaim', ['org_id', 'phone'])
op.alter_column('userphoneclaim', 'user_id', existing_type=sa.INTEGER(), nullable=True)
op.create_check_constraint('userphoneclaim_user_id_or_org_id_or_team_id', 'userphoneclaim',
sa.case([(column('user_id') != None, 1)], else_=0) +
sa.case([(column('org_id') != None, 1)], else_=0) +
sa.case([(column('team_id') != None, 1)], else_=0) == 1) # NOQA

op.add_column('userphone', sa.Column('org_id', sa.INTEGER(), autoincrement=False, nullable=True))
op.add_column('userphone', sa.Column('team_id', sa.INTEGER(), autoincrement=False, nullable=True))
op.create_foreign_key(u'userphone_team_id_fkey', 'userphone', 'team', ['team_id'], ['id'])
op.create_foreign_key(u'userphone_org_id_fkey', 'userphone', 'organization', ['org_id'], ['id'])
op.alter_column('userphone', 'user_id', existing_type=sa.INTEGER(), nullable=True)
op.create_check_constraint('userphone_user_id_or_org_id_or_team_id', 'userphone',
sa.case([(column('user_id') != None, 1)], else_=0) +
sa.case([(column('org_id') != None, 1)], else_=0) +
sa.case([(column('team_id') != None, 1)], else_=0) == 1) # NOQA

op.add_column('useremailclaim', sa.Column('org_id', sa.INTEGER(), autoincrement=False, nullable=True))
op.add_column('useremailclaim', sa.Column('team_id', sa.INTEGER(), autoincrement=False, nullable=True))
op.create_foreign_key(u'useremailclaim_org_id_fkey', 'useremailclaim', 'organization', ['org_id'], ['id'])
op.create_foreign_key(u'useremailclaim_team_id_fkey', 'useremailclaim', 'team', ['team_id'], ['id'])
op.create_unique_constraint(u'useremailclaim_team_id_email_key', 'useremailclaim', ['team_id', 'email'])
op.create_unique_constraint(u'useremailclaim_org_id_email_key', 'useremailclaim', ['org_id', 'email'])
op.alter_column('useremailclaim', 'user_id', existing_type=sa.INTEGER(), nullable=True)
op.create_check_constraint('useremailclaim_user_id_or_org_id_or_team_id', 'useremailclaim',
sa.case([(column('user_id') != None, 1)], else_=0) +
sa.case([(column('org_id') != None, 1)], else_=0) +
sa.case([(column('team_id') != None, 1)], else_=0) == 1) # NOQA

op.add_column('useremail', sa.Column('org_id', sa.INTEGER(), autoincrement=False, nullable=True))
op.add_column('useremail', sa.Column('team_id', sa.INTEGER(), autoincrement=False, nullable=True))
op.create_foreign_key(u'useremail_org_id_fkey', 'useremail', 'organization', ['org_id'], ['id'])
op.create_foreign_key(u'useremail_team_id_fkey', 'useremail', 'team', ['team_id'], ['id'])
op.alter_column('useremail', 'user_id', existing_type=sa.INTEGER(), nullable=True)
op.create_check_constraint('useremail_user_id_or_org_id_or_team_id', 'useremail',
sa.case([(column('user_id') != None, 1)], else_=0) +
sa.case([(column('org_id') != None, 1)], else_=0) +
sa.case([(column('team_id') != None, 1)], else_=0) == 1) # NOQA
42 changes: 0 additions & 42 deletions tests/unit/lastuser_core/test_model_user_OwnerMixin.py

This file was deleted.

Loading

0 comments on commit 72265c3

Please sign in to comment.