i am making chat app using django, and i follow the tutorial in youtube and documentation and i follow everything they say, but i still get the error
chat/
__init__.py
consumers.py
routing.py
templates/
urls.py
views.py
This is my code in consumers.py
this is the script in my room.html, i already have script in ReconnectingWebSocket.js
<script>
var roomName = {{ room_name_json }};
var username = {{ username }};
var chatSocket = new ReconnectingWebSocket(
'ws://' + window.location.host +
'/ws/chat/' + roomName + '/');
chatSocket.onmessage = function(e) {
var data = JSON.parse(e.data);
var message = data['message'];
var author = message['author'];
var msgListTag = document.createElement('li');
var pTag = document.createElement('p');
pTag.textContent = message.content;
if (author === username){
msgListTag.className='sent';
}
else{
msgListTag.className = 'replies';
}
msgListTag.appendChild(pTag);
document.querySelector('#chat-log').appendChild(msgListTag);
};
chatSocket.onclose = function(e) {
console.error('Chat socket closed unexpectedly');
};
document.querySelector('#chat-message-input').onkeyup = function(e) {
if (e.keyCode === 13) { // enter, return
document.querySelector('#chat-message-submit').click();
}
};
document.querySelector('#chat-message-submit').onclick = function(e) {
var messageInputDom = document.getElementById('#chat-message-input');
var message = messageInputDom.value;
chatSocket.send(JSON.stringify({
'command': 'new_message',
'message': message,
'from': username
}));
messageInputDom.value = '';
};
</script>
class ChatConsumer(WebsocketConsumer):
def fetch_messages(self, data):
messages = Message.last_10_messages()
content = {
'messages': self.messages_to_json(messages)
}
self.send_message(content)
def new_message(self, data):
author = data['from']
author_user =User.objects.filter(username=author)[0]
message = Message.objects.create(
author=author_user,
content=data['message']
)
content = {
'command': 'new_message',
'message': self.messages_to_json(message)
}
return self.send_chat_message(content)
def messages_to_json(self, messages):
result = []
for message in messages:
result.append(self.message_to_json(message))
return result
def message_to_json(self, message):
return {
'author':message.author.username,
'content': message.content,
'timestamp': str(message.timestamp)
}
commands = {
'fetch_messages': fetch_messages,
'new_message': new_message
}
def connect(self):
self.room_name = self.scope['url_route']['kwargs']['room_name']
self.room_group_name = 'chat_%s' % self.room_name
async_to_sync(self.channel_layer.group_add)(
self.room_group_name,
self.channel_name
)
self.accept()
def disconnect(self, close_code):
async_to_sync(self.channel_layer.group_discard)(
self.room_group_name,
self.channel_name
)
def receive(self, text_data):
data = json.loads(text_data)
self.commands[data['command']](self, data)
def send_chat_message(self, message):
async_to_sync(self.channel_layer.group_send)(
self.room_group_name,
{
'type': 'chat_message',
'message': message
}
)
def send_message(self, message):
self.send(text_data=json.dump(message))
def chat_message(self, event):
message = event['message']
self.send(text_data=json.dump(message))
my views.py
return render(request, 'chat/room.html', {
'room_name_json': mark_safe(json.dumps(room_name)),
'username':mark_safe(json.dumps(request.user.username)),
})
my models.py
class Message(models.Model):
author = models.ForeignKey(User, related_name='author_messages', on_delete=models.CASCADE)
content = models.TextField(null=True, blank=True)
timestamp = models.DateTimeField(auto_now_add=True,null=True, blank=True)
def __str__(self):
return self.author.username
def last_10_messages(self):
return Message.objects.order_by('-timestamp').all()[:10]
this is the error i get
i get error from this line
def messages_to_json(self, messages):
result = []
for message in messages:
result.append(self.message_to_json(message))
return result
for message in messages:
UPDATE when i tried this
def messages_to_json(self, messages):
content = {
'command': 'new_message',
'message': self.message_to_json(messages)
}
I get this error
your messages instance is not iterable,so you cannot use it in for loop,it is an instance of your Messages model that inherit from models.Model that is not an iterable,so you can simply use your message_to_json function:
content = {
'command': 'new_message',
'message': self.message_to_json(message)
}
Related
I'm trying to update the content of a database item using fetch. However, I get 403 Forbidden error in the console. I'm not using a form in my HTML template, just appending the elements to a div. The log says CSRF token missing.
document.addEventListener("DOMContentLoaded", function(){
const button = document.querySelectorAll("#edit_profile")
button.forEach(function(button){
button.onclick = function(){
const memberID = button.dataset.id;
const usernameID = button.dataset.username;
const username = document.getElementById(`username_${memberID}`);
let edit_username = document.createElement("textarea");
edit_username.setAttribute("rows", "1");
edit_username.innerHTML = username.innerHTML
edit_username.id = `edit_username_${memberID}`;
edit_username.className = `form-control username ${usernameID}`;
const saveButton = document.createElement("button");
saveButton.innerHTML = "Save";
saveButton.id = `saveButton_${memberID}`;
saveButton.className = "btn btn-success col-3";
saveButton.style.margin = "10px";
document.getElementById(`edit_${memberID}`).append(edit_username);
document.getElementById(`edit_${memberID}`).append(saveButton);
saveButton.addEventListener("click", function(){
edit_username = document.getElementById(`edit_username_${memberID}`);
fetch(`/edit_profile/${memberID}`,{
method: "POST",
body: JSON.stringify({
username: edit_username.value,
})
})
.then(response => response.json())
.then(result => {
console.log(result);
if(result[`error`]){
reset(memberID)
}
else {
username.innerHTML = result.username;
reset(memberID)
}
})
.catch(error => {
console.error(error);
})
})
}
});
I added the following decorator in views.py and it solved the problem:
from django.views.decorators.csrf import csrf_exempt
#csrf_exempt
def edit_profile(request, member_id):
if request.method != "POST":
return JsonResponse({"error": "POST request required."}, status=400)
team_members = Team.objects.get(id = member_id)
body_unicode = request.body.decode('utf-8')
body = json.loads(body_unicode)
username = body['username']
skills = body['skills']
bio = body['bio']
Team.objects.filter(id=member_id).update(username=f'{username}',skills=f'{skills}',bio=f'{bio}')
return JsonResponse({"message": "Successful", "username": username, "skills": skills, "bio": bio}, status=200)
I want to take the video data and convert it using cv2. Which part is the video data? It's a code that might be related.
I want to send video data from the client to the server using webrtc, and convert and send the converted video from server to cv2 from the client again.
app.js
from flask import Flask, render_template, request, redirect, url_for, session
from flask_socketio import SocketIO, emit, join_room, leave_room
# Next two lines are for the issue: https://github.com/miguelgrinberg/python-engineio/issues/142
import os
secretKey = os.urandom(24)
app = Flask(__name__)
app.config['SECRET_KEY'] = secretKey
print("secretKey is ",secretKey)
socketio = SocketIO(app)
_users_in_room = {} # stores room wise user list
_room_of_sid = {} # stores room joined by an used
_name_of_sid = {} # stores display name of users
#app.route("/",methods=["GET", "POST"]) #첫번째 로그인화면
def loginPage():
if request.method == "POST":
room_id = request.form['room_id']
return redirect(url_for('enter_room',room_id=room_id))
return render_template("home.html")
#app.route("/<string:room_id>/checkpoint/", methods=["GET", "POST"]) #두번째 화면
def entry_checkpoint(room_id):
if request.method == "POST":
display_name = request.form['display_name']
mute_video = request.form['mute_video']
session[room_id] = {"name": display_name, "mute_video":mute_video}
return redirect(url_for("enter_room", room_id=room_id))
return render_template("chatroom_checkpoint.html", room_id=room_id)
#app.route("/<string:room_id>/") #세번째 스트림화면
def enter_room(room_id):
if room_id not in session:
return redirect(url_for("entry_checkpoint", room_id=room_id))
return render_template("chatroom.html", room_id=room_id, display_name=session[room_id]["name"], mute_video=session[room_id]["mute_video"])
#socketio.on("connect")
def on_connect():
sid = request.sid
print("New socket connected ", sid)
#socketio.on("join-room")
def on_join_room(data):
sid = request.sid
room_id = data["room_id"]
display_name = session[room_id]["name"]
# register sid to the room
join_room(room_id)
_room_of_sid[sid] = room_id
_name_of_sid[sid] = display_name
# broadcast to others in the room
print("[{}] New member joined: {}<{}>".format(room_id, display_name, sid))
emit("user-connect", {"sid": sid, "name": display_name}, broadcast=True, include_self=False, room=room_id)
# add to user list maintained on server
if room_id not in _users_in_room:
_users_in_room[room_id] = [sid]
emit("user-list", {"my_id": sid}) # send own id only
else:
usrlist = {u_id:_name_of_sid[u_id] for u_id in _users_in_room[room_id]}
emit("user-list", {"list": usrlist, "my_id": sid}) # send list of existing users to the new member
_users_in_room[room_id].append(sid) # add new member to user list maintained on server
print("\nusers: ", _users_in_room, "\n")
#socketio.on("disconnect")
def on_disconnect():
sid = request.sid
room_id = _room_of_sid[sid]
display_name = _name_of_sid[sid]
print("[{}] Member left: {}<{}>".format(room_id, display_name, sid))
emit("user-disconnect", {"sid": sid}, broadcast=True, include_self=False, room=room_id)
_users_in_room[room_id].remove(sid)
if len(_users_in_room[room_id]) == 0:
_users_in_room.pop(room_id)
_room_of_sid.pop(sid)
_name_of_sid.pop(sid)
print("\nusers: ", _users_in_room, "\n")
#socketio.on("data")
def on_data(data):
sender_sid = data['sender_id']
target_sid = data['target_id']
if sender_sid != request.sid:
print("[Not supposed to happen!] request.sid and sender_id don't match!!!")
if data["type"] != "new-ice-candidate":
print('{} message from {} to {}'.format(data["type"], sender_sid, target_sid))
socketio.emit('data', data, room=target_sid)
if __name__ == "__main__":
socketio.run(app, host='0.0.0.0', port='5050', debug=True)
chatroom_networking.js
var myID;
var _peer_list = {};
// socketio
var protocol = window.location.protocol;
var socket = io(protocol + '//' + document.domain + ':' + location.port, {autoConnect: false});
document.addEventListener("DOMContentLoaded", (event)=>{
startCamera();
});
var camera_allowed=false;
var mediaConstraints = {
audio: true, // We want an audio track
video: true
}
function startCamera()
{
navigator.mediaDevices.getUserMedia(mediaConstraints)
.then((stream)=>{
myVideo.srcObject = stream;
camera_allowed = true;
//start the socketio connection
socket.connect();
})
.catch((e)=>{
console.log("getUserMedia Error! ", e);
alert("Error! Unable to access camera or mic! ");
});
}
socket.on("connect", ()=>{
console.log("socket connected....");
socket.emit("join-room", {"room_id": myRoomID});
});
socket.on("disconnect", (data)=>{
console.log("disconnect");
});
socket.on("user-connect", (data)=>{
console.log("user-connect ", data);
let peer_id = data["sid"];
let display_name = data["name"];
_peer_list[peer_id] = undefined; // add new user to user list
addVideoElement(peer_id, display_name);
});
socket.on("user-disconnect", (data)=>{
console.log("user-disconnect ", data);
let peer_id = data["sid"];
closeConnection(peer_id);
removeVideoElement(peer_id);
});
socket.on("user-list", (data)=>{
console.log("user list recvd ", data);
myID = data["my_id"];
if( "list" in data) // not the first to connect to room, existing user list recieved
{
let recvd_list = data["list"];
// add existing users to user list
for(peer_id in recvd_list)
{
display_name = recvd_list[peer_id];
_peer_list[peer_id] = undefined;
addVideoElement(peer_id, display_name);
}
start_webrtc();
}
});
function closeConnection(peer_id)
{
if(peer_id in _peer_list)
{
_peer_list[peer_id].onicecandidate = null;
_peer_list[peer_id].ontrack = null;
_peer_list[peer_id].onnegotiationneeded = null;
delete _peer_list[peer_id]; // remove user from user list
}
}
function log_user_list()
{
for(let key in _peer_list)
{
console.log(`${key}: ${_peer_list[key]}`);
}
}
//---------------[ webrtc ]--------------------
var PC_CONFIG = {
iceServers: [
{
urls: ['stun:stun.l.google.com:19302',
'stun:stun1.l.google.com:19302',
'stun:stun2.l.google.com:19302',
'stun:stun3.l.google.com:19302',
'stun:stun4.l.google.com:19302'
]
},
]
};
function log_error(e){console.log("[ERROR] ", e);}
function sendViaServer(data){socket.emit("data", data);}
socket.on("data", (msg)=>{
switch(msg["type"])
{
case "offer":
handleOfferMsg(msg);
break;
case "answer":
handleAnswerMsg(msg);
break;
case "new-ice-candidate":
handleNewICECandidateMsg(msg);
break;
}
});
function start_webrtc()
{
// send offer to all other members
for(let peer_id in _peer_list)
{
invite(peer_id);
}
}
function invite(peer_id)
{
if(_peer_list[peer_id]){console.log("[Not supposed to happen!] Attempting to start a connection that already exists!")}
else if(peer_id === myID){console.log("[Not supposed to happen!] Trying to connect to self!");}
else
{
console.log(`Creating peer connection for <${peer_id}> ...`);
createPeerConnection(peer_id);
let local_stream = myVideo.srcObject;
local_stream.getTracks().forEach((track)=>{_peer_list[peer_id].addTrack(track, local_stream);});
}
}
function createPeerConnection(peer_id)
{
_peer_list[peer_id] = new RTCPeerConnection(PC_CONFIG);
_peer_list[peer_id].onicecandidate = (event) => {handleICECandidateEvent(event, peer_id)};
_peer_list[peer_id].ontrack = (event) => {handleTrackEvent(event, peer_id)};
_peer_list[peer_id].onnegotiationneeded = () => {handleNegotiationNeededEvent(peer_id)};
}
function handleNegotiationNeededEvent(peer_id)
{
_peer_list[peer_id].createOffer()
.then((offer)=>{return _peer_list[peer_id].setLocalDescription(offer);})
.then(()=>{
console.log(`sending offer to <${peer_id}> ...`);
sendViaServer({
"sender_id": myID,
"target_id": peer_id,
"type": "offer",
"sdp": _peer_list[peer_id].localDescription
});
})
.catch(log_error);
}
function handleOfferMsg(msg)
{
peer_id = msg['sender_id'];
console.log(`offer recieved from <${peer_id}>`);
createPeerConnection(peer_id);
let desc = new RTCSessionDescription(msg['sdp']);
_peer_list[peer_id].setRemoteDescription(desc)
.then(()=>{
let local_stream = myVideo.srcObject;
local_stream.getTracks().forEach((track)=>{_peer_list[peer_id].addTrack(track, local_stream);});
})
.then(()=>{return _peer_list[peer_id].createAnswer();})
.then((answer)=>{return _peer_list[peer_id].setLocalDescription(answer);})
.then(()=>{
console.log(`sending answer to <${peer_id}> ...`);
sendViaServer({
"sender_id": myID,
"target_id": peer_id,
"type": "answer",
"sdp": _peer_list[peer_id].localDescription
});
})
.catch(log_error);
}
function handleAnswerMsg(msg)
{
peer_id = msg['sender_id'];
console.log(`answer recieved from <${peer_id}>`);
let desc = new RTCSessionDescription(msg['sdp']);
_peer_list[peer_id].setRemoteDescription(desc)
}
function handleICECandidateEvent(event, peer_id)
{
if(event.candidate){
sendViaServer({
"sender_id": myID,
"target_id": peer_id,
"type": "new-ice-candidate",
"candidate": event.candidate
});
}
}
function handleNewICECandidateMsg(msg)
{
console.log(`ICE candidate recieved from <${peer_id}>`);
var candidate = new RTCIceCandidate(msg.candidate);
_peer_list[msg["sender_id"]].addIceCandidate(candidate)
.catch(log_error);
}
function handleTrackEvent(event, peer_id)
{
console.log(`track event recieved from <${peer_id}>`);
if(event.streams)
{
getVideoObj(peer_id).srcObject = event.streams[0];
}
}
chatroom_ui.js
var myVideo;
document.addEventListener("DOMContentLoaded", (event)=>{
myVideo = document.getElementById("local_vid");
document.getElementById("room_link").innerHTML=`or the link: <span class="heading-mark">${window.location.href}</span>`;
});
function makeVideoElement(element_id, display_name)
{
let wrapper_div = document.createElement("div");
let vid_wrapper = document.createElement("div");
let vid = document.createElement("video");
let name_text = document.createElement("div");
wrapper_div.id = "div_"+element_id;
vid.id = "vid_"+element_id;
wrapper_div.className = "shadow video-item";
vid_wrapper.className = "vid-wrapper";
vid.autoplay = true;
vid_wrapper.appendChild(vid);
wrapper_div.appendChild(vid_wrapper);
console.log(wrapper_div)
return wrapper_div;
}
function addVideoElement(element_id)
{
document.getElementById("video_grid").appendChild(makeVideoElement(element_id));
}
function removeVideoElement(element_id)
{
let v = getVideoObj(element_id);
if(v.srcObject){
v.srcObject.getTracks().forEach(track => track.stop());
}
v.removeAttribute("srcObject");
v.removeAttribute("src");
document.getElementById("div_"+element_id).remove();
}
function getVideoObj(element_id)
{
return document.getElementById("vid_"+element_id);
}
I am working on the cs50 web development Network assignment. Essentially it is a barebones twitter copycat. I have an issue where a view from views.py is being called when I do not intend it to be called. I know below I am posting more than is needed of my code below, but I feel I need to since I don't know where the problem area is.
The views.py function follow_count() is being called eventually when I call the index view but cannot determine why. I.e. it is called every time the homepage is loaded. I do not want it to be called until it is specifically called by the clicked event listener in the js file. I cannot figure out what is causing follow_count() to run early, every time I load the index view. As I follow the path of different functions calling each other, it doesn't appear that anything is calling follow_count() yet it runs anyway.
views.py:
from django.contrib.auth import authenticate, login, logout
from django.db import IntegrityError
from django.http import HttpResponse, HttpResponseRedirect
from django.http.response import JsonResponse
from django.shortcuts import render
from django.urls import reverse
from .models import User, Post, Profile
def index(request):
print("index running in python")
if request.method == "POST":
post = request.POST["post-body"]
new_post = Post()
new_post.poster = request.user
new_post.body = post
new_post.save()
return render(request, "network/index.html")
def login_view(request):
if request.method == "POST":
# Attempt to sign user in
username = request.POST["username"]
password = request.POST["password"]
user = authenticate(request, username=username, password=password)
# Check if authentication successful
if user is not None:
login(request, user)
return HttpResponseRedirect(reverse("index"))
else:
return render(request, "network/login.html", {
"message": "Invalid username and/or password."
})
else:
return render(request, "network/login.html")
def logout_view(request):
logout(request)
return HttpResponseRedirect(reverse("index"))
def register(request):
if request.method == "POST":
username = request.POST["username"]
email = request.POST["email"]
# Ensure password matches confirmation
password = request.POST["password"]
confirmation = request.POST["confirmation"]
if password != confirmation:
return render(request, "network/register.html", {
"message": "Passwords must match."
})
# Attempt to create new user
try:
user = User.objects.create_user(username, email, password)
user.save()
except IntegrityError:
return render(request, "network/register.html", {
"message": "Username already taken."
})
login(request, user)
#auto-create a profile for new user
new_profile = Profile()
new_profile.user = user
new_profile.save()
return HttpResponseRedirect(reverse("index"))
else:
return render(request, "network/register.html")
def all_posts(request):
print("all_posts running in python")
posts = Post.objects.all()
posts = posts.order_by("-timestamp").all()
print(f"{posts}")
return JsonResponse([post.serialize() for post in posts], safe=False)
def follow_count(request, username_lookup):
print(f"follow_count running in python")
user = User.objects.get(username='dannl')
profiles = Profile.objects.get(user=user)
print(username_lookup)
try:
user = User.objects.get(username=username_lookup)
except User.DoesNotExist:
pass
try:
profiles = Profile.objects.get(user=user)
except Profile.DoesNotExist:
pass
return JsonResponse([profiles.serialize()], safe=False)
def follow(request, username_lookup):
print("follow runnning in python")
followed_user = User.objects.get(username=username_lookup)
print(f"followed_user is {followed_user.username}")
followed_profile = Profile.objects.get(user=followed_user)
following_user = request.user
print("step 3 done")
print(f"following_user is {following_user.username}")
following_profile = Profile.objects.get(user=following_user)
followed_profile.followers.add(following_user)
following_profile.following.add(followed_user)
return render(request, "network/index.html")
def unfollow(request, username_lookup):
print("unfollow runnning in python")
unfollowed_user = User.objects.get(username=username_lookup)
print(f"unfollowed_user is {unfollowed_user.username}")
unfollowed_profile = Profile.objects.get(user=unfollowed_user)
unfollowing_user = request.user
print("step 3 done")
print(f"unfollowing_user is {unfollowing_user.username}")
unfollowing_profile = Profile.objects.get(user=unfollowing_user)
unfollowed_profile.followers.remove(unfollowing_user)
unfollowing_profile.following.remove(unfollowed_user)
return render(request, "network/index.html")
def follow_button(request, username_lookup):
print("follow_button running in python")
current_logged_user = request.user
current_logged_profile = Profile.objects.get(user=current_logged_user)
print(f"current_logged_profile is {current_logged_profile.user.username}")
return JsonResponse([current_logged_profile.serialize()], safe=False)
urls.py:
from django.urls import path
from . import views
urlpatterns = [
path("", views.index, name="index"),
path("login", views.login_view, name="login"),
path("logout", views.logout_view, name="logout"),
path("register", views.register, name="register"),
path("all_posts", views.all_posts, name="all_posts"),
path("<str:username_lookup>", views.follow_count, name="follow_count"),
path("<str:username_lookup>/follow", views.follow, name="follow"),
path("<str:username_lookup>/unfollow", views.unfollow, name="unfollow"),
path("<str:username_lookup>/follow_button", views.follow_button, name="follow_button"),
path("profile_info", views.follow_button, name="profile_info")
]
index.html
{% extends "network/layout.html" %}
{% load static %}
{% block body %}
{% if user.is_authenticated %}
<div id="index-display">
<h3>All Posts</h3>
<br>
<div id="new-post">
<h5>New Post</h5>
<form action="{% url 'index' %}" method="post">
{% csrf_token %}
<textarea class="form-control" name="post-body" placeholder="Type post here"></textarea>
<input id="post-message" type="submit" class="btn btn-primary"/>
</form>
</div>
<div id="all-posts">
</div>
</div>
<div id="profile-display">
<h3 id="profile-name"></h3>
<br>
<b>Followers: </b><b id="followers"></b>
<b>Following: </b><b id="following"></b>
<div id="profile-posts">
</div>
</div>
<div id="following-display">
<h3>Following</h3>
<br>
<div id="following-posts">
</div>
</div>
{% else %}
<strong> Login To See Posts</strong>
{% endif %}
{% endblock %}
{% block script %}
<script src="{% static 'network/index.js' %}"></script>
{% endblock %}
index.js:
document.addEventListener('DOMContentLoaded', function() {
document.querySelector('#following-link').addEventListener('click', () => {
load_posts_following();
});
load_posts();
})
function load_posts() {
console.log("load_posts running");
document.querySelector('#index-display').style.display = 'block';
document.querySelector('#profile-display').style.display = 'none';
document.querySelector('#following-display').style.display = 'none';
fetch('/all_posts')
.then(response => response.json())
.then(posts => {
// Print posts
console.log(posts);
posts.forEach(post => show_posts(post));
});
}
function show_posts(post) {
console.log("show_posts running")
//create 'main' div (will add content to it below), and store it in a variable
const post_display = document.createElement('div');
post_display.id = 'post';
post_display.className = 'col-lg-10 col-md-20 col-sm-30 border';
console.log("step 1: div created")
//create new element for link to profiles, add it to the 'main' div
const post_poster = document.createElement('div');
post_poster.id = 'post-poster';
post_poster.innerHTML = post.poster;
post_poster.addEventListener('click', event => {
username_lookup = event.target.innerHTML;
load_posts_profile(username_lookup);
});
post_display.append(post_poster);
console.log("step 2 done")
//create new div to display post, add it to the 'main' div
const post_body = document.createElement('div');
post_body.id = 'post-body';
post_body.innerHTML = post.body;
post_display.append(post_body);
console.log("step 3 done")
//create new div to display timestamp, add it to the 'main' div
const post_timestamp = document.createElement('div');
post_timestamp.id = 'post-timestamp';
post_timestamp.innerHTML = post.timestamp;
post_display.append(post_timestamp);
console.log("step 4 done")
//create new div to display # of likes, add it to the 'main' div
const post_likes = document.createElement('div');
post_likes.id = 'post-likes';
post_likes.innerHTML = `Likes: ${post.likes}`;
post_display.append(post_likes);
console.log("step 5 done");
document.querySelector('#all-posts').append(post_display);
console.log("post appended");
}
function load_posts_following() {
console.log("load_posts_following running");
document.querySelector('#index-display').style.display = 'none';
document.querySelector('#profile-display').style.display = 'none';
document.querySelector('#following-display').style.display = 'block';
fetch('/profile_info')
.then(response => response.json())
.then(profiles_returned => {
console.log(profiles_returned);
profiles_returned.forEach(profile => {
fetch('/all_posts')
.then(response => response.json())
.then(posts => {
// Print posts
console.log(posts);
posts.forEach(post => show_posts_following(post, profile));
});
});
});
}
function show_posts_following(post, profile) {
console.log("show_posts_following running");
console.log(post.poster);
console.log(profile);
console.log(profile.following_usernames);
if (profile.following_usernames.includes(post.poster)) {
//create 'main' div (will add content to it below), and store it in a variable
const post_display = document.createElement('div');
post_display.id = 'post';
post_display.className = 'col-lg-10 col-md-20 col-sm-30 border';
//create new element for link to profiles, add it to the 'main' div
const post_poster = document.createElement('div');
post_poster.id = 'post-poster';
post_poster.innerHTML = post.poster;
post_display.append(post_poster);
//create new div to display post, add it to the 'main' div
const post_body = document.createElement('div');
post_body.id = 'post-body';
post_body.innerHTML = post.body;
post_display.append(post_body);
//create new div to display timestamp, add it to the 'main' div
const post_timestamp = document.createElement('div');
post_timestamp.id = 'post-timestamp';
post_timestamp.innerHTML = post.timestamp;
post_display.append(post_timestamp);
//create new div to display # of likes, add it to the 'main' div
const post_likes = document.createElement('div');
post_likes.id = 'post-likes';
post_likes.innerHTML = `Likes: ${post.likes}`;
post_display.append(post_likes);
document.querySelector('#following-posts').append(post_display);
}
}
function load_posts_profile(username_lookup) {
console.log("load_posts_profile running");
document.querySelector('#index-display').style.display = 'none';
document.querySelector('#profile-display').style.display = 'block';
document.querySelector('#following-display').style.display = 'none';
document.querySelector('#profile-name').innerHTML = username_lookup;
fetch(`/${username_lookup}`)
.then(response => response.json())
.then(profiles => {
console.log(profiles);
profiles.forEach(profile => show_follow_count(profile));
follow_button(username_lookup, profiles);
});
fetch('/all_posts')
.then(response => response.json())
.then(posts => {
// Print posts
console.log(posts);
posts.forEach(post => show_posts_profile(post, username_lookup));
});
}
function show_posts_profile(post, username_lookup) {
console.log("show_posts_profile running");
console.log(post.poster);
if (post.poster === username_lookup) {
//create 'main' div (will add content to it below), and store it in a variable
const post_display = document.createElement('div');
post_display.id = 'post';
post_display.className = 'col-lg-10 col-md-20 col-sm-30 border';
//create new element for link to profiles, add it to the 'main' div
const post_poster = document.createElement('div');
post_poster.id = 'post-poster';
post_poster.innerHTML = post.poster;
post_display.append(post_poster);
//create new div to display post, add it to the 'main' div
const post_body = document.createElement('div');
post_body.id = 'post-body';
post_body.innerHTML = post.body;
post_display.append(post_body);
//create new div to display timestamp, add it to the 'main' div
const post_timestamp = document.createElement('div');
post_timestamp.id = 'post-timestamp';
post_timestamp.innerHTML = post.timestamp;
post_display.append(post_timestamp);
//create new div to display # of likes, add it to the 'main' div
const post_likes = document.createElement('div');
post_likes.id = 'post-likes';
post_likes.innerHTML = `Likes: ${post.likes}`;
post_display.append(post_likes);
document.querySelector('#profile-posts').append(post_display);
}
}
function show_follow_count(profile) {
document.querySelector('#followers').innerHTML = `${profile.followers}`;
document.querySelector('#following').innerHTML = `${profile.following}`;
}
function follow(username_lookup) {
console.log("follow running")
fetch(`/${username_lookup}/follow`)
.then(response => null)
}
function unfollow(username_lookup) {
console.log("unfollow running")
fetch(`/${username_lookup}/unfollow`)
.then(response => null)
}
function update_followers() {
const before_followers = document.querySelector('#followers').innerHTML;
console.log(before_followers);
var after_followers = parseInt(before_followers) + 1;
after_followers = parseInt(after_followers);
console.log(after_followers);
document.querySelector('#followers').innerHTML = `${after_followers}`;
}
function update_followers_unfollow() {
const before_followers = document.querySelector('#followers').innerHTML;
console.log(before_followers);
var after_followers = parseInt(before_followers) - 1;
after_followers = parseInt(after_followers);
console.log(after_followers);
document.querySelector('#followers').innerHTML = `${after_followers}`;
}
function follow_button(username_lookup) {
console.log("follow_button running")
fetch(`/${username_lookup}/follow_button`)
.then(response => response.json())
.then(current_logged_profile => {
console.log(current_logged_profile);
current_logged_profile.forEach(profile => {
if (username_lookup === profile.username) {
console.log("own profile found - no follow button");
}
else if (profile.following_usernames.includes(username_lookup)) {
console.log("unfollow button");
const unfollow_button = document.createElement('button');
unfollow_button.innerHTML = "Unfollow";
unfollow_button.style.width = '50px';
unfollow_button.style.height = '25px';
profile_header = document.querySelector('#profile-name');
profile_header.append(unfollow_button);
unfollow_button.addEventListener('click', () => {
unfollow(username_lookup);
update_followers_unfollow();
})
}
else {
console.log("not already follower - follow button");
const follow_button = document.createElement('button');
follow_button.innerHTML = "Follow";
follow_button.style.width = '50px';
follow_button.style.height = '25px';
profile_header = document.querySelector('#profile-name');
profile_header.append(follow_button);
follow_button.addEventListener('click', () => {
follow(username_lookup);
update_followers();
});
}
});
});
}
You need to put profile_info before the <str:username>, otherwise that will be the first match, and thus fire the follow_countinstead of thefollow_button`:
urlpatterns = [
path('', views.index, name='index'),
path('login', views.login_view, name='login'),
path('logout', views.logout_view, name='logout'),
path('register', views.register, name='register'),
path('all_posts', views.all_posts, name='all_posts'),
# ↓ first profile_info before <str:username_lookup>
path('profile_info', views.follow_button, name='profile_info'),
path('<str:username_lookup>', views.follow_count, name='follow_count'),
path('<str:username_lookup>/follow', views.follow, name='follow'),
path('<str:username_lookup>/unfollow', views.unfollow, name='unfollow'),
path('<str:username_lookup>/follow_button', views.follow_button, name='follow_button'),
]
i using react as my front end and django as my backend , as such , it requires me to use token based authentication with django channels. The method i am employing is by sending the authentication token as a cookie header. The methodology was taken from this git hub post here
So far , i have gotten most of the working parts together , however i don't seem to be able to persist the connection , it will always return an error in my console:
ERR_CONNECTION_RESET
Here is my code:
FRONTEND: Websocket.js
class WebSocketService{
static instance = null;
callbacks = {};
static getInstance(){
if (!WebSocketService.instance){
WebSocketService.instance = new WebSocketService();
}
return WebSocketService.instance;
}
constructor(){
this.socketRef = null;
}
connect(token){
var loc = window.location
var wsStart = 'ws://'
if (loc.protocol === 'https'){
wsStart = 'wss://'
}
const path = wsStart + 'localhost:8000'+ loc.pathname
// console.log(path)
// console.log(path + "?token=" + token)
document.cookie = 'authorization=' + token + ';'
console.log(document.cookie)
this.socketRef = new WebSocket(path)
this.socketRef.onmessage = e => {
console.log('in on message')
this.socketNewMessage(e.data);
};
this.socketRef.onopen = () => {
console.log(this.props.token)
console.log("WebSocket open");
};
this.socketRef.onerror = e => {
console.log('error happ')
console.log(e.message);
};
this.socketRef.onclose = () => {
console.log("WebSocket closed, restarting..");
this.connect(token);
};
}
socketNewMessage(data){
const parsedData = JSON.parse(data);
const command = parsedData.command;
if(Object.keys(this.callbacks).length === 0){
return;
}
if(command === 'messages'){
this.callbacks[command](parsedData.messages);
}
if(command === 'new_message'){
console.log("okay so this was called")
this.callbacks[command](parsedData.message);
}
}
state(){
return this.socketRef.readyState;
}
waitForSocketConnection(callback){
const socket = this.socketRef;
const recursion = this.waitForSocketConnection;
setTimeout(
function(){
if(socket.readyState === 1){
console.log("Connection is made");
if(callback != null){
callback();
}
return;
}
else{
console.log("Wait for connection..");
recursion(callback);
}
}, 1);
}
}
let WebSocketInstance = WebSocketService.getInstance();
export default WebSocketInstance;
FRONTEND: Apps.js
class App extends Component {
componentDidMount() {
console.log('app mounting..')
this.props.onTryAutoSignup();
console.log(this.props.isAuthenticated)
if (this.props.isAuthenticated) {
WebSocketInstance.connect()
}
}
componentDidUpdate(oldProps) {
console.log('app updating props..')
if (this.props.token !== oldProps.token ) {
console.log(this.props.token)
WebSocketInstance.connect(this.props.token)
}
}
render() {
return (
<div>
<Router>
<CustomLayout {...this.props}>
<BaseRouter/>
</CustomLayout>
</Router>
</div>
);
}
}
const mapStateToProps = state => {
return {
isAuthenticated: state.token !== null ,
token : state.token
}
}
const mapDispatchToProps = dispatch => {
return {
onTryAutoSignup: () => dispatch(actions.authCheckState())
}
}
export default connect(mapStateToProps, mapDispatchToProps)(App);
BACKEND: token_auth.py ( A custom middleware)
#database_sync_to_async
def get_user(token_key):
try:
return Token.objects.get(key=token_key).user
except Token.DoesNotExist:
return AnonymousUser()
class TokenAuthMiddleware:
"""
Token authorization middleware for Django Channels 2
see:
https://channels.readthedocs.io/en/latest/topics/authentication.html#custom-authentication
"""
def __init__(self, inner):
self.inner = inner
def __call__(self, scope):
return TokenAuthMiddlewareInstance(scope, self)
class TokenAuthMiddlewareInstance:
def __init__(self, scope, middleware):
self.middleware = middleware
self.scope = dict(scope)
self.inner = self.middleware.inner
async def __call__(self, receive, send):
headers = dict(self.scope["headers"])
print(headers[b"cookie"])
if b"authorization" in headers[b"cookie"]:
print('still good here')
cookies = headers[b"cookie"].decode()
token_key = re.search("authorization=(.*)(; )?", cookies).group(1)
if token_key:
self.scope["user"] = await get_user(token_key)
return self.inner(self.scope)
BACKEND : Router.py
application = ProtocolTypeRouter({
"websocket": TokenAuthMiddlewareStack(
URLRouter([
path("", NotificationConsumer),
]),
),
})
TokenAuthMiddlewareStack = lambda inner: TokenAuthMiddleware(AuthMiddlewareStack(inner))
Here is my the items that were printed out in my cmd prompt:
WebSocket HANDSHAKING / [127.0.0.1:59931]
b'authorization=xxxxxxxxxxxx' #<-- token from the cookie header
still good here #<--- passed first validation
user1 #<---- went into the get_user function i declared within my middleware
WebSocket DISCONNECT / [127.0.0.1:59931] #<---- disconnects...
Please help! Im lost!
the issue was with the middleware instance , it should be :
class TokenAuthMiddlewareInstance:
def __init__(self, scope, middleware):
self.middleware = middleware
self.scope = dict(scope)
self.inner = self.middleware.inner
async def __call__(self, receive, send):
close_old_connections()
headers = dict(self.scope["headers"])
print(headers[b"cookie"])
if b"authorization" in headers[b"cookie"]:
print('still good here')
cookies = headers[b"cookie"].decode()
token_key = re.search("authorization=(.*)(; )?", cookies).group(1)
if token_key:
self.scope["user"] = await get_user(token_key)
inner = self.inner(self.scope)
return await inner(receive, send)
TokenAuthMiddlewareStack = lambda inner: TokenAuthMiddleware(AuthMiddlewareStack(inner))
thanks!
I have run into a 500 error that I cannot resolve while practicing with making a To Do app with various lists & to do items that all have full CRUD options.
To Do List code:
class TodoList (db.Model):
__tablename__ = 'todolists'
id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.String(), nullable=False)
todos = db.relationship('Todo', backref='list', lazy=True)
const todo_list_input = document.getElementById('todo_list_id');
document.getElementById('create_list_box_button').onsubmit = function(e) {
e.preventDefault();
const list_title = todo_list_input.value;
todo_list_input.value = '';
fetch('/todolists/create', {
method: 'POST',
body: JSON.stringify({
'todo_list_id': list_title,
}),
headers: {
'Contet-Type': 'application/json'
}
})
.then(response => response.json())
.then(jsonResponse => {
const li = document.createElement('li');
const checkbox = document.createElement('input');
checkbox.className = 'check-completed';
checkbox.type = 'checkbox';
checkbox.setAttribute('data-id', jsonResponse.id);
li.appendChild(checkbox);
const text = document.createTextNode(' ' + jsonResponse.description);
li.appendChild(text);
const deleteButton = document.createElement('button');
deleteButton.className = 'delete-button';
deleteButton.setAttribute('data-id', jsonResponse.id);
deleteButton.innerHTML = '✗';
li.appendChild(deleteButton);
document.getElementById('todo_lists_buttons').appendChild(li);
document.getElementById('error').className = 'hidden';
})
.catch(function() {
console.error('Error occurred');
document.getElementById('error').className = '';
})
}
#app.route('/todolists/create', methods=['POST'])
def create_todoList():
error = False
body = {}
try:
list_name = request.json()['list_name']
todoList = List(list_name=list_name)
db.session.add(todoList)
db.session.commit()
body['list_name'] = todoList.list_name
except:
error = True
db.session.rollback()
print(sys.exc_info())
finally:
db.session.close()
if not error:
return jsonify(body)
else:
abort(500)
I've tried changing variable names around throughout, no joy there, as well as a few other things to try to pinpoint the issue and am just out of ideas (still new at this) on what might be going on.
This only occurs when attempting to 'Create' a new To Do List. I can swap between lists and create/delete To Do Items no problem, it's just the Create List that isn't working.
To Do item code:
class Todo(db.Model):
__tablename__ = 'todos'
id = db.Column(db.Integer, primary_key=True)
description = db.Column(db.String(), nullable=False)
completed = db.Column(db.Boolean, default=False)
list_id = db.Column(db.Integer, db.ForeignKey('todolists.id'), nullable=False)
const todo_item_input = document.getElementById('description');
document.getElementById('create_todo_box_button').onsubmit = function(e) {
e.preventDefault();
const desc = todo_item_input.value;
todo_item_input.value = '';
fetch('/todos/create', {
method: 'POST',
body: JSON.stringify({
'description': desc,
'list_id': {{ active_list.id }}
}),
headers: {
'Content-Type': 'application/json'
}
})
.then(response => response.json())
.then(jsonResponse => {
const li = document.createElement('li');
const checkbox = document.createElement('input');
checkbox.className = 'check-completed';
checkbox.type = 'checkbox';
checkbox.setAttribute('data-id', jsonResponse.id);
li.appendChild(checkbox);
const text = document.createTextNode(' ' + jsonResponse.description);
li.appendChild(text);
const deleteButton = document.createElement('button');
deleteButton.className = 'delete-button';
deleteButton.setAttribute('data-id', jsonResponse.id);
deleteButton.innerHTML = '✗';
li.appendChild(deleteButton);
document.getElementById('todos').appendChild(li);
document.getElementById('error').className = 'hidden';
})
.catch(function() {
console.error('Error occured');
document.getElementById('error').className = '';
})
}
#app.route('/todos/create', methods=['POST'])
def create_todo():
error = False
body = {}
try:
description = request.get_json()['description']
list_id = request.get_json()['list_id']
todo = Todo(description=description)
active_list = TodoList.query.get(list_id)
todo.list = active_list
db.session.add(todo)
db.session.commit()
body['description'] = todo.description
except:
error = True
db.session.rollback()
print(sys.exc_info())
finally:
db.session.close()
if not error:
return jsonify(body)
else:
abort(500)
Web app view
Error
I would try to put a more verbose exception in your code. Also, I think you can have the error check inside your try...accept
#app.route('/todos/create', methods=['POST'])
def create_todo():
body = {}
try:
description = request.get_json()['description']
list_id = request.get_json()['list_id']
todo = Todo(description=description)
active_list = TodoList.query.get(list_id)
todo.list = active_list
db.session.add(todo)
db.session.commit()
body['description'] = todo.description
return jsonify(body)
except Exception as e:
print(e) # ------- tracing
db.session.rollback()
print(sys.exc_info())
finally:
db.session.close()
abort(500)