Project

General

Profile

FrPlugin Tutorial » History » Version 2

Robert Tome, 2013-03-21 10:16

1 1 Romain GEORGES
h1. Tutoriel du plugin Polls 
2
3
Remarque : Pour suivre ce tutoriel, vous devez avoir installé Redmine devel r1786 ou supérieur.
4
5
{{>toc}}
6
7
h2. Créer un nouveau plugin
8
 
9
Vous devez préalablement initialiser la variable RAILS_ENV sur "production" dans votre session shell pour continuer le tutotiel, pour ce faire, tapez :
10
11
<pre>
12
$ export RAILS_ENV="production"
13
</pre>
14
15
Pour créer un plugin Redmine, il existe des generateur pour les taches essentielles. 
16
17
La syntaxe des générateurs est :
18
19
<pre>ruby script/generate redmine_plugin <plugin_name></pre>
20
21
pour commencer, on va se positionner dans le répertoire de l'application Rails Redmine, puis créer la structure du plugin :
22
23
  % ruby script/generate redmine_plugin Polls
24
25
La structure du plugin est créé dans le repertoire @vendor/plugins/redmine_polls@:
26
27
<pre>
28
      create  vendor/plugins/redmine_polls/app/controllers
29
      create  vendor/plugins/redmine_polls/app/helpers
30
      create  vendor/plugins/redmine_polls/app/models
31
      create  vendor/plugins/redmine_polls/app/views
32
      create  vendor/plugins/redmine_polls/db/migrate
33
      create  vendor/plugins/redmine_polls/lib/tasks
34
      create  vendor/plugins/redmine_polls/assets/images
35
      create  vendor/plugins/redmine_polls/assets/javascripts
36
      create  vendor/plugins/redmine_polls/assets/stylesheets
37
      create  vendor/plugins/redmine_polls/lang
38
      create  vendor/plugins/redmine_polls/README
39
      create  vendor/plugins/redmine_polls/init.rb
40
      create  vendor/plugins/redmine_polls/lang/en.yml
41
</pre>
42
43
Editer @vendor/plugins/redmine_polls/init.rb@ pour adjuster les informations (attributs) du plugin (nom, auteur, description et version):
44
45
<pre><code class="ruby">
46
require 'redmine'
47
48
Redmine::Plugin.register :redmine_polls do
49
  name 'Polls plugin'
50
  author 'John Smith'
51
  description 'A plugin for managing polls'
52
  version '0.0.1'
53
end
54
</code></pre>
55
56
Redemarrez l'application Redmine et ouvrez un navigateur sur l'URL http://localhost:3000/admin/plugins.
57
58
Après vous être loggué avec les droits d'administrateur Redmine, vous devriez voir la liste des plugins tel que :
59
60
!plugins_list1.png!
61
62
h2. Générer un modèle Rails de plugin Redmine
63
64
pour le moment le plugin ne persiste aucuns résultats
65
Nous allons donc créer un modèle Poll simple, tel que :
66
67
<pre>
68
   ruby script/generate redmine_plugin_model <plugin_name> <model_name> [<fields>]
69
</pre>
70
71
La commande exacte pour notre cas sera :
72
73
<pre>
74
   ruby script/generate redmine_plugin_model polls poll question:string yes:integer no:integer
75
</pre>
76
77
cette commande crée le modèle Rails Poll et les fichiers de migration correspondant
78
79
*Remarque : Il est possible que vous deviez renommer les fichiers de migration, les migrations avec des timestamps ne sont pas supportée par le moteur Redmine Actuelle, Si les migrations portent une numérotation avec des timestamps, renommez-les avec "001" "002", etc... 
80
81
82
   <pre>cd vendor/plugins/redmine_polls/db/migrate
83
mv  20091009211553_create_polls.rb 001_create_polls.rb
84
cd ../../../../..</pre>
85
86
Si vous avez déja executé une migration, vous devez mettre à jour les informations dans la table plugin_schema_info en adequation avec la nouvelle numérotation.
87
88
Migrer la base de données avec la commande :
89
90
  rake db:migrate_plugins
