2
votes

I am making a website, this website has a chat app include, the chat app works perfect, but there is a thing I want to do but I dont know how to do it. So I have this chat view chat view, here is were there is the websocket and all that stuff, But in this view this view, is the place were I want the user to see all the chat rooms he is in, on the side of chats like the two example users that are in there. the problem is that I don´t know how to do it. can someone tell me how to do it? with a simple example, like a very simple chat, that the chats of the user appear in the home page?, thanks for the help.

My code: Chat room html or thread:

{% extends "base.html" %}

{% block content %}
<section class="msger" id="prueba">
    <header class="msger-header">
      <div class="msger-header-title">
        <i id="The_other_user"></i>{% if user != object.first %}{{ object.first }}{% else %}{{ object.second }}{% endif %}
      </div>
      <div class="msger-header-options">
        <span><i class="fas fa-comment-alt"></i></span>
      </div>
    </header>

    <main class="msger-chat">
      <div class="msg left-msg">
        <div
          class="msg-img"
          style="background-image: url(https://image.flaticon.com/icons/svg/327/327779.svg)"
        ></div>

        <div class="msg-bubble">
          <div class="msg-info">
            <div class="msg-info-name">BOT</div>
            <div class="msg-info-time"></div>
          </div>

          <div class="msg-text">
            Hola, bienvenid@ al Chat! Manda un mensaje para tener cita con la Consultora. Puedes mirar el boton de como pedir consulta????
          </div>
        </div>
      </div>

      {% for chat in object.chatmessage_set.all %}

        <div class="msg right-msg" class="msg">
          <div class="msg-img" style="background-image: url(https://cdn.xl.thumbs.canstockphoto.com/user-icon-person-profile-sign-vector-avatar-illustration-office-human-web-symbol-business-man-image_csp63452775.jpg)"></div>

          <div class="msg-bubble">
              <div class="msg-info">
              <div class="msg-info-name">{{ chat.user }}</div>
              <div class="msg-info-time"></div>
              </div>

              <div class="msg-text">{{ chat.message }}</div>
          </div>
        </div>  

      {% endfor %}

    </main>
    <form id='form' method='POST' class="msger-inputarea"> {% csrf_token %}
      <input type='hidden' id='myUsername' value='{{ user.username }}' />
      {{ form }}
      <input type="submit" class="msger-send-btn">
    </form>
</section>

<!--The Back button and Help-->
<a href="/messages" class="back"><i class="fa fa-arrow-left"></i></a>
<a class="tooltip demo" href="" data-tooltip="Empieza por decir tu nombre completo, despues di la razon de una consulta, di cuantos familiares niños tienes y tambien menciona cuanto tiempo llevas con ese problema. Seras respondid@ en menos de 2 dias">
  Como pedir consulta
</a>


{% endblock %}

{% block script %}
<script src='https://cdnjs.cloudflare.com/ajax/libs/reconnecting-websocket/1.0.0/reconnecting-websocket.js'>
</script>
<script>
// websocket scripts
// console.log(window.location)
var loc = window.location
var formData = $("#form")
var msgInput = $("#id_message")
var chatHolder = $("#chat-items")
var me = $("#myUsername").val()
var he = $("#The_other_user")
var user =  $(".msg-info-name").text();

const PERSON_IMG = "https://cdn.xl.thumbs.canstockphoto.com/user-icon-person-profile-sign-vector-avatar-illustration-office-human-web-symbol-business-man-image_csp63452775.jpg";
const msgerChat = $(".msger-chat");
const msger = $(".msger");

var wsStart = 'ws://'
if (loc.protocol == 'https:') {
    wsStart = 'wss://'
}
var endpoint = wsStart + loc.host + loc.pathname + '/'
var socket = new ReconnectingWebSocket(endpoint)


