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

Commit

Permalink
Linter fixes
Browse files Browse the repository at this point in the history
  • Loading branch information
jace committed Jun 21, 2019
1 parent 48eaaf3 commit 18e3af9
Show file tree
Hide file tree
Showing 36 changed files with 441 additions and 439 deletions.
2 changes: 1 addition & 1 deletion features/steps/failed_login.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ def given_existing_user(context):
context.test_user = dict(
username='bobthehacker',
password='bobthehacker'
)
)


@when("the nonexisting user tries to log in")
Expand Down
2 changes: 1 addition & 1 deletion features/steps/failed_registration.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ def given_new_user(context):
username='alyssa',
password='alyssa',
confirm_password='alyssa'
)
)
# registering the test user
context.browser.visit('/register')
assert context.browser.find_element_by_name('csrf_token').is_enabled()
Expand Down
4 changes: 2 additions & 2 deletions features/steps/login.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ def given_existing_user(context):
username='alyssa',
password='alyssa',
confirm_password='alyssa'
)
)

context.browser.visit('/register')
assert context.browser.find_element_by_name('csrf_token').is_enabled()
Expand All @@ -26,7 +26,7 @@ def when_login_form_submit(context):
context.login_data = {
'username': context.test_user['username'],
'password': context.test_user['password']
}
}
wait = ui.WebDriverWait(context.browser, 30)

context.browser.visit('/login')
Expand Down
4 changes: 2 additions & 2 deletions features/steps/registration.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ def given_new_user(context):
username='alyssa',
password='alyssa',
confirm_password='alyssa'
)
)


@when('a new user submits the registration form with the proper details')
Expand All @@ -29,4 +29,4 @@ def when_form_submit(context):
def then_user_registered(context):
user = User.get(username=context.test_user['username'])
assert user is not None
assert len(user.emailclaims) is 1
assert len(user.emailclaims) == 1
80 changes: 7 additions & 73 deletions lastuser_core/models/__init__.py
Original file line number Diff line number Diff line change
@@ -1,80 +1,14 @@
# -*- coding: utf-8 -*-
# flake8: noqa

# Imported from here by other models
from coaster.sqlalchemy import TimestampMixin, BaseMixin, BaseScopedNameMixin, UuidMixin # NOQA
from coaster.sqlalchemy import TimestampMixin, BaseMixin, BaseScopedNameMixin, UuidMixin
from coaster.db import db

TimestampMixin.__with_timezone__ = True

from .user import * # NOQA
from .session import * # NOQA
from .client import * # NOQA
from .notification import * # NOQA


def getuser(name):
if '@' in name:
# TODO: This should have used UserExternalId.__at_username_services__,
# but this bit has traditionally been for Twitter only. Fix pending.
if name.startswith('@'):
extid = UserExternalId.get(service='twitter', username=name[1:])
if extid and extid.user.is_active:
return extid.user
else:
return None
else:
useremail = UserEmail.get(email=name)
if useremail and useremail.user is not None and useremail.user.is_active:
return useremail.user
# No verified email id. Look for an unverified id; return first found
results = UserEmailClaim.all(email=name)
if results and results[0].user.is_active:
return results[0].user
return None
else:
return User.get(username=name)


def getextid(service, userid):
return UserExternalId.get(service=service, userid=userid)


def merge_users(user1, user2):
"""
Merge two user accounts and return the new user account.
"""
# Always keep the older account and merge from the newer account
if user1.created_at < user2.created_at:
keep_user, merge_user = user1, user2
else:
keep_user, merge_user = user2, user1

# 1. Release the username
if not keep_user.username:
if merge_user.username:
# Flush before re-assigning to avoid dupe name constraint
username = merge_user.username
merge_user.username = None
db.session.flush()
keep_user.username = username
merge_user.username = None

# 2. Inspect all tables for foreign key references to merge_user and switch to keep_user.
for model in db.Model.__subclasses__():
if model != User:
# a. This is a model and it's not the User model. Does it have a migrate_user classmethod?
if hasattr(model, 'migrate_user'):
model.migrate_user(olduser=merge_user, newuser=keep_user)
# b. No migrate_user? Does it have a user_id column?
elif hasattr(model, 'user_id') and hasattr(model, 'query'):
for row in model.query.filter_by(user_id=merge_user.id).all():
row.user_id = keep_user.id
# 3. Add merge_user's uuid to olduserids. Commit session.
db.session.add(UserOldId(id=merge_user.uuid, user=keep_user))
# 4. Mark merge_user as merged. Commit session.
merge_user.status = USER_STATUS.MERGED
# 5. Commit all of this
db.session.commit()

