Get latest message in a chat application - Django - javascript

I've coded a chat application with Django Channels and it's working fine. The only issue is getting the latest messages and displaying them when coming back to the chat app. This is resolved for the moment by adding a function that gets older messages (old_messages()) in the chatSocket.onopen = function(e) part of the js file. The only problem now is: when user A refreshes the page of chat, the other user (user B) gets the older messages two times (since the connexion is closed and open for a second time by user A). Any idea how to avoid this problem ?
Here is a part of js file :
var chatSocket = new ReconnectingWebSocket(
'ws://' + window.location.host +
'/ws/chat/' + discussion_slug + '/');
chatSocket.onopen = function(e) {
console.log("open",e)
old_messages();
};
function old_messages() {
chatSocket.send(JSON.stringify({'command': 'old_messages',
'discussion_slug': discussion_slug }));
};
In consumers.py:
def old_messages(self,data):
discussion_slug = Discussion.objects.get(slug=data['discussion_slug'])
last_msgs = discussion_slug.messages.all()[:15]
content = {
'command': 'old',
'message': self.many_msg_to_json(last_msgs)
}
return content
async def receive(self, text_data):
data = json.loads(text_data)
content = self.commands[data['command']](self,data)
await self.channel_layer.group_send(
self.room_group_name,
{
'type': 'chat_message',
'message': content
}
)
Thanks!

Have you tried ModelName.objects.all().reverse()? The sorting will be latest first so you might not need old_messages().
If this doesn’t help, let me know. I’ll take a better look once I get on my pc

Related

Run a JS script conditionally from a web source

