Flask-Socket, key error when selecting rooms - javascript

Please forgive me if i posted it in bad way, but i dont have any idea where is the mistake.
Im doing a small chat with five rooms using Flask-Socket and SocketIO. I set rooms like this:
ROOMS = ["waiting room", "food", "news", "games", "coding"]
Then i put them to html:
#app.route("/chat", methods=['GET', 'POST'])
#login_required
def chat():
return render_template('chat.html', username=current_user.username, rooms=ROOMS)
And on template:
{%for room in rooms%}
<p class="select-room"> {{ room }}</p>
{% endfor %}
The problem is when i try to send message only to room where i am by:
#socketio.on('message')
def message(data):
time_stamp = time.strftime('%b-%d %I:%M%p', time.localtime())
send({'msg': data['msg'], 'username': data['username'], 'time_stamp':time_stamp}, room=data['room'])
and from client:
document.querySelector('#send-message').onclick = () =>{
socket.send({'msg': document.querySelector('#user_message').value,
'username': username, 'room': room});
}
It makes me key error:
send({'msg': data['msg'], 'username': data['username'], 'time_stamp':time_stamp}, room=data['room'])
KeyError: 'room'
it also happens when i trying to switch rooms(leave one and connect other using this):
function leaveRoom(room) {
socket.emit('leave', {'username': username, 'room': room});
document.querySelectorAll('.select-room').forEach(p => {
p.style.color = "black";
});
}
function joinRoom(room) {
socket.emit('join', {'username' : username, 'room' : room});
// Clear message area
document.querySelector('#display-message-section').innerHTML = '';
};
For room select i use:
document.querySelectorAll('.select-room').forEach(p => {
p.onclick = () => {
let newRoom = p.innerHTML
// Check if user already in the room
if (newRoom == room) {
msg = `You are already in ${room} room.`;
printSysMsg(msg);
} else {
leaveRoom(room);
joinRoom(newRoom);
room = newRoom;
};
};
});
Where im making a mistake?
The full code is here:
https://pastebin.com/QXiBQG2u
https://pastebin.com/zfEtV4ZX
https://pastebin.com/wfkqNjf9

Related

Adding a 'show all' to django search with js/ajax if results > 5

I have a simple django search functionality using js/ajax. I want to add functionality so that when the queryset is greater than 5 a 'Show all' href will appear in the search results and it will redirect to a page with all the queryset.
This is for the case when a queryset returns a large number of results, rather than have them in one big box.
I thought I could just add a dictionary to my queryset, e.g. data.append({'pk': <add number to querset>, 'name': 'Show all results'}) but then I think this will mess around with the js logic with the forEach loop.
I'd want each search result up to 5 to link to the detail view, but then the last one should link to a completely different view.
I'm not sure what the best option is here.
My search in views.py:
def search_results(request):
"""
Handles search logic
"""
if request.is_ajax():
res = None
quote = request.POST.get('quote')
qs = Quote.objects.filter(name__icontains=quote)
if len(qs) > 0 and len(quote) > 0:
data = []
for pos in qs:
item = {
'pk': pos.pk,
'name': pos.name,
'image': str(pos.image.url)
}
data.append(item)
res = data
else:
res = 'No quotes found...'
return JsonResponse({'data': res})
return JsonResponse({})
and main.js that handles loading the search results:
const url = window.location.href
const searchForm = document.getElementById('search-form')
const searchInput = document.getElementById('search-input')
const resultsBox = document.getElementById('results-box')
const csrf = document.getElementsByName('csrfmiddlewaretoken')[0].value
const sendSearchData = (quote) => {
$.ajax({
type: 'POST',
url: 'search/',
data: {
'csrfmiddlewaretoken': csrf,
'quote': quote,
},
success: (res)=> {
console.log(res.data)
const data = res.data
let length = data.length
console.log(length)
if (Array.isArray(data)) {
resultsBox.innerHTML = ""
data.forEach(quote=> {
resultsBox.innerHTML += `
<a href="${url}${quote.pk}" class="item">
<div class="row mt-2 mb-2">
<div class="col-2">
<img src="${quote.image}" class="quote-img">
</div>
<div class="col-10">
<h5>${quote.name}</h5>
<p class="text-muted">${quote.seller}</p>
</div>
</div>
</a>
`
})
} else {
if (searchInput.value.length > 0) {
resultsBox.innerHTML = `<b>${data}</b>`
} else {
resultsBox.classList.add('not-visible')
}
}
error: (err)=> {
console.log(err)
}
}
})
}
searchInput.addEventListener('keyup', e=>{
console.log(e.target.value)
if (resultsBox.classList.contains('not-visible')){
resultsBox.classList.remove('not-visible')
}
sendSearchData(e.target.value)
})

