I'm setting up like a framework who use python in backend and html/css/js for frontend. My problem arrived during the loading of a QWebEngineView.
I search on the web how to establish a communication between python and javascript with QWebEngineView and I finally tried to use QtWebChannel.
So I setted up everything, and everything worked good with communication between python and javascript, but the next issue appeared:
First: i can't load javascript files directly in html with tags <script>
Second: javascript loaded randomly, i tried to load javascript from python with my_view.page().runJavascript(my_js) but it work one try on two. So sometimes jQuery load at the end, so an other part of the code doesn't work.
base.html:
<!DOCTYPE html>
<html lang="en">
<p id="log"></p>
<script src="qrc:///qtwebchannel/qwebchannel.js"></script>
<script>
window.onerror = function (error, url, line) {
console.error("ERROR: " + error.toString());
console.error("LINE: " + line.toString());
};
function load_app(){
new QWebChannel(qt.webChannelTransport, function (channel) {
window.app = channel.objects.app;
app.load_javascript(function(ret){
console.error("load javascript: " + ret)
});
});
}
load_app();
console.error("app loaded")
</script>
{{ application_html_content | safe }}
</html>
Another part of HTML:
{% extends 'base.html' %}
{% block content %}
<div class="row">
{% for user_id, user in user_dict.items() %}
<div id="{{ user_id }}" class="col s12 m6">
<div class="card blue-grey darken-1">
<div class="card-content white-text">
<span class="card-title">Visit Card</span>
<p>{{ user.name }}</p>
</div>
<div class="card-action">
<button id="btn_del_{{ user_id }}" class="btn blue waves-effect waves-light" onclick="delete_user({{ user_id }})">Delete</button>
<button class="btn blue waves-effect waves-light" onclick="detail_user({{ user_id }})">Detail</button>
</div>
</div>
</div>
{% endfor %}
</div>
{% endblock %}
{% block javascript %}
<script>
$(document).ready(function() {
app.request_result.connect(function (result) {
if ("delete" in result) {
user_id = result.delete;
var element = document.getElementById(user_id);
element.parentNode.removeChild(element)
}
});
console.error("ready");
});
function delete_user(user_id) {
document.getElementById("btn_del_" + user_id).innerHTML = "Waiting ...";
app.request('DemoHtml:Default:delete', user_id);
}
function detail_user(user_id) {
app.path('detail_user', {"user_id": user_id});
}
</script>
{% endblock %}
load_javascript function:
JQUERY = "vendor/Resources/js/jquery.js"
MATERIALIZE = "vendor/Resources/css/materialize/js/materialize.js"
#pyqtSlot(result=str)
def load_javascript(self):
with open(os.path.join(os.path.abspath(os.path.dirname(sys.argv[0])), self.MATERIALIZE), "r") as m_stream:
materialize_content = m_stream.read()
with open(os.path.join(os.path.abspath(os.path.dirname(sys.argv[0])), self.JQUERY), "r") as j_stream:
jquery_content = j_stream.read()
self.template_view.view.page().runJavaScript(jquery_content)
self.template_view.view.page().runJavaScript(materialize_content)
return "ok"
As you can see, normally I must see in log error:
First: "load javascript: ok"
Second: "app loaded"
but one time one two, this is reverse like:
js: app loaded
js: ERROR: Uncaught ReferenceError: $ is not defined
js: LINE: 67
js: Uncaught ReferenceError: $ is not defined
js: load javascript: ok
Any help for this?
Thank you in advance!
I resolved my problem, thanks to #ekhumoro for trying to help me, i found an answer on this thread:
How to wait for another JS to load to proceed operation ?: https://stackoverflow.com/a/8618519/8293533
So to make it work, i change my javascript to this:
I named this file app.js
function set_app() {
try{
new QWebChannel(qt.webChannelTransport, function (channel) {
window.app_channel = channel.objects.app;
});
} catch (e) {
console.error("setting_app error: " + e)
}
}
set_app();
function request(route, args) {
let interval = 10;
window.setTimeout(function () {
if (window["app_channel"]) {
app_channel.request(route, args)
} else {
try {
set_app();
}
catch(error) {
console.error("app load error: " + error)
}
window.setTimeout(arguments.callee, interval);
}
}, interval)
}
function path(route, args) {
let interval = 10;
window.setTimeout(function () {
if (window["app_channel"]) {
app_channel.path(route, args)
} else {
try {
set_app();
}
catch(error) {
console.error("app load error: " + error)
}
window.setTimeout(arguments.callee, interval);
}
}, interval)
}
function request_result(callback) {
let interval = 10;
window.setTimeout(function () {
if (window["app_channel"]) {
app_channel.request_result.connect(callback)
} else {
try {
set_app();
}
catch(error) {
console.error("app load error: " + error)
}
window.setTimeout(arguments.callee, interval);
}
}, interval)
}
I erase my code load_javascript in python because i found the way to call js with <script> tags and qrc:/// path.
Now my html head look like this:
<!DOCTYPE html>
<html lang="en">
<p id="log"></p>
<script src="qrc:///qwebchannel.js"></script>
<script src="qrc:///app.js"></script>
<script src="qrc:///jquery.js"></script>
{{ application_html_content | safe }}
<script src="qrc:///materialize.min.js"></script>
</html>
To use qrc:///xxx.js i used QResource and .qrc, .rcc files.
This is an example of my code for those who want:
class ApplicationContainer:
SRC_QRC_PATH = "src/*Bundle/Resources/qrc/*.qrc"
SRC_RCC_PATH = "src/*Bundle/Resources/qrc/*.rcc"
VENDOR_QRC_PATH = "vendor/*Bundle/Resources/qrc/*.qrc"
VENDOR_RCC_PATH = "vendor/*Bundle/Resources/qrc/*.rcc"
def __init__(self):
self.__pyqt_application = QApplication(sys.argv)
self.__pyqt_resources = QResource()
self.set_rcc_files()
#property
def application(self):
return self.__pyqt_application
#application.setter
def application(self, new_app: QApplication):
self.__pyqt_application = new_app
def set_rcc_files(self):
qrc_files = glob.glob(os.path.join(os.path.abspath(os.path.dirname(sys.argv[0])), self.SRC_QRC_PATH))
qrc_files += glob.glob(os.path.join(os.path.abspath(os.path.dirname(sys.argv[0])), self.VENDOR_QRC_PATH))
for qrc in qrc_files:
subprocess.call(["rcc", "-binary", qrc, "-o", qrc[:-3] + "rcc"])
rcc_files = glob.glob(os.path.join(os.path.abspath(os.path.dirname(sys.argv[0])), self.SRC_RCC_PATH))
rcc_files += glob.glob(os.path.join(os.path.abspath(os.path.dirname(sys.argv[0])), self.VENDOR_RCC_PATH))
for rcc in rcc_files:
self.__pyqt_resources.registerResource(rcc)
As you can see i use rcccommand, not pyrcc5
To finish, this is my .qrc file:
<!DOCTYPE RCC>
<RCC version="1.0">
<qresource>
<file alias="jquery.js">../js/jquery.js</file>
<file alias="app.js">../js/app.js</file>
<file alias="qwebchannel.js">../js/qwebchannel.js</file>
<file alias="materialize.js">../css/materialize/js/materialize.js</file>
<file alias="materialize.css">../css/materialize/css/materialize.css</file>
</qresource>
</RCC>
I know there can be a lot of improvment and optimisation in javascript code and python code. But it works like this !
Thank's and hope i help someone too.
Related
I need to create a cookie method with the current time, which will first check the data (like_finger and article_id), and if there is no data, then add a like and update the date, if there is data, then do nothing.
I have a function
$likes = request()->cookie('like_finger');
$hours = 24;
if ($likes) {
Article::find($id)
->where('updated_at', '<', Carbon::now()->subHours($hours)->toDateTimeString())
->increment('like_finger');
}
But I can't check it yet, because I got confused in the add like button
I added a button to php.blade and created a function in js
<input type="button" id="start" value="Like Finger" onclick="startCombine(this)"> {{ $article->like_finger }}
function startCombine(startButton) {
startButton.disabled = true;
startButton.disabled = false;
}
How can I make sure that a like is added when true?
I want that when the button is clicked, one like is added, which will be stored in cookies for 24 hours, I wrote an approximate function of how the like should be added, but it is not perfect, since there is no button functionality
First of all, you should never store any logic in the client side. A great alternative for this kind of feature would be using the Laravel Aquantances package.
https://laravel-news.com/manage-friendships-likes-and-more-with-the-acquaintances-laravel-package
Anyway, since you want to do it with cookies;
We can actually do this a lot easier than thought.
Articles.php
class User extends Authenticatable
{
// ...
public static function hasLikedToday($articleId, string $type)
{
$articleLikesJson = \Cookie::get('article_likes', '{}');
$articleLikes = json_decode($articleLikesJson, true);
// Check if there are any likes for this article
if (! array_key_exists($articleId, $articleLikes)) {
return false;
}
// Check if there are any likes with the given type
if (! array_key_exists($type, $articleLikes[$articleId])) {
return false;
}
$likeDatetime = Carbon::createFromFormat('Y-m-d H:i:s', $articleLikes[$articleId][$type]);
return ! $likeDatetime->addDay()->lt(now());
}
public static function setLikeCookie($articleId, string $type)
{
// Initialize the cookie default
$articleLikesJson = \Cookie::get('article_likes', '[]');
$articleLikes = json_decode($articleLikesJson, true);
// Update the selected articles type
$articleLikes[$articleId][$type] = today()->format('Y-m-d H:i:s');
$articleLikesJson = json_encode($articleLikes);
return cookie()->forever('article_likes', $articleLikesJson);
}
}
The code above will allow us to is a user has liked an article and generate the cookie we want to set.
There are a couple important things you need to care about.
Not forgetting to send the cookie with the response.
Redirecting back to a page so that the cookies take effect.
I've made a very small example:
routes/web.php
Route::get('/test', function () {
$articleLikesJson = \Cookie::get('article_likes', '{}');
return view('test')->with([
'articleLikesJson' => $articleLikesJson,
]);
});
Route::post('/test', function () {
if ($like = request('like')) {
$articleId = request('article_id');
if (User::hasLikedToday($articleId, $like)) {
return response()
->json([
'message' => 'You have already liked the Article #'.$articleId.' with '.$like.'.',
]);
}
$cookie = User::setLikeCookie($articleId, $like);
return response()
->json([
'message' => 'Liked the Article #'.$articleId.' with '.$like.'.',
'cookie_json' => $cookie->getValue(),
])
->withCookie($cookie);
}
});
resources/views/test.blade.php
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<meta name="csrf-token" content="{{ csrf_token() }}" />
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap#4.6.0/dist/css/bootstrap.min.css" integrity="sha384-B0vP5xmATw1+K9KRQjQERJvTumQW0nPEzvF6L/Z6nronJ3oUOFUFpCjEUQouq2+l" crossorigin="anonymous">
</head>
<body>
<div class="container">
#if (session('success'))
<div class="alert alert-success" role="alert">
{{ session('success') }}
</div>
#endif
<pre id="cookie-json">{{ $articleLikesJson }}</pre>
<div class="row">
#foreach (range(1, 4) as $i)
<div class="col-3">
<div class="card">
<div class="card-header">
Article #{{ $i }}
</div>
<div class="card-body">
<h5 class="card-title">Special title treatment</h5>
<p class="card-text">With supporting text below as a natural lead-in to additional content.</p>
<a href="/test?like=heart&article_id={{ $i }}" class="btn btn-primary like-button">
Like Heart
</a>
<a href="/test?like=finger&article_id={{ $i }}" class="btn btn-primary like-button">
Like Finger
</a>
</div>
<div class="card-footer text-muted">
2 days ago
</div>
</div>
</div>
#endforeach
</div>
</div>
<script src="https://code.jquery.com/jquery-3.5.1.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/popper.js#1.16.1/dist/umd/popper.min.js" integrity="sha384-9/reFTGAW83EW2RDu2S0VKaIzap3H66lZH81PoYlFhbGU+6BZp6G7niu735Sk7lN" crossorigin="anonymous"></script>
<script src="https://cdn.jsdelivr.net/npm/bootstrap#4.6.0/dist/js/bootstrap.min.js" integrity="sha384-+YQ4JLhjyBLPDQt//I+STsc9iw4uQqACwlvpslubQzn4u2UU2UFM80nGisd026JF" crossorigin="anonymous"></script>
<script>
$(function() {
$.ajaxSetup({
headers: {
'X-CSRF-TOKEN': $('meta[name="csrf-token"]').attr('content')
}
});
$('.like-button').on('click', function(event) {
event.preventDefault();
let href = $(this).attr('href');
$.ajax({
url: href,
type: 'POST',
success: function (response) {
alert(response.message)
$('#cookie-json').text(response.cookie_json)
}
})
});
});
</script>
</body>
</html>
In Blade you can have conditionals, like
#if (count($records) === 1)
I have one record!
#elseif (count($records) > 1)
I have multiple records!
#else
I don't have any records!
#endif
Example taken from https://laravel.com/docs/8.x/blade
Let's try to apply it on your specific issue
#if ($article->article_id && $article->like_finger)
<input type="button" id="start" value="Like Finger" onclick="startCombine(this)"> {{ $article->like_finger }}
#endif
Make an AJAX request in startCombine() when the button is clicked.
Your server code processing the like seems to use a cookie named like_finger, so before the request to the server is made you create that cookie:
const d = new Date();
d.setTime(d.getTime() + (24*60*60*1000)); // Expiry in milliseconds
document.cookie = "like_finger=" + d.toUTCString() +
";expires=" + d.toUTCString() +
";path=/";
(The cookie is set to expire after 24 h with the above values)
Then you want to send that to the server:
var xhttp = new XMLHttpRequest();
xhttp.open("POST", "the_place_where_php_processing_code_is.php", true);
xhttp.setRequestHeader("Content-Type", "application/json");
xhttp.onreadystatechange = function() { // When status of the ongoing request changes
if (this.readyState == 4 && this.status == 200) {
// Server has processed the like request and is done
// You can do some "summary" here, like disabling the Like button
var response = this.responseText;
}
};
var data = {
id : 1, // The id of the article being liked, not sure how to retrieve that right now
};
xhttp.send(JSON.stringify(data));
..and then you use something like this in the receiving PHP code on the server:
$id = $request->input('id'); // $id = 1 (in this case, of course)
I'm trying to make the search of 'patient' Dynamic with ajax. Every thing in my code is working well but I don't know wy request.is_ajax() always returns false. I search about it but I didn't find the solution yet, right now my code do the search but with changing of the url and that mean the js dosen't work. I don't know how work well with javascript in Django so please help me.
This is my views.py:
def index(request):
ctx = {}
url_parameter = request.GET.get("q")
if url_parameter:
queryset = Patient.objects.annotate(fullname=Concat('first_name', Value(' '), 'last_name'))
patients = queryset.filter(fullname__icontains=url_parameter)
#patients = Patient.objects.filter(name__icontains=url_parameter)
else:
patients = Patient.objects.all()
ctx["patients"] = patients
print(request.is_ajax())
if request.is_ajax():
html = render_to_string(template_name="patient/patients-results-partial.html",context={"patients": patients})
data_dict = {"html_from_view": html}
return JsonResponse(data=data_dict, safe=False)
return render(request, "patient/index.html", context=ctx)
index.html:
{% extends 'base.html' %}
{% block content %}
<div class="col-md-6 offset-md-4">
{# part added for dynamic search#}
{# icon and search-box #}
<form class="form-inline">
<i id="search-icon" class="fas fa-search" aria-hidden="true"></i>
<input id="patient-input" class="form-control form-control-sm ml-3 w-75" type="text" placeholder="Search" aria-label="Search" name="q">
</form>
{# artist-list section #}
<div id="replaceable-content" class="col-6">
{% include 'patient/patients-results-partial.html' %}
</div>
</div>
<div class="col-md-6 offset-md-4">
Ajouter un nouveau patient
</div>
<div class="col-md-6 offset-md-4">
<div class="table-responsive">
<table class="table table-striped table-sm">
<thead>
<tr>
<th>Prénom</th>
<th>Nom</th>
<th>Téléphone</th>
<th>Sexe</th>
<th>Date de naissance</th>
<th>Docteur</th>
</tr>
</thead>
<tbody>
{% for field in patients %}
<tr>
<td>{{field.first_name}}</td>
<td>{{field.last_name}}</td>
<td>{{field.phone}}</td>
<td>{{field.sex}}</td>
<td>{{field.birth_date}}</td>
<td>{{field.doctor}}</td>
<td>Details</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
</div>
{% endblock content %}
and this is my js code:
const patient_input = $("#patient-input");
const search_icon = $('#search-icon');
const patients_div = $('#replaceable-content');
const endpoint = '/patient/';
const delay_by_in_ms = 700;
let scheduled_function = false;
let ajax_call = function (endpoint, request_parameters) {
$.getJSON(endpoint, request_parameters)
.done(response => {
// fade out the patients_div, then:
patients_div.fadeTo('slow', 0).promise().then(() => {
// replace the HTML contents
patients_div.html(response['html_from_view'])
// fade-in the div with new contents
patients_div.fadeTo('slow', 1)
// stop animating search icon
search_icon.removeClass('blink')
})
})
}
patient_input.on('keyup', function () {
const request_parameters = {
q: $(this).val() // value of patient_input: the HTML element with ID patient-input
}
// start animating the search icon with the CSS class
search_icon.addClass('blink')
// if scheduled_function is NOT false, cancel the execution of the function
if (scheduled_function) {
clearTimeout(scheduled_function)
}
// setTimeout returns the ID of the function to be executed
scheduled_function = setTimeout(ajax_call, delay_by_in_ms, endpoint, request_parameters)
})
I think this kind of AJAX call, is clean and easier than what you have in your code.
This model AJAX is working for me.
Maybe this js code helps you to fix your bug.
$('#form').on('submit', function (event) {
event.preventDefault();
const form = $(this);
const submit_btn = form.find('#submit-button');
$.ajax({
url: 'your URL for send ajax call',
type: 'POST', // Method of call, such as POST or GET
data: 'data as JSON', // You can use 'form.serialize()' to
beforeSend: function () {
// This line calls before that AJAX is called.
},
success: function (data) {
// If the back-end returns a JSON response with 200 status code, js will run this line.
},
error: function (data) {
// If the back-end returns a JSON response with 400 status code, js will run this line.
},
complete: function () {
// After success or error is called , this function will be called
},
})
})
I am trying to make an interactive button(to show a message in the console) with js, which just print a message in the console when the button is pressed. My js file is:
console.log("hello this is from cart.js")
var updateBtns = document.getElementsByClassName('update-cart')
for(var i=0; i<updateBtns.length; i++){
updateBtns[i].addEventListener('click', function(){
var productId = this.dataset.product
var action = this.dataset.action
console.log("inside loop")
//console.log('product ID: ', productId, "Action: ", action)
})
}
HTML:
<button data-product="{{ i.id }}" data-action="add" class="btn btn-outline-secondary add-btn update-cart">Add to Cart</button>
Here inside loop message does not show anytime.... the consol just show the following message:
hello this is from cart.js
DevTools failed to load SourceMap: Could not load content for chrome-extension://ndjpnladcallmjemlbaebfadecfhkepb/editor/config.js.map: HTTP error: status code 404, net::ERR_UNKNOWN_URL_SCHEME
DevTools failed to load SourceMap: Could not load content for chrome-extension://ndjpnladcallmjemlbaebfadecfhkepb/editor/content.js.map: HTTP error: status code 404, net::ERR_UNKNOWN_URL_SCHEME
How can I solve this problem?
It appears that your code works correctly when I add it to the snippet, but I think the issue might be related to how you load in your javascript code. If it is a <script> tag, could you make sure that it is included after the body tag?
So like this:
<html>
<head>...</head>
<body>
...
<script src="your-javascript-file.js"></script>
</body>
</html>
The issue could be that your script is being executed before the HTML elements are created.
console.log("hello this is from cart.js")
const dataset = {
product: [
'product-1',
'product-2',
'product-3'
],
action: (product) => { alert(product); }
}
const updateBtns = document.getElementsByClassName('update-cart')
for (let i = 0; i < updateBtns.length; i++) {
updateBtns[i].addEventListener('click', function() {
const productId = dataset.product[i]
const action = () => {
dataset.action(productId)
};
action();
//console.log('product ID: ', productId, "Action: ", action)
});
}
<button class="update-cart">1</button>
<button class="update-cart">2</button>
<button class="update-cart">3</button>
Using Meteor framework version 1.2.1
I have a form which adds data to Mongo collection. However I find that the javascript code executes without errors (and all the debug console.log messages appear as i expect) but still the collection doesn't have the data which i just inserted. The issue is that this happens kind of randomly. So sometimes the insertion is working and at other times the insertion doesn't work. Similar issue with the upsert command. my html and js code is pasted below (Note i haven't removed autopublish and insecure packages). Unable to figure what the issue in my code is and need help in this matter
JS Code
ProjectList = new Mongo.Collection("projectList");
ListItem = new Mongo.Collection("listItem");
if (Meteor.isClient) {
Template.create.events({
'submit .add_chapter': function (event) {
var addtoWhat;
var chapName = event.target.chapName.value;
if (event.target.addToWhat.value) {
if (event.target.addToWhat.value.length > 0) {
addtoWhat = event.target.addToWhat.value;
} else {
}
} else {
}
if (addtoWhat) {
var addToWhatItem = ListItem.findOne({name:addtoWhat});
var item = {
name : chapName,
list : [],
}
var id = ListItem.insert(item);
if (id) {
addToWhatItem.list.push(id);
if (!ListItem.upsert({_id:addToWhatItem._id}, addToWhatItem)) {
alert("Unable to upsert");
}
} else {
alert("Unable to insert");
}
} else {
var projList;
if (!ProjectList.findOne({projectId:"123"})) {
projList = {
projectId : "123",
list : [],
};
var topid = ProjectList.insert(projList);
if (topid) {
console.log ("Top Insert succesful with id " + topid);
} else {
console.log ("Error Top Insert unsuccesful with id ");
}
}
projList = ProjectList.findOne({projectId:"123"});
var item = {
name : chapName,
list : [],
}
var id = ListItem.insert(item);
projList.list.push(id);
if(!ProjectList.upsert({_id:projList._id}, projList)) {
console.log("Upsert failed");
} else {
console.log("Upsert successful");
}
}
},
'submit .gen_tree' : function(event) {
getElements();
}
});
function getElements() {
}
if (Meteor.isServer) {
Meteor.startup(function () {
// code to run on server at startup
});
}
HTML Code
<head>
<title>test_hierarchy2</title>
</head>
<body>
<h1>Welcome to Meteor!</h1>
{{> create}}
</body>
<template name="create">
<form class="add_chapter" method="post">
<label>addToWhat</label>
<input type="text" name="addToWhat">
<label>chapName</label>
<input type="text" name="chapName">
<button type="submit">Add</button>
</form>
<form class="gen_tree" method="post">
<button type="submit">generate</button>
</form>
</template>
Try this
ProjectList.update({_id:projList._id}, projList, {upsert:true}, function(error,doc){
if(error){
console.log(error);
}
else{
console.log(doc);
}
})
I've wrote a helper for the 3 conditions of users being logged in. I've verified that the CurrentUsers collection is being populated on user login with console.log on client.js and browser console. I'm not sure if I'm going about this wrong or if its a little error. There are no error messages in server console or browser console but nothing shows up for the condition of 0 users being logged in.
JS:
CurrentUsers = new Meteor.Collection("currentUsers")
if (Meteor.isClient) {
Template.lobby.nousers = function() {
return CurrentUsers.find().count() === 0;
}
Template.lobby.oneuser = function(){
return CurrentUsers.find().count() === 1;
}
Template.lobby.twousers = function(){
return CurrentUsers.find().count() === 2;
}
}
if (Meteor.isServer) {
Meteor._onLogin = function (userId){
if(CurrentUsers.find({user: userId}).count()===0){
CurrentUsers.insert({user: userId})
}
}
Meteor._onLogout = function (userId){
CurrentUsers.remove({user: userId})
}
}
HTML:
<head>
<title>bubblepopper</title>
</head>
<body>
{{loginButtons align = "right"}}
</body>
<template name = "lobby">
{{#if nousers}}
<div class = "nouser">
Hello please sign in to enter the game lobby.
</div>
{{/if}}
</template>
You are missing {{> lobby}} in your body.
<body>
{{loginButtons align = "right"}}
{{> lobby}}
</body>
Also, as far as I'm aware Meteor doesn't offer login/logout hooks, so Meteor._onLogin and Meteor._onLogout won't work out of the box: https://github.com/meteor/meteor/issues/1074
This event-hooks package might be interesting for you.