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