How to display the values of the attributes of the data queried and retrieved by Ajax call in django

I am trying to query the database based on what the user has clicked on the page and display the data retrieved by it without refreshing the page. I am using Ajax for this. Let me show you the codes
html
<label for="landacq" class="civil-label">Land Acquisation Cases</label>
<input class="civil-category" type="radio" name="civil-cat" id="landacq" value="land acquisation" hidden>
<label for="sc" class="civil-label">Supreme Court</label>
<input class="civil-court" type="radio" name="civil-court" id="sc" value="supreme court" hidden>
<label for="limitation" class="civil-label">Limitation</label>
<input class="civil-law-type" type="radio" name="civil-law-type" id="limitation" value="limitation" hidden>
js
for (i = 0; i < lawTypeInput.length; i++) {
lawTypeInput[i].addEventListener("click", (e) => {
e.preventDefault();
cat = civilCatval;
court = civilCourtval;
lawT = civillawTypeval;
console.log("this is from ajax : ", cat, court, lawT);
$.ajax({
type: "POST",
headers: { "X-CSRFToken": csrftoken },
mode: "same-origin", // Do not send CSRF token to another domain.
url: "civil",
data: {
"cat[]": civilCatval,
"court[]": civilCourtval,
"lawT[]": civillawTypeval,
},
success: function (query) {
showCivilQ(query);
// console.log(data);
},
error: function (error) {
console.log(error);
},
});
});
}
function showCivilQ(query) {
q.textContent = query;
console.log(query);
}
So here for example, if the user the click the radio button in the html, the values are grabbed by in js file and then sent to the url mentioned as a POST request. There these values are use to filter the database and return the objects like this
views.py
def civil_home(request):
if request.is_ajax():
get_cat = request.POST.get('cat[]')
get_court = request.POST.get('court[]')
get_lawT = request.POST.get('lawT[]')
query = Citation.objects.filter(law_type__contains ='civil' ,sub_law_type__contains= get_cat, court_name__contains = get_court, law_category__contains = get_lawT)
return HttpResponse(query)
else:
subuser = request.user
subscription = UserSubscription.objects.filter(user = subuser, is_active = True)
context = {
'usersub': subscription,
}
return render(request, 'civil/civil_home.html', context)
This is the result I am getting which is correct.
My Question is these objects contain attributes having some values in for eg, title, headnote etc. How can I display these attributes in the html rather than displaying the object names returned as shown in the Image like title of the citation, headnote of the citation etc
A solution could be to return a json object instead of the query resultset; because Ajax works well with json
You need a function that translates a Citation object into a dictionary (change it based on your real attributes). All elements must be translated into strings (see date example)
def citation_as_dict(item):
return {
"attribute1": item.attribute1,
"attribute2": item.attribute2,
"date1": item.date.strftime('%d/%m/%Y')
}
This dictionary must be translated into a json through import json package
def civil_home(request):
if request.is_ajax():
get_cat = request.POST.get('cat[]')
get_court = request.POST.get('court[]')
get_lawT = request.POST.get('lawT[]')
query = Citation.objects.filter(law_type__contains ='civil' ,sub_law_type__contains= get_cat, court_name__contains = get_court, law_category__contains = get_lawT)
response_dict = [citation_as_dict(obj) for obj in query]
response_json = json.dumps({"data": response_dict})
return HttpResponse(response_json, content_type='application/json')
else:
subuser = request.user
subscription = UserSubscription.objects.filter(user = subuser, is_active = True)
context = {
'usersub': subscription,
}
return render(request, 'civil/civil_home.html', context)
In your HTML page you should be able to parse the response as a normal JSON object
I figured out another way to do it, which is giving me the required results too.
Here I am filtering the values of the query, and then converting it to a list and passing it as a JsonResponse
views.py
def civil_home(request):
if request.method == "POST" and request.is_ajax():
get_cat = request.POST.get('cat[]')
get_court = request.POST.get('court[]')
get_lawT = request.POST.get('lawT[]')
query = Citation.objects.values().filter(law_type__contains ='civil' ,sub_law_type__contains= get_cat, court_name__contains = get_court, law_category__contains = get_lawT)
result = list(query)
return JsonResponse({"status": "success", "result": result})
else:
subuser = request.user
subscription = UserSubscription.objects.filter(user = subuser, is_active = True)
context = {
'usersub': subscription,
}
return render(request, 'civil/civil_home.html', context)
And then I am recieving the reponse here and iterrating over it to print the attributes in the html
js
for (i = 0; i < lawTypeInput.length; i++) {
lawTypeInput[i].addEventListener("click", (e) => {
e.preventDefault();
cat = civilCatval;
court = civilCourtval;
lawT = civillawTypeval;
console.log("this is from ajax : ", cat, court, lawT);
$.ajax({
type: "POST",
headers: { "X-CSRFToken": csrftoken },
mode: "same-origin", // Do not send CSRF token to another domain.
url: "civil",
data: {
"cat[]": civilCatval,
"court[]": civilCourtval,
"lawT[]": civillawTypeval,
},
success: function (response) {
console.log(response.result);
civilData = response.result;
if ((response.status = "success")) {
$("#queryResult").empty();
for (i = 0; i < civilData.length; i++) {
$("#queryResult").append(
`
${civilData[i].title}
<p>${civilData[i].headnote}</p>
`
);
}
} else {
$("#queryResult").empty();
$("#queryResult").append(
`
<p>No Citations Found</p>
`
);
}
},
error: function (error) {
console.log(error);
},
});
});
}
A csrf_token can be mentioned at the top of the html page and then it can be passed in the header to avoid any conflict.

