Skip to content

Commit

Permalink
Merge branch 'develop' into ex-merge-containers
Browse files Browse the repository at this point in the history
  • Loading branch information
josephmancuso committed Sep 30, 2018
2 parents ce255d4 + 44d5b92 commit e47c8c2
Show file tree
Hide file tree
Showing 20 changed files with 608 additions and 26 deletions.
2 changes: 1 addition & 1 deletion app/http/controllers/ControllerTest.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ def test(self):
return 'test'

def returns_a_view(self, view: View):
return View('index')
return view.render('index')

def returns_a_dict(self):
return {'id': 1}
Expand Down
21 changes: 21 additions & 0 deletions masonite/auth/MustVerifyEmail.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
""" Verify Email Module """

import time

from masonite.auth.Sign import Sign


class MustVerifyEmail:
"""Class To Verify User Email
"""

def verify_email(self, mail_manager, request):
mail = mail_manager.helper()
sign = Sign()

token = sign.sign('{0}::{1}'.format(self.id, time.time()))
link = '{0}/email/verify/{1}'.format(request.environ['HTTP_HOST'], token)

mail.to(self.email) \
.template('auth/verifymail', {'name': self.name, 'email': self.email, 'link': link}) \
.subject('Please Confirm Your Email').send()
1 change: 1 addition & 0 deletions masonite/auth/__init__.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
from .Auth import Auth
from .Csrf import Csrf
from .Sign import Sign
from .MustVerifyEmail import MustVerifyEmail
9 changes: 6 additions & 3 deletions masonite/commands/AuthCommand.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,9 @@ def handle(self):
f.write("Post().route('/login', 'LoginController@store'),\n ")
f.write("Get().route('/register', 'RegisterController@show'),\n ")
f.write("Post().route('/register', 'RegisterController@store'),\n ")
f.write("Get().route('/home', 'HomeController@show'),\n")
f.write("Get().route('/home', 'HomeController@show'),\n ")
f.write("Get().route('/email/verify', 'ConfirmController@verify_show'),\n ")
f.write("Get().route('/email/verify/@id:signed', 'ConfirmController@confirm_email'),\n")
f.write(']\n')

# move controllers
Expand All @@ -34,10 +36,11 @@ def handle(self):
os.getcwd() + "/app/http/controllers/RegisterController.py")
shutil.copyfile(module_path + "/../snippets/auth/controllers/HomeController.py",
os.getcwd() + "/app/http/controllers/HomeController.py")
shutil.copyfile(module_path + "/../snippets/auth/controllers/ConfirmController.py",
os.getcwd() + "/app/http/controllers/ConfirmController.py")

# move templates
shutil.copytree(module_path + "/../snippets/auth/templates/auth",
os.getcwd() + "/resources/templates/auth")

self.info(
'Project Scaffolded. You now have 4 new controllers, 5 new templates and 6 new routes')
self.info('Project Scaffolded. You now have 5 new controllers, 7 new templates and 9 new routes')
4 changes: 4 additions & 0 deletions masonite/exceptions.py
Original file line number Diff line number Diff line change
Expand Up @@ -60,3 +60,7 @@ class StrictContainerException(Exception):

class InvalidRouteCompileException(Exception):
pass


class RouteException(Exception):
pass
19 changes: 16 additions & 3 deletions masonite/helpers/routes.py
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,22 @@ def get(url, controller):
return Get().route(url, controller)


def match(method_type, url, controller):
"""Shortcut for Match HTTP class.
Arguments:
method_type {list} -- A list of the method types you want to accept
url {string} -- The url you want to use for the route
controller {string|object} -- This can be a string controller or a normal object controller
Returns:
masonite.routes.Get -- The Masonite Get class.
"""
from masonite.routes import Match

return Match(method_type).route(url, controller)


def post(url, controller):
"""Shortcut for Post HTTP class.
Expand All @@ -50,7 +66,6 @@ def post(url, controller):
Returns:
masonite.routes.Post -- The Masonite Post class.
"""

