Giter Club home page Giter Club logo

core's People

Contributors

afdolriski avatar aisola avatar allcontributors[bot] avatar antyler avatar bjorntheart avatar bohrium272 avatar chrisbyrd14 avatar clsource avatar dsujan avatar garyburgmann avatar josephmancuso avatar kentaro0919 avatar leon0824 avatar mapeveri avatar marlysson avatar mitchdennett avatar mohi7solanki avatar mrd5061 avatar nioperas06 avatar padmini-desai avatar pmk21 avatar rfschubert avatar rickwest avatar shallow-source avatar stejas6 avatar the-robot avatar thetonus avatar trsridhar avatar vaibhavmule avatar w3x10e8 avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

core's Issues

Create an authentication system

Create a new authentication module with the methods to log in, log out, remember, and recover password. In addition to shortcuts such as generate password, etc.

add a way to "flash" some data to the next page

This will be similar to session data but will be removed after the page is done loading.

This will be used for sending things like "success messages" when a form is submitted properly and will look something like:

request().redirect('/some/url').flash({'message', 'value'})

and then used in the template:

{% if session('message') %}
    <div class="alert alert-success">
        {{ session('message') }}
    </div>
{% endif %}

but this will only be good for that request. if the page is refreshed then it will be gone.

This will have to either be inside the session and removed somehow at the end of a request or somehow inside the request object but be attached to an IP address. Since this is similar to both session data and IP addresses then it should really be inside the Session class

Add custom 404, 500, 302 etc pages.

There are a few different ways we can do this. One way is to check if a template exists before rendering it. So for example we can check if a resources/templates/errors/500.html template exists and render that, else just throw a normal error on the system. This can be done inside the new ExceptionHandler class but we will need a new method on the view class:

def show(self):
    view().exists('errors/500')
    # or 
    view().exists('/masonite/snippets/500.html')

because then inside our exception class we can do something like:

    def _render(self):
        self._app.bind('StatusCode', '500 Internal Server Error')

        # Check if DEBUG is False
        if not self._app.make('Application').DEBUG or self._app.make('Application').DEBUG == 'False':
            # Raise the exception here
            if self._app.make('View').exists('errors/500'):
                # do all the rendering stuff here
                return
            else:
                raise self._exception

        # return a view
        rendered_view = self._app.make('View')('/masonite/snippets/exception',
            {
                'exception': self._exception,
                'traceback': traceback,
                'tb': sys.exc_info(),
                'app': self._app,
                'enumerate': enumerate,
                'open': open
            }
        ).rendered_template
        self._app.bind('Response', rendered_view)

Create Resource Routes

Masonite 1.5 will focus on bug fixes and API's. This issue will be one of the leading issues to complete.

Require #41 to be closed

A Resource route will be called something like: UserResource where it's whole purpose is to be a class that returns Json or something.

Now this UserResource will need to run a serialize method which will be inherited by a base class which will come from JsonSerialize or XmlSerialize or something.

Masonite will need to now accept GET, POST, PUT, PATCH, DELETE.

This is simple as all the logic is there but it only currently is set to run on POST requests.

I'm thinking the user resource might look something like:

from app.User import User

class UserResource:

## basic methods

    def to_array(self):
        return {
            'id': self.id,
            'username': self.username
        }


## Special Methods:

    def with():
        pass

Then inside the routes/api.py should look something like:

from masonite.resources import Resource

from app.http.resources.UserResource import UserResource
from app.User import User
ROUTES = [
    Resource(UserResource(User))
]

or

ROUTES = [
    UserResource(User),
    DashboardResource(Dashboard),
    ListResource(List),
]

And that should automatically handle show, store, update, destroy

Add Better oAuth Integration Support

This will be oAuth integrations like Twitter, GitHub, Slack etc etc.

This will start off with integrations for Slack and Discord and will be open for extension for other drivers, primarily third party unless we deem necessary for other integrations.

I chose Slack and Discord because that is what I need for my current Masonite project. I want it to be a simple plug and play system.

All this will require is to add a service provider and it will simply make the integration and drivers accessible from the container.

If you want to add other third party integrations then it will simply be loading them into the container.


I'm contemplating about making this either party and wholly a third party package instead of integrating this into this core library. This might have to be something like MasoniteFramework/oAuth or something and then pip install masonite-oauth


End code will look like:

Add two routes:

