Roblox is a game, and you can also make groups (Like Clans in other games).
I am making a program that goes through these group pages, and checks to see if they have an owner. If there is not an owner, then join the group to become the owner.
I am doing this to collect some data from non-owned groups.
Lastly, I'd like it to leave the group once the data is collected.
Here is the "Join Group" button:
<div id="ctl00_cphRoblox_JoinGroup" class="btn-neutral btn-large" onclick="__doPostBack('JoinGroupDiv', 'Click');" style="margin-top: 10px;">
Join Group
</div>
Here is the snippet of code I've tried:
import requests
s = requests.session()
Join_Group = dict('JoinGroupDiv', 'Click')
s.post('http://www.roblox.com/Groups/Group.aspx?gid=40', data=Join_Group)
I get the following error:
Traceback (most recent call last):
File "C:\Users\User\Desktop\Group.py", line 18, in <module>
Join_Group = dict('JoinGroupDiv', 'Click')
TypeError: dict expected at most 1 arguments, got 2
I'm pretty sure that I'm not supposed to be sending a Post request to the page, as to join the group, it does an onClick event.
EDIT 1:
Here is my updated code:
import requests
s = requests.session()
Join_Group = {"__EVENTTARGET":"ctl00_cphRoblox_JoinGroup", "__EVENTARGUMENT":"JoinGroupDiv"}
s.post('http://www.roblox.com/Groups/Group.aspx?gid=40', data=Join_Group)
But I don't quite know what to pass as the eventArguement. I don't get any errors, but when I load the page in Google Chrome it doesn't say I've tried to join.
EDIT 2:
I've also tried this:
import requests
s = requests.session()
Join_Group = {"__EVENTTARGET":"ctl00_cphRoblox_JoinGroup", "__EVENTARGUMENT":{"JoinGroupDiv","Click"}}
s.post('http://www.roblox.com/Groups/Group.aspx?gid=40', data=Join_Group)
EDIT 3:
So what I have here is the updated Join_Group with all of the necessary fields, but not all of the information. I don't know where to get the information.
Join_Group = {"__EVENTTARGET":"JoinGroupDiv", "__EVENTARGUMENT":"Click", "__LASTFOCUS":"", "__VIEWSTATE":"a lot of mumbo jumbo", "__VIEWSTATEGENERATOR":"It is 3D1CCC47 but that might change per post", "__EVENTVALIDATION":"some more mumbo jumbo"}
Here is a correct sample POST, but I don't know where it gets that information for __VIEWSTATE, __VIEWSTATEGENERATOR, and __EVENTVALIDATION.
__EVENTTARGET=JoinGroupDiv&__EVENTARGUMENT=Click&__LASTFOCUS=&__VIEWSTATE=fM9l9%2BTw8z%2FRNbMArorqQ7HQ2w3soDiNp5gJOc5sNNQPEzEzApHiWLOHghGcAriUGv6pCVCi15my4%2BUxUozLVQyGx%2Fiq%2FU9BxRdN80kWJgMyiIyZYtSnfsvlFkqmrHaLIMNKag4eYwnKi5K3TP6JpP5xAxfNIOjekh6vpSa84YVL6eOwPsh5vqlHSN9VjFlwjA1r7AJVZkoeVliUz7vpK1f7DM6lDnOWBtFaAc66xxe2SIoLcjdMlfrVJpJADRjLTEfLp6PNARua3FLJKDezN7WOekGOlSIXHHrzAFlyMY0uZflFykzc9E3zE%2FldijdHWJnIoBVNW1c7fl2ehrbbv%2BAQWpeWqMagkuGNWOmFD6SHPixWLVNgNMlVLXrVKtLEMp3jmXLR40vqdv3bpCkJTLqA9M1XpKsBJlX5szlJlqJzYleD8NncUA8sO2sqiRhnk%2BZURIHV0EQRdPdzJIWMuENZZr%2FPKRl6MNekpZHOtF6wcWQYd4oRYptUjwzWQupbovVnaAyehNLMJbJi6sARkiXAQMC1kUyHpMQVrEdC69%2FNPEW8Cy6QIffUW1d0VBzVuK2hNJV1IgsbqEJZ56HXTtQCz4rJRlATwum2%2BcDS1ITfjA1JWuXwkbFON73TDPFsuz4fOhpVdmNvgN%2B%2F9h4YhmlxlsP3Ud%2BIfuPgzm4b%2FymVzdK%2FBOag7SjO9YRbqH6%2BrIXeXUmPf332sRw4twDy6LhqYxQmzBcr%2BLF4O0%2FTWW1N1pbusZ2p5nyVwaQEQd1FFeVTz5UXNvIUqA89x%2FWzrNHRUEdbR4ZQh5%2B9Eefd0IzIYza6TgRnWYknClVK1sq0qZ7bM1xhJfCsH3xCpWpVNqRqUZvOcWl8JH8aTrs2PhkkDU2%2Flto%2BlcsKG95lV06xukVyfa%2B2uzH%2FVp1Pph2jGLvMHTfLFdgt8jymryMt84jWtg8g%2F9N%2B%2Fb%2B69Pf4OuqLKx0md6Z6gOo4erBMvjrxSwWZxPBf%2BX674CclYnPpBsQjprvRMYGGGUtO957breZv5yQ0zWEB86BWHN6%2Fp6GJ%2Fb3TpeCEgEIKWB6VXxIt9EV7Ls9DrSb43eYSfUDKiBqpKcSD59g5W98rxrm%2FJhrzUnGQsVS4GRNR%2FquTJeWOc4NFIeyULqyLxLECaeXSPoqKe1ijkZc2cz%2FIDLNnmKY%2BMte7JslLswmWC469aL5%2BGMlgC%2FRJ%2BDhxZVbgOfAy7WZ4CoPtpoM2ixT5l5%2Ffg%2F1Z9jlRM4SAdU6XuC%2FnIJjYRBjZtA2IHE4xl87bgR8noUW%2FpMUmWeJrrScXuNpOKKhGoeM1XBg%2BiCZbFQ6oIihzGdqsvW4YQ3i%2BdzJEQvO%2FabotjD6zgekjvonlWOXTiSFXRS9h1JhyPFjMUdooDCkB7%2BtvuMj%2BUXUX2TccPtt%2BHdZpwtRVwzzf96J7bcs%2F1FaYhDsoJO01SqEtUAFWVqLO004kauPB6uJc%2FDSlBDqGI2hY02ORAl6BfyHVT4vxW8YDv55kD0R2hJhBtfhHsvQaEvrOR2BFHIB9hp5G2KW6zDuCWthVckhjUDsBDzOzc%2FDYtcBHCw8oWVXAbX%2BEjJNwHH2CVXVFO7HRSg3LEjRmqX1Hu72wXCp%2FlV3PCa%2FZcytUhuwMl%2B4PaqzD%2BQcTM0bm8JXylJAuksYMqQNkb9D%2BukLxyzADwfYFWy3aEJI1bVu0S0s6SJlLhGL1Z1E8x3sVh6vrMwYV6lZXzAU3BjYBgozfNvWpUDbM7bRJmEgBIgJFZJImFKs%2FwltOI6XACd1E%2BHQXchinr%2FHFYX2JW7uawkF0eJ7uNcYQ9O0pw9UNPWTOdVP855V3JIJZA0HvKt99Sn2Q%2FHgTWBAFmjefEI73B0wEGqIjPCTPJfljbcouvH6DfzttfGItUJ5g2lAN2H6lr%2F2UuRpjaJa3X924BF6WlIr%2FZ0JoAwxWvw1dvd00BCBamThc%2BK515yzwo5uYFKBlyt%2BQz9y%2FAf2mfRlI%2Bg%2BBV7b3LipC%2B66gfY6HJwOxNniy67qD1pkgKMRT6xeP8h86IOHUDyaG54RIMQAkYDSOyhUlKbMEsVbhq%2Fuqo9wvVq9djLSB%2BUcjpes%2Bfsn%2FyDdTl3nCWHd3xDC6MywPSvb%2F7pvhriQmpPjiXHhrvaMpWdecsXEF60kB3Hl5gm6klilE4ZkbcwakkSdGUVYn0b2mbM%2B7gq2lopcmTzAJuPAZI%2Fdp%2BnfT9mMywge6d1RP%2BCFBWCZdSXUjHHGvuWBPg2u8yfF7lQGOq7avsR%2BXZ2pi2afwwgzEyoHoxPYSfXn3J5%2FSkAINRE8rjbxK2n2qCRXSUlex1fp38OrPHK9TODFHPuq0whQQ2JYgq2IHXeUUiysJ1j5cub8JfZkoOEAm2TwnExVx9Fvvq3SadMWKKW8yOwZ6u%2BSLJUKu%2FtSzD6cXtiCbDpoZTe9LAeAgD%2FH9CDsvgX6sm6m441qf2glcOg01GsiLi%2BcVOGy14oT0I%2F0qtAjZS5qQskhMFNhrPudHgXgIw8%2BC81KK396oDN5JccahOO2Zuxkgiv3BtWO%2Fp8RBzrkPLR3hK2hj%2FVcSdwe0VUvq7%2FBNKyoRUsTN0tLWk6uvsce8P5avqG0VXXnUYuhvQTRBd88QACFMQW47kINvBq0N%2Ba8byLHlN8Kq%2BogTeBDuTn7CKOlOxi1ryxYm%2BUtzP4Ep0XBfrYba9Ztyp9L4Il0aNXElYudeV7i1NGwjh5FRgvYOPLQwTs7kHCIIUgpcYcX4oUUwdvyyZUDnzGPuWUhu1E0RELWiV89%2BJIiCrw4SKdohI86thnXhR9Ye%2FciOOjq8%2Foo0Vl9lq2Re2uJttZ9l99cCi54xFIPS1celZfZYKxR%2B2HTaB3EZ4z7%2FvdvQJ8BqXTWlfLTUh6M1wDJvZJPJkHBILh8sHMdew3NT2NSfF7dIzXIdg%2F8h5Pyy7NCQEXYn0nhlEecjuL3%2FOD4ccd4nq7FvoA9RcSLkpVg4OUy7KsQgfxwdp3KLrgJFowsqb5oN6zBojmWpFXhqaSSQFM3jsDQ6eCtxruTKTFqXc0eb23enSXNJoEIk%2BMQnwbycOYZomJ05Bi0dQrCEwMQ6jG%2Fq6pH2qfNiA5hoVHZww5miQHEHCT4vw0mTRky9d%2FuUNgjpZlK28iKV%2BT7i%2Ftq6UJ8ldEi%2FeFIpJUNi2tjQtQk2qrBw3L%2FN0Z7c%2BdkzqXxAByQCXuCA5v1Zt4yJKoC0763V6rrKU9JaIyeNAl4arqk%2BZ%2BQxfY6Ia6MmCpaGrzn4yHRnxnR52TEbn%2FhWM3LTzNeghmRphtKi4AereUSOJXbQOrdtVEG0uVF6ZNhX7DWYQ7BVI%2Bw5bN4Cp%2FBL9WxjD0s0WetzoRor0vL7IUHIzkoQkJHlBnCXXHh6Mif6Rzgm8O%2FfEgalGqhScqAwlXE5JYeZpm%2BusCO4gC0PE%2BSJzWQy63gHq5q3semEMn1cje95%2FIO5No09ZPoYkqAVd7XSBsVrYu%2BQhoGR8h95PcKeW7q2SVRanFCzC%2FhNALnQBh9qs78L23MiioERyE8D%2BnLi0K6l2Gba1BJ5tkbTaFynhuRWyq%2Bacvjbno5gPXVINSPoVf%2BbpZYSmgbZCAIrctXgInQuNBaWTzWICeJxKctTmaEIO6kXBB7y1p%2BzDpqVr4hjMkjZTS9mz8YLuU4eSAMhYD59GJZQi6mVkR1U8C9OsV6O%2BXOvnDQVWjrqQGIpVmfRv0B6sCtrBd%2BAX6N4TkaRfVehaW39%2BgnBB6SpTc0IZZ4apy%2BHXiOqVfLuABrL6JN6gH29V%2BRsd%2BybvouJRxdb47mxv7trl6JOwINUbERqsLQAPjrr54wBtS4LlRkvfBZpDAM7yCK%2FRpeT%2BjuC1X9i1p3CwL74V%2FN5Q5LxlA51Z9oxciOohCy4GkawbMSE8qor5%2BPwM4bNn%2FM%2FhgxmaOYRsoQZ4ZaEcRpAI5Vi4A3sIyYIdCbUvMmAKrEW%2FUeRhShapsCjLxcXeNuumWDCOHpJfVt3n8K0q6Ona%2FU4VkupnBbdK6Yo2%2FdBt64Zhmuzl3Pp9tnCmbYeuq%2BmR4B7PkCVNibRS0%2Fe8JI2S2mtSKb8XLVk%2BhmOXBxJ7sscsa%2FMjtWICOMVjg7fGYcwEXSUeJbVKMoCY1Jv7B6k4KV2sO9yruESkscm%2By3bV1rOFQgoQ2BFCS%2F1XwvFCWBoa4hoMgs1yVihXN7mRz61taqiPLqVoHNTSA4wOQtgS1xsYThYlZDpKyltNnFrs%2BB42yjByPn8qyR91eoobFYzjBvxnVrDg4DX58kJ2VumhFRe4NPg29seqk64Ps%2BbLUFDiCV39CVrsriWGR4G91xCeZpcv5NABou3M3RareJeoTTAmpBD3KUA3orZ8xRAUuFOkC9nDPJujH9nI117UMgScL9t9Rx7eB6l6jEt7KiMocEoRGHOMnSQJz28bbidFQWx0z0H67%2FcwOwSq0P71fDojxRc8Uhyk9yZKFfCiQ5HN6WnBS0u4O61hYDHO4oioPrFh4VvxdeYXf5Wz%2BDQFtdqUzYhC%2FlA%2FLWAWJF8WkQ%2BX7NEKUh3JO%2BxxFZJaJH28xgd4E5jnTT92orjalpTwTZ1y2Pm%2FsVUKyLm8oXhD9N2nTi%2FB2oey0H6Dn1Charhyc1MiS9dYLICym1zFBcTAQt6Our9D96Z20LRDi5UYci%2FxUDVJrwsBgREMxT4tXx41XsCJhkAxYvL1coY7HHmlgQUg6RDruY21h85VBJQeyNX0GkNUqXTaW5lTPRPflsIIbs80L0UX%2FZc6coyvlnWmkl3e93liSifT4eWW7AhhCAdXXZRKX2ZTzHKWnHzuXHoeP6MSHmSw6lA4Shi3VHv8TAmK4aumANtqASpxPw0I0rXy1U6dXW2UMj8FHEJP8pZ6BX5smKqMQaB6JuWP1pZCPgINg%3D%3D&__VIEWSTATEGENERATOR=3D1CCC47&__EVENTVALIDATION=qv5aJzTc3fM%2BcENN%2BTP2DgRs4ocXUM4qLJNP%2FtEv4q0xMardTbzlDm9uqRxoi%2BfRFn8e%2FC0PuVHiCvBR2xRuCXu%2BBQLORcJ%2BQ%2FANICydWIh6GamZbMbX0BfCN%2BuVKQqW8v1HzL9oN9IOmupGv9F%2BvyxGsToAR94w6szmvNNYvcmQKqcflo2K04UZh1lqzC7ScOHIhyMJb4xooM4oTg3qlmISKwYKDPhVgVgzU4zvzFueU2kToA0DykBBodt8%2BJcKHXbxt4UkL%2FBAZvHssrUeFA9OtAECcG4T3r68EB632IBprg8m9uiVX1wP%2BB8yQQdpQjBtYfT9rBHblz1HvaAu1mcRB0E%3D&ctl00%24cphRoblox%24GroupSearchBar%24SearchKeyword=Search+all+groups&ctl00%24cphRoblox%24rbxGroupRoleSetMembersPane%24dlRolesetList=2343447&ctl00%24cphRoblox%24rbxGroupRoleSetMembersPane%24RolesetCountHidden=2&ctl00%24cphRoblox%24rbxGroupRoleSetMembersPane%24currentRoleSetID=2343447&ctl00%24cphRoblox%24GroupWallPane%24GroupWallPager%24ctl01%24PageTextBox=1
EDIT 3:
s = requests.session()
login_data = dict(username='USERNAMEHERE', password='PASSWORDHERE')
s.post('https://www.roblox.com/newlogin', data=login_data)
page = s.get('http://www.roblox.com/Groups/Group.aspx?gid=403577')
soup=BeautifulSoup(page.content, "html.parser")
VIEWSTATE=soup.find(id="__VIEWSTATE")['value']
VIEWSTATEGENERATOR=soup.find(id="__VIEWSTATEGENERATOR")['value']
EVENTVALIDATION=soup.find(id="__EVENTVALIDATION")['value']
Join_Group = dict(__EVENTTARGET="JoinGroupDiv", __EVENTARGUMENT="Click", __LASTFOCUS="", __VIEWSTATE=VIEWSTATE, __VIEWSTATEGENERATOR=VIEWSTATEGENERATOR, __EVENTVALIDATION=EVENTVALIDATION)
join = s.post('http://www.roblox.com/Groups/Group.aspx?gid=403577', data=Join_Group)
print join
Your error is because this is not valid dict construction. You either need a literal (like {'foo': 'bar'}) or, if using the constructor, keyword arguments dict(foo='bar').
You should do a POST as that's what __doPostBack() does - post back to the same page/URL that's been served, see What is a postback?.
To determine what actually needs to be set for the POST, you should understand the __doPostBack() function.
Those arguments are used to populate hidden form fields called __EVENTTARGET and __EVENTARGUMENT.
You can read an explanation about this here:
http://www.codeproject.com/Articles/667531/doPostBack-function
Edit: It's also worth noting that, when interacting with an application in this manner, you also need to be aware of any other state that's being managed and passed to the server. There are cookies, viewstate etc. to be considered. It's best to go through the process in a browser and inspect/record the requests with the developer tools to help you determine what data is required.
Edit 2: I see that Roblox has an API. You're much better off using this if/where possible rather than interacting with their UI.
See http://wiki.roblox.com/index.php/Web_APIs#Group_APIs
If this isn't letting you get access to a list of groups (I don't see a search here at a glance) then you might consider a hybrid approach.
Edit 3: For the scraping-type approach, you may want to consider Beautiful Soup for parsing the page/form and extracting the values being added by ASP.NET -
http://www.crummy.com/software/BeautifulSoup/
Related
This is the HTML code in file 1, which is calling the function. It is linked to javascript
<form id='next' action='file2.html'>
<button id="nextTwo" onclick="nextTwo()">next2</button>
</form>
This is the JS code that receives the function.
function nextTwo(){
document.getElementById('question').innerHTML=question
}
It is searching for the id before the file changes to where the id is.
Every time I press the button that calls the function it gives me:
"TypeError: Cannot set properties of null (setting 'innerHTML')"
This is because it is searching for the id of "question" in file 1, but the id is in file 2. It tries to find the id in file 1, then it switches to file 2, where the id of "question" is.
How do I make it so that is switches to file 2 first, then searches for the id.
Maybe an if statement with a condition, if the file is switched, although I don't know the how to write that.
Thanks for your help.
This is my Js code, how do I place the arrays value into the file 2 using ajax?
let ants;
let question;
let squestion;
function check() //CHECK
{
switch(1){ //different header number is fine but do '' BUT input box will still be there
case 0:
ants = ['calculations']
question=["Element Symbol that has the atomic number of... ","atomic mass of (round to nearest whole number)..."]
squestion=["1. 50","2. 2","3. 20","4. K"]
case 1:
ants = ["0 (all atoms have a charge of 0)","11","11","4","9","Be","8","8","8"]
question=["Sodium has 11 protons and an mass of 23. What is the...","An atom has an atomic# of 4 and 5 neutrons What is the...", "Oxygen has 8 electrons and a mass of 16"]
squestion=["charge","atomic#","#of electrons", "#of protons","Mass","element symbol", "#of protons", "atomic#", "#of neutrons"]
// ants = ["Sn ","He ","Ca ","39 ", "32 ","Sn ","He ","Ca",]
// question=["Element Symbol that has the atomic number of... ","atomic mass of (round to nearest whole number)..."]
// squestion=["1. 50","2. 2","3. 20","4. K"]
break;
case 2:
ants = ["Carbon", "Chlorine", "Bromine",'Br',"Li","Sc","2","8","8" ]
question=["Carbon", "Chlorine", "Bromine", "Helium",'Br',"Li","Sc" ]
squestion=[]
}
There is a better way to go about this.
By design, forms do not communicate two-way. They take the data entered by the user and carry it over to the processing file (defined by the action= parameter on the form tag). The user is navigated away from the first webpage, and the view changes to that processing file - and it isn't supposed to go back to the first file again. Forms are very basic, primitive constructs.
This is why forms have been almost entirely replaced by AJAX. AJAX is a very simple JavaScript construct (made even simpler via jQuery - TANGENT: although jQuery is no longer recommended because modern JavaScript has made the process much easier - but the jQuery $.ajax() method still works fine and there is tons of info about how to use it).
AJAX allows you to send data from a web page to a back-end (server-side) file that receives any data you send it (optional), does something (optional), and returns new data (optional). The page the user is on need not change, blink or flash. New data received from the server-side file can be received and actively used before returning control to the user... So this sounds like exactly what you need it to do.
The back-end (AJAX) processing file is written in a server-side language (PHP, NodeJS, ASP.Net, Python, etc - PHP is a very popular one for AJAX), but you did not specify which one you wish to use, which is likely why no one responded to your question sooner.
Here are some references that might help. I chose jQuery examples because the AJAX code block $.ajax( //code goes here ).done() is very simple. To do AJAX in pure JavaScript, look for information regarding the Fetch API (newest), and XmlHTTPRequest (older).
Simple jQuery example
Ajax explained with jQuery
Another simple example with explanation
Here is a pure javascript video tutorial (5 mins)
After reviewing the examples, you can construct a basic AJAX test on your side and, if you have any trouble with it, ask another question specifying which language you are trying to do this with, and showing your code so far.
I am having some issues trying to connect to a matrix server using the matrix-js-sdk in a react app.
I have provided a simple code example below, and made sure that credentials are valid (login works) and that the environment variable containing the URL for the matrix client is set. I have signed into element in a browser and created two rooms for testing purposes, and was expecting these two rooms would be returned from matrixClient.getRooms(). However, this simply returns an empty array. With some further testing it seems like the asynchronous functions provided for fetching room, member and group ID's only, works as expected.
According to https://matrix.org/docs/guides/usage-of-the-matrix-js-sd these should be valid steps for setting up the matrix-js-sdk, however the sync is never executed either.
const matrixClient = sdk.createClient(
process.env.REACT_APP_MATRIX_CLIENT_URL!
);
await matrixClient.long("m.login.password", credentials);
matrixClient.once('sync', () => {
debugger; // Never hit
}
for (const room of matrixClient.getRooms()) {
debugger; // Never hit
}
I did manage to use the roomId's returned from await matrixClient.roomInitialSync(roomId, limit, callback), however this lead me to another issue where I can't figure out how to decrypt messages, as the events containing the messages sent in the room seems to be of type 'm.room.encrypted' instead of 'm.room.message'.
Does anyone have any good examples of working implementations for the matrix-js-sdk, or any other good resources for properly understanding how to put this all together? I need to be able to load rooms, persons, messages etc. and display these respectively in a ReactJS application.
It turns out I simply forgot to run startClient on the matrix client, resulting in it not fetching any data.
In my source connector, I'm using javascript for my database work due to my requirements and parameters.
The end result is storing the data.
ifxResults = ifxConn.executeCachedQuery(ifxQuery); //var is declared
I need to use these results in the destination transformer.
I have tried channelMap.put("results", ifxResults);.
I get the following error ReferenceError: "channelMap" is not defined.
I have also tried to use return ifxResults but I'm not sure how to access this in the destination transformer.
Do you want to send each row as a separate message through your channel? If so, sounds like you want to use the Database Reader in JavaScript mode. Just return that ResultSet (it's really a CachedRowSet if you use executeCachedQuery like that) and the channel will handle the rest, dispatching an XML representation of each row as discrete messages.
If you want to send all rows in the result set aggregated into a single message, that will be possible with the Database Reader very soon: MIRTH-2337
Mirth Connect 3.5 will be released next week so you can take advantage of it then. But if you can't wait or don't want to upgrade then you can still do this with a JavaScript Reader:
var processor = new org.apache.commons.dbutils.BasicRowProcessor();
var results = new com.mirth.connect.donkey.util.DonkeyElement('<results/>');
while (ifxResults.next()) {
var result = results.addChildElement('result');
for (var entries = processor.toMap(ifxResults).entrySet().iterator(); entries.hasNext();) {
var entry = entries.next();
result.addChildElement(entry.getKey(), java.lang.String.valueOf(entry.getValue()));
}
}
return results.toXml();
I know this question is kind of old, but here's an answer just for the record.
For this answer, I'm assuming that you are using a Source connector type of JavaScript Reader, and that you're trying to use channelMap in the JavaScript Reader Settings editing pane.
The problem is that the channelMap variable isn't available in this part of the channel. It's only available in filters and transformers.
It's possible that what you want can be accomplished by using the globalChannelMap variable, e.g.
globalChannelMap.put("results", ifxResults);
I usually need to do this when I'm processing one record at a time and need to pass some setting to the destination channel. If you do it like I've done in the past, then you would first create a globalChannelMap key/value in the source channel's transformer:
globalchannelMap.put("ProcID","TestValue");
Then go to the Destinations tab and select your destination channel to make sure you're sending it to the destination (I've never tried this for channels with multiple destinations, so I'm not sure if anything different needs to be done).
Destination tab of source channel
Notice that ProcID is now listed in the Destination Mappings box. Click the New button next to the Map Variable box and you'll see Variable 1 appear. Double click on that and put in your mapping key, which in this case is ProcID.
Now go to your destination channel's source transformer. There you would enter the following code:
var SentValue = sourceMap.get("ProcID");
Now SentValue in your destination transformer has whatever was in ProcID when your source channel relinquished control.
I've got a web service under development that uses Django and Django Channels to send data across websockets to a remote application. The arrangement is asynchronous and I pass information between the 2 by sending JSON formatted commands across websockets and then receive replies back on the same websocket.
The problem I'm having is figuring out how to get the replies back to a Javascript call from a Django template that invokes a Python function to initiate the JSON websocket question. Since the command question & data reply happen in different Django areas and the originating Javascript/Python functions call does not have a blocking statement, the Q&A are basically disconnected and I can't figure out how to get the results back to the browser.
Right now, my idea is to use Django global variables or store the results in the Django models. I can get either to work, but I beleive the Django global variables would not scale beyond multiple workers from runserver or if the system was eventually spread across multiple servers.
But since the reply data is for different purposes (for example, list of users waiting in a remote lobby, current debugging levels in remote system, etc), the database option seems unworkable because the reply data is varying structure. That, plus the replies are temporal and don't need to be permanently stored in the database.
Here's some code showing the flow. I'm open to different implementation recommendations or a direct answer to the question of how to share information between the 2 Django functions.
In the template, for testing, I just have a button defined like this:
<button id="request_lobby">Request Lobby</button>
With a Javascript function. This function is incomplete as I've yet to do anything about the response (because I can't figure out how to connect it):
$("#request_lobby").click(function(){
$.ajax({
type: "POST",
url: "{% url 'test_panel_function' %}",
data: { csrfmiddlewaretoken: '{{ csrf_token }}', button:"request_lobby" },
success: function(response){
}
});
});
This is the Django/Python function in views.py . The return channel for the remote application is pre-stored in the database as srv.server_channel when the websocket is initially connected (not shown):
#login_required
def test_panel_function(request):
button = request.POST.get('button', '')
if button == "request_lobby" :
srv = Server.objects.get(server_key="1234567890")
json_res = []
json_res.append({"COMMAND": "REQUESTLOBBY"})
message = ({
"text": json.dumps(json_res)
})
Channel(srv.server_channel).send(message)
return HttpResponse(button)
Later, the remote application sends the reply back on the websocket and it's received by a Django Channels demultiplexer in routing.py :
class RemoteDemultiplexer(WebsocketDemultiplexer):
mapping = {
"gLOBBY" : "gLOBBY.receive",
}
http_user = True
slight_ordering = True
channel_routing = [
route_class(RemoteDemultiplexer, path=r"^/server/(?P<server_key>[a-zA-Z0-9]+)$"),
route("gLOBBY.receive" , command_LOBBY),
]
And the consumer.py :
#channel_session
def command_LOBBY(message):
skey = message.channel_session["server_key"]
for x in range(int(message.content['LOBBY'])):
logger.info("USERNAME: " + message.content[str(x)]["USERNAME"])
logger.info("LOBBY_ID: " + message.content[str(x)]["LOBBY_ID"])
logger.info("OWNER_ID: " + message.content[str(x)]["IPADDRESS"])
logger.info("DATETIME: " + message.content[str(x)]["DATETIME"])
So I need to figure out how to get the reply data in command_LOBBY to the Javascript/Python function call in test_panel_function
Current ideas, both of which seem bad and why I think I need to ask this question for SO:
1) Use Django global variables:
Define in globals.py:
global_async_result = {}
And include in all relevant Django modules:
from test.globals import global_async_result
In order to make this work, when I originate the initial command in test_panel_function to send to the remote application (the REQUESTLOBBY), I'll include a randomized key in the JSON message which would be round-tripped back to command_LOBBY and then global_async_result dictionary would be indexed with the randomized key.
In test_panel_function , I would wait in a loop checking a flag for the results to be ready in global_async_result and then retrieve them from the randomized key and delete the entry in global_async_result.
Then the reply can be given back to the Javascript in the Django template.
That all makes sense to me, but uses global variables (bad), and seems that it wouldn't scale as the web service is spread across servers.
2) Store replies in Django mySQL model.py table
I could create a table in models.py to hold the replies temporarily. Since Django doesn't allow for dynamic or temporary table creations on the fly, this would have to be a pre-defined table.
Also, because the websocket replies would be different formats for different questions, I could not know in advance all the fields ever needed and even if so, most fields would not be used for differing replies.
My workable idea here is to create the reply tables using a field for the randomized key (which is still routed back round-trip through the websocket) and another large field to just store the JSON reply entirely.
Then in test_panel_function which is blocking in a loop waiting for the results, pull the JSON from the table, delete the row, and decode. Then the reply can be given back to the Javascript in the Django template.
3) Use Django signals
Django has a signals capability, but the response function doesn't seem to be able to be embedded (like inside test_panel_function) and there seems to be no wait() function available for an arbitrary function to just wait for the signal. If this were available, it would be very helpful
I'm creating an Web-Application (Frontend and Backend, so both are under my control) using Backbone and Pyramid, being connected via a RESTful API.
During development I encountered a problem several times by now, where Backbone PUTs (=updates) a new model, while it actually should POST (=create) it.
Backbone decides whether to POST or UPDATE a model depending of the presence of an ID-field (if no ID present in the current model: -> POST/create | if so: PUT/update).
However I encountered several situations by now, where this behaviour doesn't match my application logic.
Let's say our main model (and its objects being persistently saved in a relational database in the backend) is called Foo, having fields like id, field_1, field_2.
Example #1: Creating a template or preview of Foo: Before creating (=POSTing) an object of Foo, I can create and show a preview to the user and/or save it as a template.
While doing so, the backend (in case of the preview: temporarily) adds the object to the database and returns the full model - including an ID in its HTTP response - back to Backbone.
Template- and Preview-objects of Foo are (temporarily) saved into the same table, as final objects (column type indicates its type (0 = final/live, 1 = preview, 2 = template)).
When now - after previewing / saving as template - trying to actually CREATE an object of Foo, the Backbone model already has the ID field set and actually PUTs and updates the template or not-anymore-existing preview, instead of POSTing and therewith creating a new Foo inside the database (as intended).
=> solution #1: calling POST /json/preview does not return the ID field, so Backbone doesn't get confused.
=> solution #2: overriding parse() of Foo in Backbone-model to kick out ID field from response
.=> kinda works
Example #2: Having a Periodic model, which refers to a Foo-template. Intention of a Periodic is to offer the user the possibility of semi-automatically creating a new Foo object based on a Foo-template every X months.
Now there is a call GET /json/periodics, which returns all Periodic-objects with its nested Foo-objects (Foo-templates), including their IDs, e.g. [{'interval': 12, template_id: 42, template: { 'id': 42, field_1: 'foo', field_2: 'bar', .. } , { .. } , .. ].
On the frontend the user now can periodically confirm (or skip) creating a new Foo-object, by issuing: periodics[X].template.save() which however again PUTs and therewith updates the Foo-model, instead of POSTing and creating a new one (as intended).
Here again (as in example 1), I could strip out the ID field of Foo - either in the backend or frontend.
However there are situations, where I need the id-field of templates, e.g. when actually editing them, so here I'd need two calls (GET /json/templates_WITHOUT_FOO-IDs and GET /json/templates_WITH_FOO-IDs). which also sounds far from right.
Question is: What's the right (and consistent) way of avoiding Backbone falsely assuming a model should be PUT instead of POSTed in certain situations / views?
Backbone's save and fetch methods just make calls to the Backbone.sync
method, which in turn is just a wrapper for an ajax call. you can pass
in ajax parameters using the save function without having to actually
extend it. basically ends up being something like this:
model.save({attributes you want to save}, {type:'POST', url: 'apiurl/model/:id/played'});
You would have to do this every time though so it is probably better practice to extend Backbone.sync for your model.
The Backbone website has a bit of information about what I'm talking about as far as the Backbone sync and save taking ajax options. There are also a few examples I've seen on extending sync but I can't seem to track them down at the moment.