forked from DiscoverMeteor/DiscoverMeteor_fr
-
Notifications
You must be signed in to change notification settings - Fork 0
/
11-notifications.md.erb
250 lines (196 loc) · 10.1 KB
/
11-notifications.md.erb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
---
title: Les Notifications
slug: notifications
date: 0011/01/01
number: 11
points: 10
photoUrl: http://www.flickr.com/photos/ikewinski/8719868039/
photoAuthor: Mike Lewinski
contents: Ajouter une collection notifications pour notifier les utilisateurs des actions des autres utilisateurs.|Apprendre comment partager uniquement les notifications pertinentes pour un utilisateur donné.|En apprendre plus sur les publications et les souscriptions.
paragraphs: 25
---
Maintenant que les utilisateurs peuvent commenter les articles de chacun, il serait bien de les avertir qu'une conversation a commencé.
Pour ce faire, nous notifierons à l'auteur de l'article qu'il y a eu un commentaire, et nous lui fournirons un lien pour voir le commentaire.
C'est sur ce type de fonctionnalité que Meteor resplendit : parce que Meteor est en temps réel par défaut, nous afficherons ces notifications _instantanément_. Nous n'avons pas besoin d'attendre que l'utilisateur rafraîchisse la page ou vérifie par un quelconque moyen, nous pouvons simplement faire apparaître de nouvelles notifications sans même écrire de code spécial.
### Créer des notifications
Nous allons créer une notification quand quelqu'un commente sur vos articles. Dans le future, les notifications pourront être étendues pour couvrir beaucoup d'autres scénarii, mais pour l'instant ce sera suffisant pour garder les utilisateurs informés de ce qu'il se passe.
Créons notre collection `Notifications`, ainsi qu'une fonction `createCommentNotification` qui insèrera une notification correspondante pour chaque nouveau commentaire sur un de vos articles :
~~~js
Notifications = new Meteor.Collection('notifications');
Notifications.allow({
update: ownsDocument
});
createCommentNotification = function(comment) {
var post = Posts.findOne(comment.postId);
if (comment.userId !== post.userId) {
Notifications.insert({
userId: post.userId,
postId: post._id,
commentId: comment._id,
commenterName: comment.author,
read: false
});
}
};
~~~
<%= caption "collections/notifications.js" %>
Comme les articles ou commentaires, cette collection `Notifications` sera partagée côté client et serveur. Comme nous avons besoin de mettre à jour les notifications une fois que l'utilisateur les a vues, nous autorisons également les mises à jours, en s'assurant comme d'habitude de bien limiter les permissions aux propres données de l'utilisateur.
Nous avons également créé une simple fonction qui surveille l'article que l'utilisateur commente, détermine qui devrait être notifié à ce moment, et insère une nouvelle notification.
Nous créons déjà des commentaires dans une méthode côté serveur, donc nous pouvons juste compléter cette méthode pour appeler notre fonction. Nous remplacerons `return Comments.insert(comment);` par `comment._id = Comments.insert(comment)` afin de sauvegarder l'`_id` du commentaire nouvellement créé dans une variable, puis appelerons notre fonction `createCommentNotification` :
~~~js
Comments = new Meteor.Collection('comments');
Meteor.methods({
comment: function(commentAttributes) {
// [...]
// create the comment, save the id
comment._id = Comments.insert(comment);
// maintenant créez une notification, en informant l'utilisateur qu'il y a eu un commentaire
createCommentNotification(comment);
return comment._id;
}
});
~~~
<%= caption "collections/comments.js" %>
<%= highlight "8~14" %>
Publions également les notifications, et souscrivons-y coté client :
~~~js
// [...]
Meteor.publish('notifications', function() {
return Notifications.find();
});
~~~
<%= caption "server/publications.js" %>
~~~js
Router.configure({
layoutTemplate: 'layout',
loadingTemplate: 'loading',
waitOn: function() {
return [Meteor.subscribe('posts'), Meteor.subscribe('notifications')]
}
});
~~~
<%= caption "lib/router.js" %>
<%= highlight "5" %>
<%= commit "11-1", "Ajout collection notifications." %>
### Affichage des notifications
Maintenant nous pouvons continuer et ajouter une liste de notifications à l'en-tête.
~~~html
<template name="header">
<header class="navbar">
<div class="navbar-inner">
<a class="btn btn-navbar" data-toggle="collapse" data-target=".nav-collapse">
<span class="icon-bar"></span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
</a>
<a class="brand" href="{{pathFor 'postsList'}}">Microscope</a>
<div class="nav-collapse collapse">
<ul class="nav">
{{#if currentUser}}
<li>
<a href="{{pathFor 'postSubmit'}}">Soumettre l'article</a>
</li>
<li class="dropdown">
{{> notifications}}
</li>
{{/if}}
</ul>
<ul class="nav pull-right">
<li>{{loginButtons}}</li>
</ul>
</div>
</div>
</header>
</template>
~~~
<%= caption "client/views/includes/header.html" %>
<%= highlight "12~19" %>
Et créer les modèles de `notifications` et `notification` (ils partageront un même fichier `notifications.html`) :
~~~html
<template name="notifications">
<a href="#" class="dropdown-toggle" data-toggle="dropdown">
Notifications
{{#if notificationCount}}
<span class="badge badge-inverse">{{notificationCount}}</span>
{{/if}}
<b class="caret"></b>
</a>
<ul class="notification dropdown-menu">
{{#if notificationCount}}
{{#each notifications}}
{{> notification}}
{{/each}}
{{else}}
<li><span>No Notifications</span></li>
{{/if}}
</ul>
</template>
<template name="notification">
<li>
<a href="{{notificationPostPath}}">
<strong>{{commenterName}}</strong> a commenté votre article
</a>
</li>
</template>
~~~
<%= caption "client/views/notifications/notifications.html" %>
Nous pouvons voir que l'idée est de fournir dans chaque notification un lien vers l'article qui a été commenté, et le nom de l'utilisateur qui l'a commenté.
Ensuite, nous avons besoin de nous assurer que nous sélectionnons la bonne liste de notifications dans notre manager, et mettons à jour les notifications comme "lues" quand l'utilisateur clique sur le lien vers lequel elles pointent.
~~~js
Template.notifications.helpers({
notifications: function() {
return Notifications.find({userId: Meteor.userId(), read: false});
},
notificationCount: function(){
return Notifications.find({userId: Meteor.userId(), read: false}).count();
}
});
Template.notification.helpers({
notificationPostPath: function() {
return Router.routes.postPage.path({_id: this.postId});
}
})
Template.notification.events({
'click a': function() {
Notifications.update(this._id, {$set: {read: true}});
}
})
~~~
<%= caption "client/views/notifications/notifications.js" %>
<%= commit "11-2", "Afficher des notifications dans l'en-tête." %>
Vous pouvez penser que les notifications ne sont pas si différentes des erreurs, et c'est vrai que leur structure est très similaire. Il y a néanmoins une différence clé: nous avons créé une collection client / serveur synchronisée. Cela signifie que nos notifications sont *persistantes* et, tant que nous gardons le même compte utilisateur, survivront au rafraîchissement des navigateurs et des différents appareils.
Essayez-le : ouvrez un deuxième navigateur (disons Firefox), créez un nouveau compte utilisateur, et commentez sur un article que vous avez créé avec votre compte utilisateur principal (que vous avez laissé ouvert dans Chrome). Vous devriez voir apparaître quelque chose comme ça :
<%= screenshot "11-1", "Afficher des notifications." %>
### Controller l'accès aux notifications
Les notifications fonctionnent bien. Cependant, il y a un petit problème : nos notifications sont publiques.
Si vous avez encore votre deuxième navigateur ouvert, essayez d’exécuter le code suivant dans une console navigateur :
~~~js
❯ Notifications.find().count();
1
~~~
<%= caption "Console du navigateur" %>
Ce nouvel utilisateur (celui qui a *commenté*) ne devrait pas avoir de notifications. La notification qu'il voit dans la collection `Notifications` appartient en fait à notre utilisateur original.
En marge de ces potentiels problèmes de confidentialité, nous ne pouvons pas nous permettre d'avoir toutes les notifications des utilisateurs chargées dans tous les navigateurs des autres utilisateurs. Sur un assez gros site, cela pourrait surcharger la mémoire disponible du navigateur et faire apparaître des sérieux problèmes de performance.
Nous corrigeons ce problème avec les **publications**. Nous pouvons utiliser nos publications pour spécifier précisément quelle partie de notre collection nous voulons partager dans chaque navigateur.
Pour accomplir cela, nous avons besoin de retourner un curseur différent dans notre publication de `Notifications.find()`. Plus exactement, nous voulons retourner un curseur qui correspond aux notifications de l'utilisateur courant.
Faire cela est assez direct, puisqu' une fonction `publish` a l'`id` de l'utilisateur courant disponible via `this.userdId` :
~~~js
Meteor.publish('notifications', function() {
return Notifications.find({userId: this.userId});
});
~~~
<%= caption "server/publications.js" %>
<%= commit "11-3", "Synchroniser uniquement les notifications pertinantes pour l'utilisateur courant." %>
Maintenant, si nous vérifions dans nos deux fenêtres de navigateur, nous devrions voir deux collections de notifications différentes :
~~~js
❯ Notifications.find().count();
1
~~~
<%= caption "Console du navigateur (utilisateur 1)" %>
~~~js
❯ Notifications.find().count();
0
~~~
<%= caption "Console du navigateur (utilisateur 2)" %>
En fait, la liste de Notifications devrait même changer selon que vous authentifiez et vous déconnectiez de votre application. Tout cela parce que les publications sont re-publiées automatiquement quand le compte utilisateur change.
Notre application devient de plus en plus fonctionnelle, et à mesure que des utilisateurs s'inscrivent et ajoutent des liens nous courons le risque de finir avec une page d'accueil sans fin. Nous allons nous occuper de ça dans le prochain chapitre en implémentant une pagination.