ROUTES = [
    Get().route('send/to/slack', 'Controller@get_auth'),
    Get().route('from/slack', 'Controller@receive_auth'),
]

Get and send the authorization

def get_auth(self, IntegrationManager):
    IntegrationManager.driver('slack').redirect()

def receive_auth(self, IntegrationManager):
    IntegrationManager.driver('slack').user()

For Masonite 1.5, only Slack and Discord drivers will be pre installed. Social media drivers will be added in 1.6

change cookies to set an expire date

right now all cookies are set without an expiration date which makes them session cookies essentially. If a user closes out there browser completely, the cookie will be deleted. Make all cookies be defaulted to forever but can be changed by using the time parameter.

Something like:

Request.cookie('key', 'value', time='1 minute')

add a way to delete cookies

for some reason there is no delete_cookie method.

This is also a bug because whenever the developer changes their key, all cookies are now obsolete and will throw internal errors. The behavior needs to be that if a cookie cannot be decrypted, it should delete that cookie entirely. This will enable rapid changes in a Masonite secret key if it is breached without any fears of usability (minus logging people out or something)

Add a test suite for routes

Masonite needs to have phenomenal testing support out of the box. I'll need to design an entire test suite. Each major release will have a little added capabilities to the suite

This issue will pertain to testing routes

Add a way to change form requests to other request methods

Because form requests can't actually do Put, Patch and Delete, I'm thinking you can do something like:

<form action="" method="">
    <input type="request_method" value="PUT">
</form>

Masonite will check if that form value is present and if it is, it will change the request method to that method type. This could possibly be a middleware instead

New helpers for routes

For example:

from masonite.routes import Get
def get(url, controller)
    return Get().route(url, controller)

Add this helpers for GET, POST, PUT, and DELETE.

add a driver method to all driver classes.

currently in order to switch drivers, you need to use the manager class instead of the actual driver class. In other words you have to do:

def show(self, Upload):
    Upload.store(request().input('file'))

but if you want to change the driver on the fly, you need to use a manager class:

def show(self, UploadManager):
    UploadManager.driver('s3').store(request().input('file'))

I would like to have it so you can do:

def show(self, Upload):
    Upload.driver('s3').store(request().input('file'))

This will require a class to inherit from such as a new Driver class which should contain 2 methods:

class Driver:

    _manager = None

    def driver(self): 
        """ Used to switch the driver """
        return self._manager

    def load_manager(self, manager): 
        """ Load the manager class into the driver """
        self._manager = manager

and all drivers need to inherit from this (so they will need to be added to all contracts):

class UploadDiskDriver(Driver, BaseUploadDriver, UploadContract):
    ....

Then the Manager class will need to change inside masonite/managers/Manager.py:

...
            self.manage_driver = self.container.make(
                '{0}{1}Driver'.format(self.driver_prefix, driver)
            ).load_manager(self)
...

Add Sessions

Since the request is technically a singleton throughout the life of the server (it is instantiated before the server is started) we can technically have sessions. We would need to create a session() method on the request class which will generate a _session attribute on the request class that might look something like:

_session = {
    '28.029.291.199': {
        'username': 'Joseph'
    }
}

Then we can use something like:

# sets the session variable
Request.session('username', 'Mike')

or just use:

# sets the session variable
Request.session('username')
# Returns Mike

I have to make sure that somehow this is secure. Using an IP address might actually be insecure because it might be able to be spoofed and now we have cross session access. I'll need a way to somehow ensure that WSGI doesn't allow a way to set the REMOTE_ADDR as an environ variable (I think that even if one is sent it will be converted to HTTP_REMOTE_ADDR) so it should be fine. There is something called X-HTTP-FORWARDED-FOR. Might need to check that.

https://stackoverflow.com/questions/7835030/obtaining-client-ip-address-from-a-wsgi-app-using-eventlet?lq=1

This should also be it's own class and the request class should inherit it. Call the class Session which should not be able to be instantiated directly (and abstract class). Put this class inside a new file inside the base of the project called session.py. So this should be inside masonite/session.py and put the class Session inside of that.

Then import it into the request.py and inherit the Request class from it.

@mapeveri Is this something you'd want to do? It's pretty straight forward.

Add a dashboard

This should live in it's own repository and should come with:

  • a command to make a super user
  • requires a new is_admin to the user model which requires the user to make a new migration
    (or we can add one by default if we are shipping this package by default)
    • if this does ship by default we can try to be done with it before the 1.6 release and release it with that or work on it slower and target the 2.0 release
  • the dashboard that the user will use to control crud

