Putting 4.2.0 on top of 4.0.17
[usit-rt.git] / docs / initialdata.pod
1 =head1 Summary of initialdata files
2
3 It's often useful to be able to test configuration/database changes and then
4 apply the same changes in production without manually clicking around.  It's
5 also helpful if you're developing customizations or extensions to be able to
6 get a fresh database back to the state you want for testing/development.
7
8 This documentation applies to careful and thorough sysadmins as well as
9 extension authors who need to make database changes easily and repeatably for
10 new installs or upgrades.
11
12 =head1 Examples
13
14 RT ships with many initialdata files, only one of which is used to
15 configure a fresh install; the rest are used for upgrades, but function
16 the same despite being named differently.
17
18     etc/initialdata
19     etc/upgrade/*/content
20
21 The upgrade "content" files are meant to be incremental changes applied on top
22 of one another while the top level initialdata file is for fresh RT installs.
23
24 Extensions may also ship with database changes in such files.  You may find
25 some in your install with:
26
27     find local/plugins -name initialdata -or -name content
28
29 =head1 What can be in an initialdata file?
30
31 initialdata files are Perl, but often consist primarily of a bunch of data
32 structures defining the new records you want and not much extra code.  There's
33 nothing stopping you from writing a bunch of code, however!
34
35 The basic template of a new initialdata file should look something like this:
36
37     use strict;
38     use warnings;
39
40     our @Queues = (
41         # some definitions here
42     );
43
44     our @Groups = (
45         # some other definitions here
46     );
47
48     1;
49
50 The C<@Queues> and C<@Groups> arrays are expected by RT and should contain
51 hashref definitions.  There are many other arrays RT will look for and act on,
52 described below.  None are required, all may be used.  Keep in mind that since
53 they're just normal Perl arrays, you can C<push> onto them from a loop or
54 C<grep> out definitions based on conditionals or generate their content with
55 C<map>, etc.
56
57 The complete list of possible arrays which can be used, along with
58 descriptions of the values to place in them, is below.
59
60 =head2 C<@Users>
61
62     push @Users, {
63         Name        => 'john.doe',
64         Password    => 'changethis',
65         Language    => 'fr',
66         Timezone    => 'America/Vancouver',
67         Privileged  => 1,
68         Disabled    => 0,
69     };
70
71 Each hashref in C<@Users> is treated as a new user to create and passed
72 straight into C<< RT::User->Create >>.  All of the normal user fields are
73 available, as well as C<Privileged> and C<Disabled> (both booleans) which will
74 do the appropriate internal group/flag handling.
75
76 For a full list of fields, read the documentation for L<RT::User/Create>.
77
78 =head2 C<@Groups>
79
80     push @Groups, {
81         Name        => 'Example Employees',
82         Description => 'All of the employees of my company',
83     };
84
85 Creates a new L<RT::Group> for each hashref.  In almost all cases you'll want
86 to follow the example above to create a group just as if you had done it from
87 the admin interface.
88
89 Additionally, the C<MemberOf> field is specially handled to make it easier to
90 add the new group to other groups.  C<MemberOf> may be a single value or an
91 array ref.  Each value should be a user-defined group name or hashref to pass
92 into L<RT::Group/LoadByCols>.  Each group found will have the new group
93 added as a member.
94
95 Unfortunately you can't specify the I<members> of a group at this time.  As a
96 workaround, you can push a subref into C<@Final> which adds members to your new
97 groups.  An example, using a convenience function to avoid repeating yourself:
98
99     push @Final, sub {
100         add_members('My New Group Name' => qw(trs alex ruslan));
101         add_members('My Second Group'   => qw(jesse kevin sunnavy jim));
102     };
103
104     sub add_members {
105         my $group_name = shift;
106         my @members    = @_;
107
108         my $group = RT::Group->new( RT->SystemUser );
109         $group->LoadUserDefinedGroup($group_name);
110
111         if ($group->id) {
112             for my $name (@members) {
113                 my $member = RT::User->new( RT->SystemUser );
114                 $member->LoadByCols( Name => $name );
115
116                 unless ($member->Id) {
117                     RT->Logger->error("Unable to find user '$name'");
118                     next;
119                 }
120
121                 my ($ok, $msg) = $group->AddMember( $member->PrincipalObj->Id );
122                 if ($ok) {
123                     RT->Logger->info("Added member $name to $group_name");
124                 } else {
125                     RT->Logger->error("Unable to AddMember $name to $group_name: $msg");
126                 }
127             }
128         } else {
129             RT->Logger->error("Unable to find group '$group_name'!");
130         }
131     }
132
133 =head2 C<@Queues>
134
135     push @Queues, {
136         Name                => 'Helpdesk',
137         CorrespondAddress   => 'help@example.com',
138         CommentAddress      => 'help-comment@example.com',
139     };
140
141 Creates a new L<RT::Queue> for each hashref.  Refer to the documentation of
142 L<RT::Queue/Create> for the fields you can use.
143
144 =head2 C<@CustomFields>
145
146     push @CustomFields, {
147         Name        => 'Favorite color',
148         Type        => 'FreeformSingle',
149         LookupType  => 'RT::Queue-RT::Ticket',
150     };
151
152 Creates a new L<RT::CustomField> for each hashref.  It is the most complex of
153 the initialdata structures.  The most commonly used fields are:
154
155 =over 4
156
157 =item C<Name>
158
159 The name of this CF as displayed in RT.
160
161 =item C<Description>
162
163 A short summary of what this CF is for.
164
165 =item C<ApplyTo>
166
167 May be a single value, or an array reference of such; each should be
168 either an ID or Name.  If omitted, the CF is applied globally.  This
169 should not be used for User or Group custom fields.
170
171 This argument may also be passed via C<Queue>, for backwards
172 compatibility, which also defaults the C<LookupType> to
173 C<RT::Queue-RT::Ticket>.
174
175 =item C<Type>
176
177 One of the following on the left hand side:
178
179     SelectSingle            # Select one value
180     SelectMultiple          # Select multiple values
181
182     FreeformSingle          # Enter one value
183     FreeformMultiple        # Enter multiple values
184
185     Text                    # Fill in one text area
186     Wikitext                # Fill in one wikitext area
187
188     BinarySingle            # Upload one file
189     BinaryMultiple          # Upload multiple files
190
191     ImageSingle             # Upload one image
192     ImageMultiple           # Upload multiple images
193
194     Combobox                # Combobox: Select or enter one value
195
196     AutocompleteSingle      # Enter one value with autocompletion
197     AutocompleteMultiple    # Enter multiple values with autocompletion
198
199     Date                    # Select date
200     DateTime                # Select datetime
201
202     IPAddressSingle         # Enter one IP address
203     IPAddressMultiple       # Enter multiple IP addresses
204
205     IPAddressRangeSingle    # Enter one IP address range
206     IPAddressRangeMultiple  # Enter multiple IP address ranges
207
208 If you don't specify "Single" or "Multiple" in the type, you must specify
209 C<MaxValues>.
210
211 =item C<LookupType>
212
213 Labeled in the CF admin page as "Applies to".  This determines whether your CF
214 is for Tickets, Transactions, Users, Groups, or Queues.  Possible values:
215
216     RT::Queue-RT::Ticket                    # Tickets
217     RT::Queue-RT::Ticket-RT::Transaction    # Transactions
218     RT::User                                # Users
219     RT::Group                               # Groups
220     RT::Queue                               # Queues
221     RT::Class-RT::Article                   # Articles
222
223 Ticket CFs are the most common, meaning C<RT::Queue-RT::Ticket> is the most
224 common C<LookupType>.
225
226 =item C<RenderType>
227
228 Only valid when C<Type> is "Select".  Controls how the CF is displayed when
229 editing it.  Valid values are: C<Select box>, C<List>, and C<Dropdown>.
230
231 C<List> is either a list of radio buttons or a list of checkboxes depending on
232 C<MaxValues>.
233
234 =item C<MaxValues>
235
236 Determines whether this CF is a Single or Multiple type.  0 means multiple.  1
237 means single.
238
239 Make sure to set the C<MaxValues> field appropriately, otherwise you can end up
240 with unsupported CF types like a "Select multiple dates" (it doesn't Just
241 Work).
242
243 You can also use old-style C<Type>s which end with "Single" or "Multiple", for
244 example: SelectSingle, SelectMultiple, FreeformSingle, etc.
245
246 =item C<Values>
247
248 C<Values> should be an array ref (never a single value!) of hashrefs
249 representing new L<RT::CustomFieldValue> objects to create for the new custom
250 field.  This only makes sense for "Select" CFs.  An example:
251
252     my $i = 1;
253     push @CustomFields, {
254         LookupType  => 'RT::Queue-RT::Ticket',  # for Tickets
255         Name        => 'Type of food',
256         Type        => 'SelectSingle',  # SelectSingle is the same as: Type => 'Select', MaxValues => 1
257         RenderType  => 'Dropdown',
258         Values      => [
259             { Name => 'Fruit',      Description => 'Berries, peaches, tomatos, etc', SortOrder => $i++ },
260             { Name => 'Vegetable',  Description => 'Asparagus, peas, lettuce, etc',  SortOrder => $i++ },
261             # more values as such...
262         ],
263     };
264
265 In order to ensure the same sorting of C<Values>, set C<SortOrder> inside each
266 value.  A clever way to do this easily is with a simple variable you increment
267 each time (as above with C<$i>).  You can use the same variable throughout the
268 whole file, and don't need one per CF.
269
270 =item C<BasedOn>
271
272 Name or ID of another Select Custom Field.  This makes the named CF the source
273 of categories for your values.
274
275 =item C<Pattern>
276
277 The regular expression text (not C<qr//>!) used to validate values.
278
279 =back
280
281 Refer to the documentation and implementation of L<RT::CustomField/Create> and
282 L<RT::CustomFieldValue/Create> for the full list of available fields and
283 allowed values.
284
285 =head2 C<@ACL>
286
287 C<@ACL> is very useful for granting rights on your newly created records or
288 setting up a standard system configuration.  It is one of the most complex
289 initialdata structures.
290
291 =head3 Pick a Right
292
293 All ACL definitions expect a key named C<Right> with the internal right name
294 you want to grant.  The internal right names are visible in RT's admin
295 interface in grey next to the longer descriptions.
296
297 =head3 Pick a level: on a queue, on a CF, or globally
298
299 After picking a C<Right>, you need to specify on what object the right is
300 granted.  This is B<different> than the user/group/role receiving the right.
301
302 =over 4
303
304 =item Granted on a custom field by name (or ID), potentially a global or queue
305
306     CF => 'Name',
307     LookupType => 'RT::User',  # optional, in case you need to disambiguate
308
309 =item Granted on a queue
310
311     Queue => 'Name',
312
313 =item Granted on a custom field applied to a specific queue
314
315     CF      => 'Name',
316     Queue   => 'Name',
317
318 =item Granted on some other object (article Classes, etc)
319
320     ObjectType => 'RT::Class',
321     ObjectId   => 'Name',
322
323 =item Granted globally
324
325 Specifying none of the above will get you a global right.
326
327 =back
328
329 There is currently no way to grant rights on a group or article class level.
330 Note that you can grant rights B<to> a group; see below.  If you need to grants
331 rights on a group or article class level, you'll need to write an C<@Final>
332 subref to handle it using the RT Perl API.
333
334 =head3 Pick a Principal: User or Group or Role
335
336 Finally you need to specify to what system group, system/queue role,
337 user defined group, or user you want to grant the right B<to>.
338
339 =over 4
340
341 =item An internal user group
342
343     GroupDomain => 'SystemInternal',
344       GroupType => 'Everyone, Privileged, or Unprivileged'
345
346 =item A system-level role
347
348     GroupDomain => 'RT::System-Role',
349       GroupType => 'Requestor, Owner, AdminCc, or Cc'
350
351 =item A queue-level role
352
353     GroupDomain => 'RT::Queue-Role',
354       Queue     => 'Name',
355       GroupType => 'Requestor, Owner, AdminCc, or Cc',
356
357 =item A group you created
358
359     GroupDomain => 'UserDefined',
360       GroupId   => 'Name'
361
362 =item Individual user
363
364     UserId => 'Name or email or ID'
365
366 =back
367
368 =head3 Common cases
369
370 You're probably looking for definitions like these most of the time.
371
372 =over 4
373
374 =item Grant a global right to a group you created
375
376     { Right       => '...',
377       GroupDomain => 'UserDefined',
378       GroupId     => 'Name' }
379
380 =item Grant a queue-level right to a group you created
381
382     { Queue       => 'Name',
383       Right       => '...',
384       GroupDomain => 'UserDefined',
385       GroupId     => 'Name' }
386
387 =item Grant a CF-level right to a group you created
388
389     { CF          => 'Name',
390       Right       => '...',
391       GroupDomain => 'UserDefined',
392       GroupId     => 'Name' }
393
394 =back
395
396 Since you often want to grant a list of rights on the same object/level to the
397 same role/group/user, we generally use Perl loops and operators to aid in the
398 generation of C<@ACL> without repeating ourselves.
399
400     # Give Requestors globally the right to see tickets, reply, and see the
401     # queue their ticket is in
402     push @ACL, map {
403         {
404             Right       => $_,
405             GroupDomain => 'RT::System-Role',
406             GroupType   => 'Requestor',
407         }
408     } qw(ShowTicket ReplyToTicket SeeQueue);
409
410 =head3 Troubleshooting
411
412 The best troubleshooting is often to see how the rights you define in C<@ACL>
413 show up in the RT admin interface.
414
415 =head2 C<@Scrips>
416
417 Creates a new L<RT::Scrip> for each hashref.  Refer to the documentation of
418 L<RT::Scrip/Create> for the fields you can use.
419
420 Additionally, the C<Queue> field is specially handled to make it easier to
421 setup the same Scrip on multiple queues:
422
423 =over 4
424
425 =item Globally
426
427     Queue => 0,
428
429 =item Single queue
430
431     Queue => 'General', # Name or ID
432
433 =item Multiple queues
434
435     Queue => ['General', 'Helpdesk', 13],   # Array ref of Name or ID
436
437 =back
438
439 =head2 C<@ScripActions>
440
441 Creates a new L<RT::ScripAction> for each hashref.  Refer to the documentation
442 of L<RT::ScripAction/Create> for the fields you can use.
443
444 =head2 C<@ScripConditions>
445
446 Creates a new L<RT::ScripCondition> for each hashref.  Refer to the
447 documentation of L<RT::ScripCondition/Create> for the fields you can use.
448
449 =head2 C<@Templates>
450
451 Creates a new L<RT::Template> for each hashref.  Refer to the documentation of
452 L<RT::Template/Create> for the fields you can use.
453
454 =head2 C<@Attributes>
455
456 An array of L<RT::Attribute>s to create.  You likely don't need to mess with
457 this.  If you do, know that the key C<Object> is expected to be an
458 L<RT::Record> object on which to call C<AddAttribute>.  If you don't provide
459 C<Object> or it's undefined, C<< RT->System >> will be used.
460
461 =head2 C<@Initial>
462
463 =head2 C<@Final>
464
465 C<@Initial> and C<@Final> are special and let you write your own processing
466 code that runs before anything else or after everything else.  They are
467 expected to be arrays of subrefs (usually anonymous) like so:
468
469     our @Final = (sub {
470         RT->Logger->info("Finishing up!");
471     });
472
473 You have the full power of RT's Perl libraries at your disposal.  Be sure to do
474 error checking and log any errors with C<< RT->Logger->error("...") >>!
475
476 =head1 What's missing?
477
478 There is currently no way, short of writing code in C<@Final> or C<@Initial>,
479 to easily create B<Classes>, B<Topics>, or B<Articles> from initialdata files.
480
481 =head1 Running an initialdata file
482
483     sbin/rt-setup-database --action insert --datafile /path/to/your/initialdata
484
485 This may prompt you for a database password.
486
487 =head1 Implementation details
488
489 All the handling of initialdata files is done in C<< RT::Handle->InsertData >>.
490 If you want to know B<exactly> what's happening with each array, your best bet
491 is to start reading the code there.
492
493 RT takes care of the ordering so that your new queues are created before it
494 processes the new ACLs for those queues.  This lets you refer to new queues you
495 just created by Name.