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