I'm wondering if this should be a replica of the Django interface or if it should be unique and cool looking

Add view with a stack trace debugger

This might require having to make views accessible globally like how controllers are accessible globally.

  • Done

This will wrap the application in a try and catch block. and then handle the exception in a new exception provider.

This exception provider should render a new view that is located in Masonite.

This is going to be tricky to get this clean

this will also be a really big feature which a lot of changes that may get reverted in Masonite 2.0

MySQL error in craft install

Hi i want test this framework, but when run craft install command, display this error:

image

I do not use mysql (postgresql use) I force myself to install it.

sudo apt-get install mysql-server
sudo apt-get install libmysqlclient-dev

I should not or in any case ask me.

Regards!

Masonite Package integration.

Masonite Package consists of helper function to easily integrate and scaffold a Masonite project.

Things it will do:

  • create_or_append_config()

    • this will create or append a configuration file from the package and into the project.
  • append_web_routes()

    • this will append a file to the web.py routes file
  • append_api_rotues()

    • this will append a file to the api route file
  • create_controller()

    • this will copy the controller from the package and into the project

Add a flag for HTTP_ONLY cookies

Right now all cookies are set with an HTTP only flag. This prevents javascript from reading cookies. This was the intended result because it was a security measure to prevent malicious javascript code from reading cookies (like retrieving sessions)

Sometimes you may wish to actually set cookies and have your javascript code use it so there should be a parameter to set it:

request().cookie('key', 'value', encrypt=False, http_only=False)

add contracts

contracts are a great way to ensure that a class has all the methods it needs. This is very similar to a interface in other languages but Python doesn't have traditional interfaces. We can do something like:

class UploadDriverContract(object):
    
    def store(): raise NotImplemented()

    def store_as(): raise NotImplemented()

    def another_method(): raise NotImplemented()

then all drivers need to inherit from this:

from masonite.contracts import UploadDriverContract

class UploadGoogleDriver(UploadDriverContract):
    pass

Now anytime anyone creates a driver they will have a minimum amount of methods necessary required

Masonite drivers need to program to an interface and not an implementation

Add accepted file types to upload drivers

There needs to be a way to accept specific file types. The end state of the code should look something like:

def show(self, Upload):
    Upload.accept('png', 'jpg').store(request().input(file))

You may have to abstract this and make a BaseUploadDriver which contains this accept method and just make sure it works on the two drivers by inheriting from them. It should be really simple and should just be a check if the filetype is inside the list

Let me know if anyone has any additional questions

views should be accessible globally

Just like controllers /billing.controller.BillingController@show we should be able to have views accessible globally:

return view('/billing/views/settings')

Add Forms

I hate the way every other framework does forms. This solution needs to be super straight forward and as expandable and pluggable as possible.

This needs to be dead simple .... like dead simple.

improve static files with S3

Many languages have a static() function helper inside the template which basically just returns a string prefix for files.

Masonite requires this as well primarily for non local file storage

Improvements list

@mapeveri

It forces me to install mysql

I like the idea of having all the dependencies you need out of the box. I'm building the framework around what I would wan't a Python framework to be personally which comes with good and bad. The most obvious bad is that it is very opinionated although I've been programming for almost 10 years I definitely have an idea of what I was a framework to be and think I also have an idea what other developers want a framework to be, even if they don't know they want it yet. I personally feel that once we show them the way then they will like it a lot more.

At this point in the framework I want to break away from what other frameworks do and take our own path that we feel is right.

Now with that being said I completely agree that you shouldn't have to install an apt-get package on a computer and honestly I didn't know that Linux was such a widely used development platform. If I had to guess I would have thought it was around 50% Mac, 40% windows and 10% Linux but it's more like 20% Linux which is pretty big.

Solution

I think there are 2 solutions here. 1 is to use a different mysql driver (currently its mysqlclient) which is the requirement in requirements.txt but there is another one we can install. I'll do some Linux testing soon.

option 2 would be to throw an exception when they first use the model which tells them to install one of the requirements.

Install many dependencies, I would have to ask some questions and based on that install.

This is going to have to stay for several reasons. Reason 1 is that the requirements are needed for many of the Service Providers. With a batteries included framework comes many dependencies. This was always a really weird complaint from developers I never understood. Why does it matter that an application has a lot of dependencies? You don't have to use all of them and they are just dependencies. If an application is large in file size that really shouldn't matter these days since nearly all applications will be ran on dedicated servers or cloud infrastructure which has very high amounts of storage.