from masonite.routes import Post

return Post().route(url, controller)
Expand All @@ -66,7 +81,6 @@ def delete(url, controller):
Returns:
masonite.routes.Delete -- The Masonite Delete class.
"""

from masonite.routes import Delete

return Delete().route(url, controller)
Expand Down Expand Up @@ -97,7 +111,6 @@ def patch(url, controller):
Returns:
masonite.routes.Patch -- The Masonite Patch class.
"""

from masonite.routes import Patch

return Patch().route(url, controller)
Expand Down
16 changes: 8 additions & 8 deletions masonite/providers/RouteProvider.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ def boot(self, router: Route, request: Request):
one match. Routes are executed on a first come, first serve basis
"""

if matchurl.match(router.url) and route.method_type == self.app.make('Environ')['REQUEST_METHOD']:
if matchurl.match(router.url) and request.get_request_method() in route.method_type:
route.load_request(request)
if request.has_subdomain():
# Check if the subdomain matches the routes domain
Expand All @@ -53,12 +53,6 @@ def boot(self, router: Route, request: Request):
except AttributeError:
pass

"""Execute Before Middleware
This is middleware that contains a before method.
"""

route.run_middleware('before')

"""Excute HTTP before middleware
Only those middleware that have a "before" method are ran.
"""
Expand All @@ -70,9 +64,15 @@ def boot(self, router: Route, request: Request):
if hasattr(located_middleware, 'before'):
located_middleware.before()

"""Execute Before Middleware
This is middleware that contains a before method.
"""

route.run_middleware('before')

# Show a helper in the terminal of which route has been visited
if self.app.make('Application').DEBUG:
print(route.method_type + ' Route: ' + router.url)
print(request.get_request_method() + ' Route: ' + router.url)

if request.get_status_code() == '404 Not Found':
request.status(200)
Expand Down
21 changes: 19 additions & 2 deletions masonite/routes.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
import importlib
import json

from masonite.exceptions import RouteMiddlewareNotFound, InvalidRouteCompileException
from masonite.exceptions import RouteMiddlewareNotFound, InvalidRouteCompileException, RouteException
from masonite.view import View


Expand All @@ -17,7 +17,8 @@ class Route:
'int': r'(\d+)',
'integer': r'(\d+)',
'string': r'([a-zA-Z]+)',
'default': r'([\w.-]+)'
'default': r'([\w.-]+)',
'signed': r'([\w\-=]+)'
}

def __init__(self, environ=None):
Expand Down Expand Up @@ -393,6 +394,22 @@ def __init__(self):
self.list_middleware = []


class Match(BaseHttpRoute):
"""Class for specifying POST requests
"""

def __init__(self, method_type=['GET']):
"""Post constructor
"""

if not isinstance(method_type, list):
raise RouteException("Method type needs to be a list. Got '{}'".format(method_type))

# Make all method types in list uppercase
self.method_type = [x.upper() for x in method_type]
self.list_middleware = []


class Put(BaseHttpRoute):
"""Class for specifying PUT requests
"""
Expand Down
86 changes: 86 additions & 0 deletions masonite/snippets/auth/controllers/ConfirmController.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
""" The ConfirmController Module """
import time
import datetime

from masonite.auth import Auth
from masonite.auth.Sign import Sign
from masonite.request import Request
from masonite.view import View
from masonite.auth import MustVerifyEmail
from app.User import User


class ConfirmController:
"""The ConfirmController class.
"""

def __init__(self):
"""The ConfirmController Constructor
"""
pass

def verify_show(self, request: Request, view: View):
"""Show the Verify Email page for unverified users.
Arguments:
Request {masonite.request.request} -- The Masonite request class.
Request {masonite.view.view} -- The Masonite view class.
Returns:
[type] -- [description]
"""

return view.render('auth/verify', {'app': request.app().make('Application'), 'Auth': Auth(request)})

def confirm_email(self, request: Request, view: View):
"""Confirm User email and show the correct response.
Arguments:
Request {masonite.request.request} -- The Masonite request class.
Request {masonite.view.view} -- The Masonite view class.
Returns:
[type] -- [description]
"""

sign = Sign()
token = sign.unsign(request.param('id'))

if token is not None:
tokenParts = token.split("::")
if len(tokenParts) > 1:
id = tokenParts[0]
user = self.get_user(id)

if user.verified_at is None:
timestamp = datetime.datetime.fromtimestamp(float(tokenParts[1]))
now = datetime.datetime.now()
timestamp_plus_10 = timestamp + datetime.timedelta(minutes=10)

if now < timestamp_plus_10:
user.verified_at = datetime.datetime.now()
user.save()

return view.render('auth/confirm', {'app': request.app().make('Application'), 'Auth': Auth(request)})

return view.render('auth/error', {'app': request.app().make('Application'), 'Auth': Auth(request)})

def get_user(self, id):
"""Get the user from the database
Arguments:
id {str} -- The user id
Returns:
[User] -- [User model]
"""

return User.find(id)

def send_verify_email(self, request: Request):
user = request.user()

if isinstance(user, MustVerifyEmail):
request.app().resolve(user.verify_email)

return request.redirect('/home')
10 changes: 7 additions & 3 deletions masonite/snippets/auth/controllers/RegisterController.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@
from masonite.helpers import password as bcrypt_password
from masonite.request import Request
from masonite.view import View
from masonite.auth import MustVerifyEmail
from masonite.managers import MailManager


class RegisterController:
Expand All @@ -14,7 +16,6 @@ class RegisterController:
def __init__(self):
"""The RegisterController Constructor
"""

pass

def show(self, request: Request, view: View):
Expand All @@ -29,7 +30,7 @@ def show(self, request: Request, view: View):

return view.render('auth/register', {'app': request.app().make('Application'), 'Auth': Auth(request)})

def store(self, request: Request):
def store(self, request: Request, mail_manager: MailManager):
"""Register the user with the database.
Arguments:
Expand All @@ -41,12 +42,15 @@ def store(self, request: Request):