I am making a website that grabs data from an API. The API essentially consists of a script normally ran as such
<script type="text/javascript" src="https://www.fxblue.com/users/dynascalp_demo/overviewscript"></script>
it will simply create an array and push the data I need from it, like this:
if (!document.MTIntelligenceAccounts) document.MTIntelligenceAccounts = new Array(); document.MTIntelligenceAccounts.push({ "userid": "dynascalp_demo","balance": 9275.95,"equity": 9275.95,"closedProfit": -724.05,"floatingProfit": 0,"freeMargin": 9275.95,"totalDeposits": 10000,"totalWithdrawals": 0,"totalBankedGrowth": -7.24,"monthlyBankedGrowth": -0.67,"weeklyBankedGrowth": -0.16,"dailyBankedGrowth": -0.03,"bankedProfitFactor": 0.66,"deepestValleyCash": -819.04,"deepestValleyPercent": -8.19,"troughInBalance": 9175.79,"peakInBalance": 10020.11,"historyLengthDays": 331,"averageTradeDurationHours": 2.17,"worstDayPercentage": -1.44,"worstWeekPercentage": -2.32,"worstMonthPercentage": -4.31,"tradesPerDay": 2.5,"totalClosedPositions": 589,"totalOpenPositions": 0,"bankedWinningTrades": 382,"bankedLosingTrades": 207,"bankedBreakEvenTrades": 0,"bankedWinPips": 1486.3,"bankedLossPips": -1604.6,"initialDeposit": 10000,"totalBankedPips":-118.3,"totalOpenPips":0,"peakPercentageLossFromOutset": -8.24,"riskReturnRatio": -1.21,"openAndPendingOrders": []});
My idea is to run this code conditionally, in another, bigger script. I will query my database and check whether the data is already in the database. If it is, then skip the request altogether and send the data from the database through an ajax request handled by the server, which will return a JSON. If it isn't or the data has expired, meaning it has not been updated for at least a day, it should grab the data from the API and update the database. This is done by the front-end as there is no Node.js support in the back-end.
The only thing I'm missing is how I should execute this script from mine, instead of calling it directly in the HTML.
For example, Fetch() does not work. I believe the request is malformed, or it is not the type of request it expects. Unexpected end of input is thrown and the request does not succeed.
This code should result in a number being shown
function fxBlue_retrieveAPI() {
document.MTIntelligenceAccounts = new Array();
const url = "https://www.fxblue.com/users/dynascalp_demo/overviewscript";
//var fxblue_API_Names = ["dynascalp_demo", "fxprogoldrobot", "fxprosilverrobot", "forex_gump_ea"];
var varNames = ["totalDeposits", "balance", "totalBankedGrowth", "monthlyBankedGrowth", "deepestValleyPercent", "historyLengthDays"];
var experts = [];
var s = document.createElement("script");
s.setAttribute("type", "text/javascript");
s.setAttribute("src", url);
document.body.appendChild(s);
for (var i = 0; i < document.MTIntelligenceAccounts.length; i++) {
experts.push({ name: document.MTIntelligenceAccounts[i].userid, id: i });
if (document.getElementById(experts[i].name + varNames[0])) { document.getElementById(experts[i].name + varNames[0]).innerHTML = document.MTIntelligenceAccounts[experts[i].id].totalDeposits; }
if (document.getElementById(experts[i].name + varNames[1])) { document.getElementById(experts[i].name + varNames[1]).innerHTML = document.MTIntelligenceAccounts[experts[i].id].balance; }
if (document.getElementById(experts[i].name + varNames[2])) { document.getElementById(experts[i].name + varNames[2]).innerHTML = document.MTIntelligenceAccounts[experts[i].id].totalBankedGrowth + "%" };
if (document.getElementById(experts[i].name + varNames[3])) { document.getElementById(experts[i].name + varNames[3]).innerHTML = document.MTIntelligenceAccounts[experts[i].id].monthlyBankedGrowth };
if (document.getElementById(experts[i].name + varNames[4])) { document.getElementById(experts[i].name + varNames[4]).innerHTML = document.MTIntelligenceAccounts[experts[i].id].deepestValleyPercent + "%" };
if (document.getElementById(experts[i].name + varNames[5])) { document.getElementById(experts[i].name + varNames[5]).innerHTML = document.MTIntelligenceAccounts[experts[i].id].historyLengthDays };
}
}
<script type="text/javascript" src="/cdn-cgi/scripts/API/jquery-3.1.1.min.js" async></script>
<script type="text/javascript" src="/cdn-cgi/scripts/API/test.js"></script>
<body onload="fxBlue_retrieveAPI()">
<h3>Total banked growth data example</h3>
<p id="dynascalp_demototalBankedGrowth"></p>
</body>
Assuming (or hoping) that you won't experience CORS problems with your data source (here at SO it is not possible to reach the source), you could do something like this to get to the actual contents of the script file:
const actualText=`if (!document.MTIntelligenceAccounts) document.MTIntelligenceAccounts = new Array();\ndocument.MTIntelligenceAccounts.push({\n"userid": "dynascalp_demo","balance": 9275.95,"equity": 9275.95,"closedProfit": -724.05,"floatingProfit": 0,"freeMargin": 9275.95,"totalDeposits": 10000,"totalWithdrawals": 0,"totalBankedGrowth": -7.24,"monthlyBankedGrowth": -0.67,"weeklyBankedGrowth": -0.16,"dailyBankedGrowth": -0.03,"bankedProfitFactor": 0.66,"deepestValleyCash": -819.04,"deepestValleyPercent": -8.19,"troughInBalance": 9175.79,"peakInBalance": 10020.11,"historyLengthDays": 331,"averageTradeDurationHours": 2.17,"worstDayPercentage": -1.44,"worstWeekPercentage": -2.32,"worstMonthPercentage": -4.31,"tradesPerDay": 2.5,"totalClosedPositions": 589,"totalOpenPositions": 0,"bankedWinningTrades": 382,"bankedLosingTrades": 207,"bankedBreakEvenTrades": 0,"bankedWinPips": 1486.3,"bankedLossPips": -1604.6,"initialDeposit": 10000,"totalBankedPips":-118.3,"totalOpenPips":0,"peakPercentageLossFromOutset": -8.24,"riskReturnRatio": -1.21,"openAndPendingOrders": []});`;
// fetch("https://www.fxblue.com/users/dynascalp_demo/overviewscript")
fetch("https://jsonplaceholder.typicode.com/users/3") // (some dummy data source for demo purposes only)
.then(r=>r.text())
.then(text=>{ text=actualText; // mimmic the text received from www.fxblue.com ...
obj=JSON.parse(text.replace(/(?:.|\n)*push\(/,"").replace(/\);$/,""))
console.log(obj)
})
It is then up to you to decide whether you want to use the data or not.
Whatever you do, it is important that the action happens in the callback function of the last . then() call. Alternatively you can of course also work with an async function and use await inside.
My idea is to run this javascript code conditionally, by querying my database
For this you could do an jquery ajax call, and act based on the response you get. I recommend using jquery for the ajax call. Here is the jquery ajax call where you pass whatever data is necessary to the controller.
$.ajax({
type: "GET",
url: "/ControllerName/ActionName",
data: { data: UserIdOrSomething },
success: function(response) {
// you can check the response with an if, and implement your logic here.
}
});
You can place this ajax call in the document.ready function to automatically call it whenever the page loads.
$( document ).ready(function() {
// place the above code here.
});
As an example, here is how an asp.net core controller action would look like that would handle this ajax call;
[HttpGet("ActionName/{data:string}")]
public IActionResult ActionName(string data) // parameter name should match the one in jquery ajax call
{
// do stuff. query your database etc.
var response = "the response";
return Json(response);
}
finally, keep in mind handling sensitive data in javascript is generally not a good idea, as the javascript code is open to everyone. For example, in this case, you will be giving out a way for people to check if a user exists in your database, which could be problematic. I would suggest using guid as id for the users table if possible, which may or may not be useful to mitigate the dangers depending on how you query the database.

