How to manage several users in nitrogen/inets erlang - erlang

I am building a simple web site for my family usage, using Nitrogen/Inets.
The current version works as expected as long as I have a single client connected to the web server.
If I try to connect a new user, the 2 sessions seems to share the same state variables:
browser 1: read the index page, click on connect, and login as user1.
browser 2: read the index page, the user is user1 --> not OK
- go to login and enter as user2. Seems ok.
browser 1: reload the home page --> user changed to user2 --> very bad :o(
in addition I have included a display to show the timeout counter -> the values are synchronized on both browser.
Can you tell me what I must do to manage several users at the same time? the code i wrote is the following:
extract of index.erl
header() ->
% if the user is not defined, show in the header a button to connect, change the title and display a reduced menu (thanks to common module)
% if the user is defined, show in the header a button to disconnect, change the title and display a complete menu (thanks to common module)
User = wf:user(),
Msg = case User of
undefined ->
"Pas connecté";
User ->
"Welcome " ++ User
end,
case User of
undefined ->
common:header(Msg, #button { id=dcnx, text="Connexion", postback=connexion , class = rightalign});
User ->
common:header(Msg, #button { id=dcnx, text="Deconnexion", postback=deconnexion , class = rightalign})
end.
body() ->
#container_12 { body= #grid_8 { alpha=true, prefix=2, suffix=2, omega=true, body=inner_body(wf:user()) }}.
inner_body(User) ->
Msg = case User of
undefined -> "Pas connecté";
_ -> User ++ " home"
end,
[
#h2{ text= Msg },
#p{}
].
event(deconnexion) ->
% a temporary popup just to display the user name and check the function call
wf:wire(#alert { text="Bye bye " ++ wf:user() }),
wf:clear_session(), % erase the session information
wf:redirect("index"); % redisplay the index page
event(connexion) ->
wf:redirect_to_login("login");
event(E) -> common:event(E).
extract of login.erl:
body() ->
% the login requires a name and a password,
% checks that {name,password} exists
Body = [
#label { text="Name" },
#textbox { id=nameTextBox, next=passwordTextBox },
#p{},
#label { text="Password" },
#password { id=passwordTextBox, next=continueButton },
#p{},
#button { id=continueButton, text="Continue", postback=continue }
],
wf:wire(continueButton, nameTextBox, #validate { validators=[
#is_required { text="Obligatoire." },
#custom { text="utilisateur invalide.", tag=tag_name, function=fun name_validator/2 }
]}),
wf:wire(continueButton, passwordTextBox, #validate { validators=[
#is_required { text="Obligatoire." },
#custom { text="mot de passe incorrect.", tag=tag_password, function=fun password_validator/2 }
]}),
Body.
event(continue) ->
Name = wf:q(nameTextBox), % retreive the name
wf:user(Name), % define as user
wf:role(admin,is_admin(Name)), % define role
wf:session(logged,true), % define as logged
wf:redirect_from_login("index"); % go back to the calling page or index if not defined
event(_) -> ok.

The session information is stored with a cookie as the key.
Are you opening the page in another window of the same browser, or are you opening a completely separate browser (IE, Chrome and Firefox)? If you're just opening another window or tab within the same browser, the cookie information is certainly going to be shared, leading to the effect you've described.
So make sure you're firing up two completely different browsers.
The code you've posted looks right - nothing stands out as sharing information across sessions.

Related

Can't get Firefox extension logs to show up