Get current logged in user in JSON Format from views.py

I'm trying to build a follow and unfollow button, I want to show the button only For any other user who is signed in, a user should not be able to follow themselves.
How can I return from my views.py the currently logged-in user as a JSON format to my JS file?
I'm building the button in the JavaScript file and not in the template, I tried to return as JSON format but didn't succeed
views.py
def display_profile(request, profile):
try:
profile_to_display = User.objects.get(username=profile)
profile_to_display_id = User.objects.get(pk=profile_to_display.id)
except User.DoesNotExist:
return JsonResponse({"error": "Profile not found."}, status=404)
# Return profile contents
if request.method == "GET":
return JsonResponse(profile_to_display.profile.serialize(), safe=False)
else:
return JsonResponse({
"error": "GET or PUT request required."
}, status=400)
models.py
from django.contrib.auth.models import AbstractUser
from django.db import models
class User(AbstractUser):
pass
class NewPost(models.Model):
poster = models.ForeignKey("User", on_delete=models.PROTECT, related_name="posts_posted")
description = models.TextField()
date_added = models.DateTimeField(auto_now_add=True)
likes = models.IntegerField(default=0)
def serialize(self):
return {
"id": self.id,
"poster": self.poster.username,
"description": self.description,
"date_added": self.date_added.strftime("%b %d %Y, %I:%M %p"),
"likes": self.likes
}
class Profile(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE)
following = models.ManyToManyField(User, blank=True, related_name="following")
followers = models.ManyToManyField(User, blank=True, related_name="followers")
def serialize(self):
return {
"profileID": self.user.id,
"following": int(self.following.all().count()),
"followers": int(self.followers.all().count()),
}
index.js
function load_user_info(user_clicked_on){
document.querySelector('#page-view').style.display = 'none';
document.querySelector('#posts-view').style.display = 'none';
document.querySelector('#show-posts').style.display = 'none';
document.querySelector('#load-profile').style.display = 'block';
fetch(`/profile/${user_clicked_on}`)
.then(response => response.json())
.then(profile => {
const profile_element = document.createElement('div');
const followers = document.createElement('div');
const following = document.createElement('div');
const follow_button = document.createElement('button');
followers.innerHTML = 'Followers: ' + profile.followers;
following.innerHTML = 'Following: ' + profile.following;
if (profile.profileID == ?? ){
follow_button.innerHTML = 'Sameuser';
}else{
follow_button.innerHTML = 'Not same user';
}
profile_element.appendChild(followers);
profile_element.appendChild(following);
profile_element.appendChild(follow_button);
profile_element.classList.add('profile_element');
document.querySelector('#user-profile').appendChild(profile_element);
});
document.querySelector('#user-profile').innerHTML = `<h3>${user_clicked_on.charAt(0).toUpperCase() + user_clicked_on.slice(1)} Profile</h3>`;
}
I think all you need is the detail of the logged in user right?
may be you can get it from the request object by using
{{request.user}}
this returns the logged user instance
{{request.user.username}} {{request.user.email}}
this returns username and email
I dont know if you can directly use it in javascript , but you can kind of save this in template using a hidden field lik
<input type="hidden" value="{{request.user.username}}" id='user_detail'>
and grab it using id selector (getElementById, or jquery)
$('#user_detail').val()

express validator; error variable not defined within ejs