# 6. Return keep_user.
return keep_user
from .user import *
from .session import *
from .client import *
from .notification import *
from .helpers import *
2 changes: 1 addition & 1 deletion lastuser_core/models/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ def _scope_get(self):
if not self._scope:
return ()
else:
return tuple(sorted([t.strip() for t in self._scope.replace('\r', ' ').replace('\n', ' ').split(u' ') if t]))
return tuple(sorted(self._scope.split()))

def _scope_set(self, value):
if isinstance(value, basestring):
Expand Down
73 changes: 73 additions & 0 deletions lastuser_core/models/helpers.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
# -*- coding: utf-8 -*-

from .user import db, User, UserEmail, UserEmailClaim, UserExternalId, UserOldId, USER_STATUS

__all__ = ['getuser', 'getextid', 'merge_users']


def getuser(name):
if '@' in name:
# TODO: This should have used UserExternalId.__at_username_services__,
# but this bit has traditionally been for Twitter only. Fix pending.
if name.startswith('@'):
extid = UserExternalId.get(service='twitter', username=name[1:])
if extid and extid.user.is_active:
return extid.user
else:
return None
else:
useremail = UserEmail.get(email=name)
if useremail and useremail.user is not None and useremail.user.is_active:
return useremail.user
# No verified email id. Look for an unverified id; return first found
results = UserEmailClaim.all(email=name)
if results and results[0].user.is_active:
return results[0].user
return None
else:
return User.get(username=name)


def getextid(service, userid):
return UserExternalId.get(service=service, userid=userid)


def merge_users(user1, user2):
"""
Merge two user accounts and return the new user account.
"""
# Always keep the older account and merge from the newer account
if user1.created_at < user2.created_at:
keep_user, merge_user = user1, user2
else:
keep_user, merge_user = user2, user1

# 1. Release the username
if not keep_user.username:
if merge_user.username:
# Flush before re-assigning to avoid dupe name constraint
username = merge_user.username
merge_user.username = None
db.session.flush()
keep_user.username = username
merge_user.username = None

# 2. Inspect all tables for foreign key references to merge_user and switch to keep_user.
for model in db.Model.__subclasses__():
if model != User:
# a. This is a model and it's not the User model. Does it have a migrate_user classmethod?
if hasattr(model, 'migrate_user'):
model.migrate_user(olduser=merge_user, newuser=keep_user)
# b. No migrate_user? Does it have a user_id column?
elif hasattr(model, 'user_id') and hasattr(model, 'query'):
for row in model.query.filter_by(user_id=merge_user.id).all():
row.user_id = keep_user.id
# 3. Add merge_user's uuid to olduserids. Commit session.
db.session.add(UserOldId(id=merge_user.uuid, user=keep_user))
# 4. Mark merge_user as merged. Commit session.
merge_user.status = USER_STATUS.MERGED
# 5. Commit all of this
db.session.commit()

# 6. Return keep_user.
return keep_user
39 changes: 18 additions & 21 deletions lastuser_core/models/notification.py
Original file line number Diff line number Diff line change
@@ -1,46 +1,43 @@
# -*- coding: utf-8 -*-

from sqlalchemy.ext.declarative import declared_attr
from coaster.utils import LabeledEnum
from baseframe import __
from ..registry import OrderedDict
from . import db, BaseMixin, BaseScopedNameMixin
from .user import User, UserEmail, UserPhone
from .client import Client
from . import db, BaseMixin

__all__ = ['SMSMessage', 'SMS_STATUS']


# --- Flags -------------------------------------------------------------------

class SMS_STATUS(LabeledEnum):
QUEUED = (0, __(u"Queued"))
PENDING = (1, __(u"Pending"))
DELIVERED = (2, __(u"Delivered"))
FAILED = (3, __(u"Failed"))
UNKNOWN = (4, __(u"Unknown"))
QUEUED = (0, __(u"Queued")) # NOQA: E221
PENDING = (1, __(u"Pending")) # NOQA: E221
DELIVERED = (2, __(u"Delivered")) # NOQA: E221
FAILED = (3, __(u"Failed")) # NOQA: E221
UNKNOWN = (4, __(u"Unknown")) # NOQA: E221


