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