socket.onmessage = function(e){
    console.log("message", e)
    var chatDataMsg = JSON.parse(e.data)
    // chatHolder.append("<li>" + chatDataMsg.message + " via " + chatDataMsg.username + "</li>")
    // Append the message frontend
    var side_append = "msg right-msg";

    if (chatDataMsg.username != me) {
    var side_append = "msg left-msg";
    };

    msgerChat.append(`
      <div class="${side_append}" class="msg">
      <div class="msg-img" style="background-image: url(${PERSON_IMG})"></div>

      <div class="msg-bubble">
          <div class="msg-info">
          <div class="msg-info-name">${chatDataMsg.username}</div>
          <div class="msg-info-time">${formatDate(new Date())}</div>
          </div>

          <div class="msg-text">${chatDataMsg.message}</div>
      </div>
      </div>
    `)

    // Utils
    msgerChat.scrollTop += 500;
    function get(selector, root = document) {
    return root.querySelector(selector);
    }

    function formatDate(date) {
    const h = "0" + date.getHours();
    const m = "0" + date.getMinutes();

    return `${h.slice(-2)}:${m.slice(-2)}`;
    }

    scrollWin()
}

socket.onopen = function(e){
    console.log("open", e)

    formData.submit(function(event){
        event.preventDefault()
        var msgText = msgInput.val()
        // chatHolder.append("<li>" + msgText + " via " + me + "</li>")

        var finalData = {
            'message': msgText
        }
        socket.send(JSON.stringify(finalData))
        formData[0].reset()
    })
}
socket.onerror = function(e){
    console.log("error", e)
}
socket.onclose = function(e){
    console.log("close", e)
}

window.onload = function() {
  scrollWin()
}

//Scroll auto funct
const chatContainer = document.querySelector(".msger-chat");
function scrollWin() {
    chatContainer.scrollTo(0, chatContainer.scrollHeight)
}


$( ".msg" ).each(function() {
  var users =  $(this).find(".msg-info-name").text();
  if (users != me) {
    $(this).removeClass("msg right-msg");
    $(this).addClass("msg left-msg");
  };
});


</script>
{% endblock %}

the messages room, were I want to see all users chat rooms:

{% load static %}
<!DOCTYPE html>
<head>
    <title>Consultoria</title>
    <script src="https://kit.fontawesome.com/e66aaa0c91.js" crossorigin="anonymous"></script>
    <link rel='stylesheet' type='text/css' href="{% static 'css/chats.css' %}">
    <link rel='stylesheet' type='text/css' href="{% static 'css/cards.css' %}">
    <link rel='stylesheet' type='text/css' href="{% static 'css/buttons.css' %}">
    <style>
      a{text-decoration:none}
    </style>
</head>
<body>

<!--The Message chats-->

<div class="container clearfix" style="position: fixed; left: 20px; top: 67px;">
  <h1 style="position: relative; top: 17px; right: -75px;">CHATS</h1>
  <div class="scrollable">
    <ul class="list">

      <a class="clearfix" href="#">
        <img src="https://s3-us-west-2.amazonaws.com/s.cdpn.io/195612/chat_avatar_01.jpg" />
        <div class="about">
          <div class="name">Vincent Portr</div>
          <div class="status">
          online
          </div>
        </div>
      </a>
      
      <a class="clearfix" href="#">
        <img src="https://s3-us-west-2.amazonaws.com/s.cdpn.io/195612/chat_avatar_02.jpg" />
        <div class="about">
          <div class="name">Aiden Chavez</div>
          <div class="status">
          offline
          </div>
        </div>
      </a>   
      
    </ul>
  </div>
</div>

<!--The Message chats-->


<!--The Consultors cards-->
<main class="page-content">
  <div class="card">
    <h1 class="subtitle">CONSULTORA FAMILIAR</h1>
      <div class="content">
          <h2 class="title">Marcela Santamaria</h2>
          <p class="copy">Check out all of these gorgeous mountain trips with beautiful views of, you guessed it, the mountains</p><a class="btn" href="Marcela/">Contactar</a></div>
  </div>
  <div class="card">
      <div class="content">
          <h2 class="title">Coming Soon</h2>
          <p class="copy">Más consultores vendrán pronto</p></div>
  </div>
</main>
<!--The Consultors cards-->


<!--Back and help buttons-->
<a href="/home" class="home"><i class="fa fa-home"></i></a>
<a href="#" class="help"><i class="fa fa-question"></i></a>
<!--Back and help buttons-->

</body>
</html>

