Live-coding: Laravel Admin Seed, Tenants CRUD and Email Invitations

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
hello guys recently i released a video a demo project about tenants and asset management and i compiled it into 10-minute short video with explaining some parts of the code but initially the plan was that it would be a full course of me life coding the whole project so i've shot 3 videos of that and realized it would be just too long so i stopped shooting the course and instead shot this 10 minute video but one of the followers in youtube comments suggests i'd really like to see those three videos it still would be useful and two likes for that comment so i thought okay so in this video you will see around 40 minutes of me live coding a simple tenant management system and there is a github repository public with three commits first commit is creating new laravel project and seeding the administrator user to log in and i use laravel ui for the auth scaffolding then second lesson would be managing the tenants so it's basically a crud add a tenant user edit and delete or soft delete and then third lesson is the invitation of that tenant user so sending emails confirmation of the email setting the password and actually activate the user so this all is upcoming in the 40 minutes video after i finish talking here and the link to the repository is in the description of this video enjoy so let's begin our project and the first goal in the first lesson is to generate new laravel project generate some design with laravel ui i will choose old way laravel ui for the design and then seed administrator user login with that user and create some menu item which will be empty for now and we will also use the seeders4 roles in our system we'll have three rows administrator company and simple user let's begin from largo new project project will be a folder in that folder laravel will download the project and run composer install and everything let's wait for a few minutes okay we have a new project cd project and let's try it in browser i have a domain prepared project.test and it's a default laravel 8 landing page now let's generate administrator user with role administrator first we need to create a model called row php artisan make model row minus m for migration and also s for cedar everything created successfully now let's open phpstorm so we have the migration for roles table and all we need is one field table string name so role name and also we should make it fillable in app models row fillable name and now let's see the three rows so we go database seeders row cedar and let's just run three sentences row create name administrator and then we duplicate command d in my php store company and user now let's add that seeder into database here for the whole project we add this call row cedar class okay so we will see the rows and now let's see one more user which will be administrator user let's do file save as here in row cedar admin user seeder for example let's rename the class and in here user create and what will be the parameters name administrator email let it be admin admin com password should be encrypted by bcrypt method for example secret and also we need a role for that user so for now let's add role id field which will be equal to one and one is our role for the administrator so we will see the admin user seeder we don't need role anymore here and we will add admin user seeder into database heater here duplicate admin user seeder and now we need to create that role id field so we go php artisan make migration add row id to users table okay and we go table foreign id this is a syntax that appeared in laravel seven so role id constrained this means that it will create role id field and also foreign key to the database table rows and then we need to open user model and make that fillable as well so user model which comes from laravel by default row id as another field and in the database here let's remove this line and now let's re-migrate and receive all the database so php artisan my grade fresh minus minus seed successful let's check the database refresh the tables users content and we have our administrator user final step in this lesson let's install laravel ui and try to log in with that user so composer require liarable ui if we open laravel ui documentation we will generate a simple bootstrap without view or react this design with scaffolding with auth okay so we copy this and paste into our terminal now we need to run npm installing vm run dev and we should be ready paste and let's wait for a minute okay build successful let's refresh our page and we should see login and register here and if we click login we should be successfully logged in with admin admin con and secret let's try and we are in so this was our goal for this lesson to log in as administrator and see that administrator as a user so we wouldn't need to create that manually every time in the next lesson we will work on managing the tenants so role id number two companies in this lesson let's create a management system for role number two for tenants or companies tenants and companies will be the same throughout all this project and they are also users so user will just have role id2 and another database field called domain so every tenant will be created with their own domain or subdomain so let's create that field php artisan make migration add domain to users table okay table stream domain and also nullable because only those types of user will have that domain otherwise it will be no for everyone else and in the user we need to make that fillable domain now let's create a menu item here for administrator to manage tenants so we go to our app blade php in the layouts scroll down to the navigation bar and here we have from laravel ui empty placeholder for any menu items that you may need so let's add a menu item it should be class math item and then we have with class nav link tenants and the route will be route tenants index for now doesn't exist let's create that in routes web we will have route resource sentence tenant controller and let's generate that controller php artisan make controller tenant controller dash dash resource okay so tenant controller is ready index is ready and for now let's return just some text success and let's refresh our page french we have tenants here if we click tenant controller does not exist probably we need to change that to instead of tenant controller we need to have tenant controller class like this the logic has changed in laravel eight yeah that was exactly the change so now we have the page and instead of returning success let's return the view tenants index and the tenants will be user where row id equals to get all tenants and then we'll pass that to the index like this and in the index tenants index it doesn't exist yet so let's take the default level ui resources use home blade and let's do file save as resources views standards index blade and let's delete everything here so tenants card body and in here we will have a table so table bootstrap class table then head of the table and columns name email domain and then actions now we have table body and for each of the tenants as talent and and four and four each like this auto format with php storm and then each tenant is aligned with tenant name and duplicate duplicate email domain and then we will have some actions but we will get to them later and also what i like to use is instead of for each use for else so instead of adding if tenants count or something and then empty line i do for else like this then and for else and then there's empty so empty and inside of that empty i can put the html for the condition of empty tenants so zero tenants and i have this empty so it will show with call span four no tenants let's reformat again and let's refresh the page home tenants and there we go we have a table empty table with non tenants yet let's create one above the table let's create a button or link to route tenants create with class button button primary for example add new tenant break let's test how it looks refresh yeah we have add new tenant actually one more new line is required add new tenant for now it doesn't show anything because that method is empty so telling controller create return view tenants create so we need to create a form let's open tenants index file save as tenants create and inside of that create we need add new tenant and in card body it will be a form so instead of that table we will have a form action route tenants store then we need csrf hidden input field for the security and now let's copy some stuff from other page which is off login blade it has everything that we need form group row with all the validation here so this will be one field okay so we have the field for the email exactly as it should be from the registration form now let's copy and above the email we should have a name field so name field label for name i will quickly do the editing okay so we have the name field ready and let's copy and paste it into below space for the domain the third field and also i'll quickly do the editing okay and final thing what we need to do is a submit button we take it from login blade just copy and paste another block we don't need this but we do need the button submit save tenant okay let's refresh the page and we have this add new tenant form so tenants add new tenant and we have the form now let's take care of the submit let's make a validation request php artisan make requests tenant request and what will be the rule for our request so store tenant request authorize will be true by default we will take care of the rows and permissions in later videos but for the rules for validation we have name required email email and also required and also unique should be unique in users domain is also required and unique in users so we cannot assign the same domain to another tenant and in our store method intents controller instead of request we do store tenant request then we create that user create request validated validated it's not request all it's only the request variables that will come after validation so all of those three it's kind of a security measure that no one would actually pass anything malicious so request validated and also we need to add role id role id will be 2 in this case and not only that we also need the password and password for now let it be something like this secret because we will send the email to the tenant and they will create the password themselves and the result of that will be return redirect to the route of tenants index let's try it out refresh the page fill in the form with fake filler chrome extension save tenant and for some reason we don't have any talents let's check the database users nothing the reason is i've noticed only later in the url we have the token the name and all of that so we didn't pass the method post here create blade at the very top in the form we need to add method post i intentionally won't edit that out because you will see the actual errors how to debug them and how to fix them so now we fill that in we save the tenant unknown column domain we didn't migrate php artisan migrate now refresh and now we see the new talent with name email and domain okay now we need to continue managing the tenants with edit and delete actions so to have full cred so let's add edit button here in the list so in the index blade we add in this empty column link to route route tenants edit and parameter should be tenant id that tenant edit comes from route resource as edit method so we have edit here let's add a class so class button button small and button info for example edit refresh the page and we have the edit button for now it doesn't do anything let's fill in the edit method in the controller let's close everything else we need to add actually show we won't have the show here we will have edit so return view tenants edit contact tenant and that tenant may come from the find inside of that method or we can use so-called route model binding so user will be the class name and object variable will be tenant and that tenant automatically goes here and let's fix the dog block as well so user tenant and we have opened create blade for tenants and we do file save as edit blade edit blade and that edit will change edit tenant the action will be tenants update method post but then we need to add method put and then in terms of date that should be also a variable tenant id and then in the values of all the fields there should be instead of all there should be tenant name talent email and term domain like this save tenant everything else should be fine let's refresh the page and there we go we have edit tenant form with three fields filled in and with save tenant leading to the update method let's fill in the update method so in the controller it should be pretty similar to store and we may reuse the same form request it will be identical actually in the store or in the update these rules should be identical let's try it out so update instead of request with restore tenant request and instead of id we will do also route model binding so user tenant and let's try let's change that as well tenant update request validated and return redirect to route tenants index that's it let's try it out i'm not sure if it works but let's see so let's add dot dot save tenant and we have a problem validation rules after all they cannot be the same because email and domain has already been taken by the same record so we need to change the update rules to exclude the id that is currently being edited so we just go store tenant request save as update tenant request like this rename the file class update tenant request and we will change that email to we need to change that to add a custom rule so instead of that being a string we will have an array of rules first rule will be email next rule will be required and then instead of unique users we will have rule unique table users ignore and we pass this tenant as in full tenant object which comes from here from tenant and behind the scenes i've changed in the update update tenant request and in store we will have store tenant request and let's finish it up with a domain so also array required and instead of unique users we will have copy this line paste here rule unique users ignore this tenant so same thing let's try it out let's refresh the page change something and we have successfully edited now let's add the delete and for that we will add soft deletes i like personally to use soft deletes everywhere just in case in all models so let's add subdeletes php artisan make migration add soft deletes to users table so add soft deletes just table soft delete and in the model of user we need to add them soft deletes and they probably should be added here automatically by phpstorm yes correct and now in the index blade of tenants let's add the form to delete so form action route tenants i don't remember if it's delete or destroy let's add destroy method closed in here we have csrf and also method method delete and submit button button type submit class button button danger delete actually button small danger and also we need to add on click the confirmation so let's just add it as a simple javascript so on click return confirm our new show like this refresh the page and of course we forgot to migrate hpr to something great okay refresh the page now missing parameters of course destroy what so it should be tenant id like this and we have the button let's make it in the same line so in the form let's have some styling it's just in line style so style display in line block from what i remember like this refresh and we have it in the same line now if we delete and cancel nothing will happen but if we delete and confirm then it will load the destroy method by controller here this one we do user here so also route model binding talent and then we do ten and delete and return redirect route tenants index if the tenant is not found then it will throw 404 page let's refresh continue and as you can see no tenants so again add new tenant fake filler save tenant let's add one more form save tenant let's edit something save tenant and let's delete okay one should be renamed so now we have four credits for talent and next should be the invitation for the tenant so to set the password they would receive an email and then confirm their username in this lesson let's send email invitation to tenants but first there are a few cleanup things i've noticed from a previous lesson not sure if you've noticed but menu item tenants is accessible not only by admin but for anyone so i'm not locked in currently but i still see the tenant and i can manage the tenants so let's fix that by doing route group so in this route resource that route resource should have a middleware of auth but instead of doing that let's start creating route group which would be protected by middleware so route group the first parameter is array of various parameters for route group and we will have middleware auth and then second is a callback function function like this and then we can get that route resource for tenants inside of that auth and now if we refresh the page i should be redirected to login as you can see and then if i'm logged in as admin with secret add new tenant is accessible to me and not only that we need to hide the tenants menu item so if i click login this should not be visible right so we go to app blade and we will have off here off and off like this so this menu item and maybe more will be accessible only for logged in users refresh the page and this is not visible anymore and another thing i wanted to fix is that domain name should not contain spaces so imagine domain or subdomain in our case or test something.project.test something should be only alpha numeric and let's add that to the validation errors so store talent validation rule sorry domain required i think it's alphanum like this now actually i've checked the documentation it's underscore alphanum like this one so in here and then in update and request same thing required domain alpha and now let's try to add the incorrect domain so we fake filler save tenant and the domain may contain only letters and numbers so no spaces okay so those two fixes and now let's send the email invitation to tenants so we will create a notification class to invite the tenant so php artisan make notification tenant invite notification like this and let's open it up notifications tenant invite notification default email notification return mail to mail line the introduction to the notification instead of that let's do you have been invited as a tenant and then the action will be accept invitation and url will be not the core url it will be a url specifically for that notification and we will have it as a private variable here inside of the notification so private url and we will pass that in the constructor so url and then we assign that to private property so this url will be equal url and we will pass that when creating the notification and then we pass that here as url here this url and now we call that notification intent controller when we create the tenant in store we create the user and we need the result of that call let's actually make it two lines and then we need to notify that user so user notify new tenant invite notification and the parameter will be url and for that url let's use laravel function called signed routes so there's a function in facade of url url signed route name invitation for example and parameters let it be user object as a parameter like this to test the sending of emails i will use a service called mailtrap i use it for all email testing and i need to copy username and password to my emd file in the section of mail username and password from here mail trap is by the way configured by default from default laravel and also we need to specify from address otherwise it wouldn't work finally to make it all work in tenon controller we created a signed route for invitation and we need to create that route in routes web so we go to routes web and it will be a public route route get invitation [Music] slash user and we will use the same tenant controller just another method invitation and we will assign name invitation in fact the syntax is a bit different it should be an array i'm still getting used to level 8 new syntax of routes so controller class and method name and now let's try to send an email we open the form fill it in with fake filler let's make the domain something in one word we save the tenant and let's see if the email has been sent the tenant created successfully if we look at the mail trap we have a new email hello you have been invited as a tenant except invitation and here's the link that we have just created so that signed route is invitation slash user id and then you have the signature so the signature for making sure that that url is unique and now we will create that route and controller check that signature and log in as that tenant so we specified that inside of that controller we will create invitation method let's do exactly that so function invitation and the parameter will be user we will use route model binding and then we need to check the request for signed url and if the signed url is incorrect we will abort with 401 which means unauthenticated so if request like this we don't need this one and there's a method has valid signature so if not has valid signature or if the password is already set then we will abort 401 so user password not equals secret remember we're storing secret as the first password by default so if any of those conditions are true then we abort with 401 it will just show our page with 401 code otherwise if everything is good with request signature we log in with that user so login with user and redirect to home return redirect to home route home like this and let's try it out let's log out as administrator and let's click the link in the email accept the invitation and as you can see we're automatically logged in as that user and we direct it back to home so basically we accepted the invitation but now we need to add one more step that tenant needs to set their own password and until they do that we will redirect back to the setting password page so we will create a middleware of checking the password and if the password is secret so while the password is secret then it keeps redirecting to set your password page so first let's create that password setting page and then we will protect that by middleware so we generate the controller artisan make controller set password controller and inside of that we will have two methods so set password controller we'll have a method create for the form and it will return view auth set password for example and let's open something from resources view auth login and let's do file save as and do set password blade set password blade and we change this to set password or set your password and the form will be to action set password store so store the password and then we need only one field actually let's copy from register there are two fields for password and password confirmation so we need those exactly as they are without any changes so we copy from there and paste here so password like this and instead of login save password like this we don't need this route and it should be good now in routes web we create that route get inside of the auth middleware because i'm already logged in to set my password so route get set password without any user and we will have set password controller create name set password let's try it out the url set password instead of home and of course we haven't defined set password store so let's define that duplicate the line and then post to set password will fire set password controller class store method and let's call it set password score okay and now we have that form now let's set that in store so public function store request as a parameter and we update the password so auth user update password equals decrypt of request password and then we redirect back so return redirect route home with message password set successful like this let's make it to line and now in our route home in the home blade we will add one more line actually we will use the same session status so we don't need any message so status will be visible and show here in class alert of bootstrap so let's try it out let's set the password to something we save the password and password set successfully but of course we need to validate that password right so if we come back to set password the request should be not just request in here it should be specific store password request so let's create that php artisan make request store password request like this store password request and what should be the rules the only field is password and it need to be set so minimum for example six characters string and it also needs to be confirmed so there should be another field password underscore confirmed or password underscore confirmation i think it's called let's double check name password confirmation so it should be identical values between password and password confirmation so let's use our store password request now instead of just request store password request and now if we enter something invalid in here for example to short password and of course i forgot to set not just the rules but the authorized should be true and now if we enter something invalid in this form it should throw some validation error so password confirmation does not match so now let's try again and we save the password and final thing let's add a middleware to redirect to the set password page until it's actually set so we create a new middleware php artisan make middleware is password set middleware like this and then inside of that is password set middleware we check if the user is logged in so if auth check but the password is auth password equals secret secret and there's no password being passed to the request so not set request password then we redirect return redirect route set password which means on all the pages until the password is not secret we will continuously redirect to set password then we need to register that middleware in the kernel have http kernel php we need to assign some kind of name and we will assign that middleware to all the pages in web group so on every page it will be checking is password set middleware class let's try it out let's refresh the home and it won't redirect anywhere but now let's change that password to secret directly in the database like this and now if we launch home which should be redirected to set password which was successful but it redirected too many times so probably we need to set another condition so if request is not set password so if request is not set password set password so the url is not set password like this then we redirect back refresh yeah we had set password but if we go to tenants we are redirected back again and if we choose to go to home then we're still redirected back until we set the password let's do that set the password and save and now we are in home we access tenants or whatever menu item we want so now we officially have set our password as a tenant and we are logged in as verified user
Info
Channel: Laravel Daily
Views: 22,613
Rating: undefined out of 5
Keywords:
Id: rgOlkcTncv8
Channel Id: undefined
Length: 41min 18sec (2478 seconds)
Published: Fri Nov 27 2020
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.