diff --git a/.env-example b/.env-example index 2dd2c28..5af10c2 100644 --- a/.env-example +++ b/.env-example @@ -2,9 +2,10 @@ APP_NAME=Masonite 2.3 APP_ENV=local APP_DEBUG=True AUTH_GUARD=web +APP_URL=http://localhost:8000 KEY=your-secret-key -MAIL_DRIVER=smtp +MAIL_DRIVER=terminal MAIL_FROM_ADDRESS= MAIL_FROM_NAME= MAIL_HOST= diff --git a/.env.testing b/.env.testing new file mode 100644 index 0000000..1ad83c1 --- /dev/null +++ b/.env.testing @@ -0,0 +1,2 @@ +DB_CONNECTION=sqlite +DB_LOG=True \ No newline at end of file diff --git a/.gitignore b/.gitignore index d32099d..e5f41de 100644 --- a/.gitignore +++ b/.gitignore @@ -7,3 +7,4 @@ venv .pytest_cache node_modules package-lock.json +!.env.testing diff --git a/.travis.yml b/.travis.yml index ab0cd07..6b4639e 100644 --- a/.travis.yml +++ b/.travis.yml @@ -5,9 +5,8 @@ python: - "3.6" matrix: include: - - python: 3.7 + - python: "3.7" dist: xenial - sudo: true install: - pip install masonite-cli - craft install diff --git a/README.md b/README.md index 63288a1..6c062f0 100644 --- a/README.md +++ b/README.md @@ -11,6 +11,9 @@