password = bcrypt_password(request.input('password'))

auth.AUTH['model'].create(
user = auth.AUTH['model'].create(
name=request.input('name'),
password=password,
email=request.input('email'),
)

if isinstance(user, MustVerifyEmail):
user.verify_email(mail_manager, request)

# Login the user
if Auth(request).login(request.input(auth.AUTH['model'].__auth__), request.input('password')):
# Redirect to the homepage
Expand Down
12 changes: 12 additions & 0 deletions masonite/snippets/auth/templates/auth/confirm.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
{% extends 'auth/base.html' %}

{% block content %}
<div class="col-xs-4 col-xs-offset-4">
<div class="panel panel-default">
<div class="panel-heading">Verified</div>
<div class="panel-body">
Thank you for confirming your email. Click here to go to the <a href="/home">home</a> page.
</div>
</div>
</div>
{% endblock %}
12 changes: 12 additions & 0 deletions masonite/snippets/auth/templates/auth/error.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
{% extends 'auth/base.html' %}

{% block content %}
<div class="col-xs-4 col-xs-offset-4">
<div class="panel panel-default">
<div class="panel-heading">Verifying Error</div>
<div class="panel-body">
Confirming email failed. Click here to go <a href="/home">home</a>
</div>
</div>
</div>
{% endblock %}
13 changes: 13 additions & 0 deletions masonite/snippets/auth/templates/auth/verify.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
{% extends 'auth/base.html' %}

{% block content %}
<div class="col-xs-4 col-xs-offset-4">
<div class="panel panel-default">
<div class="panel-heading">Verify</div>
<div class="panel-body">
Please check your email and follow the link to verify your email. If
you need us to resend the email. Click <a href="/email/verify/send">here</a>
</div>
</div>
</div>
{% endblock %}
Loading

0 comments on commit e47c8c2

Please sign in to comment.