91
92
Il est à noter que chaque plugin à son propre jeux de migration.
93
94
Nous allons ajouter des Votes via la console rails pour pouvoir faire des tests avec.
95
La console Rails permet l'ajout interactif d'enregistrement sur les modèles rails, c'est une shell Ruby Irb, qui pré-charge l'environnement de l'application rails depuis laquelle il est lancé.
96
Pour le moment nous allons juste créer un objet Poll
97
98
99
100
<pre>
101
script/console
102
>> Poll.create(:question => "Pouvez-vous voir ce vote ?")
103
>> Poll.create(:question => "Pouvez-vous voir cet autre vote ?")
104
>> exit
105
</pre>
106
107
Editez @vendor/plugins/redmine_polls/app/models/poll.rb@ dans le répertoire de votre plugin et ajoutez une méthode #vote qui sera appelée par votre controller:
108
109
<pre><code class="ruby">
110
class Poll < ActiveRecord::Base
111
  def vote(answer)
112
    increment(answer == 'yes' ? :yes : :no)
113
  end
114
end
115
</code></pre>
116
117
h2. Generer un controller
118
119
Pour le moment le plugins ne fait rien, donc nous allons créer un controller Rails pour celui-ci.
120
Nous pouvons utiliser le générateur Redmine prévue à cet effet :
121
122
<pre>ruby script/generate redmine_plugin_controller <plugin_name> <controller_name> [<actions>]</pre>
123
124
la commande exacte pour notre cas est :
125
126
<pre>
127
% ruby script/generate redmine_plugin_controller Polls polls index vote
128
      exists  app/controllers/
129
      exists  app/helpers/
130
      create  app/views/polls
131
      create  test/functional/
132
      create  app/controllers/polls_controller.rb
133
      create  test/functional/polls_controller_test.rb
134
      create  app/helpers/polls_helper.rb
135
      create  app/views/polls/index.html.erb
136
      create  app/views/polls/vote.html.erb
