Django Channels Real-time Communication Project: Building a Chat Website

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
hey guys I'm code with Stein in this video I will show you how to build a real-time chat for websites using Django channels JavaScript and Tailwind Django and channels will be used for the backend and we will use JavaScript for handling the socket in the front end and Tailwind will be used for The Styling for the database we will use sqlite for development but we will also learn how to deploy this project to digitalocean where we will use postgresql as the database Eric is a little demo of the project we are building so we have a very basic website with a home and an about page and here you can see adjust bubble in the back end you can see that we can have multiple users where some can be managers and some can be agents the managers will have to possibilities add users and you can go to chat admin here to get this here you can also update the users if you want to do that where you can change the road down here all the rooms will be listed so if I try to go here now open up the chat bubble right Stein for example join chat Welcome to our chat please type your message below and wait for an agent to join so when I go to the back end again and refresh you can see that here is a room name Stein status is waiting and agent is none yet different click join here so you can see that I can start chatting with this user and if I go back here you can see that the admin slash agent has joined the chat hello and if I don't go back again to the back end you can see our stylist writing a message hello this was actually supposed to be deleted so I will fix that in this tutorial here you can also see the address that the user is coming from so if I start typing something here now hello there you can see here standover which is the agent is writing a message and as soon as I click Send it's deleted from there and that was what's supposed to happen here as well but I will fix that of course so even now go to the page here you can see that this is now active and steinwool is the agent of this I can go in here again I can talk to this user more if I want to do that hello again again but if I now refresh this page and refresh this page you can see that the chat is closed and I can just see this here now so that's basically how everything here will be working and I hope that this looks interesting to build it by the way if you haven't subscribed to my channel list please do that now and also click like below if you want more content like this anyways now it's time to get started with coding [Music] so here you can see the to-do list that we are going to go through I'm going to begin by just installing setting up everything that we're going to handle authentication start working with the chat set up the chat bubble working more on the chat bubble make it possible to connect to the web socket make password to send messages then we're going to work on the chat Administration make it possible to send a message just by hitting enter scrolling automatically to the bottom work with user management making booster board to delete a room we can put the view a room inform the user run an agent is writing and similar and at the end of this tutorial we are going to work with deployment where we're going to deploy this to digitalocean so anyways let's just start with the first task create a virtual environment so by the way the name of this project is yacht which just means to talk in Norwegian feel free to call it whatever you want on your computer of course so if I just go to the command line I've created an empty folder called yacht the hair as well and in here I want to create a virtual environment and I do that by saying Python 3 Dash M EnV sorry event and then the name of the environment which just can be EnV or what what you want to call it this is what I do on my Mac on Windows this can be a little bit different but just go to Google and say create python virtual environment windows or similar and you will probably find a way to do this on your computer as well anyways when that is done you can see here I've got in the folder so we can activate it by saying Source Envy then activate and then I get the name of the environment there okay so now we have it so I can go to the to-do list as the first task to done next step then is to download and set up the starter pack so I've prepared a little bit of code for this project I will go through everything here it's very simple actually it's just so that I don't have to spend time setting up the HTML for the menu this and similar so I will add a link in the description below for this but you can find it on github.com starter once you're here you can just click code copy this address or you can download this as a zip if you want to do that and then in the terminal I can just say git clone and then paste in the address and hit enter okay okay um did not work maybe if I switched to https get clone yes that worked a little bit better so select https and then the address there so now I have a new folder here called just the dash store stir I can move it rename this to something else for example just yet okay so now I have downloaded this and then add the first step in this task is to install everything that we have in the requirements file so if I just open up that I can go through it for example we have a Django and then we have a few other things most of these packages here are actually connected to Daphne and channels which is what we are going to use for the web socket so if I just type in here Django channels this is what Django used to handle asynchronous functions and similar so then you can see here that inside installation you are asked to install channels this way so this will now give you channels 4 and not the channels three so if you install it like this you will probably get almost all of these packages anyways okay so let's install this you can go into this folder see the yacht and then say pip install Dash or requirements.txt and now this will install everything that we have in that list so that you now will have the same environment as me nice and when that is done I can go to the to-do list just set this to done as well and then I want to install Tailwind um if you want to see the detailed version of this Tailwind CSS then we can go in here go to the talks and into Tailwind CLI so I have followed this version down here to install it but since we downloaded this starter pack we already have the Tailwind config we will set up the folder for where we have the Tailwind clauses inside the package the Json you have the same version of Tailwind CSS as me so now this should be very easy to install by using npm installed and then that will go through this package.json file and install everything there so if I now open up the package look you can see here that this is installed and a little bit other dependence is that Tailwind has to work so now Tailwind should actually work so we need to then run Tailwind CSS to make sure that it finds all the files and similar so if I just open up a new tab here or window or whatever you use on your computer then I go into the same project then I can run Tailwind CSS here and I do that by saying MPX Tailwind CSS Dash I dot slash static so then I find the input CSS file which is main.css and the output for this should be dot slash static slash CSS main dot Min dot CSS dash dash watch so now this will be running in the background at any time so every time we save a file this will be automatically updated and inside that main CSS file which we can Define here we have just imported things from Tailwind as you can see here how it's done and here is also the command I used to run just a little bit different because we have the files in different places okay so now that everything there is installed um I can set this here to done then um I can go through a little bit of the files we have a JavaScript file here this should actually not be there now I want this to be empty so I Can Begin by doing that just remove everything in there remove everything in there and save those two because I want to do this manually of course and then inside the core we have a few views we have one View for the front page one for about page set up separate URLs file there are no models and inside the templates just very basic so the index file is just a very simple it's just static HTML the base includes the main Min CSS which was generated from this command and nothing much more just messages so that you can show some feedback to the user there is a block Scripts and we have a block for the content as well so we can extend this so there's not much more to see there the account I'm going to go through this in the next task as you can see here go over the account tab okay so let's just start with this one add channels slash definitely to settings so it says that I already have this in the starter pack so I can just see that it's okay if I go to iota settings.pi then I have already added Daphne there and also the two apps that this starter pack comes with I want to set up the login URLs so this will be the login page this is where you will be logged so redirected to after a login when you log out you'll be redirected to the front page and we also set the old user model to account user because you have a custom user model for this project so one more thing we need to do for Daphne is to configure how the layers are going to work um we could use um for example I read this and similar but I just want to have everything in the memory for now because that's the easiest way to do this and I've also set up a list sorry option for the asgi which is for handling asynchronous uh tasks so this points to this file which we will do something with later in this tutorial so let's configure how the channels is going to work so here we can say Channel layers equals and then a dictionary and set the default default one more dictionary and then we set the back end to use to be used here which is channels dot layers dot in memory Channel layer and this works actually very good for development but also in production if you don't have a very big website because when we send the message to the backend we will save it in the database anyways so it will work very flawlessly so if I just go here now we can try to run this quickly just to see that it's working python mentioned by run server so there are no errors and you can also see here that it says starting asgi Daphne version 4 development server at this address and if you click that you will see this front page the chat bubble isn't there but we will work on that later so we also had it empty about page nice so now I can set this to done and I can set this to run and I can set tested on because we have run and tested that it's working and I can also set this to done nice before I continue I just want to say thanks to all of my patrons if you do want to support me you will find a link in the description below so then I just want to go over the authentication as well before we start with the fun which is to start working with the chat so if I just open up the account here if you can see that we have a few forums we have a login form we have add user form and the edit user form so I will come back to this later when we're actually going to work with adding users and handling the user management there are no views there are one URLs for logging in which just uses the built-in login view from Django we just specify which template to use and that we're using our own login form from forms.pi because we need to use the username and password and not what's built in so for the model we have done a little special things here so we'll set up a custom manager to make it easier to create new users so we have a separate function for super users and one for users which both utilizes this function and what the custom user manager is is that we replaced the default dot objects remember user.objects so instead of using the built-in there we use this instead so we just extend it so for example user.orges.all will still use the default user manager we just used a custom manager for these functions and then we have a separate user model here where we pause in this because we're going to use that and you can see here that we have two different roles we set up the unique IDE for the IDE field set of email field so we don't have the username we set up the name field so we don't have a first name last name we just have one name field and then a role which is a selection between these two roles if the user is active super user and stuff when you were joining when you lost logged in and then down here you can see how we are overriding the just objects down here we specify that the username field is email the email field is also email and the required Fields name um where a person name is just so that these will be working so that you can for example say python managed by create super user so everything here should be okay now you can see here that I get an error or a warning because we have unapplied migrations so let's fix that python Pi make migrations just to see that there are no that's good and then just migrate to run migration Scripts so now I've got the database model sorry the database here the sqlite3 perfect so that's basically how everything here is working and as I show you here that this is how you specify that we're going to use this model instead of the built-in user model that Django comes with okay so done and done I hope everything until now has been okay to follow I'm sorry that this just been a very much explanation if you have any questions feel free to leave a comment below and I will answer as soon as I can but now we are going to start working with more code nice okay so we're going to begin with creating a basic consumer so a consumer is just a simple python file that handles the communication with the front end is where we have the function for connecting disconnecting receiving messages and passing them out to the room or whatever you want to call it so let's begin by creating a new app for this so python manage.pi start app chat then we can add this to the installed apps list chat save and just close these files and then inside this chat app we can create a new file called consumers.pi first we can begin by importing a few things that we're going to need here so import Json and then we're going to import more from SGI RF dot sync import sync to async and from channels.generic dot web socket import async websocket consumer so this will be used for working with data in and out this is what we need to do in order to talk to the database and this is the consumer or the websocket itself so now we can create a class for this by the way if you want to read a little bit more about this you can just go to Google and search for Django channels you can go to their website and read through their talks if you want to read more about any of the things that I'm talking about in detail okay so then we can create a new class class chat consumer now we just pass in a sync websocket consumer then we can create one function for connecting to this so a sync Dev connect self so this function will now work inside this class and we use async because we are talking to the database and similar and we want to be able to post the function before we continue and similar so first I want to create or set up the room name self.room name room name might be the best explanation word for this but once we have started working this you will probably understand more why I have called it this self.scope URL route K works room name so what we are doing here is that we create a new variable called room name and assign it to this value so self.scope is sort of like the request parameter in typical views then we access the URL route and get the arguments from that and specifically we want the argument called room name group name [Music] equals chat underscore percentage s so you can format strings a few different ways in Django but this is one way to do it or you can just do it like this and set F there for format so now we just set the room group name to chat underscore to whatever we have in the URL and then we want to just add a comment there join room group await self Channel layer dot group and self dot room group name and self Dot channel name we don't have that but that is a variable built into the chat consumer itself so what happens there is that we call await now and wait for this to finish before we continue to the next line so we set up the channel layer which is what we had in the settings.pi we set our name here locally to root room group name and pause in self.channel name and then await cell dot accept so now the user which connects to this should be connected to the websocket and have a connection running and then we want one function for disconnecting so a sync Dev disconnect percent self and close code and then in here comment for leave room just so it's a little bit easier to follow what's going on here await self dot Channel layer dot group discard so this is just exactly opposite of and self dot room group name so I've got channel name negative two lines between this and this is the most basic a consumer can be I think you can probably make this a little bit easier if you wanted to but this is how I like to do it so now we have a unique room or group name for each of the users that connects to this from the front end so it's very easy to connect to this from the back end again okay so now that we have this I can take this to set create basic consumers to done next I want to set up the routing so just like that we have the urls.toy for the views I like to have a separate routing file for the consumer so inside this chat tab create a new file routing dot pi then we can import path from Django so from Django in dot URLs import path and then I would import the consumer's file so from dot import consumers then we set up the URL patterns that I like to go like that so get URL patterns equals create the list path and then here it's a WS for web socket so if the URL begins with websocket we go in here slash and then we want the string called um string called roon name and this room name is what we are getting here so K works is the arguments that I put into this path and then at the end here we can just say consumers dot chatconsumer dot s a s g i and add the parentheses so that is the routing itself very easy so not very long because I listed on and then we're going to set up the asgi file so the Asti file was the file that handles the connections from the web server so let's open up SGI pi and do some changes here first just remove this command and then we need to import a few things from channels so I can do that below this Django we can have it there so from channels.org import Port middleware stack this is something I like to use to make it easier to access the user and similar inside the consumer from channels.routing import protocol type router and URL router from channels dots security dot websocket import allowed hosts origin validator um then we set up for we use this to get the asj application we are in then we configure the environment by setting your dot settings your test on this file settings is this file and then we can import the routing file we just created so import chat dot routing or maybe we can just say um from chat or Dot import routing will probably more correct then instead of sending it like this we can say Django sji application equals get this so that we get this not 100 for sure what this actually does but this is how I always do this and then we set up the application so application equals protocol type router parenthesis and then in here a dictionary then we're going to use https Django hi application then we set the web socket passing allowed hosts origin validator parenthesis or middleware stack pause in url router and then here we can just say routing Dot web socket underscore URL patterns think that is correct let me try to run see if there are any errors cannot import name routing from yesterday okay no it's because I'm not in the correct folder so here I can say from chat import routing stop start again and now it seems to be working so what actually happens here now is that we do this to get the application we are in then we set up their router we specify what the HTTP we're going to use this is um the other type of use for example the front page similar and then the web socket here we're just passing in these and this to make sure that security is handled and similar I think that if you go into the tutorial here you can probably learn more about this in details if you want to do that okay so now that we have the asgi application up and running you can set this to done so then I can create the database model for the messages so inside chat models.pi we can create it here so first I just want to import the user so from account dot models import user so that you have the user so you can connect messages and rooms to this specific user class message passing models.model here and just first can begin with import the models.txt field this is the message itself as sent by equals models.char field set the max length to 255. so this is something that I want to add for each message has been sent so this is either the user in the front end or the name of the agent I want to know when the message was created Created at equals models.date time field and then I can pass in Auto now add to true so this is automatically added by Django and then I create that by equals models.forine key so this should then go to the user that you imported here I want to set this to blank equals true and null equals true in case it's the user in the front end we sent this message because then we don't have a user to connect this to and on delete models.set null so if the user is deleted this will just be set to null so then it just won't have the connection to a specific user in your system I need to have some clothes matter because we need to set the default ordering of the messages ordering this can be set to create it at so that the newest messages is at the bottom and not at the top now we can also set the string representation so depth Str self return F like that plus end self dot sent bye so now it's very easy to see in the admin interface and similar who sent a specific message so then turn on and then we need a model for the room as well close room model dot model so a room just to make sure that it's easy to follow now um if I go into the back end that I was showing you earlier this down here is then a room which you can go into and similar so let's go to the code again and add some field to here here I want to record the uuid equals small.jar field max length 255 so this is not the uuid that you might be used to using in Django it's just a unique idea that I'm going to render in the front end in JavaScript and send here so you could call astronomical JavaScript ID or similar or maybe a room ID or whatever you want and then I'm going to specify a client equals models dot chart field max length G55 this is the user in the front end when they click the the chat bubble you know the one you see here stein which was the one that connected from in the front end agent equals models.49k user so this is the agent that takes a room and talks to the user a related name can be rooms blank equals true and null equals true this has to be able to be not connected to a specific user in case or since the we are waiting for an agent to accept a connection and the same here on delete models.set null I also want one field here for the messages which is a connection up to the message here more this is a model dot many to many field and then we just pass in message and set blank equals true in case you don't have any messages yet which we usually don't have when we just create a room put one field for the URL and that is this one where the URL or the page the user is on when it clicks the chat bubble Char field max length 255 we can set this blank equals true and null equals true in case this is something that you don't want to have in your system and then I want the status if it's waiting for an agent if it's active or if the connection is closed so you can add this as a constant a pair first waiting [Music] oops waiting and active and closed and to make it very easy to choose between this we need to set up a couple choices status equals when a new Tuple with the Tuple in here pause in waiting and set the label that will be showing in the forms so we just copy and replace it a little bit now closed and closed like that and then we need a field for storing this information so status equals models.char field max length can be set to 20 because none of these variables or values are very long set of the choices to be choices status default is waiting when this was created so I can copy that field from here create that at paste it there we can set these two here as well so just copy the mirror and the string representation here we can say minus created at because we want the newest one in the back end to be on the left side here and the string representation can here be client but we can also show the self.u ID here okay so then we can update the database I think python mentioned by May make migrations and python measured by migrate so now I can run the server so we have it in the back end background sorry for now everything looks okay not much has happened but at least we now have the chat app with the basic consumer we have the routing we have the asgi file and the models for the rooms and the messages nice okay so let's start working on HTML for the chat bubble so in the demo you can see the chat bubble here and now I want to add it here as well okay so if I go to visual studio code then inside this chat application I can create a new template a folder for the templates in there one for the chat since this is the name of the app in here I want the folder called partials and this is where I want the bubble HTML to live so inside there again I create a file called chat bubble.html and I can just say chat here and include it in the indested HTML file in the core app so at the bottom of content you can say include chat partials slash chat bubble dot HTML and close it so if I go to the front page here on here refresh template does not exist okay what did I do wrong chat partials chat public HTML chat partials chat bubble HTML templates let's just start and stop again yes now it's working and you can see there sometimes Django needs to be restarted when you use a few things okay so now we have it there as a chat so how do I make this sticky to the down corner like it is there so you can on a scrolling you can still see it there so if I just minimize this a little bit find chat bubble again then I Can Begin by creating a new div and set the ID to chat so it's easy to get this element using JavaScript later close I want this is the max width for this div to 300 pixels so max w Max Dash w and then we specify 300 pixels hard coded like this and to make make it fixed without the Clauses fixed and then right dash 2 so it's 2 ramps or whatever it's called from the right side and also the same from the bottom set the padding inside this to four so it's based on the top and bottom and also on both sides set the background to be white I want to have a border is that the border to be border gray 300 and around the dash XL so if I write something in there now go back and refresh almost worked if I just hard refresh it was moved down here so now it's sticky down there and it's there every time that I scroll nice so let's add the chat icon so div ID chat up chat icon and I use these IDs to make it very easy to find these elements using and using JavaScript and then in here a button ID chat open so this would then be used to toggle open the chat I need some classes on this as well so close W dash 50 pixels we need to add a flex container and set the items Center so everything in there will be centered vertically and horizontally and then in here I need a chat bubble so to find this icon I just go to here row icons and search for chat then you can actually select which one you want there I can just go for this now go back here again and paste it inside this button can be saved and test this so it almost worked let's see it doesn't have the right color and it's a little bit small so if I hear on this SVG element I guess a text rows 600 go back and refresh so now it's the correct color nice um and then I should fix this size for this and I think to fix the width of it I can just remove these two classes let's save and check it out refresh yes so it's just a little bit too fat so I can set the stroke to one instead of 1.5 nice like that so now it's just like the demo perfect so the to-do list still says this but now we have this and okay I can create the next thing in here as well so below the chest icon I want to have the next screen so when I click this I want to have this as well but I think that I can just set this to download since this is like the navigation that when I click this it will open a similar so in here as a div ID chat welcome class hidden because we don't want to see this on the page has loaded and then in here I need the input field for the name so input type text and accept the name to be name ID checked name this is important and then close W Dash full so it's full screen margin bottom 4 or MP4 that's a padding or a vertically and px-6 for horizontal padding rounded XL set the BG or the background to be gray 100 you can also set the placeholder here it's a placeholder your name close this one and we also want a button here as well so button ID chat join so this is then open for open a chat and I will just join for actually joining the chat close now we set some spacing here as well so py-2 px6 rounded l and text y because at the background BG rows 600 and the text can be join chat and save so if I go here now I refresh nothing has happened so now we need to make possible to click this so when we click this it will be replaced with this screen so then I can open up the file main.js which is in the yacht test static Js so to begin adding a comment here and says said say here element because I want to specify these at the top here elements const chat element that will be this entire box now to find it we just chat element equals document dot query selector hash chat and then this will now find this ID here so now we can manipulate this and similar I also want to find the open button and the join button so const chat open element and let you add element that all of these variables just so that I know that it's actually a HTML element documented query selector hash chat open I can just copy this for the chat join replace with the chat join and I want the icon which is this screenword icon is so chat icon element chat icon and the welcome so welcome and welcome and this welcome is of course this screen um then below here we can add one more command as a event listeners nurse so I want to check that if this chat open has been clicked it should be very easy now but just saying chat open element dot on click equals function pass in the event there and in here is the E dot prevent default just to make sure that H doesn't refresh and similar and end this function with return false and then in here what I want to do is say chat icon element dot class list dot add hidden so then we add this hidden Clause this to this screen so then this will go away and now we do the exact opposite on the welcome screen so chat welcome element.close list dot remove hidden and Save so then I just need to include this main.js file so if Adam just close a few here so it's easier to watch if I open up index.html and I can say block Scripts and block and then in here as a script SRC and a link to this so that's static so we use this built-in function from Django Js main.js let me close this script tag like that I think I've already added the load static this was in the starter pack so if I save now go back and refresh open up the inspector there are no errors just the Fab icon is missing so if I click this now it was replaced with this screen nice so we are still on this task now I just want to make sure that when we join chat that we are sent to the last screen here so if I then go back to visual studio code and into chat bubble we can create the element for this so div ID chat room class also hidden so we don't see it before we are actually on that screen and then I want one div for this one and one for the form itself div ID chat log so I call it chat log or I can call it chat messages or whatever you want but in my tutorial I use it as chat log and then add some classes to this for example mb-4 there is space below this p-4 series space inside as you can see here space inside a margin button below and then I set the background to be PG gray 100 I want to round it Excel Corners I want to set the height to be 300 pixels so it's hard coded 300 pixel tall which makes it easier to have the scroll inside so you can just say over overflow scroll so everything that's more than 300 pixels there will make this scroll inside there so this can just be like that and then we add a paragraph in here Welcome to our chat please type your message and wait for an agent to join and below here we have the form we can begin by setting an input so input type text and the name air can be a name message or body it doesn't really matter because it's probably not going to use this attribute and then set the ID to chat message input and then some classes so class W fill so it fills out the whole screen as you can see here and b-4 space down to the button p-4 and BG gray 100 and rounded Dash XL and then we can also set the placeholder which will be type your message glow here I just want the simple button for sending the message so button ID chat message sent or submit close py-2 px-6 PG rows 600 so it follows the same the sign is everywhere else text White and rounded XL texture can just be sent okay see if I refresh on the oops on the page now nothing happens because we haven't made it possible to go to this yet so I need to make it possible that when I click this this screen here is able to be showing so we need a few more elements here chat join is this so we already have that one but we need this the chat room so replace the title there or the valid change chat room chat room element um and then we can have an unclick on this chat join as well if I just copy everything here we can replace this chat join element and then here we want to have this to add the Clause hidden and the chat room element to remove hidden so that should make the everything here work join and then I sent there nice okay before I set this to done I just want to specify a few more variables here so I have them for later so here I can say const or actually let chat name because this is needed to be changed this will be the name for the user and then I want one left chat socket so this is then a reference to the socket itself it can just be set to null let chat window URL this is the page we are on for example in the demo we saw that the user was on this page which is then just this URL so now we can just a window dot location Dot hrf and let's let chat room uu ID this is what we are storing in the database actually in this field so I don't know what the way to randomizedly generate this which is actually very easy to do with JavaScript math dot random dot to string 36 dot slice two twelve so now this will give us a string which is I guess 10 characters long from 2 to 12. so if I know that console log we can check that this was actually working like that so just console it log it like that so if I open up the inspector refresh and you can see here that we generated this automatically now nice so we don't have to have this here so it doesn't fill up anything here and make things confusing so then I think everything is done you can say variables here just to keep this as clean and easier to understand as possible so then I can go back here and set this to done okay so now it's time to start working with making any possible the connector backend using the web socket first I just want to set up an end point so that we can create rooms and store them in the database so if I go to visual studio code and then I find I've used Pi inside the chat tab then first I Can Begin by importing Json because I know that I need to return Json data here I can then also import the Json response so from Django dot HTTP import Json response and I need to import one decorator as well so from Django dot views Dot decorators dot HTTP import require HTTP methods actually so here that we have actually something called require post so I can probably just use that one then I also need to import room model so from dot models import room and then I can create the API endpoint first and it's the add require post because only they're going to allow post method to this View and then def create room and since we have this you will not be able to go to this in the browser that will just give you an automatic error request and then a unique ID for this one and this unique ID is the one that we have here so then I can get the name of the user first name equals request dot post get name can default this to blank and the same with the URL that the user is on so URL and URL then we can create the roombathing room dot objects.create uuid equal to you ID set client equals name and URL equals URL never go to the multiply you can see that this will be filled automatically this will be automatically or defaulted to waiting we don't have any messages yet and there is no agent yet either so then I can just return Json response and then create a dictionary in here with one value message and say a room created so now I have this end point and then I just want to create the URLs file in here for making it possible to reach this from the front end so URL stopped by now we can begin by importing Port from Django from Django Dot um URLs import port and now we can import all of the views from the chat app from dot import views you can also search app name I don't think that I'm going to need it but I do it anyway and then URL patterns which is a list and right now we are only going to have one view here create Dash room set the name to be create Dash room and the view we're going to use is the views dot create room so I think I also want to add API at the beginning here and also I need to have this in there as well so I'm going to expect a string called uu ID so we are expecting a string equal uu ID which is the name of the parameter that we have here so now that should be available then we just need to add this to the main URLs file so if I just go to yacht urls.pi we can add it at the top pair part and when this is empty just like this we will go in here and check if it matches any of these URLs so chat.urls so if now the URL is actually we can have it below the core since this is where we have one empty but if it's for example chat admin or API then it will not match anything there but it will go in here and find this one and match it so now the URLs is set up the view is a setup and all of the things that we need in the back end should work so I can set this to down then I just need to set up the JS for connecting so then we need to do a few things there and if I just close this for now then I need a way to get the name from inside the chat bubble so I need to be able to get this one and I need to be able to get this here that should be available chat room yes so let's add one for the name just copy one of these rename the chat name and rename this the chat name this will then be the client name or the user name since I already are there now I can make this available and also the input and the chat message as well so I can copy make three rename this to be chat log chat log and then chat input element chat input and chat submit element chat submit so I think that's great chat message submit Maybe okay chat message submit and check the message input so then I think everything there should be okay so then I can head over to the JavaScript so in here when we have made this available let's just room then we want to call a function here so in here I want to call a function called join chat room I'm not created this yet so I'm going to do that next now you can have it above the event listeners oops so in here I can say functions and then I can say function join just run so log join chat room and then I can test it this is working now by going here refresh click the chat bubble write the name and then it was actually not cold here so why wasn't this called join console log test hard refresh try one more time okay now it was working so I probably just didn't refresh okay so I can remove this now scroll up again to the function and then first I can say chat name which is the variable from up here equals chat name element dot value so I will get the value from this input field and then I can do one more console log here so console.log join s and then we can print the name here chat name and we can also console.log the room uu ID and this should be available in chat room uuid we can try this one more time refresh write the name join chat room join chat room AS ASDF and then we have the ID for the chat room name perfect then I just want to set up a form data for what we are going to send to the back end const data equals new form data and then we can append the name that are dot append name and here we want to pause in the chat name and there are DOT append URL should be chat window URL which is the URL we are on and these should be available then inside these two variables okay so when this is done we can use fetch to call the back end so fetch this is built into all browsers now slash API slash create room slash and then we can use a variable in here chat room you you ID you can see here that this isn't available so we just need to convert these two here to backtx so then you can see it's turned light to Blue perfect and we need to set the method to be post here so method post and then headers this can just be empty for a few more seconds and body should be data and then when this is done we will get some information back sorry guys are just done function rest for response and let me just a return rest dot Json so let me pass this on to the next function so dot then function data and then we can say console.log data data so we can see it what we are getting from the back end and then in here since we are using a post request now we need to send in the csrf token so using it x dash csrf token so capital of these letters and then lowercase on okay then we can call a function called get cookie plus ncsrf token so then you might wonder where we get this from we actually need to create this so at the top or above here you can say function get cooking and then in here in one parameter called name which is this is the srf token like I said war cookie value equals null so we first set this to null and then we need to get or check if there are any cookies in the browser if document dot cookie and document.cookie not equals empty so if there are a cookie and it's not empty then we can go in here and we can get all the cookies by saying War cookies equals document dot cookie dot uh split and we split this by semicolon then we can Loop through each of these cookies by saying four VAR I equals zero and as long as I is lower than cookies dot length 10 I plus plus and iteration will continue equals cookies now we get this exact one dot i and we want to trim unnecessary values from this if cookie Dot substring zero name dot length plus one equals name plus equals so that means that now the cookie name is the same as the name that we are looking for in this cookie and if that's correct you can say Okay value equals the code URI URI component cookie Dot substring name dot length plus one and plus one is because all names have this at the end and when this is done we can say break to just quit this for Loop and then at the bottom below this for Loop actually at the bottom here we can say return cookie value and this will give us the value of the csrf token so we can try this now if I just refresh write the name then you can see here this was sent to the back end and the room is actually created if I see here there are no errors and you can see that it was automatically or correctly posted to this so if I go to the admin page go to Rooms then actually have a room here from ASDF you can see here there are many messages in the database now these are just testing things for me from previously and the uuid which you can see in there okay and this was the URL the user was on and similar it's closed because the user has refreshed or it has not connected correctly sorry anyways now that that is done we have the name and everything for the chat the room is created in the database so after this is finished we can connect with the chat socket and to be able to do something when this is finished we need to make this as an asynchronous function so a sync and here is it await before we call fetch now below here we can say chat socket equals new web socket and then pass in WS instead of http and then we use a variable in here window.location dot host because here we just want to get the beginning part one to seven eight thousand two we don't want if you are on the sub page and similar slash WS slash chat slash and then we want one more variable in here and that is the chat room uuid and slash at the end and close this with the back deck see here now I have two curly braces because one of them was supposed to be there one was supposed to be there and then I can remove them like that and now this looks okay then below here we want the function for when we are getting a message from the back end so chat socket dot on message equals function passing the event there then we can say console.log on message and on this closes we just want to say something to the console chat socket dot on close equals function e console.l log on close chat socket was closed and we can also have a chat socket dot on open equals function console log on open chat socket was opened like that so no I should be able to go back here refresh create a new room okay there was something that failed no path found for WS chat and then this so why was that not found let me go back and check so what did we have in the routing that Pi with just a WS and we did not have a chat there so let me just add chat or I can go back here and remove it from there that's probably as easier one more test create one more chat token was open if I go here now it says handshaking to check that everything is okay and then connect if I now refresh you can see here that it was disconnected perfect that means that now it's possible to connect it from the front end to the back end using web sockets next I've done will be to make a possible to send a message from the front end to the back end and we will also want to make it possible to store them in the database so now first I want to create a function for sending and receiving information in the consumer so close everything here and open up the consumer dot Pi because here I want to receive information from the front end and then send it out to the room again so below here I can say sync death receive whoops receive self and Text data and this text that contains all of the information about the message the name if it's an agent and similar so just like we have comments here I can have one comment here as well receive message from web socket front and text Data Json so we can convert this information to Json Json but loads Text data and that's just the information we get from the websocket from front end now we can get the type from here type equals text Data Json type and this will be from chat message if it's an update when we start typing a similar we'll come back to more of this later and then message equals text Data Json message copy this one create one more for name this will not be the name of the user or the agent and then agent agent and these values can be empty for example the user itself will not be will not have an agent value and since this is optional you can do it a little bit different present text.json dot get agent and now we can default this to empty I guess if type equals message then we know that this is a message print receive now we can print the typer just so they can see that it's actually correct and if it is a message then we can say send message to group or room and then a weight so we want to wait for this to finish self dot Channel layer just like we appear connect and disconnect it we can use this to sand it so group send self.room group name and then a dictionary and now we want to pause and type chat message and we want to pass in the message itself Sage copy this now place here with the name the name and the agent agent and we also want a few more Fields here I want to have oops initials initials for the user because if we go to the demo okay I don't have that running now yes who's there this is the initial I want to load and generate this in the back end based on the name so you can create this function very soon initials we're just passing the name of the user and create that at here I want to use a filter from Django called time since we pass in new message dot created at okay so here we can see a lot of things going wrong let's begin by fixing this initials so we can create this function [Music] so I actually want to create a template thank you for this because we're going to use this in the front end as well so it will require a little bit of code but there's nothing we can't handle so inside here you create a new folder called template tags and to make this a function or a package or at least you make Django pretend that is we create an empty file called init.pi and one more file called chat extras dot pi and then in here we need to import a couple of things from Django from Django import template and then we set this and we call register template.library so we can make it possible to actually um register template thanks and to register it we say at register.filter the name should be initials so now in the front end because uh we could for example use this as name and then initials now we will get the initials in return non-def initials value so that value will be the name for the user we want to get the initials for and then I create a new string initials equals just an empty string and then I Loop through the name inside the value is over and about my name is Stein over and a little bit Stein and Louver in this here because it's split it on the space and then we check if this is a name the value that we get and the length of this string is lower than 3 then we continue because we don't want initial string to be longer than two characters and if it goes in here it just append the first letter of the name uppercase it to this string and we can just return initials and Save so now that this is done we can import and use this function here as well so from dot template tags dot chat extras import initials so now this error should be gone at least if I spell it correctly initials great so then we can handle this one time since this is also one thing we can just import from Django So Below this import we can say from Django dot utils time since import time since and this will give us example when it was posted 10 minutes ago it will say 10 minutes ago instead of the actual timestamp so if I save now this is also gone so then you can see we get one more error here um so this is actually the message that we should store in the database um we can fix that in the next part so right now we can just return an empty string and comment out this so let's just save this for now so that this is done at least then we want to create one more function before we can test this so here is a sync death chat message and the name of this function is the same that we have in there self event and this event contains all of this information so then in here we can say send message to the web socket front and so we get it up here then we send it to this function which then handles the standing to the actual front end so here we can say a weight self dot send is a built-in function to this async web socket consumer class and then in here we say text Data equals json.damps we can revert everything into Json we can send in the type which should be inside event type which then will be this value that we can say message this is also something you want to send to the front end event message let's just copy this and replace with name name agent agent and then the initials initials initials and last but at least created at created at this will now be empty since it's set to be empty there so if we save now go to the to-do list then I can set this first toaster done because now we have handled receiving the message and also sending it then we just need to do some changes in the front end to make it possible to send the message itself so let's open up the main.js file so we have a function in here call on message and this is when we get messages from the back end let's handle sanding first so we don't have a function for that yet so we need to add a event listener to this button here and we have that button in this element so we can just copy that name scroll to the bottom and say chat submit element dot on click equals function e dot prevent default so I can just uh fix that it doesn't refresh and similar return false and inside here I just want to call a function called send message and nothing more there so let's scroll up and this message function can be here actually wherever you want but I want this regular function up here and I'm going to async function at the bottom here so function send oops function send message and then here is a chat socket jet socket dot send Json Dot stringify so I'm a stringify the data we want to send to the back end message sorry type should be a message and this type here is what we are checking for in the consumer up here if the type is chat message so scroll go back here again and we also want to send the message which should be inside the chat input element dot value and we want to set the name as well which is in the chat name variable and this variable here was set down here so you don't have to get it from the Dom one more time and this will be updated all the times we need to get it whenever we send a message and when this is done we can say chat input element dot value equals empty so that we empty the submission form so we can test this now go back refresh join a room web socket open try to send something the socket was closed so there is something wrong initials was empty yes we are not sending the initials to the back end there event sorry I think I just had a typo initials initials correct so have the typo there oh darn let's try again name send a message send one message everything here should be okay receive message so yes looks like everything there was working perfect So based on the to-do list we still need to work on this because we need to get the message and show it in the chat bubble as well so as you saw in the browser here it says on message because you get the message back from the back end once we have sent it so down here I want to call a function on chat message and there we pass in and the way we call this and in here I want to call a function called on chat message we recall json.porous and now we get the data from the event here and this is something we get from the back end so now we just need to create this function we can have this below the sent message function one message here we get a variable called Data console log on chat message now we can see the content of this data and then if data DOT type equals chat message which is what we set inside the consumer there then we can go into this if condition if data.agent that means that it's one of the agent that I sent this message else that means that I sent this and when I send it I want it element to be on the right side of the box so here is a chat log element dot inner HTML plus equals and then div and then sorry I can use the back ticks here as well then I can just print the message quickly to see that it is working there are DOT message so let's try this refresh hopefully the message should appear here now yes nice but just like in the demo I want the blue uh bubble on the right side here okay so let me change this here a little bit first I want to div with the class of flex so that I can have the bubble on one side and then text message on the other the width of this element should be take out the whole screen or the whole element I want the margin top to be too so I have some space between the different bubbles space x-3 so has no space between the bubble and the bubble the bubble and Avatar and I want the max width of this to be this size as well so medium is the max size so it doesn't fill out the whole box and then created one more div here this one div class Flex shrink so it doesn't grow and it's at a static height of 10 and with 10 around that full background 300 text Center and padding top two that means that this is now the inner little rounded box for the initials and then in here I can just add data dot initials you can close the div for this little rounded bubble and then when this is closed I can create one empty div and then one more div for the chat bubble so this should maybe actually be blue 300 and some padding around that on the left side and around that on the bottom right side and in there I want the one paragraph element with the text SM and then we can print out data.message in there then I can close the paragraph and I can close the div and this div is done this with the blue bubble below this bubble I want one more span for telling me when this message was sent so I set the text to be extra small set the text to be gray and leading none so that there are very dense text and then I print out when it was created and just add a go at the end there so then I can close the span I can close the empty div that I created and the outer bubble div so let's save this now and try it out connect fill in a name send the message it did not work very good let me try to hard refresh no not working that either so I have the message from the user I have the create at the moment where time is missing yes that's because it is missing in the consumer as well as that is to be empty so don't mind this but the initial part why doesn't that work so none of the classes here are added um Dave close PG blue 300. all of these should be working okay I think maybe the Tailwind that this let me try to add one more sub folder here see if that make it work restart refresh no so what is wrong with this one h10 and the bubble isn't there okay I know why this is not working it is because these Clauses are not in this HTML it's not in a python file it's in this file so I need to add this Java Script file as well to this content generator so dot slash static slash JS and all files that is named anything and ends with Js so then it should hopefully work name send message yes perfect so now we have the initial bubble and the bubble itself but you can see that they have mixed up something here because I want my messages to be on this side okay so I need to fix that the Avatar or the initials it's on this side and also move it to the other side so let's do that if I just go back to the end of the chat bubble but it's inside here somewhere if I move this and clean it up a little bit maybe it's easier to see what I have done wrong then like that so now I have this on the left side this should be on the right side or below the bubble there now also think that this should have a few other clauses think that if I add margin left to be Auto and justify myself to the end that it should work you can try to refresh set the name send the message and then I have the bubble there the bubble is correctly on the right side perfect and then the other users or the agent should be on the left side there so let's set up HTML for that as well I can actually first just copy this and paste it and then I can remove these Clauses so it will not be moved to the right side then I move this to be above the messages here and this can be great because I only want my own bubbles to be blue so that means that if I go here now I can set this to done and then we can just handle this saving this in the database this is done in the consumer.pi and I will remember to fix this as well so at the bottom we can use this here that we imported previously so we can now say at sync to async because it's going from an asynchronous function to asynchronous function def create message pause itself who sent this which is sent by the message and agent and then here is a message equals message Dot objects.create see we need to import this so from those models import message scroll down again and I want to create this because at the body to be message and sent by is sent by now you can check that if this message is sampled by an agent or a user every replacing if agent which means that the field was filled out which means that it was summed by an admin if admin then message dot created by yeah sorry created by equals user.objects dot get where primer key equals agent and this is where we will send in the um the ID for the user you can also see that I get a new warning here so we need to import this from account dot models import user and then we need to save this passing message dot save then we can say self dot room dot messages equals sorry self.room.messages.ed message return message so now this message will be returned to this function and we need to be able to set the room as well and that is something I need to do a pair just two seconds and right up here we checked if it was a message type now we can say new message equals self dot create message now we can pause in the name of the client or agent the message we want to store and if it is an agent or not a bit before we continue down to this we need to make sure that this is finished we can set this to be a weight and then we can comment out this so that we actually get the correct time since value then I just need to make sure that we have this somewhere and this should actually be set up here in the connect so before we add this we can call a function called self.get room then we just need to uh get the room that was created invised by down here so scroll to the bottom one more time you need to use this because you need to talk to the database you can just add F and get room self and then we set the value self with room equals room.object so get uuid equals self.room name and the cell for the room menu is set to pair which comes from the URL then I just need to handle this Warning by adding room to the list of models that we import so now I think everything there should be okay we can try to refresh Stein join chat test message send okay so it looks like it wasn't I get it back here it was created zero minutes ago so if I then go to Safari where I have the back end then I should be able to go to rooms to see the room that I created sorry this is actually not the correct front and this is the front end for the demo um so I need to log into this one I don't remember if I created a super user or not admin at the.com foreign and then run the server again so that I cannot log in with this user and then the password I just created so I can't even see the rooms here so let's fix that by going to admin dot point in the chat from dot models import room and message admin.site.register room admin.site dot register message and Save and now go back and refresh the rooms are here this is the one I just created and inside messages I have the message test message perfect so then you can go to the to-do list set listed on tested on and now we have to possibility to send messages and the messages will be stored in the database which will mean that when we go to the admin interface we will be able to see it on there as well okay so now I want to start working on the chest Administration this is the pages where the administrator or the manager can add a chance and where the rooms will be listed out where you can go and talk to users and similar so first I want to create a basic page for listing out the rooms so I want to have this in the views of Pi inside the chat app as well so let me just close all of this so I just have this so down here I can create the view for this so I definitely want the user to be logged in when they're going to this page so I'm going to use the login decorator from Django so from django.com trip.org dot decorators import login required then I can scroll down say add login required and then create the view So Def admin pass in the request parameter so here I want to get all of the rooms from the database so rooms equals room dot object dot all and I also want to get all of the users that are in this project so users equals user.objects dot filter is stuff equals true and I say stuff equals true in case you have other types of users and similar so get a little warning here so I need to import this model from account.models import user and then I can return and render this return oops oops then error the render Plus in the request parameter and then we set the template name and the template name can just be checked slash admin.html and then I want to pass in the rooms here so this will be available rooms and users users so you can see I get the warning here so I need to import this again from Django dot shortcut import render so then the warning is gone nice then I can import these two URLs so that is done part and then this can be chat Dash admin slash and the view I want to use is views dot admin and we can give this name of admin so now this will be available under chat colon admin so now I can add a link in the menu for this before I create the template so if I just open up the paste.html then I can first check here if the current user is authenticated if request.user that is authenticated then I want to show a button appear so then I guess a hrf use the URL function chat colon admin close that one you need some classes on this first you can set this to be an inline block since this is a link py4 and px-6 so in the demo I think I have it yes you can see the button here so we need a background which is a little bit darker so BG rows 800 set the text to be white and we want rounded corners now we can just say chat admin as the label so if I save now go to the real page refresh you won't see anything there because I'm not logged in here but if I go here to the front page this is the one we are working on now then you can see here chat admin and now we get this template does not exist but that is okay because we haven't created this yet so it will be in the next step so inside this folder here oops not in Portals but in the chat folder we can create a new file called admin.html so I wanted to extend the base template of course so extends core slash paste.html oops and then we want to block content close this as well and block and then in here we can begin by adding a title H1 plus text Dash to excel chat admin again close to H1 and we can save this so we can go and test so if I refresh now you'll see that they get the title appear and now I'm logged in nice so then at the top here I want to list out the users so then we can use the built in permissions for Django to check if the user is allowed to add users to do that you can say if perms Dot user.ed user and if can add users so let's try this refresh no it's logged out okay okay so now you can see here that I'm logged in and this says that I can add users so let me go to the admin interface to check this so inside the users have this admin at the other and I can see down here that none of these are actually set to be able to do this but since I'm a super user I'm actually allowed to do anything that is in here so what we could also do here now is to create a new group for managers and the managers should be able to create users similar and I also wanted them to be able to do anything with just room and the chat messages actually I think the yes everything of this has to be over there now we can save and add another one and I want one more group for the agents agents and an agent should not be able to do any of these four but an agent should be able to do all of this at least view a room maybe not the least and similar so let's just add this for now and we will come back to this later save and then I'll go into my user then you can I want this to be a manager manager so save okay so if I go back here now you can still see that I can do this and that's because I'm a super user so I will come back to more uh permission stuff later right now I just want to add a button here so right now I just want to add a div hair div Clause empty eight so we get some space up to the title and then H2 close margin bottom four and text should be LG the title layer can be users and then below here I can have a button for adding user a hrf this can just be empty for now since we don't have that page yet uh at the inline block since this is an inline element padding in the y direction should be two and in X Direction PX 6. and then we can have the background to be b0 rows 600 texts to be white and the corners should be around that Dash XL the title in here can be add user test that this is working back in back refresh I have the title and this button nice I'm not below here I just want to list out all of the users in our system so we add a new div clause empty-6 so you can space up to this one and then we can just F4 user and users and for and then I want to create a grid for each of the user div class grid grid calls 4 and get this Force space between these columns and a little bit of space in there padding or py2 and we want to use a tag from Django called cycle PG gray 100 and empty on the earth cycle and what this cycle here does is that on the first iteration of this Loop here it will add this plus and on the second it will add this which is empty now but it could for example the BG blue 200 so that it Cycles between these two you can even add more Clauses here if you want to do that but that's how you can create the zebra stripe for a table then we can begin with the name p clause px2 then in here we can show the name for the user user.name then next to this we can print email user dot email set of course one more user dot get rolled display and what this get role display is that if you look at the model for this you can see that the role will either be agent or manager but since you are using get role display we get the display variant of this which is one of these two then add one more for editing the user so here we can say edit so in here I want the link a h or F it can just be empty for now but I want to close on this which is just underline to make it easier to understand this you can actually click this edit each of these three paragraphs should also had a class px-2 and this one I want to have a text write on as well so let's save and test this now oops okay I have one yes I forgot to add this one because I removed it when I try to explain how it was working refresh and you can see we have a gray one nice so now we have the cycle for the users we will come back to adding more later if you want you can go to the backend here and add one it's a thing let this be an agent here you can add specific user permission just for this user if you want to do that as well agent at the at that com agent testing agent is active is stuff and yes let's say refresh no not the correct page refresh and we can say this is now white nice okay and then below here I want to list out all of the rooms as well So Below this and if here we can create a new grid div class empty mt-8 and then between these two I do not have a HR as well close m1-6 so I have a good separation between this and this or this and the button above or the title and then in here we can Loop through the rooms for room and rooms for and then I can create a new div for each of the room div clause p-4 so I have some space inside there around that Dash XL then I want to have a different Clause based on what the status of the room is so if room dot status equals what I think so that I was waiting for someone to take this air that we can set the background to the pg Emerald 100 alif that room dot status equals active then it can be yellow feel free to change the color release as you want PG yellow 100 else so when it's not available anymore then we can say BG gray 100 and four so then I can close that div and then just type something to test this okay so cannot parse the remainder of active forgot one take um invalid black okay sorry and if not and four and this should probably be removed like that so now it should work so now I have a few rooms down here and I don't want to fill out the whole screen for this of course so I need to add a grid around this so Eric is a div close grid grid calls 4 and GAP four and then we close this save refresh and now they are listed out much better maybe we should even have a title above here so above the grid because H2 class mb-4 text LG and rooms nice okay as you can see many of these are waiting and that is because we have not handled what happens when the user goes out of a chat and similar so we can consider this as deleted later anyways let's continue with the content for this in here I want H3 H3 class mb-4 text LG and the title can be chat close close H3 is that correct it okay so down below here we can have some details about the room p and then B ID this is then The UU ID so room dot uu ID it's just save and check that it's working yes you had a chat and then the ID nice and then together with this one I want to show the name of the user you're talking to name which is room.client the brake line at the end what the status of this room is so get status display brake line one more and the last one here is H and two to know who the agent or the owner of this is so here we can say room dot agent dot name and I think this will crash now or it will just be empty but we can use one more tag from Django if we just add the percentage there and say first off and what this does is that it checks if this value exists if not it will take the value of this string so you can use a none yet if I refresh now every one of these will say none yet but as soon as one of the agents goes into this and activate it this will change to the name of the user because then this value will be true and then I want the button for going in to the room hey hrf can just be empty for now but we can add a class to this one empty-4 inline block and we want some spacing py2 PX 6 BG rows 600 or actually Emerald Emerald 800 was what I had planned here set the text to be white and around that Dash XL I can just say join so let's save this now go back and refresh and I will now have a join button on all of these perfect so I think that now can go here and see that this task is now done and then I want to set the room list in a separate file because I know that the code inside this list will be reused at least one more place in the admin interface so what I can do then is to make copy of this grid div and create a new file inside the portals here and this can then be room list list.html paste it and Save then I can just say include chat slash partials slash room list.html and then I have it more available and easy to reuse perfect so then I can set this task as well to done so then the next step will be to make it possible to open a room so we can begin with the view for this so if I just go to visit Pi in the chat app let's say add login required and then death Rune request uu ID because I want to know which specific room the user clicked on now we get the room from the database passing room equals room dot objects.get uuid equals uuid which comes from the URL then I can make a copy of this and the template I want to use is room.html room room and close this okay so let's add this to the URLs as well you can just add it at the end here and tell just like we do up here that we are expecting a string called uuid and when this is a match I want to use if we use the room and the name for this is room so that's done make it possible to click the room in the room list which is this one I can use the URL function chat colon room and then we just pass in room dot uu ID so then remember to click this but I will now get the template does not exist yet so that's okay that was expected of course so if I just close this open up the at the minute HTML again I can copy it to pair create a new file and save this as a room.html just make sure that it's in chat templates chat save so now here we can print out the room and then the room IP room Dot uuid so it's a little bit easier to keep track of what room you are in and block say go back and refresh and then we'll see it here room and then the ID perfect so then below here we can begin by adding an HR just to separate things as good as possible and b-6 and since this no actually I want space up as well so and y-6 and then here we can create the div another paragraph and add the clause and b-6 and here I want the details of the room to be written so we can begin with the name of the user room.name break line and then started so that we can know when the chat was started room dot created at pipe this into the filter time since and then we just add Eggo at the end there so this comes from Django it will always work in the template and similar then the status of this chat room that I get status display oops and then here at the bottom page so you know what URL the user is coming from in case you have for example a e-commerce website a similar then you now know which product the user comes from so room dot URL then last but not least oops I want the agent name to be printed out there so then we use the first off again first off room dot created by name non yet like that so if I now refresh it will say name empty so this was a bit client so I had the name of the one I'm talking to when the chat was started what the status is pager comes from and who the agent is okay let's add a break now HR again close and B dash six and then down here I want the chat log so div ID chat log class mb-4 I guess in space below down to the form where the user is supposed to write things p4s as padding inside PG gray 100 rounded corners of course and I want to look at the height height at 300 pixels so that it's scrollable the content where the message is is overflow scroll and I want this to be a flex box so that I can have the chat bubbles next to each other Flex column Flex grow and yes that was it can test that it is working yes here we have this gray area and then in here we can Loop through the messages and to get the messages you can just F4 message in room dot messages dot all right close this end for like that and then for each of the messages I want to have a flex container div if class Flex W full so it fills out the whole available place but we'll also have a Max width so max w idth is medium of the screen I also want to have a empty Tuesday or a space between the messages in the vertical Direction and space Dash X3 so there's space between them horizontally as well so now this will be one type of the message but if the message comes from yourself I want them to be on the right side of the screen and to do that you first need to check if it is your message so if message dot created by equals sorry if messages created but then we automatically actually know that it is an agent because the messages that comes from the users in front end have a non-value in this so only this check we can just say margin left Auto and justify and like that and if I close that and do it like this if I just add something in there refresh not much will happen there but we get this margin top and similar so let's start working on the message so we can first check if it's not your message so copy this paste it if not then we know that the bubble should be on the left side sorry the initials should be on the left side of the chat bubble so div class Flex reflects sure shrink Dash zero the height should be 10 the width should be 10. and then because they're rounded full and BG gray 100 text Center and pt2 so this is exactly what we did in the chat bubbles for the front end and we can say message Dot sent by pipe this in to filter called initials and how do we get this here now while we need to load the chat extras template text that we created previously so load chat extras this will unload the chat extras function in here and now we get this filter we just pipe in the name and now we get the initials back so that's how you do it like this okay so then we can close this and if and then in the middle then we can add a div and then we have the div class and here I also want to check if it is your message or not so I can copy this again so if it is your message I want the background to be blue so PG blue 600 text White and if it's not your message then we say else and then we pass in BJ gray 300 instead close the end if and then we can close this div and then in here we just print the message but I want the text to be small turn it at a closer text SM and then message dot body close and then below this bubble itself I want to print when the message was sent so span close text Dash XS text Gray 500 so it's muted a little bit leading none message dot created at pipe this into the time since filter and say ago so this is a built-in filter and this is something I created ourselves and then at the bottom here we can show the chatbot bubble if it is you now we want the right side of the screen so if message dot Creator by we have it like this instead so let's save refresh and actually have a test message here and that should probably be a little bit darker so let's say 200 better and then I was a space for this one which should be in here p-4 rounded XL yes much better so this is then a message that you got from the user so what we then can do instead of down here we can show a form if the status of the room is active So Below the chat log it's important that we do it below this div now we can say if room dot status equals active then we know that you are going to chat with the user and if and then we can actually just copy a little bit from the front end so if I open up the chat bubble then I can copy these two elements here and just paste them in there and I think that this particular chat is not active no it's waiting so let's change it if I just find this in the admin interface this one if we set this to be active and that agent that is owning this save refresh then we have the chat bubble sorry chat information error then we can do one more thing and that is inside the view for this and that is that if the room. status equals room dot waiting then we want to change the status for the room so room dot status equals room DOT active and room dot agent equals request dot user and when this is done we can say room dot save now the agent that clicks on this room which is the waiting will automatically get this and be the owner of that one so soon to check the tight tasks there and now we are made a possible to open a room nice so now we can start working on this which is to make it possible to connect to the web circuit and load messages we are loading messages from the database but we also want to get my suggested or sent from the front end so then we need to introduce some JavaScript so inside the room.html at the bottom below and block we can use the block scripts again because here we want to pass in some JavaScript and block and then here we want to check if the status is active because only then we want to load the JavaScript we don't need it if not so let's paste this here and then in here we can say script search theme aesthetic and the file we want to load here is JS main at domain.js so this file should be created already but it is empty but if I console it log 9 admin save you can go back and refresh okay I get an error because aesthetic isn't a valid block tag and that is because I need to add static here as well together with this one if I say refresh open up the console if I can do that here in sephorian okay let me just close Safari open up the Vivaldi instead actually haven't used this browser for this user because I need to log in and I think this is going to crash again yes this field is required that doesn't tell me anything but inside login.html we have this one which is the email but I think that if I changed name to username Let's test to see if that is working yes now that was working and it is because just how the different forms are talking to each other and similar so now you can also see that this has the status of active and agent agent testing and if I go into this now open up the inspector so you can see in the console main admin which comes from this file nice but before I start doing anything in this file I want to do a little change in the room.html again because we need to post in some values like the you rooms uuid the username the user ID and similar in to this file and to get it there I want to create something called here and by doing that as a room.u ID and pass this into something called Json script and I just call the value room uu ID so we can save this now and go and see what this looks like so if I refresh open up the inspector again scroll down then you can see here that I now got a new script ID room uu forgot the D and then the value of the room there so now this is very easy to get in the back end sorry in this file as well so I need two more of these so we can just copy paste room should just be a representrequest DOT user.name this is then the agent's name and request.user.id this can be replaced with user ID and user name so now these three here should be easier to get inside this JavaScript file without printing anything anywhere weird way and similar okay so let me just remove this one and then I can add a comment there variables and then I want one variable for the chat room which is then the chat room uuid const chat room equals document dot query selector and I want the one called room uuid and if I then go back here you can see that I get this one and I get the value in there so first a select element and then I just say dot text content dot replace hold and I want to replace all quotes with nothing so I can say console log chat room chat room so if I refresh now and see in the console chat room and then the ID so now I have this available and just like in the other main.js I want to set the left chat socket to null so I'll take and assign this in the function and make it globally available then I can get some of the elements from the HTML so elements let me open up the other file main.js and copy a few of them so I can copy the chat log this is one I know that I have I'm going to use and the input and the submit so I can copy these two as well so these three is now available inside and then there there and the chest log so chat log yes chat log correct nice then I can set up the web socket so below here create one more Command Web socket and then I can just say chat socket which first in this variable equals new web socket 12 socket in one word like that and then the URL I would use is oops like that the same as in the front end WS colon slash and then we pass in the URL for the browser or the website window dot location Dot dot host and I use dot host because I only want this little Port here and not the rest here and then we add the slash at the end there WS slash and then one more variable chat room which is then the ID so now this will find the consumer and we will then have have the ID just like this so that is how I can connect to it in the admin place as well then I want one event listener for the dot on message equals function passing the event console.log on message and I want one as well for on open so I can just copy this on open so log on open and last but not least the on close on close and then in here a second sold log chat socket closed and expectedly like that so hopefully if I now refresh I get the on open and if I go to the terminal you can see the handshaking and the connect so now I can connect as well and load messages okay that should actually just be a separate task so I can do that um receive and show real time messages okay so that will be the next step so I can set this to done so now I'll make it possible to receive messages so I think that a little part of that is already if I go to the front end create a new one hello now her name hello hi Sand then if I go to the backend refresh I have a new name from Hello join and now we should both be connected here test okay now have to fix this but let me try this one more message and if I go here you can see that I got the own message so I don't just need to show the message here after that I will make it possible to send the message as well okay so I know that I sort of can receive messages here now I just need to show them just like we do here so in the front end sorry when I say front end I just mean this one then I have the own message as you can see here based on who sent the message we select one of these two HTML to pass in so I can actually just copy this on chat message function and paste it here if you want to create one more Commander functions like that and then we use it inside the own message to show how I did it there like that safe so that was actually everything I need to do there I think let me try again create a new chat here send message go to here chat admin there is now a new chat go into it and then enter to send a message so now it appear there but it appeared like I was the one who sent that which is not correct if there are not agent that means that this okay if I just if not there are the agent so that means that it should work there but um yes okay so now I think that should work if I just said if it's not the right agent then it's on the left side but before I test that I can set this one to done and just go straight to this one to make it possible to send messages it's a little bit easier to test the other one as well okay so then I want to fix this send functionality so if I go to main.js I can copy this function here as well the send message go back here again and copy it inside the function list there so um the value should be type message the message is chat input element which you get up here the name should be the one that we created and to do here so we need to get that so to get it as a document dot query selector user underscore name which then we'll select this field there dot text content dot replace all so we just replace all quotes again with an empty string then I want to get the ID as well agent user underscore ID like that and then agent will have the user ID value okay so then I just need to copy a last thing here and that is the event listener the submitter so you can copy this go back here again create a new command event oops here Vamp listeners paste it so when you click this we call the function send message which will handle the sending to the back end test this refresh then I'm still in this errone because it's not closed on the front end here so hello sent and it appeared here there receive the message nice and if I go here you can see that I got a bubble there and this then comes from the agent AJ is then the username I selected which was agent just and that means that now they can talk to each other if I send this again then we can see that it appeared on the left side perfect so now the users can talk to each other nice scent so as you can see here it's a little bit annoying that it's not automatically sent to the bottom but that's one of the upcoming tasks somewhere here um so that means that I'm gonna set this to done because it's done and now the chat Administration is done well not all the chat Administration I'm going to work with users and a little bit more permissions and similar as well so then we can continue to the next task by the way if you want to learn even more Django or view from me you should check out my website codedtime.com the site has many premium courses and a lot of awesome blog posts and for as little as 20 per month you will get access to all of my content and you will be able to track your progress you can talk to me on similar so go to codedtime.com after the video and sign up okay so then I would make a possible to send messages by hitting enter on the keyboard so that should be very easy just add one more event listener here so if I just find the code for this I can begin with the main admin.js and then down here below this I can just say chat input element dot on key app equals function pause in the event just so that you have it because we need to check that if e dot key key code equals 13 which is the integral number for the enter key then we can just send message so let me just call the same message as you do when we click this okay so for now copy this I'm going to main.js paste it at the bottom there then I can save go back to the front end refresh this go into this type a name type a message click enter and then the message is automatically sent perfect so that was very quick let me just check that it's working in the back end here's the chat room there's the messages hello hit enter that did not work okay there are no errors let me try to refresh one more time yes now it was working so probably the JS file was just not Reloaded so that means that now I can set this to done next are done is make sure that we are scrolled to the bottom of the conversation when we receive a message and send one but also When an Admin is entering a chat so the first thing I want to do then is to create a function for this so inside the main.js if I find the command where we have the functions then we can add this at the top and we can just say function scroll to bottom remember the parenthesis bank is a chat log element which is the element this gray screen here dot scroll top so then we set how many pixels from the top we should be and that should just be chat log element chat log element dot scroll height and we get this from the browser and then we need to call this when we get a message so at the bottom of um the function on chat message you can edit here now we can just say scroll to bottom but I also want to have this whenever we join a chat it should not be necessary for the front end but we can have it anyway so at the bottom here we have it so if I now save go and refresh start the new just scroll as the name join and then we can add a few messages and then you can see that every time I send a message I'm automatically sent to the bottom so if I scroll up send a message and scroll to the bottom again nice so then I can copy this scroll functionality to the admin so copy this go to main admin find the functions list and paste it at the top pair and then we want to call this at the bottom of on chat message here as well like that but also the bottom of on open so if I now go to Vivaldi where I have the backend do a hard refresh then you can see there's actually scroll to the bottom but I can try a new one so go into this and you can see as I was at the bottom if I type a message hit enter I'm also scrolled to the bottom nice so that means that now I can set this task as well to Don so then we can go to the next task which is to make sure that the URL is pushed in when we are joining a chat so let me just close everything open up the models.pi for the chat then you can see here that we have a field for the URL so that's taken care of inside the views I think this is where we create a room then we actually Post in the URL there so this task should actually maybe already work yes I have the URL there so why do I have this as a separate task I have already done this okay yes then I can just set this as done so then we can start working a little bit on the user management for the administrators and similar so then at the top of the back end in chat admin we have the users there so this is already done but now I want to make it possible for managers to create adjust so this should be activated and have a separate page so if I now just close everything here I want to check inside the account there where the forms.pi where we already created this so here we have a simple user form where it says the model to use which fields we want the user to fill out and then we had added some videos here so that we can control the classes for the input fields so we add a full so it fills out with or is a vertical padding horizontal padding set the corner to be rounded and we want a gray border on the text inputs so now I want to use this and I want this page to be located in the chat as well because I want most of the functionality to be located in this chat app so if I open up reviews.pi inside the chat app we can create the view there so at the bottom here you can say at login required because we want the user to be logged in to do this add user posting the request parameter and then first we can just initialize and empty instance of deform as a form equals add user form and don't pause in anything so you can see that I get a warning so I need to import this so from account dot forms import add user form think there is one more I can just import it so I don't need to read afterwards so then I have that and then I can just return oops return render request pause in chat slash add user.html and then to make the form available at this dictionary we're passing one key with this value and Save so let's also add this to the URLs so that's done then I can add it above this since this hair is dynamic we want hard-coded URLs to be above this port chat admin slash add Dash user views dot add user name can also be add underscore user and say so then I can open up the admin.html and activate this button so URL chat colon add underscore user save so this now should work and if I click it I sent there and you can just see that I get the template does not exist yet so let's fix that so inside this chat folder here create any file add underscore user.html and just like all the other Pages let me just copy top there paste it replace the title with add user you can say and block as well so for now refresh we will see this add user page perfect next I've done is to just show the form below here and add a button so adding the form is very easy we just start with HTML tag for this form method post and we can set action to be on the page we are on here we need the csrf token since it's a post request like that and then we can render the form very easy by using form.sp and then we create the button below here I can copy this from the admin.html if I just copy this Clause attribute button post it in add user so then everything looks like this let me go back refresh then we have the form here maybe we want some space between these two and these two so the title can get mb-6 and also the button empty-6 so then I go to margin bottom and the margin top so that's how this is going to work now if I submit this form nothing will happen because we haven't handled this in the back end here so the first thing we can do on top here is to check if the user has the permission to actually add users and to do that we can use if request.user.hasper user dot add user so now this just take the user model and checks that the user has access to this permission on this model then we move this in one and then in here we need to check if the user has submitted the form by saying if request dot method equals post else we use this pass so in here we will do some validation and also save the user but we want to show a message if the user doesn't have this permission and do this and move this in there and then here we can say else and then a message messages which we need to import from Django that's pair somewhere from django.com trip import messages okay this needs to go to the top so I have everything alphabetically and then it was a lowercase M of course dot error Post in the request parameter and say you don't backslash that have access to add users and then we just redirect this user back to the admin interface so return redirect slash chat Dash admin then I get a new warning here because this isn't defined so we can import this which is a shortcut coming from Django dot shortcuts import render and redirect so then that is taken care of and this will now be added to the do the session and if you go to base.html we have already handled here how this is presented so here we just check if there are messages then we show a red box and then we print each of the messages by looping through them and when we are show them one time on the screen they will just be gone okay so let's create a new instance of the form form equals add user form and pass in request.posts then we get information from this form and we can check if it's valid if forum.s valid and instead of actually saving the user now we need to create an instance for user and not send it to the database and we do that using user equals form dot save and passing commit equals false so now this is a user object but it doesn't exist in the database yet and the reason why I want to do that is because when you're adding user here it needs to have a permission called is stuff so user.is stuff equals true and this makes it possible for the user to actually log into the admin interface and similar plus I need to set the password that we get from here because we are just filling in this as a as a hard-coded text and then we convert it and make sure that it's scripted in the database so you should not set password and then request.post.get password which comes from that form and then we can call and oops user.save and when we now say user let's save it's saved to the database plus if the user is a manager we need to test this and actually add it to the group to the group of managers so if the user.roll which also comes from the form as you can see here is manager then with a group equals group dot objects.get so we get this from the database based on this name and just say group dot user Dash set sir underscore set dot add and then pass in this user now you can see here that I get the warning so we need to import this from Django from django.com trip.org dot models import group and I will need also need to make sure that in the back end we actually have this um group here so if I log into the admin interface see authentication and authorization insert groups we have the massager managers here then we can also see the permissions that the users in this group has so now that is taken care of we can show a message to the user I suggest dot success Quest the user was added now we can redirect the user to the admin interface again just like down there save so let's try to refresh here now try to create a user so a gent seven at yeah.com agent 7 roll agent password can just be something random random password add user the user was added now we have agent 7 there if I go to users here now you also find agent7 adjuster.com um I haven't added him to the agents group because it's not really necessary if you don't want to in that case you need to just do the same thing as you did here you can see that we have the easy stuff it's true so we can log in but none of these here are added so I think everything now is okay with this user and as you can see here this is what the password looks like in the database so it's not a clear text stored there okay so now that we can add users I can set this to done and then the next step is to make it possible to see the detailed view of a user with all of the rooms connected to this user so if now just go back here then I can add this view above this or below it doesn't matter at login required we need that depth user detail a request and then the PK which is the primary key or the ID for the user actually when I think about that if I open up the models for the account we use the uuid field here so let's just rename this uuid and then we get the user from the database passing user equals user.objax dot get where primary key is uu ID then we can just say return render Plus in the request parameter the template chat view or user detail.html and the dictionary we're passing the user if you want to clean this up a little bit you can move this straight up there and just have it like this it depends on what you want to achieve here this is less code but if you have the user object there you can do other things with it as well so let's create the urls.play file furnace admin slash users slash string or uu ID since this is actually a correct EU idea in comparison to this which is a short string short random string and we call this uuid and then this uuid is the name that we have here and the view we want to use is views dot user detail name user detail and Save so let's activate the link for this so down on the name here because a hrf URL chat colon user detail pass in user.pk which will give us the uuid for this user and Save so if I now go to the backend find this admin Administration here then I should be able to click this let's try administer and now we get the template does not exist okay since we haven't created this let's do that now Can Begin by just copying to pair create a new file and say view user save this as usual detail.html user detail or yes that's correct that's what I call everything there user detail and then we can say user.name here just to see that we are on the correct user and similar close this and block save for refresh now see user detail and then the name you can actually show the name instead of saying user detail there and then down here I won't have a list of all of the rooms that this user is connected to so here I can for example copy this lines there these six lines here one two three four five six seven oops paste it there so then we have the rooms and like that press save now go back refresh there are no rooms connected to this user that's not correct we just need to get the rooms a pair um I can move the user up here again use your equals like this rooms equals user.rooms.org I think this was the way to do this let me open up monster Pi in the chat app so rooms is the related name that we can use to get do this reverse there okay so then we just need to pause in user again here and the rooms so rooms and now go back and refresh we have a list of rooms that the agent is set to the same person as we are on if I go to agent 7 there are no rooms but at least we now have the detail page for a user then we want to make it possible for managers to add that agents and if I go to the admin.html you can see that we have this here we have already checked a pair if the user can add user but we can have this check around this edit Button as well see if we can add that user okay so then we can create a view for this as you can see up here we have imported this form so then I want to make a copy of these lines because we need the user detail information let's rename the view to edit user and then you can check here also if you can edit a user and its user and only if that is okay we go in here if not we can say else and then here we do the same thing as down here show a message to the user and redirect them to the front page you don't have access to edit users okay so let's create a form form equals update user form and pass in instance equals user if you don't do that no sorry when we do this the form will be pre-filled with information for this user now we can return and show the template return render request Post in the template name which is chat slash update underscore user.html and here we want to pause in the user if we need anything for the user and also the form like that so when that is done we can add this to the urls.pi just make a copy of the user detail line and add edit at the end there and instead of saying user detail we can say addict underscore user and edit user nice next step done is to activate this button here URL chat colon edit underscore user and pause in user.pk so just like with all of the other places I will get the template does not exist yet but everything else seems like it's working nice the template will be almost identical to this so just copy everything here create a new file paste it and save this as edit underscore user.html I can replace the title and the button title with save changes so if I save now go back and refresh we see the edit user form with the information pre-filled here perfect and then if I now go into this dot Pi we need to handle the form submission just like we do down here it's just a little bit different first we check if the user has submitted anything by saying if request dot method equals post else we just show the form like this but here we need to say form added user form pause in instance equals user and say actually I think request dot post comes at the beginning so we pause in this information and also this one and since we say instance equals user Django automatically now automatically now knows that we are going to update a user and not create one and form dot save then we can show a message to the user and redirect so copy these two lines paste it in there the changes was saved so let's try this one changed save changes the changes was saved and you can see here that this was stored in the database as well perfect so let's go to the to-do list again make it was both the managers to add that maybe we should have a check in the back end as well so copy this line no sorry already did that of course yes so check and check okay so now I want to make it possible to delete a room so here in the room list I want to have a delete button as well it should be easy to fix if I just copy these lines here if request dot user that has perm just to see that we can do this room dot delete room and this name you can find it in the back end um where do you have it chat room can delete room um okay I can't actually see it here but um we pause in the model here and then the action at the end there can delete room so I think that should work now request post and then we don't need to pause sorry fixed annotation as a else and then down here we have the same messages as down there you don't have access to edit rooms and then we just redirect you back to the list of rooms then in here we get the room from the database based on the URL we are on we need to rename this to delete room and also this sorry delete rooms and then in here we can use the room dot delete and the room is deleted show a message let's copy these two lines again and paste them here and we can say the room was deleted redirect you back so let's add this to the urls so we can add it below this one delete these dot delete room and the name is also delete underscore room so then we can activate the button for this or actually create the button if I find admin.html sorry you need to go into room list where the rooms are so next to this but oops next to this button create a new one a hrf say URL just the Lego colon delete room room Dot uuid like this we also want to close this on this we can copy all of the Clauses and just replace the green color with rows 800 say delete save so if I now go and refresh we have the delete button there this should go next to each other if you just have a big enough screen I have a very small now since I want the font to be big so now I can try to delete a room that the room was deleted seems like this is working nice so then I can clean up a few old rooms this a lot of space here and I don't need them now nice so now all the rooms and the messages are gone nice so like I said this task as well to Don when an agent opens a room I want to set the status to be active and agent to be the owner I think I have already done this yes here I check if the status is waiting then I started to be active set the room agent save and show it so don't that was very quick okay so then I want to make it possible to open an old conversation and see the conversation messages okay so let's create a new room Stein test let's see his name hello this is a message hit enter and then go into it join and then this actually isn't working none yet why am I not the manager hello but it's correct there and here you can see and if I go into this it still says none yet okay let me just check this out in room.html maybe adding something wrong with the first off room dot a jumped not created by K7 now refresh you can see it there so this is not working and I'm still a part of this conversation that's good and if I go in here now you can see that this is active but if I go here now refresh the connection should be closed as you can see there and if I then refresh it still says that it's active so I need to handle what happens when a user quits a chat so inside the consumers.pi we can do it here on the disconnect but I don't want this to happen when an admin is leaving the chat only when the user is leaving a chat so this needs to be for all users because you want the user to be able to actually leave and then here we can say if the user doesn't have the staff set true which an anonymous user of course won't then we can set the room status to be um if the user isn't stiff it's just regular user then I want to say await selfie set room closed now this is a function that I need to create so I can have this at the bottom somewhere down here because you need to talk to the database so async to sink left set room closed and say was in self there then I can just change the status and that's very easy since we have the room available like this you can just self dot room dot status equals room Dot um what is the different statuses [Music] closed of course so closed sacred room dot save so let's try to create one more room from the front end test two send a message [Music] see it here join now this is working at least send go here again to the front end refresh there you can see okay chat and object has no attribute user okay I thought that I set it up here but I have not done that yet so I need to do that then before we can test one more time and reduce that by saying self producer equals self.scope user this would be the same as user request requested user but this is how you access the user here in the consumer or in channels so let's do one more test refresh one more third test chat send the message go to the back end refresh just go to chat admin join and then down here send the message okay so if I now refresh hopefully so it's just a disconnect and if and now go to chat admin you can see that the status for this is closed nice see here that this is set to none um to why was that changed that is weird okay I will come back to that because now um when I go into this it is actually working already what I wanted to achieve here and that is that um if the room status is active only then we show this and if it's active only then we'll load this so that actually means that this task is also done now but at least we made it possible for the user to log out and change the status for the chat okay so then I just wonder why the room agent was changed room.agent we only change it there so there is no reason why that should be updated hmm just test this very quickly again refresh non-join and now this is the one who has this if I go to front end refresh refresh and then this is again set to none okay so why is that happening create message no see if this are stored somewhere so just added two comments to test this so create one more conversation join chat send a message go here join so that does not have anything to say there send the message it's correct so for now refresh we are disconnected but here it already says that agent is none but if I hear against sf.room.agent equals self.user and know that can't be correct because this is not the logged in user the two Y is this reset okay let me try to print a pair as well print self go to room dot agent X1 very professional debugging X2 X 4 and X3 okay one more test join set message right there join and if I refresh now and see here now so why cannot call this okay I can't call it a pair now of course since this is a database called hmm okay let's just try to print a few other things here so I thought room and what other fields of the client print self.room.client quick test again fresh join now this user has it close the connection refresh and it's closed okay so scroll down and you can see this at least was working let's have the room and the client is also there is death but why is the agent not working okay I think it is because when the user um yes the reason for this is probably that when the user joins the room a pair the this is then stored in the memory and when this is stored in memory the agent isn't present in this object so down here I think we just need to run this again so self dot get room I'm done that should be available so that's one more time yes hopefully should work scroll back go in here go in there refresh everything looks okay for now refresh to close the connection because okay go back to the back end refresh nope nope that did not work Maybe if I call it like this self.room print cell.room.a chant okay now you should work work work work work there join leave the conversation refresh and now finally it was working so the reason why this didn't work server make also sell to get through is probably that we should add this away but this doesn't work um like it should and I guess that since these two are both in sync I think we don't wait for this to finish before we run this so anyways now it is working so now I want to inform the user when an agent is joining the chat so the first thing I can do then is just close everything to keep it as clean as possible and open up the consumers.pi and if I scroll to the top here where we are going through the connect below where the connection is accepted we can say inform user here and then we can check if we are a staff just like we do down here just opposite if self.user.is stiff that means that we are a manager or a agent and then here you can say a weight self dot Channel layer dot group send just like when we send messages down here we send a chat message we want to do something very similar so group send parenthesis um self dot room group name so we send it to the group name we all run and one more comma and then on the next line you create a dictionary and say type users update so then we need to create a new function called users update as you see down here the type is chat message that's why we have this function so you can create one more a sync death users update which we get from there and then we pass in self comma event we can have a comma here send in formation to the web socket front and await self.send Text data and we just inform what we want to send and that is just Json dot terms in plural create a dictionary type and then again users underscore update now this will be sent to the front end telling the user that the other user has joined so if I open up main.js we need to handle this here so we have this on chat message this will be triggered because everything we get from the backend is a message so we have already handled the chat message and then below here it has else if type sorry data DOT type equals users underscore update and then we know that the admin has joined our conversation and then it's very easy to just chat log element dot inner HTML plus equals write a paragraph with the class empty-2 so we have some space up to the bubbles the admin slash agent has joined the chat okay let's try this so let's go here create a new one testing join if I go to the backend Now find it there click join then you can see here no errors and if I go to the front end we have this message the admin slash agent has joined the chat nice so now we can actually inform the user that there is an active agent handling the chat in the back end check check then I want to inform the user when the agent is writing a message so we can begin with the back end again for this so we need one more information or one more function here so at on this receive we can check if the type is different so alif type equals update so we update information by that you have started writing and then send update to the room and then we call a similar function like this a weight selected Channel layer dot group send dot room group name so it's sent out to the whole group that you are on type this can be writing active so that means that the admin has activated the writing and then we can pause in a few more things think I can copy initials agent name and message and paste it in like this that is not entirely correct sorry um we can pause it in like we do up here so copy these four lines and paste it like that sorry about that and then we need a similar function like this again So async Def writing active so we get this type as a function self event send right thing is active to room and then a weight select send Text data now we tell what we want to send to the front end json.dumps parentheses and create a dictionary and then in here I can copy these five lines and just paste it like this so we don't need the crater that because this will be added and then just delete that when the message is sent so we can save this just go to the terminal to see that there are no errors nice so first I want to handle the abdomen site of this but when you start writing or when the input field gets focused this should be sent to the back end so down on the event listeners we can say chat input element dot on Focus equals function passing the event and then we can say chat socket dot send Json Dot stringify so this is very similar to what we do up here when we send this information to the back end so let's just copy these four lines here scroll down again and paste it the and oops almost create parenthesis like that so this is closed and closed and that's the function but we don't want this to be a type message we want this to be an update so let me send this it will be triggered or pair that the type is update and also the type inside the back end is writing active which is this function okay the message can just be hard-coded writing active which makes it easier for us to handle this and Save so now I think that if I go here now I can say parent is update let me just try this from the back end refresh type something so if I now go out there go in again you can see it's update go out go in you can see here so now this is sent to the servers and uh further out to the front end so what you need to do then is in the main.js handle that when we get this information we want to delete old information about this if there are any like we did now if the user or the admin Clicks in and out and similar we want to delete the old ones and then insert a new one so in here on the on chat message we do one more else if there are the type equals writing active then we can say if data dot agent and we pass in the agent information here so that we know if the information comes from the agent and not yourself because if it comes to the store itself we just ignore it here now we can say let TMP info equals document.queryselector.tmp info so now we get an element with this clause and assign it to this variable so we can delete it but we need to check give it accessed first so if this exists now we can say TMP info dot delete Sorry remove and then we just want to insert this to the front end again so chat log element dot inner HTML plus equals with the backticks here because we want some variables in here then we can say div clause TMP info so now we know that this is the class that we get a pair and remove Flex W Dash full because we want to have a similar bubble as we use a pair so actually maybe I should just copy this from tick to tick scroll down again and instead of showing a message in there I can say the agent slash admin is writing a message then I can remove this one because we don't need to know when this happened and remember to add this Clause again TMP info so that this will be found number testing and if I go here now refresh start a new one hello or Stein test hello and then in here go to the chat admin join the admin has joined and if I click here now go here again now the admin is writing a message nice so if I then send this now this is still there which is not good but at least the message was added there so I need to handle that these are deleted when we get a message as well so just copy this and scroll up and find the message so if it's a chat message we can remove this information as well so let's just test this very quick refresh create a new one go back join send message joined if I type there the admin is writing send it and then it's gone and replaced with this message perfect so now we have the possibility to inform the user when an agent is writing a message now we want to do the opposite as well we want to inform the agent when a user is writing msh so just like we have the on focus on the bottom of the main admin this go to main here paste it and here we don't have an agent so just to replace this with an empty string and the name is stored in one of the variables chat name so paste it like that and since this is empty we can try to just remove it and see if it works as we want so then I can go to admin.pi as at minus Pi main admin.js sorry and when we get an information for the writing active here we want to show this so go here make copy of a few lines so we can copy everything from yes just copy these lines from the elsif and where we delete this and paste it at the end there close the if close that one here we don't want to check here we want to see that if it's not an agent which means that it's the front-end user then we get this and delete it and there we want to copy this information so we get it on the left side so copy this as you see here if it's not an agent so we use the same code down there oops I removed the backtick and just like the other place at the TMP info here as well and just like we did in the front end we want to delete this when it's a chat so on the front-end user sends the chat message it's deleted so let's try one more time hello go here to chat admin join no messages if I type there you can see right thing active okay I need to replace that a little bit and you can also see I forgot to remove this so in the main admin let's scroll down again in the right active you can see here the user or client is typing remove this and Save so let's try again refresh create a new conversation just send a random message so we have it there join I can see this message and if I try to click there you can see the client is typing perfect so that is working send it and then it's gone from there and the message was replaced with the one ascent perfect so now I can set this to done as well so now all of the to-do's for the chat application is finished okay so we have now reach the last part of this tutorial now we are going to deploy this projector live server on digitalocean if you want you can find the link in the description below and click it and then you will get 100 that you can test digitalocean for free for 60 days as you can see the first task here is to set up a server on digitalocean you can use other services as well as long as you use Ubuntu like I'm going to do in this areas so if I just find digital ocean in the browser login and then you will be presented with the screen like this in the top here you can click create and then find the droplets in the list here you will first need to select which region you're going to use I'm just going to use Frankfurt since that's the closest one to Norway but usually you want to use the region where most of your users are located or as close to them as possible so Frankfurt and then down here I'm going to select the OS you can see here Ubuntu selected and 22.10 I want to change this to 22.04 since this is LTS version which stands for long term support which means that I will get security patches and similar then down here you can see that shared GPU is selected by default and that's exactly what I want and I want to select a regular where the disk type is SSD because I don't need a premium CPU or a better SSD and then the smaller server has just 512 megabytes of ram which can be too small so I like to go for this one which costs six dollars per month and then I do not need more storage than here you can select how you want to connect to your server you can either use SSH key or password so right now I just want to use a password so then down here you can add the metrics so that the digital lotion will send you emails if you use too much of the little storage to measure Ram CPU and similar you can also have very simple backups and manage database if you want to use that then you have the hostname this can just be like it is then I know that it is Ubuntu I have one CPU one gigabyte of ram it's in front and this is Step number one server and then just click create droplets a droplet is just another name for a VPS or a virtual private server okay so when this is done you can see here that now this is active which means that it should be ready to be used so let me copy this IP address and go to the terminal so then it doesn't open one more window here and log into it by using SSH root at and then the IP address yes I want to continue and then I just use the password sometimes this can take a few minutes before it's ready the first time so if it doesn't work just wait a little bit and try again so now that this is done the first thing I want to do is to just go to the to-do list and set this to dot because now we have the server you can also move this task down to there and do this instead so update and upgrade and install software first we can and just run a quick update to make sure that all of the information is correct here so apt update this will check that all of the mirrors and images as the correct versions and similar and find out exactly what we need to upgrade and when this is done we can run apt upgrade to run the actual upgrade command and here you can see everything that will be updated on the server and yes I want to continue this will probably take a few minutes okay so now it says there's a new kernel available and it's just them has to restart to load so you should consider rebooting okay so let's click enter and hit enter again and maybe we should restart we can do that by saying restart or reboot maybe yes so now I was kicked out of the server so then you just need to wait for it to start again so just click up a few times just try to login Pro publishing already yes so now it's restarted okay maybe I should use the correct password [Music] there so now I'm logged in again everything is now updated and upgraded so now let's install some of the software we're going to need so we need to run the command apt install Python 3 pip to make it possible to use pip to install the Django for example and Python 3 Dev which is a few things that Django needs to run and then we have three packages connected to postgresql which is the database server we're going to use supervisor which is a software that you're going to be running in the background on the server to make sure that g unicorn the the the the web server is running and nginx which is also a web server which is sort of the face out I'm going to explain this more when I start to go through them so then hit enter yes I want to install all of this okay so now that is installed so then I can go to the to-do list and set this task as well to done and configure it so go back again and now we need to log in to the postgres grab server still here on this server and to log in we say sudo-u to change the user to postgres which is the user and there will run the command psql which open UPS the command center so here we want to create a new database button create data base and then the name which in our case can just be hit enter so now we have a new database that we can use next I also want to create a user so create user yacht with password you want to change this to a more secure password of course but in my case it's this is just a demo I just use this to make it easier to show you next I need to do some configuration for this role in order to work properly with Django so we alter the row or the user and I'm setting client encoding to utf-8 which is the information that will be stored in the database I want to run one more command just the same we change this road or user and set the default transaction isolation to read committed and I think this is information that Django gets back every time you commit or do anything with the database the last change of the role is to set the default time zone to UTC so this is just how time is stored and used in the database the last command I want to run for a postcard postgresql configuration is Grant all privileges on database to this user so is the database name and this is the user and now this means that this user can do anything it wants with this database for example read write delete and similar and then we can just quit this command button impactslash q and hit enter so now the database is set up it's still empty which we're going to fix when we have moved the file from the local computer to the server so let's go to the to-do list again set this to us to done next step is to create a user and group and a home folder for the project so we want to separate Ubuntu user for permissions and similar and I want this user to be a part of a specific group that we're also going to create first we can create the home folder which is web apps Yota so MK there Dash p which will create this whole path now we can go into it the website if you want more projects on the same server you can also have them in this web apps folder so now we have a home for this user and project we can begin by creating the group passing sudo group pad in one word system and then the name of the group which is also web apps and this group name can be reused for other projects as well so now that we have the home folder and we have the group we can create the user as well so sudo use red Dash system so we add this to the system we specify which group to add this user to we set the default shell for this user to slash bin slash set the home folder to web apps and then the username which is also yacht and this user has nothing to do with the user that we created up here this is the postgresql user this is the Ubuntu user just so that these are a little bit separated so now we can set this to done as well next step is to do some changes in the settings.pi file I want to create a separate settings.pi file for production so if I just go to visual studio code then I can copy everything in here create a new file paste it and save it as settings prod dot pi so then you can see that for example we have set debug to true we want to change this to false in production because here we don't want to expose the error messages similar here we just want to show in default 500 error page you just need to set the allowed hosts here I want to pause in yacht.com which is the domain name I'm going to use for this demo but we also need the IP address for the server so if I go back to digitalocean make a copy of this address go back and paste it there and by the way this here is not my own domain it's just something that I make my computer believe that I have so I can show you how to do that as well on Mac you just say sudo VI Etc hosts and then pass in your password and then here I paste my IP address and just say yacht.com so every time I now go to this in a browser I will just be sent to this address but now this server will also think that I'm on this domain name on Windows just search how you change your hosts file on Google and you will find a information about that as well there it's very easy okay so I can close this now so that they just have the server running here if I go back to visual studio code I want to do one more thing I want to add a new um constant secure cross or region underscore opener underscore policy equals none and this is just because I'm not going to use https and that means that I don't get the error in the browser um and that's it for a pair this can just be like it is the only change is done down here you need to change the back end to be postgresql so here we say psycho pg2 underscore don't think that is correct let me try to Google this Django postgres ql back and so here should be something can't it's not just postgresql backend yes it's this one the correct setting in Django 3 so at least this is what I use to do but we can try this and see if it works so just Tango the DB back ends postgresql set up the name which in my case was yacht this is the database name Now set up a user name which was also yachta this was the postgresql user set up the password which I also set to yet them and Host this can be localhost because a posterior scrap is running on the same server and Port this can just be empty so now we can save this so if I go here now I think I can set this to done because now we have done everything we need done we can start moving the project from my computer to the server you can read this a number of different ways you can use or sync to send all of the files one and one you can zip the folder for the project and send it using sap you can use FTP or SFTP to send the files you can send the files to git and download them again a similar so I'm just going to make a sip of the folder and send it so if I go to the project parent folder create a set from this ZIP Dash R for making it recursive you have to.zip which is the name of the zip I want to create under folder I want to create a Ziploc is yacht if you want to you can just find the folder in the finder and just right click and create archive or whatever you do in Windows and then I have it here so I just need IP address for the server again copy this go back and use SCP so SCP and then the file I want to send sorry it just.zip and I want to send it to root at the IP address colon dot so now this will be placed in the home folder for the root user then I just pass in the password for the server I can see here that now this is sending so the project is very small so it doesn't take very long time but now it's on the server and if another run LS slash root you'll see that in the home folder for the root user we have a zip folder let's move it to this folder by saying MV slash root yacht.zip yet sorry dot to move it to this folder now I want to unzip this folder to that I just unzip.zip and then I get error because I haven't installed unzip so just run apt install and zip so if I now just clicked up Arrow a couple of times I will find this command again unzip after dot zip and then have the folder there as well so let's remove this RM yacht.zip I don't need that anymore so then this is done but I need one more here set up the environment so just like you have an environment locally here you can see EnV I want the same here and if I just say LS to see what files I have in there we have this requirements of txt file and this requirements file contains information about which Django user and Django version I'm using version of definite channels and a few other things so let's install all of this on the server as well this is very easy now I just need to create a virtual environment first so python3 Dash M van EnV you can see here again I got one more error because I forgot to install this so apt install python 3.10 event yes I want to install this okay so click appear again to find this command to create the environment and then when that is created I can activate it passing Source Envy then activate so then I can install the same things that I had locally buzzing pip install Dash r yet the Slash requirements.txt so now this will install everything that I have locally on the server so that the environment is identical which means that it's much more unlikely that things will crash and similar you're going to just go back here say um initialize the database okay so now everything is installed and I can set this to done and then I need to initialize the database so if I go in to the Django project and say python management pi migrate Dash settings equals yachten dot settings prod so now I specify that I'm using the settings product by file inside this and then maybe this will work hit enter okay you can see here now that error loading psycho pg2 module um and that might be because of this we can try to install the module and see if it works so pip install psycho pg2-binary so now this will install at least so you can try to run the migrate command again okay so password authentication failed for user root think that might be because this was maybe just supposed to be user but instead of fixing it here and sending everything again I can just fix it directly on the server by saying VI yacht settings prod and then go down until I find the database information so should be down here somewhere yes instead of saying username I say e user then I just hit escape and colon WQ to write and quit and I think since I just used username Django didn't know what user to use so it just used the user I'm on here so let's try the migrate command again and now the database was set up perfect so now we have the database running in postgresql instead of sqlite which is more suitable for an environment product environment in production so let's go back again set this to Dawn then I want to set up G unicorn and something called UV corn so these are two um sort of web servers that will handle Django and long time connections like web sockets which this will take care of and this will talk to each other these are just sort of running on server and then nginx will be the face out that will just pass on the traffic to this one so might sound a little bit weird but it will make more sense when we start doing this so first we can install G unicorn and uvi corn maybe it's pronounced some other way but this is at least G unicorn so let's go back here as a pip install G uni corn and the other uvi cord is installed a little bit different it was in PIP install UV sorry thick UV corn and the version we want to install is called standard so this is how I do it at least so now this will install web sockets and a few other things that this is taking care of so it sounds a little bit Advanced this here since we need so much in order for everything it is to run but if you just try to go through this tutorial a couple of times it will hopefully make more sense and if you have any questions feel free to leave it up in the comment below and so now I can go up one folder and then in here I just want to create a folder for the logs just that I have a folder for log files anyways in order for G unicorn to run we need a script to activate Django teller Django is located and similar so to do that we need to create a new file by saying touch EnV bin G unicorn start and then we can edit it by saying VI EnV bin T unicorn start so first you just want to make sure that this is a bash script so hash exclamation mark slash bin slash Bash and then I want to set up a few constants with information about where Django is located and similar so the name of this project is yacht the Django there where my project is located is web apps this is just a home folder and then the Django project this socket file will be created automatically when g-unicorn is running this script this is the Ubuntu user this is the ubit group number of uber workers um is how many instances the server which should be running on the server at once three is just that you multiply the number of CPUs that you have on the server with two and and one since we have one CPU we take one CPU multiplied two which is 2 add 1 which gives us three and then which settings file to use which is your dot settings prod and then we want to specify the Django asgi module to be yacht.asgi which is the entry points which just centers send the user information further in the Django project and timeout is if we need to wait for something to finish before it can continue and then we just tell the script to go into Django directory and activate it by saying Source oops here is a little error because it's it's in source so I go up one folder into EnV bin and activate it then we export information about the settings file into the default Django thing and Export all of this into the python pod so that it's executable by Django and then below here we set up the Run directory which is the socket file and I would test if this exists if not it will be created automatically by this script and then at the end we say execute and then we go up one folder because we are still in this one bin G unicorn and I will pass in the asgi module and run the application inside there let me just build this up with information from a pair so then we can quit and save this so let's try to run this it'll probably give us an error but before we run it we need to make this executable c h mod to change the modification of this to plus X and then the name of the file so now this should be executable so I can say dot slash NV bin tune corn start okay so now this did not work let's see if we can find error the apps aren't loaded yet sounds a little bit weird so it might be because this is not uh the right user different ls-lord you can see that root is owning everything here and that is not how we want this to be we want this to be owned byte and the web apps group so it's a change owner or CH own Dash capital or to make this recursive which is the user colon web apps just a group and Dot so we do this on this folder and all of the children let's just run the script again and it's still crashing so I I think this might be because I need to add one more sentence to the G unicorn script so let's try to edit it again the vi and we've been unicorn start and then at the end here and it add information here that you're going to use uvi corn as well so at the end here I think I can just say Dash K to prod worker clause which is uvicorn.workers dot uvicorn worker let's try to save and quit this again and then execute it again so it's stored a little bit different 2y isn't this working let's try to Google this error here Tango UVA corn okay yes I think I might need to do some changes to the asgi file as well so VI yacht asgi ate asgi to get into the correct folder here I have first of all I need to use settings.prod instead of just dot settings and I think that I also want to move this above everything here so if I just copy this and delete it by saying DD scroll above here so before we start importing things there we run run this and then also Django dot setup to start everything now we can just import this as it is so if I save and quit now we can try to run this again still didn't work because Django is not defined okay that's because I forgot to import Django we need to do that of course one more try and now it is running so let's just stop this now and continue and see if we can get the rest of this to work as well so now we have uvi corn sorry G unicorn running we just need to tell um supervisor that this should be running at all time so to do that you need to create a script in the supervisor folder pressing touch Etc not environment it is the supervisor conf and then the name which can be iota G unicorn Dot conf then we can edit it by using VI again so here we create a new program called yate the command we want to execute is this one the folder and then the script you created we're going to use this Ubuntu user and print the information or the logs to this one and then just some other types of configuration so let's save and quit this when you have typed in everything here by the way I will add all of these files to the GitHub repository so you can find it in the description below if you don't want to type it yourself and now we just need to tell supervisor to start this script for the first time so supervisor CTL re read just to see that it's available yes and then update so you can run the status command to see that this is running yes so now yacht is running and it looks like everything is okay nice okay so now that we have this script for running G unicorn which will also take care of the evil icon stuff that we need we can create one more script for running Daphne or channels in the back end or the background so we need a similar script for that so touch EnV then definitely store so now this is in the environment bin folder not the supervisor folder so hit enter to create it now we can edit it and then here we do a little bit like we did first so we make sure that this is the bash script and then we set up the Django there equals web apps slash iota and then the file where the settings is so Django settings mod tool now we need to go in to the Django directory so CD for change directory to Django there and then we export the two uh variables here like we did in the previous script so we use this to export commands and then we start Daphne by saying def me Dash b000 which is localhost specify what port we want this to run on we can use 8002 for example and then just yet dot asgi colon application now this will tap into the application part of the asgi file so now we can save and quit this and then we can create a supervisor file for this as well so touch Etc supervisor and conf yet not the other.g unicorn but the other dot def name then we added this file and this looks very similar we call this fname this is definitely is the same as channels by the way and then the command to start with user which log files and the rest of the configuration to make sure that it's running properly then we can run the re-read command against supervisor or CTL re read available perfect and update to add it to the list then status so then you can see here back of this is not executable I forgot to do that so c h mod Dash X to make it executable Envy bin def me start so that we can try to restart FNB I think supervisor CTL restart the F name Dil says that it's not executable LS Lord Envy pin so this is still owned by the user so that's probably why CH own Dash or we can just do this on all files just one more time call on web apps Dot and CH mod plus X okay I did it wrong up here I said minus or Dash X it's plus X NV Ben Daphne Dart let's try to restart again not running that's correct and it could not start okay so open up log file was entailed logs Daphne definite command not found so can't if I say Daphne here it looks like it's working [Music] let me just take the last line of the script cut Envy then Daphne Dart and then I can do this on P 8010 [Music] this will fail now because I'm not in the correct folder let's go into yet again see that specified Dash p two times so as you can see here it is running so definitely accessed and everything is okay I think that I missed one part of the script so V I envy em V sorry I need to go up one folder sorry for about all of this mess VI EnV bin Daphne underscore Stars I need to say Source dot slash NV then activate because you need to activate environment where Django is of course so this is not working I'm not going to run that anyways we're going to run this script but we can try to restart supervisor to see if it will start now so now we can see started see the status yes so now we have both yachta running which is the G unicorn and UV Acorn and Daphne which is the channel part running nice so I think like I said this to do now this is also done now I did it inside this task and then we need to set up nginx as the face out of this server so it is already created but or installed but if you go to CD Etc and GNX sites enabled then we can RM default so it just delete this default file here create a new one touch here Dot conf VI after conf to edit it and then here we first need to set up Upstream so apps stream here underscore app server this is just that I have a connection to the green corn socket file server Unix unicorn dot stock fail underscore time out equals zero because this shouldn't have a timeout and then we set up one server in this configuration file and we want to listen to Port 8. let me set up a server name which is the IP address for the server which in my case is yorktown.com and then I want to set up the access log so every time we visit this page an entry will be added here with a little bit information about your browser and similar and one more error log so now we have an error for Daphne we have one for G unicorn and we also have one for nginx so it's very easy to get trap to keep track where the error is coming from and since we are using static files for example for the JavaScript we need to set up a location slash static so that nginx will now host or serve these files so every URL that starts with the slash direct will just be automatically pulled out of this folder now we can do the same thing for media files media Alias web apps yeah the media and then we're one more location for the Django project itself whoops changed window so every time we go to the front page or any other URL you go in here and here we need to set up a few proxy and this is just configuration to make sure that everything is properly forwarded from here and to the G unicorn so we'll also send this information up to this one so we're going to test that the request isn't the file name and if it's not done we go into this one so let me just proxy pass it into HTTP colon slash into this and into this and then Django will take care of the rest then we just need one more location and that is the location for the web socket or WS so if it begins with WS we need this still there and this one which maybe is called carrot not sure but yes you need this to make sure that it will work then I have a few more settings that I want to add here now so what this does is that first it proxy sends everything to one to seven zero zero one which is also localhost and A2 8002 which was the Port we used when we run the definite command inside the definite script and then just a little bit more configuration for timing out connection timeout and similar so now we can close the location and we can close the server then we can save and close this so for now run service engine X restart we should have stopped nginx server and started it again so maybe if I'm lucky now and go to iota.com oops there you have it open up the inspector just to see that everything is okay there are no errors let me try to connect there is nothing wrong with the browser every time I click something I'm thrown out so oops Stein join okay so you can see here I get 403 Forbidden so I was connected but I am thrown out let me see if I can find some more information in the network tab if there is a good reason for throwing me out csrf verification failed yes and if I go back to the code I will show you why in the main.js we use this get cookie command and this isn't really available when you are not on https https and in order to go around this you just need to change the view file for the front page and in order to fix it I just need to change the view file for the front page so if I just go back to the folder I was on which is the parent folder by saying CD Dash and into there again and then VI chat views dot pi if a kit index file isn't there but nvi core views here it is then I just need to do one quick fix here and let this do ensure that the cookies are actually printed on the page which is the problem that it's not now I need to add The Decorator called Ensure csrf token and then I just need to import this so from django.views import oh sorry jungle reviews dot decorators dot csrf import and then ensure csrf token I'm gonna quit this and then I need to restart g-unicorn and I can do this by saying supervisor CTL restart and then which is the Django project so then that's taken care of is let's try to refresh okay now I got a different kind of error here um what is the status it is running so why am I getting this I probably did something wrong here it's not csrf token it's csrf cooking save and quit and then we can restart yacht again here every time you do a Django change you need to restart using supervisor refresh and then I'm back here so let me try to login here join chat then you can see here room created if I scroll down chat token was opened hello and then this was sent to the server nice so maybe I should now create a backend user just to make sure that it is added and that the backend user can talk to the front end so let's create a super user by saying python man oops python managed by create super user that's just settings equals Iota dot settings product because you need to make sure that you're using this file add menu.com [Music] and then a password so now that is done I can try to log in in a different browser .yout.com admin admin.com and then the password I used nice so if I go to Rooms then there are one room by Stein which is correct first I came from this website which is also correct and then in messages you see there is one message from Stein nice okay let me try to go to auto.com chat admin instead okay I can see my user you can see the room if I join it go back here you can see the admin slash agent has joined the chat and this is now active so it actually sends information there hello information is sent back and forth nice hello so now you can see that this is working both ways nice and there we have it a great a great chat application that you now can use however you want feel free to use the code if you want to use it please do some more things to it like add for example better ways to know which page come from you can update this for example unsimilar if you have any questions about today's code feel free to leave comment below I will answer as soon as I can see you in the next video
Info
Channel: Code With Stein
Views: 38,016
Rating: undefined out of 5
Keywords: code with stein, django, learn django, django tutorial, django realtime chat, django real time chat, djangochannels, django web sockets
Id: 9e7CTR2Ya4Y
Channel Id: undefined
Length: 262min 59sec (15779 seconds)
Published: Tue Jun 13 2023
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.