Upgrade 4.0.17 clean.
[usit-rt.git] / docs / initialdata.pod
CommitLineData
45030404
MKG
1=head1 Summary of initialdata files
2
3It's often useful to be able to test configuration/database changes and then
4apply the same changes in production without manually clicking around. It's
5also helpful if you're developing customizations or extensions to be able to
6get a fresh database back to the state you want for testing/development.
7
8This documentation applies to careful and thorough sysadmins as well as
9extension authors who need to make database changes easily and repeatably for
10new installs or upgrades.
11
12=head1 Examples
13
14RT ships with many initialdata files, only one of which is used to
15configure a fresh install; the rest are used for upgrades, but function
16the same despite being named differently.
17
18 etc/initialdata
19 etc/upgrade/*/content
20
21The upgrade "content" files are meant to be incremental changes applied on top
22of one another while the top level initialdata file is for fresh RT installs.
23
24Extensions may also ship with database changes in such files. You may find
25some 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
31initialdata files are Perl, but often consist primarily of a bunch of data
32structures defining the new records you want and not much extra code. There's
33nothing stopping you from writing a bunch of code, however!
34
35The 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
50The C<@Queues> and C<@Groups> arrays are expected by RT and should contain
51hashref definitions. There are many other arrays RT will look for and act on,
52described below. None are required, all may be used. Keep in mind that since
53they're just normal Perl arrays, you can C<push> onto them from a loop or
54C<grep> out definitions based on conditionals or generate their content with
55C<map>, etc.
56
57The complete list of possible arrays which can be used, along with
58descriptions 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
71Each hashref in C<@Users> is treated as a new user to create and passed
72straight into C<< RT::User->Create >>. All of the normal user fields are
73available, as well as C<Privileged> and C<Disabled> (both booleans) which will
74do the appropriate internal group/flag handling.
75
76For 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
86Creates a new L<RT::Group> for each hashref. In almost all cases you'll want
87to follow the example above to create a group just as if you had done it from
88the admin interface. B<Do not> omit the C<< Domain => 'UserDefined' >> line.
89
90Additionally, the C<MemberOf> field is specially handled to make it easier to
91add the new group to other groups. C<MemberOf> may be a single value or an
92array ref. Each value should be a user-defined group name or hashref to pass
01e3b242 93into L<RT::Group/LoadByCols>. Each group found will have the new group
45030404
MKG
94added as a member.
95
96Unfortunately you can't specify the I<members> of a group at this time. As a
97workaround, you can push a subref into C<@Final> which adds members to your new
98groups. 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
142Creates a new L<RT::Queue> for each hashref. Refer to the documentation of
143L<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
154Creates a new L<RT::CustomField> for each hashref. It is the most complex of
155the initialdata structures. The most commonly used fields are:
156
157=over 4
158
159=item C<Name>
160
161The name of this CF as displayed in RT.
162
163=item C<Description>
164
165A short summary of what this CF is for.
166
167=item C<Queue>
168
169May be a Name or ID. The single queue or array ref of queues to apply this CF
170to. This does not apply when C<LookupType> does not start with C<RT::Queue>.
171
172=item C<Type>
173
174One 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
205If you don't specify "Single" or "Multiple" in the type, you must specify
206C<MaxValues>.
207
208=item C<LookupType>
209
210Labeled in the CF admin page as "Applies to". This determines whether your CF
211is 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
219Ticket CFs are the most common, meaning C<RT::Queue-RT::Ticket> is the most
220common C<LookupType>.
221
222=item C<RenderType>
223
224Only valid when C<Type> is "Select". Controls how the CF is displayed when
225editing it. Valid values are: C<Select box>, C<List>, and C<Dropdown>.
226
227C<List> is either a list of radio buttons or a list of checkboxes depending on
228C<MaxValues>.
229
230=item C<MaxValues>
231
232Determines whether this CF is a Single or Multiple type. 0 means multiple. 1
233means single.
234
235Make sure to set the C<MaxValues> field appropriately, otherwise you can end up
236with unsupported CF types like a "Select multiple dates" (it doesn't Just
237Work).
238
239You can also use old-style C<Type>s which end with "Single" or "Multiple", for
240example: SelectSingle, SelectMultiple, FreeformSingle, etc.
241
242=item C<Values>
243
244C<Values> should be an array ref (never a single value!) of hashrefs
245representing new L<RT::CustomFieldValue> objects to create for the new custom
246field. 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
262In order to ensure the same sorting of C<Values>, set C<SortOrder> inside each
263value. A clever way to do this easily is with a simple variable you increment
264each time (as above with C<$i>). You can use the same variable throughout the
265whole file, and don't need one per CF.
266
267=item C<BasedOn>
268
269Name or ID of another Select Custom Field. This makes the named CF the source
270of categories for your values.
271
272=item C<Pattern>
273
274The regular expression text (not C<qr//>!) used to validate values.
275
276=back
277
278Refer to the documentation and implementation of L<RT::CustomField/Create> and
279L<RT::CustomFieldValue/Create> for the full list of available fields and
280allowed values.
281
282=head2 C<@ACL>
283
284C<@ACL> is very useful for granting rights on your newly created records or
285setting up a standard system configuration. It is one of the most complex
286initialdata structures.
287
288=head3 Pick a Right
289
290All ACL definitions expect a key named C<Right> with the internal right name
291you want to grant. The internal right names are visible in RT's admin
292interface in grey next to the longer descriptions.
293
294=head3 Pick a level: on a queue, on a CF, or globally
295
296After picking a C<Right>, you need to specify on what object the right is
297granted. 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
316Specifying none of the above will get you a global right.
317
318=back
319
320There is currently no way to grant rights on a group or article class level.
321Note that you can grant rights B<to> a group; see below. If you need to grants
322rights on a group or article class level, you'll need to write an C<@Final>
323subref to handle it using the RT Perl API.
324
325=head3 Pick a Principal: User or Group or Role
326
327Finally you need to specify to what system group, system/queue role,
328user 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
361You'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
387Since you often want to grant a list of rights on the same object/level to the
388same role/group/user, we generally use Perl loops and operators to aid in the
389generation 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
403The best troubleshooting is often to see how the rights you define in C<@ACL>
404show up in the RT admin interface.
405
406=head2 C<@Scrips>
407
408Creates a new L<RT::Scrip> for each hashref. Refer to the documentation of
409L<RT::Scrip/Create> for the fields you can use.
410
411Additionally, the C<Queue> field is specially handled to make it easier to
412setup 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
432Creates a new L<RT::ScripAction> for each hashref. Refer to the documentation
433of L<RT::ScripAction/Create> for the fields you can use.
434
435=head2 C<@ScripConditions>
436
437Creates a new L<RT::ScripCondition> for each hashref. Refer to the
438documentation of L<RT::ScripCondition/Create> for the fields you can use.
439
440=head2 C<@Templates>
441
442Creates a new L<RT::Template> for each hashref. Refer to the documentation of
443L<RT::Template/Create> for the fields you can use.
444
445=head2 C<@Attributes>
446
447An array of L<RT::Attribute>s to create. You likely don't need to mess with
448this. If you do, know that the key C<Object> is expected to be an
449L<RT::Record> object on which to call C<AddAttribute>. If you don't provide
450C<Object> or it's undefined, C<< RT->System >> will be used.
451
452=head2 C<@Initial>
453
454=head2 C<@Final>
455
456C<@Initial> and C<@Final> are special and let you write your own processing
457code that runs before anything else or after everything else. They are
458expected to be arrays of subrefs (usually anonymous) like so:
459
460 our @Final = (sub {
461 RT->Logger->info("Finishing up!");
462 });
463
464You have the full power of RT's Perl libraries at your disposal. Be sure to do
465error checking and log any errors with C<< RT->Logger->error("...") >>!
466
467=head1 What's missing?
468
469There is currently no way, short of writing code in C<@Final> or C<@Initial>,
470to 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
476This may prompt you for a database password.
477
478=head1 Implementation details
479
480All the handling of initialdata files is done in C<< RT::Handle->InsertData >>.
481If you want to know B<exactly> what's happening with each array, your best bet
482is to start reading the code there.
483
484RT takes care of the ordering so that your new queues are created before it
485processes the new ACLs for those queues. This lets you refer to new queues you
486just created by Name.