# Put here the TalkJS API credentials.
TALKJS_APP_ID = os.environ.get('TALKJS_APP_ID') TALKJS_API_SECRET = os.environ.get('TALKJS_API_SECRET') TALKJS_API_BASE_URL = os.environ.get('TALKJS_API_BASE_URL')
from django.conf import settings from django.http import HttpResponse from django.views.decorators.csrf import csrf_exempt from django.contrib.auth.decorators import login_required app_id = settings.TALKJS_APP_ID content_type = 'application/json' secret = settings.TALKJS_API_SECRET authorization = f'Bearer {secret}' talkjs_base_url = f'{settings.TALKJS_API_BASE_URL}{app_id}' headers = { 'Content-type': content_type, 'Authorization': authorization, }
{% if user.is_authenticated %} <script> (function(t,a,l,k,j,s){ s=a.createElement('script');s.async=1;s.src="https://cdn.talkjs.com/talk.js";a.head.appendChild(s) ;k=t.Promise;t.Talk={v:1,ready:{then:function(f){if(k)return new k(function(r,e){l.push([f,r,e])});l .push([f])},catch:function(){return k&&new k()},c:l}};})(window,document,[]); </script> {% block extrajs %}{% endblock extrajs %} {% else %} <script>sessionStorage.removeItem('currentSession')</script> {% endif %}
{% if user.is_authenticated %} <script> (function(t,a,l,k,j,s){ s=a.createElement('script');s.async=1;s.src="https://cdn.talkjs.com/talk.js";a.head.appendChild(s) ;k=t.Promise;t.Talk={v:1,ready:{then:function(f){if(k)return new k(function(r,e){l.push([f,r,e])});l .push([f])},catch:function(){return k&&new k()},c:l}};})(window,document,[]); </script> <script src="{% static 'games/js/main.js' %}"></script> {% block extrajs %}{% endblock extrajs %} {% else %} <script>sessionStorage.removeItem('currentSession')</script> {% endif %}
const currentSessionKey = 'currentSession' async function createTalkUser(user) { await Talk.ready return new Talk.User({ id: user.id, name: user.name, email: user.email, photoUrl: user.photoUrl, welcomeMessage: user.welcomeMessage ? user.welcomeMessage : null }) } function getSessionCredentials() { return $.ajax({ type: 'GET', url: `/talk/session/current/` }) } async function buildSession({ me, appId, signature }) { await Talk.ready window.talkSession = new Talk.Session({ appId: appId, me: await createTalkUser(me), signature: signature }) } async function initializeSession() { const currentSession = sessionStorage.getItem(currentSessionKey) if (currentSession) { await buildSession(JSON.parse(currentSession)) return } await buildSession(await getSessionCredentials()) sessionStorage.setItem(currentSessionKey, JSON.stringify(talkSession)) } $(async function() { await initializeSession() initializeUnreadMessages() })
import hmac import hashlib from django.conf import settings from django.http import HttpResponse from django.views.decorators.csrf import csrf_exempt from django.contrib.auth.decorators import login_required
@login_required def current_session(request): if request.is_ajax(): hash = hmac.new( bytes(secret, 'utf-8'), bytes(str(request.user.id), 'utf-8'), hashlib.sha256 ) return JsonResponse({ 'appId': app_id, 'me': get_talkjs_user_object(request.user), 'signature': hash.hexdigest() }) return bad_request() def get_talkjs_user_object(user): return { 'id': user.id, 'name': user.username, 'email': user.email, 'photoUrl': user.profile.image_url, 'welcomeMessage': user.profile.welcome_message }
$(async function() { await Talk.ready await initializeSession() $(this).on('click', '#private-message', function() { const otherId = $(this).data('other-id') const subject = $(this).data('conv-subject') $.ajax({ type: 'GET', url: `/talk/private/${otherId}/`, success: async function(response) { const me = await createTalkUser(response.me) const other = await createTalkUser(response.other) const conversation = talkSession.getOrCreateConversation( Talk.oneOnOneId(me, other)) conversation.setAttributes({subject: subject}) conversation.setParticipant(me) conversation.setParticipant(other) const popup = talkSession.createPopup(conversation, { keepOpen: true }) popup.mount({ show: true }) }, error: function(error) { console.log(error) } }) }) })
import hmac import hashlib from django.conf import settings from django.contrib.auth.models import User from django.http import HttpResponse from django.views.decorators.csrf import csrf_exempt from django.contrib.auth.decorators import login_required
@login_required def private_message_to_talkjs_chat(request, other_id): if request.is_ajax(): other = User.objects.get(pk=other_id) return JsonResponse({ 'me': get_talkjs_user_object(request.user), 'other': get_talkjs_user_object(other) }) return bad_request()
const currentSessionKey = 'currentSession' function initializeUnreadMessages() { talkSession.unreads.on('change', function(conversationIds) { const amountOfUnreads = conversationIds.length $('span#notifier-badge') .text(amountOfUnreads) .toggle(amountOfUnreads > 0) if (amountOfUnreads > 0) document.title = '(' + amountOfUnreads + ') Games Chat' else document.title = 'Games Chat' }) } async function createTalkUser(user) { await Talk.ready return new Talk.User({ id: user.id, name: user.name, email: user.email, photoUrl: user.photoUrl, welcomeMessage: user.welcomeMessage ? user.welcomeMessage : null }) } function getSessionCredentials() { return $.ajax({ type: 'GET', url: `/talk/session/current/` }) } async function buildSession({ me, appId, signature }) { await Talk.ready window.talkSession = new Talk.Session({ appId: appId, me: await createTalkUser(me), signature: signature }) } async function initializeSession() { const currentSession = sessionStorage.getItem(currentSessionKey) if (currentSession) { await buildSession(JSON.parse(currentSession)) return } await buildSession(await getSessionCredentials()) sessionStorage.setItem(currentSessionKey, JSON.stringify(talkSession)) }
let selectedConversationId = null $(async function() { await initializeSession() const inbox = talkSession.createInbox({ feedConversationTitleMode: 'subject' }) inbox.mount(document.getElementById('talkjs-container')) inbox.on('conversationSelected', function(selectedConversation) { if (selectedConversation) { $('#chat-options').removeClass('hidden') selectedConversationId = selectedConversation.conversation.id if (selectedConversation.others.length > 1 && selectedConversation.others.length < 4) { $('#chat-clipboard').removeClass('hidden') } else $('#chat-clipboard').addClass('hidden') $('#chat-additions').removeClass('disabled') } else { selectedConversationId = null $('#chat-options').addClass('hidden') $('#chat-additions').addClass('disabled') } }) $('#chat-additions').on('click', '#chat-leave', function(e) { e.preventDefault() $.ajax({ type: 'GET', url: `/talk/leave/${selectedConversationId}` }) }) $('#chat-additions').on('click', '#quick-message', function(e) { e.preventDefault() $.ajax({ type: 'POST', url: `/talk/quick/${selectedConversationId}/`, data: { message: $(this).text() } }) }) })
This is what you should see when the user has no chats:
@login_required def leave_talkjs_chat(request, conversationId): url = get_request_prerequisites(f'/conversations/{conversationId}/participants/{request.user.id}') response = requests.delete(url, headers=headers) return get_response_result(response) def get_request_prerequisites(endpoint, data=None): url = f'{talkjs_base_url}{endpoint}' if data is None: return url return url, json.dumps(data) def get_response_result(response): if response.ok: return ok_request() return bad_request() def bad_request(): return HttpResponse(status=400) def ok_request(): return HttpResponse(status=200)
You can easily leave a chat by making a delete request to the TalkJS API with the chat id.
@csrf_exempt @login_required def quick_message_to_talkjs_chat(request, conversationId): if request.is_ajax() and request.method == 'POST': url, data = get_request_prerequisites(f'/conversations/{conversationId}/messages', [{ 'text': request.POST['message'], 'sender': str(request.user.id), 'type': 'UserMessage' }]) response = requests.post(url, data=data, headers=headers) return get_response_result(response) return bad_request()
This Chatbox should reinitialize immediately whenever a new chat is created.
style="display: none !important;"
From this code:
<div class="chatbox-header" style="display: none !important;"> <div id="header-avatar"></div> <p id="header-usernames"></p> <p id="header-subject"></p> </div>
class ChatSettings { defaultPhotoUrl = 'https://www.pnglot.com/pngfile/detail/107-1071726_chat-icon-png-icon-for-group-chat.png' constructor(subject = '', welcomeMessage = '', photoUrl = ''){ this.subject = subject this.welcomeMessage = welcomeMessage if (!photoUrl && photoUrl === '') { this.photoUrl = this.defaultPhotoUrl this.isDefaultPhotoUsed = true } else { this.isDefaultPhotoUsed = false this.photoUrl = photoUrl } } } let chatSettings = new ChatSettings() function initializeConversation(conversation, participants, me, isPrivateChat, isChatWithMe = false) { const chatbox = talkSession.createChatbox(conversation, { showChatHeader: false }) chatbox.mount(document.getElementById('talkjs-container')) let imageUrl = chatSettings.photoUrl const headerUsernames = isChatWithMe ? `${me.name} (you)` : participants.filter(p => p.id !== me.id).map(p => p.name).join(', ') if (isChatWithMe) { imageUrl = participants[0].photoUrl } else if (isPrivateChat && chatSettings.isDefaultPhotoUsed) { imageUrl = participants.filter(p => p.id !== me.id)[0].photoUrl } $('#header-avatar').css('background-image', 'url(' + imageUrl + ')') $('#header-usernames').text(headerUsernames) $('#header-subject').text(chatSettings.subject) } $(async function() { await Talk.ready await initializeSession() // Initial conversation with me, myself and I const me = await createTalkUser(talkSession.me) const conversation = talkSession.getOrCreateConversation(me.id) conversation.setParticipant(me) initializeConversation(conversation, [me], me, false, true) $('#chat-options-modal').on('hide.bs.modal', function() { const subject = $(this).find('#chat-subject').val() const welcomeMessage = $(this).find('#chat-welcome-message').val() let photoUrl if ($(this).find('#chat-photo-url').val()) photoUrl = $(this).find('#chat-photo-url').val() chatSettings = new ChatSettings(subject, welcomeMessage, photoUrl) }) })
class ChatSettings { defaultPhotoUrl = 'https://www.pnglot.com/pngfile/detail/107-1071726_chat-icon-png-icon-for-group-chat.png' constructor(subject = '', welcomeMessage = '', photoUrl = ''){ this.subject = subject this.welcomeMessage = welcomeMessage if (!photoUrl && photoUrl === '') { this.photoUrl = this.defaultPhotoUrl this.isDefaultPhotoUsed = true } else { this.isDefaultPhotoUsed = false this.photoUrl = photoUrl } } } let invitedUsersIds = [] let chatSettings = new ChatSettings() let chatActionsShown = false function initializeConversation(conversation, participants, me, isPrivateChat, isChatWithMe = false) { const chatbox = talkSession.createChatbox(conversation, { showChatHeader: false }) chatbox.mount(document.getElementById('talkjs-container')) let imageUrl = chatSettings.photoUrl const headerUsernames = isChatWithMe ? `${me.name} (you)` : participants.filter(p => p.id !== me.id).map(p => p.name).join(', ') if (isChatWithMe) { imageUrl = participants[0].photoUrl } else if (isPrivateChat && chatSettings.isDefaultPhotoUsed) { imageUrl = participants.filter(p => p.id !== me.id)[0].photoUrl } $('#header-avatar').css('background-image', 'url(' + imageUrl + ')') $('#header-usernames').text(headerUsernames) $('#header-subject').text(chatSettings.subject) } function reset() { invitedUsersIds = [] $('button#invite-user') .removeClass('btn-danger') .addClass('btn-primary') .text('Invite') $('#invited-users-count').text(`Selected ${invitedUsersIds.length}/4`) $('#chat-actions').fadeOut() chatActionsShown = false chatSettings = new ChatSettings() $("#chat-options-modal") .find("input") .val('') .end() } $(async function() { await Talk.ready await initializeSession() // Initial conversation with me, myself and I const me = await createTalkUser(talkSession.me) const conversation = talkSession.getOrCreateConversation(me.id) conversation.setParticipant(me) initializeConversation(conversation, [me], me, false, true) $(this).on('click', '#invite-user', function() { const otherId = $(this).data('other-id').toString() if (invitedUsersIds.indexOf(otherId) === -1 && invitedUsersIds.length < 4) { invitedUsersIds.push(otherId) $(this) .text('Remove') .removeClass('btn-primary') .addClass('btn-danger') } else if (invitedUsersIds.indexOf(otherId) !== -1 && invitedUsersIds.length < 5){ invitedUsersIds.splice(invitedUsersIds.indexOf(otherId), 1) $(this) .text('Invite') .removeClass('btn-danger') .addClass('btn-primary') } if (invitedUsersIds.length == 1) { if (!chatActionsShown) { $('#chat-actions').css('display', 'flex').hide().fadeIn() chatActionsShown = true } $('#create-chat').text('Create private chat') } else if (invitedUsersIds.length > 1) $('#create-chat').text('Create group chat') else if (invitedUsersIds.length == 0) { $('#chat-actions').fadeOut() chatActionsShown = false } $('#invited-users-count').text(`Selected ${invitedUsersIds.length}/4`) }) $('#create-chat').on('click', function() { const { subject, welcomeMessage, photoUrl } = chatSettings $.ajax({ type: 'POST', url: `/talk/chat/`, data: { participants: invitedUsersIds, subject, welcomeMessage, photoUrl }, success: async function({ conversationId, participants }) { const conversation = talkSession.getOrCreateConversation(conversationId) const mappedParticipants = await Promise.all(participants.map( p => new Promise(resolve => resolve(createTalkUser(p))))) initializeConversation(conversation, mappedParticipants, me, invitedUsersIds.length == 1) reset() }, error: function(error) { reset() console.log(error) } }) }) $('#chat-options-modal').on('hide.bs.modal', function() { const subject = $(this).find('#chat-subject').val() const welcomeMessage = $(this).find('#chat-welcome-message').val() let photoUrl if ($(this).find('#chat-photo-url').val()) photoUrl = $(this).find('#chat-photo-url').val() chatSettings = new ChatSettings(subject, welcomeMessage, photoUrl) }) })
@csrf_exempt @login_required def create_talkjs_chat(request): if request.is_ajax() and request.method == 'POST': participantsIds = request.POST.getlist('participants[]') participants_count = len(participantsIds) is_group = participants_count > 1 # excluding the current user participantsIds.append(str(request.user.id)) synchronize_talkjs_participants(participantsIds, is_group) conversationId = 'chat_' + ''.join(random.choices(string.digits, k=5)) url, data = get_request_prerequisites(f'/conversations/{conversationId}', { 'participants': participantsIds, 'subject': request.POST['subject'], 'welcomeMessages': [request.POST['welcomeMessage']] if request.POST['welcomeMessage'] else None, 'photoUrl': request.POST['photoUrl'] if request.POST['photoUrl'] else None }) response = requests.put(url, data=data, headers=headers) if response.ok: message = f'This is a group chat with {participants_count} more people!' if is_group else 'This is a private chat!' send_talkjs_system_message(message, conversationId) participants = [] for participantId in participantsIds: participant = get_talkjs_user_object(User.objects.get(id=participantId)) participants.append(participant) talkjs_chat_data = { 'conversationId': conversationId, 'participants': participants } return JsonResponse(talkjs_chat_data, status=200) return bad_request() def synchronize_talkjs_participants(participants, is_group): for participantId in participants: synchronize_talkjs_participant(participantId, is_group) def synchronize_talkjs_participant(participantId, is_group): participant = get_talkjs_user_object(User.objects.get(pk=participantId)) url, data = get_request_prerequisites(f'/users/{participantId}', { 'name': participant['name'], 'email': [participant['email']], 'photoUrl': participant['photoUrl'], 'welcomeMessage': None if is_group else participant['welcomeMessage'] }) response = requests.put(url, data=data, headers=headers) return get_response_result(response) def send_talkjs_system_message(message, conversationId): url, data = get_request_prerequisites(f'/conversations/{conversationId}/messages', [{ 'text': message, 'type': 'SystemMessage' }]) response = requests.post(url, data=data, headers=headers) return get_response_result(response)
<div class="col"> <div class="chatbox-container"> <div class="chatbox-header"> <div id="header-avatar"></div> <p id="header-usernames"></p> <p id="header-subject"></p> </div> <div id="talkjs-container" style="width: 100%; height: 570px;"> <i>Loading chat...</i> </div> </div> </div>
.chat-container { width: 420px; max-width: 100%; margin: auto; } .chatbox-header { width: 100%; height: 70px; max-width: 420px; margin: 0 auto; position: relative; background-color: var(--main-color); display: flex; flex-direction: row; justify-content: flex-start; border-radius: 10px 10px 0 0; margin-bottom: -3px; padding: 10px; } #header-avatar { position: absolute; height: 50px; width: 50px; background-size: cover; background-repeat: no-repeat; background-position: center; border-radius: 50%; border: 2px solid #eee; } .chatbox-header p { font-family: "Helvetica", sans-serif; margin: 0; position: absolute; color: #fff !important; left: 70px; } #header-usernames { top: 7px; font-size: 18px; font-weight: bold; } #header-subject { top: 35px; font-size: 15px; }
inbox.on('conversationSelected', function(selectedConversation) { if (selectedConversation) { $('#chat-options').removeClass('hidden') selectedConversationId = selectedConversation.conversation.id if (selectedConversation.others.length > 1 && selectedConversation.others.length < 4) { $('#chat-clipboard').removeClass('hidden') const port = window.location.port ? `:${window.location.port}` : '' const url = `${window.location.protocol}//${window.location.hostname}${port}/talk/invitation/${selectedConversationId}` $('#chat-link').val(url) } else $('#chat-clipboard').addClass('hidden') $('#chat-additions').removeClass('disabled') } else { selectedConversationId = null $('#chat-options').addClass('hidden') $('#chat-additions').addClass('disabled') } }) $('#chat-additions').on('click', '#chat-link-copy', function(e) { e.preventDefault() $('#chat-link').select() document.execCommand("copy") })
@login_required def invite_to_talkjs_chat(request, conversationId): conversation = get_talkjs_conversation(conversationId) participants_count = len(conversation['participants']) if participants_count < 5: synchronize_talkjs_participant(request.user.id, True) url, data = get_request_prerequisites(f'/conversations/{conversationId}/participants/{request.user.id}', [{ 'access': 'ReadWrite', 'notify': True }]) response = requests.put(url, data=data, headers=headers) if response.ok: return redirect('inbox') return redirect('error-invitation')
import json import hmac import string import random import hashlib import requests from django.conf import settings from django.shortcuts import redirect from django.contrib.auth.models import User from django.http import HttpResponse, JsonResponse from django.views.decorators.csrf import csrf_exempt from django.contrib.auth.decorators import login_required