mailto client does not work in mobile devices and blocks the popup

I am trying to add a mailto button to send an email using email client
Here is my code:
clickEmail(e) {
let storyId = this.refs.storyToEmail.getAttribute('id');
if (storyId != undefined) {
let urlToSend = this.createURL(storyId) + "?ref=emailShare";
let subjectLine = "Shared story - " + this.props.headline;
let hrefValue = "mailto:?subject=".concat(subjectLine, "&body=", "I thought you might find this interesting:%0D%0A %0D%0A", urlToSend, "%0D%0A %0D%0AConnecting Communitie %0D%0A %0D%0A");
let email = this.refs.storyToEmail;
email.href = hrefValue;
return email.href;
}
}
However this works for me and almost all desktops and not working on many mobile devices.
After searching I noticed it needs permission from the browser as follows:
https://blog.hubspot.com/marketing/set-gmail-as-browser-default-email-client-ht
But the issue is I cannot find anyway to do the setting as suggested in the link for mobile(chrome)?
Can anyone shed light on this?

casperjs test register form

I have a form inside my page for user that want to register inside the site. After registration I insert user inside database create an activation key and send an email, until user doesn't click the link inside the email with the activation key he can't login inside the site.
With CasperJS I would like to test this functionality, the fillForm is ok but how can I test the activation key?
I have thought to create an input hidden with the activation key (only if is in TEST mode not i production!) and retrieve this value with getFieldValue function.
Is this the right way to do it or there is a better mode to do?
this is my casperjs test to retrieve activation key after registration (I create an input hidden with the activation code):
view = 'users/registered';
casper
.start(webroot + view)
.then(function() {
__utils__.log("Retrieving data from input activation-key");
activationKey = __utils__.getFieldValue('activation-key');
}).then(function() {
__utils__.log("Activating account with the key " + activationKey);
}).then(function(){
this.evaluate(function() {
__utils__.log("Activating account with the key " + activationKey);
window.location = webroot + 'users/activate/' + activationKey;
});
}).then(function(){
this.echo(this.getCurrentUrl());
});
casper.run(function() {
this.echo('test registeration successful!').exit();
});
casper.viewport(page.width, page.height);
casper.test.done();
I managed to do what i wanted with registration, it could help you : CasperJS- Register on a site and validate the mail sent on Gmail -for both slimer and phantom-
And before i did some scraping with an activation code too, for manual activation (pure JS, no jQuery here, i didn't want to inject JQuery on gmail DOM environment) :
this.waitForSelector("div.msg",function(){
this.test.assertSelectorHasText("a","Activation message");
//var code declared in the main scope
code = this.evaluate(function(){
var strongs = document.getElementsByTagName('strong')
,i
,l = strongs.length
;
for (i = 0; i < l; ++i) {
if(strongs[i].textContent === "activation code:"){
//get back the code in DOM context -> split to get back only what I want
return (strongs[i].parentNode.textContent.split(' ')[2]);
}
}
});
this.echo("code : " + code,"INFO");
});

Display summary of choices in JS

this is my first time here as a poster, please be gentle! I have zero knowledge of JS (yet, working on it) but am required to do some JS anyway. Here's my problem. I got some code (not mine) allowing a user to select multiple choices. I found the function that gathers these choices and store them
function getProductAttribute()
{
// get product attribute id
product_attribute_id = $('#idCombination').val();
product_id = $('#product_page_product_id').val();
// get every attributes values
request = '';
//create a temporary 'tab_attributes' array containing the choices of the customer
var tab_attributes = [];
$('#attributes select, #attributes input[type=hidden], #attributes input[type=radio]:checked').each(function(){
tab_attributes.push($(this).val());
});
// build new request
for (var i in attributesCombinations)
for (var a in tab_attributes)
if (attributesCombinations[i]['id_attribute'] === tab_attributes[a])
request += '/'+attributesCombinations[i]['group'] + '-' + attributesCombinations[i]['attribute'];
$('#[attsummary]').html($('#[attsummary]').html() + attributesCombinations[i]['group']+': '+attributesCombinations[i]['attribute']+'<br/>')// DISPLAY ATTRIBUTES SUMMARY
request = request.replace(request.substring(0, 1), '#/');
url = window.location + '';
// redirection
if (url.indexOf('#') != -1)
url = url.substring(0, url.indexOf('#'));
// set ipa to the customization form
$('#customizationForm').attr('action', $('#customizationForm').attr('action') + request);
window.location = url + request;
}
I need to make a simple display summary of these choices. After quite a bit of searching and findling, I came with the line with the DISPLAY SUMMARY comment, this one:
$('#[attsummary]').html($('#[attsummary]').html() + attributesCombinations[i]['group']+': '+attributesCombinations[i]['attribute']+'<br/>')
In the page where I want those options, I added an empty div with the same ID (attsummary):
<div id="attsummary"></div>
Obviously, it is not working. I know I don't know JS, but naively I really thought this would do the trick. May you share with me some pointers as to where I went wrong?
Thank you very much.
Correct form of the line it isn't working for you:
$('#attsummary').html($('#attsummary').html() + attributesCombinations[i]['group']+': '+attributesCombinations[i]['attribute']+'<br/>')

Email Client in Android using phonegap

I am tryin to use an email client in my application. I am using plugins for the same.
The code that am using is
function tellAFriend()
{
var succcallback = function(result) {
//alert("Mail sent");
};
var errorcallback = function(e) {
//alert("error:" + e);
};
var body1='Hi,\n I came across this new app and thought you might be interested';
var body2=body1+'.You can check it out at \n';
var href1='market';
var anchortext;
anchor1 = document.createElement("a");
anchortext = document.createTextNode('Test');
anchor1.appendChild(anchortext);
anchor1.href=href1;
anchor1.setAttribute('href','https://market.android.com/details?id=com.unisys.cps&feature=search_result#?t=W251bGwsMSwxLDEsImNvbS51bmlzeXMuY3BzIl0');
//alert(anchor1);
window.plugins.webintent.tellAFriend({
mailSubject : 'CPS Mobile App',
mailRecepients: '',
mailBody: href1
//mailBody: 'Hi,\n I came across this new app and thought you might be interested.You can check it out at \nhttps://market.android.com/details?id=com.unisys.cps&feature=search_result#?t=W251bGwsMSwxLDEsImNvbS51bmlzeXMuY3BzIl0 \nor \nhttps://www.cargoportalservices.com/lmsweb/DownloadCPSMobileApp.jsp'
}, succcallback, errorcallback);
}
Thats the function. In the function, the mail body that i have provided needs to be a text. but I need to pass a hyoerlink to it. Meaning, when the email client opens up, the text should be displayed as hyperlinks.
Any suggestions on how that can be achieved.

Categories