+ **NOTE: This repository is the general shell of the framework. This repository is responsible for managing the installation of all new applications. All core framework related code has been abstracted out into it's own PYPI package which can be found [in this GitHub Repo](https://github.com/masoniteframework/core).** + + ## About Masonite The modern and developer centric Python web framework that strives for an actual batteries included developer tool with a lot of out of the box functionality with an extremely extendable architecture. Masonite is perfect for beginner developers getting into their first web applications as well as experienced devs that need to utilize the full potential of Masonite to get their applications done. @@ -29,6 +32,8 @@ Masonite works hard to be fast and easy from install to deployment so developers Masonite strives to have extremely comprehensive documentation. All documentation can be [Found Here](https://docs.masoniteproject.com/v/v2.1/) and would be wise to go through the tutorials there. If you find any discrepencies or anything that doesn't make sense, be sure to comment directly on the documentation to start a discussion! +If you are a visual learner you can find tutorials here: [MasoniteCasts](https://casts.masonite.dev) + Also be sure to join the [Slack channel](http://slack.masoniteproject.com/)! @@ -54,7 +59,7 @@ $ sudo apt-get install python3.6-dev libssl-dev ## Windows -With windows you will need to have the latest OpenSSL version. Install OpenSSL [32-bit](http://slproweb.com/download/Win32OpenSSL-1_1_0h.exe) or [64-bit](http://slproweb.com/download/Win64OpenSSL-1_1_0h.exe) +With windows you will need to have the latest OpenSSL version. Install [OpenSSL 32-bit or 64-bit](https://slproweb.com/products/Win32OpenSSL.html). ## Mac @@ -133,33 +138,34 @@ Getting started is very easy. Below is how you can get a simple Hello World appl ## Installation -You can easily create new applications with `craft`. To create a new application run: - - $ craft new project_name - -**** +The best way to install Masonite is by starting in a virtual environment first. This will avoid any issues with filesystem permissions. -

-* * * * -

+``` +python3 -m venv venv +``` -NOTE: If you do not have the craft command, you can run `pip install masonite-cli` which will install `craft` command line tool. +Then activate the virtual environment: -

-* * * * -

+``` +WINDOWS: $ ./venv/Scripts/activate +MAC: $ source venv/bin/activate +``` -**** -This command will create a new directory called `project_name` with our new Masonite project. +You can easily create new applications with `craft`. To create a new application run: -You can now cd into this directory by doing: +``` +$ pip install masonite-cli +$ craft new project . +``` - $ cd project_name +The `.` will tell craft to create the project in the current directory instead of a new directory. -Now we just need to add the pip dependencies. You can run `pip3 install -r "requirements.txt"` or you can run the `craft` command: +``` +$ craft install +``` - $ craft install +This will install all of Masonites dependencies as well as create a new `.env` file consisting of all of your environment variables. **** @@ -176,11 +182,11 @@ NOTE: Python craft commands are essentially wrappers around common mundane tasks **** -This will install all the required dependencies to run this framework. Now we can run the `craft` command: +Now we can run the `craft` command: $ craft serve -This will run the server at `localhost:8000`. Navigating to that URL should show the Masonite welcome message. +This will run the server at `localhost:8000` and be in an auto-reloading state. When you change files, your server will restart. Navigating to that URL should show the Masonite welcome message. If that port is blocked you can specify a port by running: @@ -189,27 +195,21 @@ If that port is blocked you can specify a port by running: Or specify a host by running: $ craft serve --host 192.168.1.283 - -The server can also be auto reloaded by passing in a `-r` flag (short for `--reload`) - - $ craft serve -r - -This will reload the server when Masonite detects file changes. This is very similiar to Django. ## Hello World All web routes are in `routes/web.py`. In this file is already the route to the welcome controller. To start your hello world example just add something like: ```python -Get().route('/hello/world', 'HelloWorldController@show'), +Get('/hello/world', 'HelloWorldController@show'), ``` our routes constant file should now look something like: ```python ROUTES = [ - Get().route('/', 'WelcomeController@show'), - Get().route('/hello/world', 'HelloWorldController@show'), + Get('/', 'WelcomeController@show'), + Get('/hello/world', 'HelloWorldController@show'), ] ``` @@ -235,16 +235,14 @@ In order to make the `HelloWorldController` we can use a `craft` command: $ craft controller HelloWorld -This will scaffold the controller for you and put it in `app/http/controllers/HelloWorldController.py` - -We will have a `show()` method by default which is the typical method we will use to "show" our views and content. +This will scaffold the controller for you and put it in `app/http/controllers/HelloWorldController.py`. This new file will have all the imports for us. Inside the `HelloWorldController` we can make our `show` method like this: ```python -def show(self): +def show(self, view: View): """ Show Hello World Template """ - return view('helloworld') + return view.render('helloworld') ``` As you see above, we are returning a `helloworld` template but we do not have that yet. All templates are in `resources/templates`. We can simply make a file called `helloworld.html` or run the `craft` command: diff --git a/app/http/controllers/WelcomeController.py b/app/http/controllers/WelcomeController.py index 04636d7..1d47598 100644 --- a/app/http/controllers/WelcomeController.py +++ b/app/http/controllers/WelcomeController.py @@ -2,9 +2,10 @@ from masonite.view import View from masonite.request import Request +from masonite.controllers import Controller -class WelcomeController: +class WelcomeController(Controller): """Controller For Welcoming The User.""" def show(self, view: View, request: Request): @@ -12,7 +13,7 @@ def show(self, view: View, request: Request): Arguments: view {masonite.view.View} -- The Masonite view class. - Application {config.application} -- The application config module. + request {masonite.request.Request} -- The Masonite request class. Returns: masonite.view.View -- The Masonite view class. diff --git a/app/http/middleware/AuthenticationMiddleware.py b/app/http/middleware/AuthenticationMiddleware.py index 526c062..f62bcdd 100644 --- a/app/http/middleware/AuthenticationMiddleware.py +++ b/app/http/middleware/AuthenticationMiddleware.py @@ -10,7 +10,7 @@ def __init__(self, request: Request): """Inject Any Dependencies From The Service Container. Arguments: - Request {masonite.request.Request} -- The Masonite request object + request {masonite.request.Request} -- The Masonite request class. """ self.request = request diff --git a/app/http/middleware/CsrfMiddleware.py b/app/http/middleware/CsrfMiddleware.py index e2664bb..cb8d621 100644 --- a/app/http/middleware/CsrfMiddleware.py +++ b/app/http/middleware/CsrfMiddleware.py @@ -6,6 +6,13 @@ class CsrfMiddleware(Middleware): """Verify CSRF Token Middleware.""" - exempt = [] + """Which routes should be exempt from CSRF protection.""" + exempt = [ + # + ] + + """Whether or not the CSRF token should be changed on every request.""" every_request = False + + """The length of the token to generate.""" token_length = 30 diff --git a/app/http/middleware/LoadUserMiddleware.py b/app/http/middleware/LoadUserMiddleware.py index 4662f41..a87d38e 100644 --- a/app/http/middleware/LoadUserMiddleware.py +++ b/app/http/middleware/LoadUserMiddleware.py @@ -11,7 +11,8 @@ def __init__(self, request: Request, auth: Auth): """Inject Any Dependencies From The Service Container. Arguments: - Request {masonite.request.Request} -- The Masonite request object. + request {masonite.request.Request} -- The Masonite request object. + auth {masonite.auth.Auth} -- The Masonite authentication object. """ self.request = request self.auth = auth diff --git a/app/http/middleware/VerifyEmailMiddleware.py b/app/http/middleware/VerifyEmailMiddleware.py index 69ea83e..e673697 100644 --- a/app/http/middleware/VerifyEmailMiddleware.py +++ b/app/http/middleware/VerifyEmailMiddleware.py @@ -10,7 +10,7 @@ def __init__(self, request: Request): """Inject Any Dependencies From The Service Container. Arguments: - Request {masonite.request.Request} -- The Masonite request object + request {masonite.request.Request} -- The Masonite request class. """ self.request = request diff --git a/config/application.py b/config/application.py index d54bd1c..4cda326 100644 --- a/config/application.py +++ b/config/application.py @@ -33,7 +33,7 @@ Sets the root URL of the application. This is primarily used for testing """ -URL = 'http://localhost:8000' +URL = env('APP_URL', 'http://localhost:8000') """Base Directory Sets the root path of your project diff --git a/config/auth.py b/config/auth.py index f18d24c..fe73b24 100644 --- a/config/auth.py +++ b/config/auth.py @@ -33,3 +33,14 @@ }, } } + +DRIVERS = { + 'cookie': {}, + 'jwt': { + """Whether or not to reauthenticate with the database when the token expires.""" + 'reauthentication': True, + + """How long the token should live for before being refreshed.""" + 'lifetime': '5 minutes' + } +} diff --git a/config/database.py b/config/database.py index 9908bba..f90c2f0 100644 --- a/config/database.py +++ b/config/database.py @@ -1,6 +1,7 @@ -import logging """Database Settings.""" +import logging + from masonite import env from masonite.environment import LoadEnvironment from orator import DatabaseManager, Model @@ -53,7 +54,7 @@ logger = logging.getLogger('orator.connection.queries') -logger.setLevel(logging.DEBUG ) +logger.setLevel(logging.DEBUG) formatter = logging.Formatter( 'It took %(elapsed_time)sms to execute the query %(query)s' diff --git a/config/factories.py b/config/factories.py new file mode 100644 index 0000000..95df754 --- /dev/null +++ b/config/factories.py @@ -0,0 +1,15 @@ +from orator.orm import Factory +from app.User import User + +factory = Factory() + + +def users_factory(faker): + return { + 'name': faker.name(), + 'email': faker.email(), + 'password': '$2b$12$WMgb5Re1NqUr.uSRfQmPQeeGWudk/8/aNbVMpD1dR.Et83vfL8WAu', # == 'secret' + } + + +factory.register(User, users_factory) diff --git a/config/middleware.py b/config/middleware.py index e5c2f37..efbd021 100644 --- a/config/middleware.py +++ b/config/middleware.py @@ -22,7 +22,7 @@ ] """Route Middleware -Specify a dictionary of middleware to be used on a per route basis here. The key will +Specify a dictionary of middleware to be used on a per route basis here. The key will be the alias to use on routes and the value can be any middleware class or a list of middleware (middleware stacks). """ diff --git a/config/providers.py b/config/providers.py index c9ae5bd..d9d1ea5 100644 --- a/config/providers.py +++ b/config/providers.py @@ -6,6 +6,7 @@ SessionProvider, StatusCodeProvider, UploadProvider, ViewProvider, WhitenoiseProvider) +from masonite.validation.providers.ValidationProvider import ValidationProvider from masonite.logging.providers import LoggingProvider from masonite.validation.providers import ValidationProvider @@ -35,6 +36,7 @@ BroadcastProvider, CsrfProvider, HelpersProvider, + ValidationProvider, # Third Party Providers LoggingProvider, diff --git a/config/queue.py b/config/queue.py index 6d234b7..109d49b 100644 --- a/config/queue.py +++ b/config/queue.py @@ -16,6 +16,9 @@ """ DRIVERS = { + 'async': { + 'mode': 'threading' + }, 'amqp': { 'username': env('QUEUE_USERNAME', 'guest'), 'vhost': env('QUEUE_VHOST', ''), diff --git a/craft b/craft old mode 100644 new mode 100755 index 3f21f86..f403b8b --- a/craft +++ b/craft @@ -1,3 +1,4 @@ +#!/usr/bin/env python """Craft Command. This module is really used for backup only if the masonite CLI cannot import this for you. diff --git a/databases/seeds/user_table_seeder.py b/databases/seeds/user_table_seeder.py index a4dd949..40a7a56 100644 --- a/databases/seeds/user_table_seeder.py +++ b/databases/seeds/user_table_seeder.py @@ -1,16 +1,16 @@ """User Table Seeder. -You can run this seeder in order to generate users. +You can run this seeder in order to generate users. - Each time it is ran it will generate 50 random users. - All users have the password of 'secret'. - You can run the seeder by running: craft seed:run. """ -from orator.orm import Factory from orator.seeds import Seeder from app.User import User +from config.factories import factory class UserTableSeeder(Seeder): @@ -19,13 +19,4 @@ def run(self): """ Run the database seeds. """ - self.factory.register(User, self.users_factory) - - self.factory(User, 50).create() - - def users_factory(self, faker): - return { - 'name': faker.name(), - 'email': faker.email(), - 'password': '$2b$12$WMgb5Re1NqUr.uSRfQmPQeeGWudk/8/aNbVMpD1dR.Et83vfL8WAu', # == 'secret' - } + factory(User, 50).create() diff --git a/resources/__init__.py b/resources/__init__.py index 929115e..ea18e76 100644 --- a/resources/__init__.py +++ b/resources/__init__.py @@ -1,5 +1,5 @@ """Resources directory. -This directory is responsible for storing any resource based files such as +This directory is responsible for storing any resource based files such as templates and SASS files """ diff --git a/resources/templates/base.html b/resources/templates/base.html new file mode 100644 index 0000000..824158a --- /dev/null +++ b/resources/templates/base.html @@ -0,0 +1,29 @@ + + + + + + + + + {% block title %} {{ config('application.name', 'Masonite') }} {% endblock %} + + + + + {% block css %}{% endblock %} + + + + +
+ +
+ {% block content %} + + {% endblock %} +
+
+ + + \ No newline at end of file diff --git a/resources/templates/welcome.html b/resources/templates/welcome.html index ac6a7be..ff77c69 100644 --- a/resources/templates/welcome.html +++ b/resources/templates/welcome.html @@ -1,41 +1,36 @@ - - - - - - - - - {{ config('application.name') }} - - - - - - - - - -
- -
-
- {{ config('application.name') }} -
- - -

- - -
+{% if exists('auth/base') %} + {% extends 'auth/base.html' %} +{% else %} + {% extends 'base.html' %} +{% endif %} + +{% block css %} + + +{% endblock %} + +{% block title %} + Welcome To {{ config('application.name', 'Masonite') }} +{% endblock %} + +{% block content %} +
+
+ {{ config('application.name') }}
- - - + + +

+ + +
+{% endblock %} \ No newline at end of file diff --git a/storage/static/__init__.py b/storage/static/__init__.py index 6ccd860..9999d58 100644 --- a/storage/static/__init__.py +++ b/storage/static/__init__.py @@ -1,5 +1,5 @@ """Static file storage directory. -This directory is responsible for storing static assets such as +This directory is responsible for storing static assets such as CSS, JS, public assets etc. """ diff --git a/tests/database/test_user.py b/tests/database/test_user.py new file mode 100644 index 0000000..73fcdef --- /dev/null +++ b/tests/database/test_user.py @@ -0,0 +1,24 @@ +"""Example Database Testcase.""" + +from masonite.testing import TestCase + +from app.User import User +from config.factories import factory + + +class TestUser(TestCase): + + def setUp(self): + """Anytime you override the setUp method you must call the setUp method + on the parent class like below. + """ + super().setUp() + + def setUpFactories(self): + """This runs when the test class first starts up. + This does not run before every test case. + """ + factory(User, 1).create() + + def test_created_user(self): + self.assertTrue(User.find(1)) diff --git a/tests/feature/test_feature_works.py b/tests/feature/test_feature_works.py deleted file mode 100644 index c9a477c..0000000 --- a/tests/feature/test_feature_works.py +++ /dev/null @@ -1,2 +0,0 @@ -def test_feature(): - assert True diff --git a/tests/framework/test_file_locations.py b/tests/framework/test_file_locations.py deleted file mode 100644 index 6b2768f..0000000 --- a/tests/framework/test_file_locations.py +++ /dev/null @@ -1,8 +0,0 @@ -import os - -from config import application - - -def test_env_file_exists(): - """ Test should be True if .env file is present """ - assert os.path.exists(os.path.join(application.BASE_DIRECTORY, '.env')), '.env file should exist' diff --git a/tests/framework/test_imports.py b/tests/framework/test_imports.py deleted file mode 100644 index 2a32b86..0000000 --- a/tests/framework/test_imports.py +++ /dev/null @@ -1,7 +0,0 @@ -def test_masonite_import(): - """ Application should be able to import Masonite modules """ - try: - import masonite - assert True - except ImportError: - assert False, 'Should import Masonite. Package not installed' diff --git a/tests/unit/test_works.py b/tests/unit/test_works.py index bbc0853..b7af096 100644 --- a/tests/unit/test_works.py +++ b/tests/unit/test_works.py @@ -1,2 +1,7 @@ -def test_unit(): - assert True +from masonite.testing import TestCase + + +class TestUnit(TestCase): + + def test_example_assertion(self): + self.assertTrue(True)