Reason 2 is that Service Providers (and drivers) require these dependencies and therefore the install process would ask questions and have to build a PROVIDERS list automatically somehow and associate the dependencies with them. I feel like this would be a pretty incredible feat and hard to maintain.

Reason 3 is I hate question installs because when first creating a program, I don't know what I need and I don't want to have to run through an hour of documentation and time to install something I said no to and didn't think I needed. I just want things to be there when I need it.

Also because service providers are designed to load before the server starts, Adding service providers will not slow the application down. Only a very few service providers that are required by the application need to be loaded on every request. if people want to strip the application when it comes time to deploy then they can simply remove service providers before deploying.

  • The application generated by craft does not contain PEP8.

I want to keep it this way. To be fair I accepted the PEP8 because it was not client facing and only developers contributing will see it but PEP8 is extremely ugly. like really ugly. I know Python required PEP8 but quite frankly, everyone takes PEP like it's the law of the land and not following by it is death.

Developers have to understand that PEP's are just guidelines and aren't strict measurements. I like the comments and the standards of the application generated by craft because they look beautiful.

Also know that PEP8 also says:

Many projects have their own coding style guidelines. In the event of any conflicts, such project-specific guides take precedence for that project.

PEP8 is good for the core library but anything client facing should look nice over PEP8 standards

Support to sqlite3. I would have to support at least mysql, postgresql and sqlite3.

Orator does support all three. I need to create documentation for Orator from scratch. Their documentation is not the best. I just keep dread writing it because the library has so many features.

The migrations would be good that you can pass a flag to tell you what type of migration I want and the generator to put a code related to that flag. Why I wanted to create a new table and by default

put me with self.schema.table ('blogs') as table: and when running the migration I made an alter table.

Can you explain this one more? There are only 2 types of migrations needed:

  • a creation migration to create tables
  • a table migration to do everything else with tables (update, delete, rename, drop etc etc)

if you want to alter a table you simply make the table migration and use the .change() method. Again I'll have to create solid documentation on the Orator ORM

Generate a controller based on a model and that I put together the methods for a crud.

This could be good. Let's open an issue and discuss more about this.

this could be a craft controller NameOfController --crud which can fill in the show store update delete methods.

let's talk more about this in an issue

When you generate a controller, that does not need to put "NameController" with making craft controlller Name, it would have to reach. This is because I generated a "Name" file alone.

Can you explain this more? You want to do something like craft controller Name which will append "Controller" to the end?

This might not be good because not all controllers require the "XController" signature. I don't want to force developers to have to call all controllers "XController" (although that is the default convention of Masonite) This can change though if you have other thoughts.

When a controller is generated, I have the possibility to add the templates.

Do you mean something like craft controller DashboardController --templates dashboard dashboard/user dashboard/profile? If so let's open up and issue for this and discuss more. This could be a good feature after some discussion.

Resource routes.

I like. let's open an issue and discuss how this will work.

It generates the file of a model with capital letter.

What do you mean? all classes in Masonite are "StuddlyCase" by default so models should keep the class naming convention of Masonite. This is more of a naming convention thing.

You should be able to do craft model user which will create the file name and model name it in lowercase. If this does not then let's open a bug issue

Generate a model based on a table in the database. So that by default you know which table to use.

Can you explore more? If you name a model the singular and the table the plural then it will default to that table.

For example, if I have a photos table then I make a model called Photo which will automatically point to the photos table. If you want to change the table it points to you can specify the __table__='another_table' attribute on the model. Again I need to update the documentation.

Command to create a default user.

Explain this further. You mean like Django's super user? I do agree with this and have realized that I need to do craft auth and then sign up manually. Let's open an issue and discuss this

add better container injection

experiment with better container injection. right now it gets all the parameters, injects them and then gets all the annotations and injects them. Try looking for a "inject in place" solution.

from masonite.requests import Request

def show(self, request: Request, Upload):
    pass

does not work. Get this to work

create code for redirecting back to the previous page

A lot of the time you will need to redirect to a different page and quickly redirect back.

For example you may want the user to login but then go right back to the page they were at.

right now the solution is something like:

  • set an parameter in the url:

domain.com/login?back=/user/1

and then catching that in the show controller:

def show(self):
    if request().has('back'):
        request().session.set('back', request().input('back'))

