1 DEBIAN GFORGE PLUGINS HOWTO
2 --------------------------------
4 Here is a short HOWTO explaining how plugins work in Debian
5 GForge, and how to make a new one.
7 It was written by Roland Mas <lolando@debian.org>.
9 WHAT PLUGINS ARE, AND WHY THEY ARE USEFUL
10 -----------------------------------------
12 Plugins are extensions to the "core" of GForge, providing extra
13 functionality without being tightly integrated within Sourceforge
14 proper. They are useful because they allow for independent
15 development of third-party functionality, and they add flexibility to
16 Sourceforge as to what features are available on a particular
19 As an example, it's been suggested to integrate a shared calendar
20 application in Sourceforge. It's a good idea and an interesting
21 feature, but not one that everybody wants. Thus, including it in the
22 GForge code would piss off someone. Additionnally, there might
23 be several competing implementations for such a calnedar application.
24 Choosing one among them would also piss off people. So it is made
25 possible to have a system so that different implementations can exist
26 and be installed separately.
31 It is expected that a plugin is just some new feature added to
32 GForge, and not a change in the behaviour of existing features.
33 A plug-in should therefore only add files, not change existing ones.
34 Whether these files be web pages, offline scripts, static
35 documentation or else is not relevant.
37 Of course, *some* changes will have to be made to the "core" files,
38 if only to add links to new web pages, for instance. These changes
39 are acceptable, and will be discussed below. Here come the details
40 about how the plugin system is implemented.
42 - A plugin will be identified primarily by a string handle, which will
43 be static across all installations of this plugin. It should be
44 composed of lowercase letters only, because it's going to be used in
45 table names and we don't want namespace conflicts. For instance, if
46 the ACME company writes a time tracking tool plugin, the handle for
47 that plugin could be "acmetimetracker". When installed, the plugin
48 will be assigned an integer identifier. This id might vary from site
49 to site, and should not be depended upon.
51 We [the GForge-proper maintainers team] will maintain some sort
52 of list of allocated plugin names so that different plugins get
53 different allocated identifiers, see below.
55 - Tables in the database schema: special tables have been added to the
56 database schema to keep track of installed plugins. They are
57 described below (simplified descriptions):
59 | CREATE TABLE plugins (plugin_id integer,
60 | plugin_name character(32),
62 | CONSTRAINT plugins_pkey PRIMARY KEY (plugin_id)
64 | CREATE TABLE group_plugin (group_plugin_id integer,
67 | CONSTRAINT PRIMARY KEY (plugin_id),
68 | CONSTRAINT FOREIGN KEY (group_id) REFERENCES groups(group_id)
70 | CREATE TABLE user_plugin (user_plugin_id integer,
73 | CONSTRAINT PRIMARY KEY (plugin_id),
74 | CONSTRAINT FOREIGN KEY (user_id) REFERENCES users(user_id)
78 "plugins" lists the installed plugins, with the numeric id, the
79 string handle (say, "acmetimetracker") and a description.
81 "group_plugin" is a way to store the fact that a group "uses" a
82 plugin without needing to add a "uses_acmetimetracker" to the groups
83 table for each known plugin.
85 "user_plugin" is the same, for users.
87 - A plugin may create its own tables in the same database. These
88 tables must be named plugin_foo_* if the plugin's string identifier is
89 "foo". One suggested table is plugin_foo_meta_data, which should be
90 used to store the plugin meta-data, such as the installed version.
91 The plugin can then use some code like db-upgrade.pl if its database
92 schema changes over time.
94 [TODO: Standardise the command/script/something below]
95 These tables may have foreign key referential integrity constraints
96 going from them to standard tables, but not the other way round. If
97 they have, then a command/script/something must be provided so that
98 the main db-upgrade.pl can disable the constraints and re-enable them
99 afterwards in case some database schema changes are needed.
101 Similarly, a plugin may create sequences, indexes, views, etc,
102 provided that their names are prefixed with plugin_foo_ too.
104 A plugin should not modify the data in tables that do not belong to
105 it. If it really needs to, then please discuss it with us first,
106 there might be cases where it's needed/useful. Reading those data is
107 okay, but it must be careful not to leak any info to places/users
108 which normally wouldn't have had access to it.
110 - Functions in Group.class.php and User.class.php: the Group and User classes
111 now have a usesPlugin() method. It takes a single parameter, the
112 "acmetimetracker" identifier for the module, and returns a boolean if
113 the particular user/group has turned on the use of that module. Also
114 provided are setPluginUsage() methods, taking a plugin name and a
115 boolean value as arguments and returning true on success and false on
118 - A plugin should not change the existing files. Of course, it will
119 need a way to adds links to its own web pages. This is done by a
120 "hook" system. Each plugin can hook itself up to a number of hook
121 points in the main code, and execute arbitrary code when that point is
122 reached. Basically, the plugin registers itself to a global object
123 (of the PluginManager class, if you want to know). You have to call
124 the register_plugin() function, providing it an object of a subclass
125 of the Plugin class that is provided by the main code. That object
126 must provide a GetHooks() method, which returns a list of hook names.
127 Whenever one of these hooks is encountered, the object's CallHook()
128 method is called with the hook name and extra parameters that depend
129 on the hook. Adding a link to your page in some place is just a
130 matter of "subscribing" yourself to the hook that is in the
131 appropriate place, and printing the appropriate link whenever your
132 CallHook() method is called from that place.
134 Registering your plugin is done by providing a
135 /usr/share/gforge/plugins/<pluginname>/include/<pluginname>-init.php.
136 It will be parsed by the PluginManager object. That file should
137 contain a call to register_plugin(), passing it an object of the
138 appropriate class. See the helloworld plugin for an example.
140 The hooks are managed centrally by the GForge code maintainers.
141 If you need one, please ask, we'll add it. The current list of
142 hooks is provided at the end of this document.
143 I rely on you plugins developers to provide more ideas :-)
145 - Plugin-specific web pages should reside either in the /plugin/*/
146 URL-space (that is, plugin "foo" will probably put its files in
147 /usr/share/gforge/www/plugins/foo/) or (if the web interface is not
148 written in PHP) in /plugin/*/cgi-bin/ URL-space (files in
149 /usr/lib/sourceforge/cgi-bin/plugins/foo/).
151 If possible, and as much as possible, a plugin should use the layout
152 functions defined by GForge (Layout.class.php, HTML.class.php, or
153 whatever they're called), to ensure a consistent look and themability.
155 Of course, the previous point only applies to plugins written in
156 PHP. Plugins written in other languages are not excluded by this
157 proposal, and there is no need to restrict them. Should they appear,
158 they might need to recode some of GForge's functions in Perl or
159 another language. I see no need to restrict that either. Only thing:
160 it would be better if the porting were as straightforward as possible.
161 Do not reimplement, please. Just translate from PHP to Perl or
162 whatever. If you do, please submit your translation to us, so that it
163 can be provided by GForge proper and maintained in common.
165 [TODO: Think about that, design, implement]
166 Speaking of languages... There should be some way to have
167 plugin-specific language files, so that the plugins can use the
168 standard methods used elsewhere in Sourceforge. I haven't thought
169 about that very deeply yet, but I think it will evolve into a
170 recommendation that the "handles" in the language files are
171 plugin_foo_page / item (as compared to the current page / item model
172 used for "core" GForge i18n strings).
174 - A plugin should register itself into the database using the provided
175 register-plugin script on its installation, and unregister itself
176 using unregister-plugin on removal. When unregistering, be careful
177 to delete all the rows in tables that contain a reference to your
178 plugin_id, so that the unregistration process (which deletes your row
179 in the plugins table) does not fail due to referential integrity errors.
181 HOW DO I MAKE A PLUGIN?
182 -----------------------
184 Your best bet would be to start with the sample "helloworld" plugin
185 and change parts of it. It shows an example of most of the things you
186 should need to make your plugin: PHP pages, configuration files, bits
187 of Apache configuration, cron jobs, etc. If you need something else,
188 please ask, we'll discuss it, (hopefully) reach an agreement on how to
189 Do It Right, and implement a sample in helloworld.
191 HOW TO NAME MY PLUGIN
192 ---------------------
194 If you plan on distributing your plugin to the public, please contact
195 the GForge maintainer with your proposed name, and we'll add it
196 to the list below. This ensures that no other plugin will use the
197 same name, so as to reduce the risk of name conflicts.
199 If you only intend to keep your plugin for yourself, you might still
200 contact us with your plugin name. If you're really nice, we might
201 consider adding it here too, so that other people who want to
202 distribute their plugin do not reuse the same name.
204 For reference, this is the list of currently used plugin names:
206 - helloworld, the plugin provided as an example.
207 - extldapauth, a plugin allowing on-the-fly account creation from an
208 existing LDAP directory;
210 CURRENT LIST OF PLUGIN HOOKS
211 ----------------------------
213 The following is a list of hooks available in GForge for plugins to utilise.
214 Each hook is listed with its name, locations in the source code where the
215 hook is called, and parameters that are passed into the hook and a brief
216 description. There may be other hooks available, added after this section
219 Hook Name : session_set_entry
220 Locations : common/include/session.php
221 Description: Called before checking if the user is logged in by
222 reading session cookie.
223 You can use this hook to handle session setup specific
226 Hook Name : session_set_return
227 Locations : common/include/session.php
228 Description: Called after checking if the user is logged in by reading
230 You can use this hook to handle session setup specific
233 Hook Name : artifact_extra_detail
234 Parameters : artifact_id - The ID of a tracker item
235 Locations : www/tracker/detail.php
236 www/tracker/mod-limited.php
238 Description: Use this hook to provide additional information about a
239 tracker item based upon its ID.
241 Hook Name : before_logout_redirect
242 Locations : www/account/logout.php
243 Description: Called once the GForge user has had their session logged
244 out, and before the user is redirected to the homepage of
248 Locations : www/include/Layout.class.php
249 Description: Used to include a CSS link element to include in the page
250 layout. The hook should return a complete <link> element.
253 Locations : www/include/Layout.class.php
254 Description: Used to include inline CSS into the page layout. The
255 hook should return pure CSS, without surrounding
258 Hook Name : group_approved
259 Parameters : group_id - The numeric ID of the group
260 Locations : www/admin/approve-pending.php
261 Description: When a group is approved by a site admin, this hook is called.
263 Hook Name : groupisactivecheckboxpost
264 Parameters : group_id - The numeric ID of the group
265 Locations : www/project/admin/editgroupinfo.php
266 Description: Called when a plugin is activated for a specific group from
267 the group's Edit Public Info page. Use this to perform
268 actions to initialise the plugin for a specific group.
270 Hook Name : groupisactivecheckbox
271 Parameters : group_id - The numeric ID of the group
272 Locations : www/project/admin/editgroupinfo.php
273 Description: Used to display a portion of a form on a group's Edit
274 Public Info page. It should return a HTML <tr> line containing
277 Hook Name : groupmenu
278 Parameters : DIRS - A reference to the array of tab URLs
279 TITLES - A reference to the array of tab titles
280 toptab - A reference to a string containing the name of
281 the GForge tab menu in use (eg. admin, tracker)
282 selected - A reference to an array index of the tabs.
283 group - The numeric ID of the current group
284 Locations : www/include/Layout.class.php
285 Description: Used to provide a plugin specific tab in when viewing
287 [TODO: The use of the 'group' name as a parameter is inconsistent
288 with most other group plugin hooks - which use group_id.]
290 Hook Name : groupmenu_scm
291 Parameters : DIRS - A reference to the array of tab URLs
292 TITLES - A reference to the array of tab titles
293 toptab - A reference to a string containing the name of
294 the GForge tab menu in use (eg. admin, tracker)
295 selected - A reference to an array index of the tabs.
296 group_id - The numeric ID of the current group
297 Locations : www/include/Layout.class.php
298 Description: Provides a tab for the SCM system in the group pages.
300 Hook Name : headermenu
301 Parameters : toptab - A reference to a string containing the name of
302 the GForge tab menu in use (eg. admin, tracker)
303 template - An HTML template giving how to add the menu.
304 Locations : www/include/Layout.class.php
305 Description: Used to provide a plugin specific menu entry in the header
306 top menu (after: Login, Logout, My Account).
307 See plugin online_help for example of use.
309 Hook Name : javascript
310 Locations : www/include/Layout.class.php
311 www/include/LayoutSF.class.php
312 Description: Provides a place to add inline Javascript into the page.
313 The output of the hook should be pure Javascript, as it will
314 be placed within an existing <script> block.
315 [TODO: The output of the hook appears after the closing SGML comment marker
316 and before the closing </script> element. Is this what is really indended?]
318 Hook Name : project_admin_plugins
319 Parameters : group_id - The numeric ID of the group
320 Locations : www/project/admin/index.php
321 Description: Provides a place for plugin authors to add a link on the
322 group summary page to the admin page for a plugin.
324 Hook Name : project_after_description
325 Parameters : group_id - The numeric ID of the group
326 Locations : www/include/project_home.php
327 Description: Provides some space for plugin specific text on a group's
330 Hook Name : project_public_area
331 Parameters : group_id - The numeric ID of the group
332 Locations : www/include/project_home.php
333 Description: Used to provide plugin specific infos on a group's
336 Hook Name : scm_admin_update
337 Parameters : group_id - The numeric ID of the group
338 Parameters : scmradio
339 A number of scm specific values generated from the
340 form fields created by the scm_admin_page hook.
341 Locations : www/scm/admin/index.php
342 Description: When the SCM admin page is submitted, this hook is called.
343 [TODO: Is scmradio actually used anywhere or is it legacy? A grep through
344 the source code seems to indicate its never used!]
346 Hook Name : scm_admin_page
347 Parameters : group_id - The numeric ID of the group
348 Locations : www/scm/admin/index.php
349 Description: Used to generate an administrative form for the SCM
350 plugin. All the form fields generated by this hook should
351 be named [pluginname]_[fieldname] where [pluginname] is the
352 SCM plugin name and [fieldname] is a field name for the
353 form element. Using this naming scheme ensures the fields
354 are properly passed as parameters to the scm_admin_update hook.
357 Parameters : group_id - The numeric ID of the group
358 Locations : www/scm/index.php
359 Description: Show a page for the SCM in use by a group.
361 Hook Name : scm_plugin
362 Parameters : scm_plugins - A reference to an array of plugins providing
363 SCM features. Each element is a plugin string name.
364 Locations : common/scm/SCMFactory.class.php
365 Description: This is used by GForge to identify SCM plugins. Any plugin that
366 provides SCM features should add itself to the scm_plugins array
367 when this hook is called.
369 Hook Name : scm_stats
370 Parameters : group_id - The numeric ID of the group
371 Locations : www/include/project_home.php
372 Description: Shows SCM specific statistics on the group's summary page.
374 Hook Name : search_engines
375 Locations : www/search/include/SearchManager.class.php
377 Hook Name : session_before_login
378 Parameters : loginname - The login as passed in from the user
379 passwd - The password as passed in from the user
380 Locations : common/include/session.php
381 Description: Authentication plugins can use this hook to authenticate
382 a user before GForge passes the authentication details on
383 to its own database. The hook should return true if the
384 authentication succeeds.
386 Hook Name : site_admin_option_hook
387 Locations : www/admin/index.php
388 Description: Use this to provide a link to the site wide administrative
389 pages for your plugin. The hook should return HTML within
390 a <li> block and will appear on the Site Admin page in the
393 Hook Name : task_extra_detail
394 Parameters : task_id - The numeric ID for a task
395 Locations : www/pm/detail_task.php
397 Description: Provides a place to include extra information about a
398 task. The hook should return a <tr> row containing 2 cells
399 (or colspan'ed to 2).
402 Locations : www/include/html.php
403 Description: Prints out a tab to show when displaying user pages.
404 Unlike the groupmenu hook, this hook should use the PrintSubMenu
405 method to display the tab itself.
408 Locations : common/include/Role.class.php
409 Description: Provides a place to read role from another subsystem (LDAP, DB,
412 Hook Name : role_update
413 Locations : common/include/Role.class.php
414 Description: Triggered when new a role is updated
416 Hook Name : role_setuser
417 Locations : common/include/Role.class.php
418 Description: Provides a way to extend the way user information are stored
420 hook Name : outermenu
421 Parameters : DIRS - A reference to the array of tab URLs
422 TITLES - A reference to the array of tab titles
423 Location : www/include/Layout.class.php
424 Description: Used to provide a plugin specific tab in main menu.
426 Hook Name : project_public_area
427 Parameters : group_id - The numeric ID of the group
428 Locations : www/include/project_home.php
429 Description: Used to provide plugin specific infos on a group's
432 -- Roland Mas <lolando@debian.org>