I have an issue that I've been trying to figure out for some time now, and was hoping someone may be able to point me in the right direction.
My variable (error) that I'm passing along in the res.render{} object, is unusable within my layouts file. The issue is logging as a reference error.
If I take the ejs code out, my error properly logs to the terminal; I'm just unable to use it within my layout file.
Following is the layout.ejs code, in part.
<% for(var i = 0; i < errors.length - 1; i++){ %>
<li> <%= errors[i] %> </li>
<% } %>
and POST...
//POST route
app.post('/articles/add', function(req, res){
req.assert('title', 'Enter title').notEmpty();
req.assert('author', 'Enter author').notEmpty();
req.assert('body', 'Enter an article').notEmpty();
//get errors
req.getValidationResult().then(function(err){
if(err.isEmpty()){
console.log(err);
res.render('add_article',{
title: 'Add Article',
errors: err // <-
});
}
else {
let article = new Article();
article.title = req.body.title;
article.author = req.body.author;
article.body = req.body.body;
article.save(function(e){
if(e) {console.log(e)}
else{
req.flash('success', 'Article Added');
res.redirect('/');
}
});
}
});
Thanks for any help.
As per I see there are two bugs within your code. First, the if(err.isEmpty()), when err is empty then you are trying to send err!! And another is use of req.getValidationResult(), it will resolve with result object not an array. Below is the code that might help.
//POST route
app.post('/articles/add', function(req, res){
req.assert('title', 'Enter title').notEmpty();
req.assert('author', 'Enter author').notEmpty();
req.assert('body', 'Enter an article').notEmpty();
//get errors
req.getValidationResult().then(function(result){
if(!err.isEmpty()){
console.log(err);
res.render('add_article',{
title: 'Add Article',
errors: result.array() // <-
});
}
else {
let article = new Article();
article.title = req.body.title;
article.author = req.body.author;
article.body = req.body.body;
article.save(function(e){
if(e) {console.log(e)}
else{
req.flash('success', 'Article Added');
res.redirect('/');
}
});
}
});
And the result.array() will produce something like this:
[
{param: "email", msg: "required", value: "<received input>"},
{param: "email", msg: "valid email required", value: "<received input>"},
{param: "password", msg: "6 to 20 characters required", value: "<received input>"}
]

Customer is not getting created in braintree (js+python)

I am getting error while creating customer
AuthenticationError at /vissa/assign-plan/
My js
<script src="https://js.braintreegateway.com/v2/braintree.js"></script>
{% if cust %}
$(document).ready(function() {
braintree.setup("{{ client_token }}", "dropin", {
container: "checkout",
form: "checkoutForm"
});
$("#submitPayment").on("click", function () {
$("button").off("click");
$("a").off("click");
$('body').off("click");
var btn = $(this).button("loading")
setTimeout(function () {
btn.button('reset');
}, 3500)
});
});
</script>
{% endif %}
And client token i am trying to get in context processor.
def payment_data(request):
try:
userone = UserProfile.objects.get(user=request.user)
indi_user = IndividualUser.objects.get(user_profile=userone)
plan = int(indi_user.selected_plan)
amount = int(plan)
except:
plan = None
amount = None
try:
merchant_obj = UserMerchantId.objects.get(user=request.user)
cust = True
merchant_customer_id = merchant_obj.customer_id
print merchant_customer_id
client_token = braintree.ClientToken.generate({
"customer_id": merchant_customer_id
})
except:
cust = False
client_token = None
try:
custom = Transaction.objects.filter(user=request.user)[0]
paid = custom.success
except:
paid = False
return {'cust':cust, "plan":plan,"amount": amount, "paid": paid,"client_token":client_token} #"plan": plan}
but i am getting above error.
if i tried
client_token = braintree.ClientToken.generate()
getting authentication error.
I am not getting how to create client token in django.
is there a way to create client token without customer_id?
Creating customer.
def new_user_receiver( instance, *args, **kwargs):
try:
merchant_obj = UserMerchantId.objects.get(user=instance)
except:
new_customer_result = braintree.Customer.create({
"first_name": instance.first_name,
"last_name": instance.last_name,
"email": instance.email,
"phone": instance.get_profile().telephone_number
})
if new_customer_result.is_success:
merchant_obj, created = UserMerchantId.objects.get_or_create(user=instance)
merchant_obj.customer_id = new_customer_result.customer.id
merchant_obj.save()
print """Customer created with id = {0}""".format(new_customer_result.customer.id)
else:
print "Error: {0}".format(new_customer_result.message)
It worked after making the change
import braintree
braintree.Configuration.configure(braintree.Environment.Production,
merchant_id=settings.BRAINTREE_MERCHANT_ID,
public_key=settings.BRAINTREE_PUBLIC_KEY,
private_key=settings.BRAINTREE_PRIVATE_KEY)
in production instead of "Sandbox" need to use "Production".

Categories

Resources