and then inside the store controller (or wherever you are processing the form)

def store(self):
    if request().session.has('back'):
        return request().redirect(request().session.get('back'))

I'm wondering if there is a shorter way to do this.

Add a driver base class

A lot of the managers look very similar. Remove the redundant create driver method and replace it with class attributes.

Move some commands from craft to into the core repository

I see a problem in the near future.

the Craft command tool should be able to be used by any Masonite version. The problem here though is that some changes in the API might lead to some negative side effects.

For example when creating an authentication system. There might be some changes to how controllers are made (such as inheriting from a new class only available in Masonite 1.6 or something).

The solution here is to load the commands in when the craft command is called. We can load commands into craft inside a service provider because craft grabs all the commands from the service container. Now each version will be able to have it's own changes in the commands

Condense ALL dependencies into the masonite requirements

Right now the dependencies are split between the the masonite core repository and the actual masonite repo (MasoniteFramework/masonite). These need to all be combined into this repo. The only dependency inside the MasoniteFramework/masonite should be Masonite

add better module controllers

@mapeveri Thoughts?

currently there is this:

get('/url/here', 'Controller@method')

which will look for: app.http.controllers.Controller.py

Good so far.

Now in order to do a controller from say a billing module:

get('/url/here', 'Controller@method').module('billing.controllers')

this will look for a controller in billing.controllers.Controller.py

This seems a little weird to me. I think we should do something like:

get('/url/here', '\billing.controllers.Controller@method')

All this will do in the backend is check if the string starts with a backslash and get the controller accordingly. This logic is in the Route class.

If we go this route I say we remove the module method completely.

Change or verify that the container can make from an instance of a class

for example currently we can pass in the class we need as an annotation:

from masonite.requests import Request

def show(self, obj: Request):
    obj # returns Request class

good so far

what we need to do is pass in an instance and get that like a contract

For example:

from masonite.contracts.UploadContract import UploadContract

def show(self, obj: UploadContract):
    obj # returns Upload class

This will just search the container for anything that has an instance of the class provided.

NOTE

this might actually already work but if it does, it is untested

Add CSRF protection

So this will require a few moving parts here.

So how CSRF works is that there is a random key generated (like 8yr8738b8b87b8br48gf84b7bv) at the start of each request. This changes on every request so it needs to be random.

This token can be used inside forms so there needs to be a {{ csrf_field() }} function which just points to the request.get_csrf() method or something. Check the HelpersProvider for how helper functions work. Especially in templates (it uses the View.share) method.

Then when the request is submitted via POST, the CSRF token outputted by the csrf_field() function is checked against the one that was at the start of the request. If it's the same then the request was made by the current. If it wasn't then there is something wrong and it should throw an exception like InvalidCSRFToken

Now there is something to be aware of and that is that not all routes should have to be CSRF protected. It should be up to the developer to choose the ones that are not protected (all routes should be protected by default).

What I'm thinking of is that only new CSRF tokens should be generated if it is a GET request. This allows you to have a POST request and check if the CSRF token is valid

Please let me know if you have any questions

Masonite sets multiple values of the same cookie

there are cookies like:

csrf_token 287827437843847
csrf_token 93948395738957
csrf_token 218937129847294
token dh38y8t7y987984bfy487fty48

after a while going back and forth between pages. We have to check if a cookie of that value already exists and then set if it does not. This should prevent the duplication of the same cookie keys

Add real time support

Masonite, being a framework that will be much better than django when it comes to writing modern applications, needs real time support for web applications.

Out of the box there needs to be 2 drivers, Pusher and a more local websocket approach like tornado or something.

This solution needs to be DEAD simple and should look something like:

def show(self, Socket):
    Socket.broadcast('channel1', message)
    Socket.broadcast(['channel1', 'channel2'], message)
    Socket.broadcast('*', message)
    Socket.broadcast_group('group1', message)

Add template caching support

sometimes views don't need to be loaded over and over again and can just be rendered from a cache. I should be able to cache on a per template basis. Maybe something like:

def show(self):
    view('welcome').cache() # cache forever
    view('welcome').cache_for(5, 'minutes')
    view('welcome').cache_for(5, 'hours')
    view('welcome').cache_for(5, 'days')
    view('welcome').cache_for(5, 'months')
    view('welcome').cache_for(5, 'years')

This should ignore the template rendering entirely and just show the already rendered cached template

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.