class NOTIFICATION_FLAGS(LabeledEnum):
DELIVERY = (0, __(u"Delivery"))
READ = (1, __(u"Read"))
BOUNCE = (2, __(u"Bounce"))
DELIVERY = (0, __(u"Delivery")) # NOQA: E221
READ = (1, __(u"Read")) # NOQA: E221
BOUNCE = (2, __(u"Bounce")) # NOQA: E221


class NOTIFICATION_TYPE(LabeledEnum):
MANDATORY = (0, u'mandatory', __(u"Mandatory")) # Mandatory service announcement
TRANSACTIONAL = (1, u'transactional', __(u"Transactional")) # Result of user activity
ALERT = (2, u'alert', __(u"Alert")) # Periodic alert based on set criteria
MASS = (3, u'mass', __(u"Mass")) # Mass mail from the service provider
MANDATORY = (0, u'mandatory', __(u"Mandatory")) # Mandatory service announcement # NOQA: E221,E241
TRANSACTIONAL = (1, u'transactional', __(u"Transactional")) # Result of user activity # NOQA: E221,E241
ALERT = (2, u'alert', __(u"Alert")) # Periodic alert based on set criteria # NOQA: E221,E241
MASS = (3, u'mass', __(u"Mass")) # Mass mail from the service provider # NOQA: E221,E241


# A note on frequency: scheduling/batching is done by Lastuser, not by the client app
class NOTIFICATION_FREQUENCY(LabeledEnum):
IMMEDIATE = (0, u'immed', __(u"Immediately")) # Alert user immediately
DELAYED = (1, u'delay', __(u"Delayed")) # Send after a timeout, allowing app to cancel (tentative)
DAILY = (2, u'daily', __(u"Batched daily")) # Send a daily digest
WEEKLY = (3, u'weekly', __(u"Batched weekly")) # Send a weekly digest
MONTHLY = (4, u'monthly', __(u"Batched monthly")) # Send a monthly digest
IMMEDIATE = (0, u'immed', __(u"Immediately")) # Alert user immediately # NOQA: E221,E241
DELAYED = (1, u'delay', __(u"Delayed")) # Send after a timeout, allowing app to cancel (tentative) # NOQA: E221,E241
DAILY = (2, u'daily', __(u"Batched daily")) # Send a daily digest # NOQA: E221,E241
WEEKLY = (3, u'weekly', __(u"Batched weekly")) # Send a weekly digest # NOQA: E221,E241
MONTHLY = (4, u'monthly', __(u"Batched monthly")) # Send a monthly digest # NOQA: E221,E241


# --- Transport Channels ------------------------------------------------------
Expand Down
10 changes: 5 additions & 5 deletions lastuser_core/models/user.py
Original file line number Diff line number Diff line change
Expand Up @@ -44,9 +44,9 @@ class Name(UuidMixin, BaseMixin, db.Model):

__table_args__ = (
db.CheckConstraint(
db.case([(user_id != None, 1)], else_=0) +
db.case([(org_id != None, 1)], else_=0) +
db.case([(reserved == True, 1)], else_=0) == 1,
db.case([(user_id != None, 1)], else_=0)
+ db.case([(org_id != None, 1)], else_=0)
+ db.case([(reserved == True, 1)], else_=0) == 1,
name='username_owner_check'), # NOQA
db.Index('ix_name_name_lower', db.func.lower(name).label('name_lower'),
unique=True, postgresql_ops={'name_lower': 'varchar_pattern_ops'})
Expand Down Expand Up @@ -478,12 +478,12 @@ def autocomplete(cls, query):
db.session.query(UserExternalId.user_id).filter(
UserExternalId.service.in_(UserExternalId.__at_username_services__),
db.func.lower(UserExternalId.username).like(db.func.lower(query[1:]))
).subquery())).options(*cls._defercols).limit(100).all() + users
).subquery())).options(*cls._defercols).limit(100).all() + users
elif '@' in query:
users = cls.query.filter(cls.status == USER_STATUS.ACTIVE, cls.id.in_(
db.session.query(UserEmail.user_id).filter(UserEmail.user_id != None).filter( # NOQA
db.func.lower(UserEmail.email).like(db.func.lower(query))
).subquery())).options(*cls._defercols).limit(100).all() + users
).subquery())).options(*cls._defercols).limit(100).all() + users
return users