Following these instructions, I went to about:debugging -> This Firefox and clicked Inspect on my extension, which shows a console. But no logs show up there when I trigger my extension. Using the list-cookies example, I added the last two lines:
gettingAllCookies.then((cookies) => {
//set the header of the panel
var activeTabUrl = document.getElementById('header-title');
var text = document.createTextNode("Cookies at: "+tab.title);
var cookieList = document.getElementById('cookie-list');
console.log('I can't see this log!');
cookieList.parentNode.appendChild(document.createTextNode(Date()));
When I invoke the popup, I see the current date/time in the popup, but no log shows up in the console.
I tried setting extensions.sdk.console.logLevel and restarting as mentioned here (even though I think that's for older versions), but it didn't help.
I thought maybe there's a console permission or something I might need to add to the manifest, but didn't find any such thing.
Complete code for reference. I only changed the lines marked with +/-:
function showCookiesForTab(tabs) {
//get the first tab object in the array
let tab = tabs.pop();
//get all cookies in the domain
var gettingAllCookies = browser.cookies.getAll({url: tab.url});
gettingAllCookies.then((cookies) => {
//set the header of the panel
var activeTabUrl = document.getElementById('header-title');
var text = document.createTextNode("Cookies at: "+tab.title);
var cookieList = document.getElementById('cookie-list');
- activeTabUrl.appendChild(text);
+
+ console.log('I can't see this log!');
+ cookieList.parentNode.appendChild(document.createTextNode(Date())); // I see this updated even though I don't see the log
if (cookies.length > 0) {
//add an <li> item with the name and value of the cookie to the list
for (let cookie of cookies) {
let li = document.createElement("li");
let content = document.createTextNode(cookie.name + ": "+ cookie.value);
li.appendChild(content);
cookieList.appendChild(li);
}
} else {
let p = document.createElement("p");
let content = document.createTextNode("No cookies in this tab.");
let parent = cookieList.parentNode;
p.appendChild(content);
parent.appendChild(p);
}
});
}
//get active tab to run an callback function.
//it sends to our callback an array of tab objects
function getActiveTab() {
return browser.tabs.query({currentWindow: true, active: true});
}
getActiveTab().then(showCookiesForTab);
Firefox console has been divided into different areas. The result of console.log() can be viewed in the relative area.
Multiprocess Browser Console Ctrl+Shift+J
Mostly logs by Firefox itself
Web Developer Tools Ctrl+Shift+I or F12
Logs by Tab/Webpage and Content scripts of addons
Extension Toolbox about:debugging#/runtime/this-firefox ➜ XYZaddon ➜ Inspect
Logs by background scripts of XYZaddon
Update
Based on comments, here is a tested simplified code that you can work on. The log shows on Extension Toolbox.
async function showCookiesForTab() {
// get the first tab object in the array
const tabs = await browser.tabs.query({currentWindow: true, active: true});
// get all cookies in the domain
const cookies = await browser.cookies.getAll({url: tabs[0].url});
console.log(cookies);
// Array(6) [ {…}, {…}, {…}, {…}, {…}, {…} ]
}
showCookiesForTab();
I had a similar issue. I didn’t figure out the cause, but I find a way to see the console.log in the Extension Toolbox.
I added a background script to handle most of the popup.js logic.
And since there is a background script running, I can see the log.
Still don’t why I couldn’t see the log in the first place.

Password protect dropdown menu on google sheets. (javascript)

I'm a total noob when it comes to javascript unfortunately thats what google sheets is using. what i am tasked with is to password protect a drop down menu (data validation) on my google sheets file. so when they try to select their name it asks them for a password, is this possible?
Answer:
With data validation, no this is not possible. You could in theory write an Apps Script workaround but anyone with edit access to the sheet would be able to see the passwords so it would be useless as a protection.
Simple Example:
You'll want to make a data validation dropdown on a cell like normal:
and then write an onEdit function to run when the value is changed:
// define each user password (this is insecure and not recommended)
const userPasswords = {
"Name 1": "password1",
"Name 2": "anotherPassword",
"Name 3": "insecureIsMyMiddleName",
"Name 4": "name4nocapitalsorspaces"
}
function onEdit(e) {
const namesCell = "C2" // the cell with the dropdown
if (e.range.getA1Notation() != namesCell) {
return
}
// show prompt for password:
var ui = SpreadsheetApp.getUi()
const response = ui.prompt("Password protected range",
"Please enter your password:",
ui.ButtonSet.OK_CANCEL)
const button = response.getSelectedButton()
const text = response.getResponseText()
// don't run if the user pressed cancel or close
if (button != ui.Button.OK) {
return
}
// check the passwords
if (text != userPasswords[e.value]) {
ui.alert('Incorrect Password', 'Please try again', ui.ButtonSet.OK);
e.range.setValue(e.oldValue) // reset to old value
}
}
References:
Simple Triggers | Apps Script | Google Developers
Event Objects | Apps Script | Google Developers
Dialogs and Sidebars in Google Workspace Documents | Apps Script | Google Developers

Add user to actioncable channel without page refresh.

When I'm referring to actioncable channels, i am referring to this:
.
After creating the chatroom + chatroom_users, the user has to refresh the page to connect to that specific chatroom_id channel. Is it possible to connect to that channel without a reloading the page?
It is possible to create connection upon a custom action in your view (instead of page refresh). Please have a look at the code below,
createconusmer = (send_params) ->
App.chatbot = App.cable.subscriptions.create { channel: "ChatbotChannel" , auth_token: send_params , url: string },
connected: ->
# Called when the subscription is ready for use on the server
disconnected: ->
# Called when the subscription has been terminated by the server
received: (data) ->
console.log(data)
speak: (data, responder, payload) ->
#perform 'speak' , message: data , responder: responder , payload: payload
Now you can define custom function in your coffee file as,
nameclick = (value) ->
createconusmer value
window["nameclick"] = nameclick
Now in your view, you can use function nameclick to create a new streaming. Also, I am adding my bit of code to make sure they are unique or not, so to avoid addition of repititive connections.
connections = []
addConnection = (id) ->
connections.push(id)
removeConnection = (id) ->
index = connections.indexOf(id)
connections.splice(index, 1) if index > -1
connectedTo = (id) ->
connections.indexOf(id) > -1
nameclick = (value) ->
if connectedTo(value) == false
addConnection(value)
createconusmer value

drupal redirect language url alias

I would like to redirect urls that are using the wrong url alias.
Example, in my site I have:
English -> /prices/high-school -> node/112
Spanish -> (/es)/precios/high-school -> node/115
When a person or search engine reaches /es/prices/high-school a 404 is returned. What I would like is to redirect /es/prices/high-school to node/115.
I would like to do this in a general form, writing a module or using an existing one if possbile.
Thanks.
I already figured it out.
In the preprocess hook I need to check the page, strip the prefix and get the node id from the original id.
See code below:
if(current_path()=="search404")
{
$url = request_path();
if (startsWith($url,'es/') ||
startsWith($url,'de/') ||
startsWith($url,'it/') ||
startsWith($url,'fr/') )
{
$originalPath = substr($url,3,strlen($url)-3);
$path = drupal_lookup_path("source", $originalPath,"en");
if (isset($path))
{
$node = menu_get_object("node", 1, $path);
if (isset($node))
{
$prefix = substr($url,0,2);
$translated_paths = translation_path_get_translations('node/' . $node->nid);
if (isset($translated_paths) && array_key_exists ($prefix,$translated_paths))
{
if (isset($_GET['destination'])) {
unset($_GET['destination']);
}
$new_path = $translated_paths[$prefix];
drupal_goto($new_path, array(),301);
}
}
}
}
}
It won't be a solution to add different url aliases for the language versions? I mean:
node/112 -> /prices/high-school
node/115 -> /es/precios/escuela-secundaria
i18n module handles language based paths and redirects too.

How to do Oauth Authentication using seperate new tab for verification of account?

What is the Authentication Strategy for opening new (tab) Window for Oauth Authentication and returning to previous tab (logged In) upon successful authentication?
I am using passportjs authentication strategies for Twitter, Facebook and Google. But all of that does authentication in the same window-tab. Is there a predefined strategy which I can follow to do the above?
I can open the permission window in new account using a(target="_blank"), but it does not return to previous tab upon account authentication (by user).
Edit (based on following answer)
Login Page looks like:-
!!!
html
head
script.(type='text/javascript')
function newWindow (auth_target) {
authWindow = window.open(auth_target);
var authenticationSuccessUrl = "/home"
authWindow.onClose = function () {
alert('onClose called.');
authWindow.close();
window.location = authenticationSuccessUrl;
}
}
body
button(type="button", onclick="newWindow('auth/google');").btnLogin with Gmail
For New Window (home) i wrote:-
!!!
html
head
script(type='text/javascript').
function onAuthSuccess() {
authWindow=window.location;
window.onClose();
}
body(onload='onAuthSuccess();')
Its not a full code i was suppose to write, but even this does not work. If the Home page is called after an intermediate authentication window (by google, for password entry) the above code does not work, and window does not close.
// just as some more information, ignore if not necessary
Also please note, that,
window.close()
works only if the parent window that triggered it open is open. If the current window is a standalone the above window.close() will not close the window. Likewise, the above Home page code fails to close current window.
When creating the new window for authentication you can get the reference to the window object.
var authWindow = window.open("location","");
In the authentication tab you on authentication success you can call a method which would close the window and set a property or call a method on the source window suggesting that authentication is complete.
var authenticationSuccessUrl = "http://auth-sucess.url"
authWindow.onClose = function () {
authWindow.close();
window.location = authenticationSuccessUrl;
}
On the authentication window javascript:
var onAuthSuccess = function (){
window.onClose();
}
Be sure to remove the reference to the authWindow at the end of processing. Having window objects as references could potentially lead to memory leaks in the application.
Here is how I see the code can be changed as: This would just create one popup window and it will get closed after authentication.
You have Login page code as :
!!!
html
head
script.(type='text/javascript')
function newWindow (auth_target) {
authWindow = window.open(auth_target);
authWindow.onClose = function (authenticationSuccessUrl) {
alert('onClose called.');
authWindow.close();
window.location = authenticationSuccessUrl;
}
}
body
button(type="button", onclick="newWindow('auth/google');").btnLogin with Gmail
The newWindow('auth/google') should have the following code.
!!!
html
head
script(type='text/javascript').
function onAuthSuccess(authSuccessUrl) {
window.onClose(authSuccessUrl);
}
function ajaxPost() {
var uname = $("#name");
var pass = $("#password");
$.ajax({
url: "/auth/google/",
type: "POST",
data: {username : uname, password: pass}
}).success(function(data){
var redirectUrl = data.url; // or "/home" as you had mentioned
onAuthSuccess(redirectUrl);
});
}
body
p UserName:
input#name(type="text", name="username")
p Password:
input#password(type="text", name="password")
p: button(type="submit", onclick="ajaxPost()").btnLogin
If you can post through ajax to the google authentication service and get the the success response you can use this method.
Hope this works out well for you.

Resources