my models:

    from django.db import models

    from django.conf import settings
    from django.db import models
    from django.db.models import Q


    class ThreadManager(models.Manager):
        def by_user(self, user):
            qlookup = Q(first=user) | Q(second=user)
            qlookup2 = Q(first=user) & Q(second=user)
            qs = self.get_queryset().filter(qlookup).exclude(qlookup2).distinct()
            return qs

        def get_or_new(self, user, other_username): # get_or_create
            username = user.username
            if username == other_username:
                return None
            qlookup1 = Q(first__username=username) & Q(second__username=other_username)
            qlookup2 = Q(first__username=other_username) & Q(second__username=username)
            qs = self.get_queryset().filter(qlookup1 | qlookup2).distinct()
            if qs.count() == 1:
                return qs.first(), False
            elif qs.count() > 1:
                return qs.order_by('timestamp').first(), False
            else:
                Klass = user.__class__
                user2 = Klass.objects.get(username=other_username)
                if user != user2:
                    obj = self.model(
                            first=user, 
                            second=user2
                        )
                    obj.save()
                    return obj, True
                return None, False


    class Thread(models.Model):
        first        = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE, related_name='chat_thread_first')
        second       = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE, related_name='chat_thread_second')
        updated      = models.DateTimeField(auto_now=True)
        timestamp    = models.DateTimeField(auto_now_add=True)
        
        objects      = ThreadManager()

        @property
        def room_group_name(self):
            return f'chat_{self.id}'

        def broadcast(self, msg=None):
            if msg is not None:
                broadcast_msg_to_chat(msg, group_name=self.room_group_name, user='admin')
                return True
            return False


    class ChatMessage(models.Model):
        thread      = models.ForeignKey(Thread, null=True, blank=True, on_delete=models.SET_NULL)
        user        = models.ForeignKey(settings.AUTH_USER_MODEL, verbose_name='sender', on_delete=models.CASCADE)
        message     = models.TextField()
        timestamp   = models.DateTimeField(auto_now_add=True)

my consumers.py:

    import asyncio
    import json 
    from django.contrib.auth import get_user_model
    from channels.consumer import AsyncConsumer
    from channels.db import database_sync_to_async

    from .models import Thread, ChatMessage

    class ChatConsumer(AsyncConsumer):
        async def websocket_connect(self, event):
            print("connected", event)

            other_user = self.scope['url_route']['kwargs']['username']
            me = self.scope['user']
            # print(other_user, me)
            thread_obj = await self.get_thread(me, other_user)
            self.thread_obj = thread_obj
            chat_room = f"thread_{thread_obj.id}"
            self.chat_room = chat_room
            await self.channel_layer.group_add(
                chat_room,
                self.channel_name
            )

            await self.send({
                "type": "websocket.accept"
            })
            # await asyncio.sleep(10)

        async def websocket_receive(self, event):
            # when a message is received from the websocket
            print("receive", event)

            front_text = event.get('text', None)
            if front_text is not None:
                loaded_dict_data = json.loads(front_text)
                msg =  loaded_dict_data.get('message')
                user = self.scope['user']
                username = 'default'
                if user.is_authenticated:
                    username = user.username
                myResponse = {
                    'message': msg,
                    'username': username,
                }

                await self.create_chat_message(user, msg)

                # broadcast the message event to be send
                await self.channel_layer.group_send(
                    self.chat_room,
                    {
                        "type": "chat_message",
                        "text": json.dumps(myResponse)
                    }
                )

        async def chat_message(self, event):
            # sends the actual message
            await self.send({
                "type": "websocket.send",
                "text": event['text']
            })

        async def websocket_disconnect(self, event):
            # when the socket connects
            print("disconnected", event)

        @database_sync_to_async
        def get_thread(self, user, other_username):
            return Thread.objects.get_or_new(user, other_username)[0]

        @database_sync_to_async
        def create_chat_message(self, me, msg):
            thread_obj = self.thread_obj
            return ChatMessage.objects.create(thread=thread_obj, user=me, message=msg)



        
1
It's recommended to paste your formatted code here and not send screenshotsKen4scholars
@Ken4scholars I already upload my code, Can you help me?Rodrigo
It seems your issue is in the frontend components. Can't help you with that unfortunatelyKen4scholars
@Ken4scholars ouh, okey don´t worry, but, do you know someone that can help me?Rodrigo

1 Answers

1
votes

By looking at your models, in your views you can make a context and then in your messages room you can use that context with django template tag, to loop all the chat rooms of your user, try this:

all_rooms = Thread.objects.by_user(request.user)
context = {
    'my_chats': all_rooms
}

this is an option I see that you try with your models