Expand Down
2 changes: 1 addition & 1 deletion lastuser_core/registry.py
Original file line number Diff line number Diff line change
Expand Up @@ -198,4 +198,4 @@ def callback(self, *args, **kwargs):
'email': None, # Verified email address. Service can be trusted
'emailclaim': None, # Claimed email address. Must be verified
'email_md5sum': None, # For when we have the email md5sum, but not the email itself
}
}
6 changes: 3 additions & 3 deletions lastuser_oauth/providers/openid.py
Original file line number Diff line number Diff line change
Expand Up @@ -42,8 +42,8 @@ def login_openid_success(resp):
Called when OpenID login succeeds
"""
openid = resp.identity_url
if (openid.startswith('https://profiles.google.com/') or
openid.startswith('https://www.google.com/accounts/o8/id?id=')):
if (openid.startswith('https://profiles.google.com/')
or openid.startswith('https://www.google.com/accounts/o8/id?id=')):
service = 'google'
else:
service = 'openid'
Expand All @@ -55,7 +55,7 @@ def login_openid_success(resp):
'oauth_token': None,
'oauth_token_secret': None,
'oauth_token_type': None,
}
}
if resp.email:
if service == 'google':
# Google id. Trust the email address.
Expand Down
1 change: 1 addition & 0 deletions lastuser_oauth/views/login.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ def openid_log(message, level=0):
import sys
print(message, file=sys.stderr)


oidutil.log = openid_log


Expand Down
2 changes: 1 addition & 1 deletion lastuser_oauth/views/oauth.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# -*- coding: utf-8 -*-

from flask import flash, render_template, redirect, request, jsonify, get_flashed_messages
from flask import render_template, redirect, request, jsonify, get_flashed_messages
from coaster.utils import newsecret
from coaster.auth import current_auth
from coaster.sqlalchemy import failsafe_add
Expand Down
2 changes: 1 addition & 1 deletion lastuser_oauth/views/resource.py
Original file line number Diff line number Diff line change
Expand Up @@ -637,7 +637,7 @@ def resource_login_providers(authtoken, args, files=None):
'oauth_token': unicode(extid.oauth_token),
'oauth_token_secret': unicode(extid.oauth_token_secret),
'oauth_token_type': unicode(extid.oauth_token_type)
}
}
return response


Expand Down
2 changes: 1 addition & 1 deletion lastuser_ui/views/dashboard.py
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ def dashboard_data_users_by_client():
):
clients = db.session.query('client_id', 'count', 'title', 'website').from_statement(db.text(
'''SELECT client_users.client_id, count(*) AS count, client.title AS title, client.website AS website FROM (SELECT user_session.user_id, session_client.client_id FROM user_session, session_client, "user" WHERE user_session.user_id = "user".id AND session_client.user_session_id = user_session.id AND "user".status = :status AND session_client.updated_at >= (NOW() AT TIME ZONE 'UTC') - INTERVAL :interval GROUP BY session_client.client_id, user_session.user_id) AS client_users, client WHERE client.id = client_users.client_id GROUP by client_users.client_id, client.title, client.website ORDER BY count DESC'''
)).params(status=USER_STATUS.ACTIVE, interval=interval).all()
)).params(status=USER_STATUS.ACTIVE, interval=interval).all()
for row in clients:
client_users[row.client_id]['title'] = row.title
client_users[row.client_id]['website'] = row.website
Expand Down
2 changes: 1 addition & 1 deletion lastuser_ui/views/org.py
Original file line number Diff line number Diff line change
Expand Up @@ -119,7 +119,7 @@ class TeamView(UrlForView, ModelView):
route_model_map = { # Map <name> and <buid> in URLs to model attributes, for `url_for` automation
'name': 'org.name',
'buid': 'buid'
}
}

def loader(self, name, buid):
obj = Team.get(buid=buid, with_parent=True)
Expand Down
Loading

0 comments on commit 18e3af9

Please sign in to comment.