Skip to content

Commit

Permalink
Master (#518)
Browse files Browse the repository at this point in the history
* added new config helper function

* flake8

* added docstrings

* flake8

* removed need for config prefix

* Add in container (#520)

* added contains method to container

* formatted and added tests

* bumped version

* Add ability to login using multiple columns (#521)

* add list to auth class

* adds ability to set a password column

* formatted

* fixed space in exception
  • Loading branch information
josephmancuso authored Jan 10, 2019
1 parent 7f1adbb commit 2805d61
Show file tree
Hide file tree
Showing 10 changed files with 177 additions and 4 deletions.
2 changes: 1 addition & 1 deletion config/database.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@
"""

DATABASES = {
'default': os.environ.get('DB_DRIVER'),
'default': os.environ.get('DB_DRIVER', 'sqlite'),
'sqlite': {
'driver': 'sqlite',
'database': os.environ.get('DB_DATABASE'),
Expand Down
3 changes: 3 additions & 0 deletions config/storage.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,9 @@
'secret': os.getenv('S3_SECRET', 'HkZj...'),
'bucket': os.getenv('S3_BUCKET', 's3bucket'),
'location': 'http://s3.amazon.com/bucket',
'test_locations': {
'test': 'value'
}
}
}

Expand Down
3 changes: 3 additions & 0 deletions masonite/app.py
Original file line number Diff line number Diff line change
Expand Up @@ -348,3 +348,6 @@ def _find_obj(self, obj):

raise MissingContainerBindingNotFound(
'The dependency with the {0} annotation could not be resolved by the container'.format(obj))

def __contains__(self, obj):
return self.has(obj)
18 changes: 16 additions & 2 deletions masonite/auth/Auth.py
Original file line number Diff line number Diff line change
Expand Up @@ -63,9 +63,23 @@ def login(self, name, password):
"""
auth_column = self.auth_model.__auth__
try:
model = self.auth_model.where(auth_column, name).first()
password_column = self.auth_model.password if hasattr(self.auth_model, 'password') else self.auth_model.__password__
except AttributeError as e:
raise AttributeError('Your model does not have a password column or a designated __password__ attribute. Set the __password__ attribute to the name of your password column.') from e

if model and bcrypt.checkpw(bytes(password, 'utf-8'), bytes(model.password, 'utf-8')):
try:
# Try to login multiple or statements if given an auth list
if isinstance(auth_column, list):
model = self.auth_model.where(auth_column[0], name)

for authentication_column in auth_column[1:]:
model.or_where(authentication_column, name)

model = model.first()
else:
model = self.auth_model.where(auth_column, name).first()

if model and bcrypt.checkpw(bytes(password, 'utf-8'), bytes(password_column, 'utf-8')):
if not self._once:
remember_token = str(uuid.uuid4())
model.remember_token = remember_token
Expand Down
1 change: 1 addition & 0 deletions masonite/helpers/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,4 @@
from .misc import random_string, dot, clean_request_input
from .Extendable import Extendable
from .time import cookie_expire_time
from .structures import config, Dot
103 changes: 103 additions & 0 deletions masonite/helpers/structures.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
"""A Module For Manipulating Code Structures."""

import pydoc


class Dot:

def locate(self, search_path, default=''):
"""Locate the object from the given search path
Arguments:
search_path {string} -- A search path to fetch the object from like config.application.debug.
Keyword Arguments:
default {string} -- A default string if the search path is not found (default: {''})
Returns:
any -- Could be a string, object or anything else that is fetched.
"""
value = self.find(search_path, default)

if isinstance(value, dict):
return self.dict_dot('.'.join(search_path.split('.')[3:]), value)

if value is not None:
return value

def dict_dot(self, search, dictionary):
"""Takes a dot notation representation of a dictionary and fetches it from the dictionary.
This will take something like s3.locations and look into the s3 dictionary and fetch the locations
key.
Arguments:
search {string} -- The string to search for in the dictionary using dot notation.
dictionary {dict} -- The dictionary to search through.
Returns:
string -- The value of the dictionary element.
"""
if "." in search:
key, rest = search.split(".", 1)
try:
return self.dict_dot(dictionary[key], rest)
except (KeyError, TypeError):
pass
else:
try:
return dictionary[search]
except TypeError:
pass

return self.dict_dot(dictionary, search)

def find(self, search_path, default=''):
"""Used for finding both the uppercase and specified version.
Arguments:
search_path {string} -- The search path to find the module, dictionary key, object etc.
This is typically in the form of dot notation 'config.application.debug'
Keyword Arguments:
default {string} -- The default value to return if the search path could not be found. (default: {''})
Returns:
any -- Could be a string, object or anything else that is fetched.
"""
value = pydoc.locate(search_path)

if value:
return value

paths = search_path.split('.')

value = pydoc.locate('.'.join(paths[:-1]) + '.' + paths[-1].upper())

if value:
return value

search_path = -1

# Go backwards through the dot notation until a match is found.
while search_path < len(paths):
value = pydoc.locate('.'.join(paths[:search_path]) + '.' + paths[search_path].upper())

if value:
break

value = pydoc.locate('.'.join(paths[:search_path]) + '.' + paths[search_path])

if value:
break

if default:
return default

search_path -= 1

return value


def config(path, default=''):
return Dot().locate('config.' + path, default)
2 changes: 1 addition & 1 deletion masonite/info.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
"""Module for specifying the Masonite version in a central location."""

VERSION = '2.1.5'
VERSION = '2.1.6'
33 changes: 33 additions & 0 deletions tests/helpers/test_config.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import pydoc

from masonite.helpers import config, Dot


class TestConfig:

def setup_method(self):
self.config = config

def test_config_can_get_value_from_file(self):
assert self.config('application.DEBUG') == True

def test_config_can_get_dict_value_lowercase(self):
assert self.config('application.debug') == True

def test_config_can_get_dict_default(self):
assert self.config('sdff.na', 'default') == 'default'

def test_dict_dot_returns_value(self):
assert Dot().dict_dot('s3.test', {'s3': {'test': 'value'}}) == 'value'

def test_config_can_get_dict_value_inside_dict(self):
assert self.config('database.DATABASES.default') == 'sqlite'

def test_config_can_get_dict_value_inside_dict_with_lowercase(self):
assert self.config('database.databases.default') == 'sqlite'

def test_config_can_get_dict_inside_dict_inside_dict(self):
assert isinstance(self.config('database.databases.sqlite'), dict)

def test_config_can_get_dict_inside_dict_inside_another_dict(self):
assert self.config('storage.DRIVERS.s3.test_locations.test') == 'value'
10 changes: 10 additions & 0 deletions tests/test_auth.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,11 +18,15 @@ class MockUser():
__auth__ = 'email'
password = '$2a$04$SXAMKoNuuiv7iO4g4U3ZOemyJJiKAHomUIFfGyH4hyo4LrLjcMqvS'
email = 'user@email.com'
name = 'testuser123'
id = 1

def where(self, column, name):
return self

def or_where(self, column, name):
return self

def first(self):
return self

Expand Down Expand Up @@ -62,6 +66,12 @@ def test_login_user(self):
assert isinstance(self.auth.login('user@email.com', 'secret'), MockUser)
assert self.request.get_cookie('token')

def test_login_user_with_list_auth_column(self):
user = MockUser
user.__auth__ = ['email', 'name']
assert isinstance(self.auth.login('testuser123', 'secret'), user)
assert self.request.get_cookie('token')

def test_get_user(self):
assert self.auth.login_by_id(1)
assert isinstance(self.auth.user(), MockUser)
Expand Down
6 changes: 6 additions & 0 deletions tests/test_container.py
Original file line number Diff line number Diff line change
Expand Up @@ -180,6 +180,12 @@ def test_can_substitute_with_object(self):

assert isinstance(app.resolve(self._test_substitute), MakeObject)

def test_can_use_in_keyword(self):
app = App()
app.bind('test', 'value')

assert 'test' in app

def test_can_substitute_with_make_object(self):
app = App()
app.swap(SubstituteThis, MakeObject())
Expand Down

0 comments on commit 2805d61

Please sign in to comment.