137
</pre>
138
139
un controlleur Rails  @PollsController@ avec 2 actions (@#index@ et @#vote@) vient d'être créé.
140
141
Editez @vendor/plugins/redmine_polls/app/controllers/polls_controller.rb@ dans le répertoire @redmine_polls@ pour implémenter ces deux actions.
142
143
<pre><code class="ruby">
144
class PollsController < ApplicationController
145
  unloadable
146
147
  def index
148
    @polls = Poll.find(:all)
149
  end
150
151
  def vote
152
    poll = Poll.find(params[:id])
153
    poll.vote(params[:answer])
154
    if poll.save
155
      flash[:notice] = 'Vote saved.'
156
      redirect_to :action => 'index'
157
    end
158
  end
159
end
160
</code></pre>
161
162
Ensuite, editez la vue @vendor/plugins/redmine_polls/app/views/polls/index.html.erb@ qui va afficher les votes existants.
163
164
165
<pre>
166
<h2>Polls</h2>
167
168
<% @polls.each do |poll| %>
169
  <p>
170
  <%= poll[:question] %>?
171
  <%= link_to 'Yes', {:action => 'vote', :id => poll[:id], :answer => 'yes'}, :method => :post %> (<%= poll[:yes] %>) /
172
  <%= link_to 'No', {:action => 'vote', :id => poll[:id], :answer => 'no'}, :method => :post %> (<%= poll[:no] %>)
173
  </p>
174
<% end %>
175
</pre>
176
177
Vous pouvez supprimer la vue @vendor/plugins/redmine_polls/app/views/polls/vote.html.erb@ comme il n'y a pas de rendu pour l'action correspondante.
178
179
Redemarreez le serveur Rails de Redmine et ouvrez votre navigateur sur l'URL http://localhost:3000/polls.
180
Vous devriez voir deux votes et vous pouvez les essailler : 
181
182
!pools1.png!
183
184
Remarque : les resultats des votes sont remis à zero à chaque requête si vous ne lancez pas votre application en environnement "production", vue que le modèle Poll est stocké dans une variable de classe dans notre exemple. 
185
186
187
h2. Traductions
188
189
L'emplacement des fichiers YAML d'internationalisation peut varier en fonction de votre version de Redmine :
190
191
|_. Version |_. Path|
192
| < 0.9 | @.../redmine_polls/lang@ |
193
| >= 0.9 | @.../redmine_polls/config/locales@ |
194
195
Si vous voulez que votre plugin marche dans les deux cas vous devez ajouter les fichiers dans les deux cas au bon format.
196
197
198
h2. Gestion des menus
199
200
Notre controller marche bien, mais nos utilisateurs n'en connaissent pas l'existence, il faut donc utilser l'API Redmine pour etendre les menus
201 2 Robert Tome
Nous allons ajouter un onglet au menu Application
202 1 Romain GEORGES
So let's add a new item to the application menu.
203
204
h3. Gestion du menu application
205
206
Editez le fichier @vendor/plugins/redmine_polls/init.rb@ à la racine de votre plugin et ajoutez la ligne suivante dans le bloc ""registration"" :
207
208
<pre><code class="ruby">
209
Redmine::Plugin.register :redmine_polls do
210
  [...]
211
  
212
  menu :application_menu, :polls, { :controller => 'polls', :action => 'index' }, :caption => 'Polls'
213
end
214
</code></pre>
215
216
la syntaxe est :
217
218
  menu(menu_name, item_name, url, options={})
219
220
Il y a cinq menu dans Redmine que vous pouvez étendre :
221
222
* @:top_menu@ - le menu en haut à gauche
223
* @:account_menu@ - le menu en haut à droite avec la gestion des comptes et connexions
224
* @:application_menu@ - Le menu affiché quand un utilisateur n'est dans aucuns projets.
225
* @:project_menu@ - Le menu affiché quand un utilisateur est dans un projet.
226
* @:admin_menu@ - le menu d'administration 
227
228 2 Robert Tome
les options disponibles sont :
229 1 Romain GEORGES
230
* @:param@ - la clef parametre utilisée pour les id de projet (valeur par défaut @:id@)
231
* @:if@ - un Proc appelé avant de faire le rendu du menu,l'item est affiché que si le Proc retourne true
232
* @:caption@ - Le label du menu du type:
233
234
  * un symbole de chaine de caratères localisée
235
  * une chaine de caratères
236
  * un Proc qui peut pendre le project_id en argument
237
238
* @:before@, @:after@ - specifie ou l'item du menu doit être inséré (ex. @:after => :activity@)
239
* @:first@, @:last@ - si ils sont true, l'item est positionné au début ou a la fin du menu (ex. @:last => true@)
240
* @:html@ - un hachage d'options html passés à @link_to@ pour le rendu du menuitem
241
242
Dans notre exemple, nous avons ajoutez un item au menu application, qui est vide par defaut.
243
244
Redemarrez l'application et allez à l'URL http://localhost:3000:
245
246
!application_menu.png!
247
248
Maintenant vous pouvez accéder aux votes en cliquant sur l'onglet Polls depuis l'ecran d'accueil de Redmine
249
250
h3. Etendre le menu projet
251
252
On va considérer, mantenant que les votes sont définis au niveau des projets (même si ce n'est pas le cas dans le modèle de notre exemple)
253
Donc, on veut ajouter l'onglet au menu Projet et plus au menu Application.
254
255
Editez le fichier @init.rb@ et replacez la dernière ligne que nous avons ajoutez par les deux lignes suivantes :
256
257
<pre><code class="ruby">
258
Redmine::Plugin.register :redmine_polls do
259
  [...]
260
261
  permission :polls, {:polls => [:index, :vote]}, :public => true
262
  menu :project_menu, :polls, { :controller => 'polls', :action => 'index' }, :caption => 'Polls', :after => :activity, :param => :project_id
263
end
264
</code></pre>
265
266
267
la deuxième ligne ajoute l'onglet Polls dans le menu Projet juste derrière l'onglet Activité.
268
la première ligne sert à déclarer que nos deux actions du @PollsController@ sont publiques.
269
Nous reviendrons plus tard sur les permissions.
270
271
Redémarrez encore l'application et entrez dans un de vos projets:
272
273
!http://www.redmine.org/attachments/3773/project_menu.png!
274
275
If you click the Polls tab, you should notice that the project menu is no longer displayed.
276
To make the project menu visible, you have to initialize the controller's instance variable @@project@.
277
278
Si vous cliquez sur l'onglet Polls, vous constatez que le menu projet n'est plus affiché.
279 2 Robert Tome
Pour continuer à l'afficher, nous devons initier la variable d'instance @@project@ du controlleur.
280 1 Romain GEORGES
281
Editez votre PollsController tel que:
282
283
<pre><code class="ruby">
284
def index
285
  @project = Project.find(params[:project_id])
286
  @polls = Poll.find(:all) # @project.polls
287
end
288
</code></pre>
289
290
L'id du projet est disponible dans @:project_id@ grace à l'option @:param => :project_id@ dans la déclaration du menu item précédante.
291
292
Maintenant, vous devriez continuer à voir le menu projet quand vous visualisez un vote :
293
294
295
296
!http://www.redmine.org/attachments/3774/project_menu_pools.png!
297
298
h2. Ajouter des nouvelles permissions
299
300
Pour le moment, tout le monde peut voter.
301
On peut rendre ceci configurable en ajoutant des permissions Redmine.
302
Nous allons definir deux permissions au niveau Projet, une pour visualiser et une pour voter.
303
Ces permissions ne seront donc plus publiques (l'option @:public => true@ disparait)
304
305
306
Editez @vendor/plugins/redmine_polls/init.rb@ pour remplacer la permission précedante avec les deux lignes suivantes :
307
308
<pre><code class="ruby">
309
310
  permission :view_polls, :polls => :index
311
  permission :vote_polls, :polls => :vote
312
</code></pre>
313
314
Redemarrez l'application et allez à l'URL http://localhost:3000/roles/report:
315
316
317
!permissions1.png!
318
319
on voit donc deux permissions de plus ajoutable à votre role.
320
Biensur, il va falloir ajouter du code au PollsController, donc ces actions sont pour le moment protégé par les permissions de l'utilisateur courant.
321
322
Pour cela, nous avons juste à ajouter le filtre @:authorize@ et faire en sorte que la variable d'instance @project est initialisée avant d'appeler ce filtre  
323
324
Voici à quoi ça doit ressembler dans l'action @#index@ :
325
326
327
<pre><code class="ruby">
328
class PollsController < ApplicationController
329
  unloadable
330
  
331
  before_filter :find_project, :authorize, :only => :index
332
333
  [...]
334
  
335
  def index
336
    @polls = Poll.find(:all) # @project.polls
337
  end
338
339
  [...]
340
  
341
  private
342
  
343
  def find_project
344
    # @project variable must be set before calling the authorize filter
345
    @project = Project.find(params[:project_id])
346
  end
347
end
348
</code></pre>
349
350
Récupérer le projet courant avant le @#vote@ peut-être fait de façon très similaire.
351
Après ça, voir un vote et voter ne sera accessible qu'aux administrateur ou aux utilisateurs que on un rôle approprié dnas le projet.
352
353
Pour traduire les symboles de vos permissions dans plusieurs langues, vous devez ajouter les labels de textes necessaires dans vos fichiers de langues tel que :
354
labels like this:
355
356
<pre><code class="ruby">
357
358
  permission_view_polls: Voir les votes
359
  permission_vote_polls: Voter
360
361
</code></pre>
362
363
Dans cette exemple, on a créé le fichier fr.yml, mais on peut créer des fichiers pour toutes les langues que l'on souhaite.
364
365
On voit dans cette exemple, que le lable est le symbole de la permission @:view_polls@ et @:vote_polls@ préfixé de @permission_@
366
367
368
Redemarrez votre application et pointer sur la section permissions.
369
370
h2. Créer un module de projets
371
372
Pour le moment, la fonctionnalité de vote est ajoutée à tous vos projets, mais on souhaite la rendre activable ou désactivable pour chaque projet.
373
On va donc créer un module de projet 'Polls'.
374
On fait ceci en inclant les permissions dans un bloc @#project_module@.
375
376
377
Editez @init.rb@ et changez la déclaration des permissions :
378
379
<pre><code class="ruby">
380
  project_module :polls do
381
    permission :view_polls, :polls => :index
382
    permission :vote_polls, :polls => :vote
383
  end
384
</code></pre>
385
386
Redemarrez votre application et pointer sur un de vos projet dans sa configuration.
387
Cliquez sur l'onglet Modules, vous y verez le module Polls à la fin de la liste de modules, désactivé par defaut.
388
389
!modules.png!
390
391
Vous pouvez l'activer ou le désactiver pour chaque projet. 
392
393
394
h2. Améliorer la vue du plugin
395
396
h3. Ajouter des Styles CSS
397
398
On va commencer par ajouter un CSS à notre vue 
399
400
Créez un fichier nommé @voting.css@ dans le répertoire @vendor/plugins/redmine_polls/assets/stylesheets@ :
401
402
<pre>
403
a.vote { font-size: 120%; }
404
a.vote.yes { color: green; }
405
a.vote.no  { color: red; }
406
</pre>
407
408
Quand on redemarrer l'application, les plugin assets sont copié dans @public/plugin_assets/redmine_polls/@
409
par le moteur de Rails pour les rendrent disponibles via votre serveur Web.
410
Donc toute modification des CSS des plugins impliques un redemarrage de Rails.
411
Ensuite, on va devoir ajouter les lignes suivantes dans la vue @vendor/plugins/redmine_polls/app/views/polls/index.html.erb@ pour que nos CSS soient pris en compte et incluent dans le header de cette vue par Redmine :
412
413
414
<pre>
415
<% content_for :header_tags do %>
416
    <%= stylesheet_link_tag 'voting', :plugin => 'redmine_polls' %>
417
<% end %>
418
</pre>
419
420
Notez que l'option @:plugin => 'redmine_polls'@ est requise quand on appelle le helper @stylesheet_link_tag@.
421
422
Les Javascripts peuvent être inclut dans le plugin en utilisant le helper @javascript_include_tag@ de la même manière.
423
424
h3. Modifier le titre de la page
425
426
on peut modifier le titre HTML de la page depuis le vue elle-même grace au helper @html_title@ 
427
Exemple:
428
429
  <% html_title "Polls" -%>
430
431
432
h2. Tester votre plugin
433
434
h3. test/test_helper.rb:
435
436
Voici le contenu de mon fichier de tests :
437
438
<pre>
439
require File.expand_path(File.dirname(__FILE__) + '/../../../../test/test_helper')
440
</pre>
441
442
h3. Exemple de test:
443
444
Contenu de requirements_controller_test.rb:
445
446
<pre>
447
require File.dirname(__FILE__) + '/../test_helper'
448
require 'requirements_controller'
449
450
class RequirementsControllerTest < ActionController::TestCase
451
  fixtures :projects, :versions, :users, :roles, :members, :member_roles, :issues, :journals, :journal_details,
452
           :trackers, :projects_trackers, :issue_statuses, :enabled_modules, :enumerations, :boards, :messages,
453
           :attachments, :custom_fields, :custom_values, :time_entries
454
455
  def setup
456
    @skill = Skill.new(:skill_name => 'Java')
457
    @project = Project.find(1)
458
    @request    = ActionController::TestRequest.new
459
    @response   = ActionController::TestResponse.new
460
    User.current = nil
461
  end
462
463
  def test_routing
464
    assert_routing(
465
      {:method => :get, :path => '/requirements'},
466
      :controller => 'requirements', :action => 'index'
467
    )
468
  end
469
</pre>
470
471
h3. Initialisation de la base de test :
472
473
Il semble plus facile d'initialiser la base de tests directement par la commande rake :
474
475
<pre>
476
rake db:drop db:create db:migrate db:migrate_plugins redmine:load_default_data RAILS_ENV=test
477
</pre>
478
479
h3. Executer les tests:
480
481
Pour executer the requirements_controller_test.rb on utilise la commande suivante :
482
483
<pre>
484
rake test:engines:all PLUGIN=redmine_requirements
485
</pre>
486
487
h3. Tester avec des utilisateurs et des projets 
488
489
If your plugin requires membership to a project, add the following to the beginning of your functional tests:
490
491
Si votre plugin requière de appartenances à un projet, ajouter les lignes suivantes pour que ce soit opérationnel :
492
493
<pre>
494
def setup
495
  @request    = ActionController::TestRequest.new
496
  @response   = ActionController::TestResponse.new
497
  User.current = nil
498
end
499
500
def test_index
501
  @request.session[:user_id] = 2
502
  get :index, :project_id => 1
503
  assert_response :success
504
  assert_template :index
505
end
506
</pre>