Putting 4.2.0 on top of 4.0.17
[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, {
45030404
MKG
81 Name => 'Example Employees',
82 Description => 'All of the employees of my company',
83 };
84
85Creates a new L<RT::Group> for each hashref. In almost all cases you'll want
86to follow the example above to create a group just as if you had done it from
af59614d 87the admin interface.
45030404
MKG
88
89Additionally, the C<MemberOf> field is specially handled to make it easier to
90add the new group to other groups. C<MemberOf> may be a single value or an
91array ref. Each value should be a user-defined group name or hashref to pass
01e3b242 92into L<RT::Group/LoadByCols>. Each group found will have the new group
45030404
MKG
93added as a member.
94
95Unfortunately you can't specify the I<members> of a group at this time. As a
96workaround, you can push a subref into C<@Final> which adds members to your new
97groups. 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
141Creates a new L<RT::Queue> for each hashref. Refer to the documentation of
142L<RT::Queue/Create> for the fields you can use.
143
144=head2 C<@CustomFields>
145
146 push @CustomFields, {
45030404
MKG
147 Name => 'Favorite color',
148 Type => 'FreeformSingle',
149 LookupType => 'RT::Queue-RT::Ticket',
150 };
151
152Creates a new L<RT::CustomField> for each hashref. It is the most complex of
153the initialdata structures. The most commonly used fields are:
154
155=over 4
156
157=item C<Name>
158
159The name of this CF as displayed in RT.
160
161=item C<Description>
162
163A short summary of what this CF is for.
164
af59614d 165=item C<ApplyTo>
45030404 166
af59614d
MKG
167May be a single value, or an array reference of such; each should be
168either an ID or Name. If omitted, the CF is applied globally. This
169should not be used for User or Group custom fields.
170
171This argument may also be passed via C<Queue>, for backwards
172compatibility, which also defaults the C<LookupType> to
173C<RT::Queue-RT::Ticket>.
45030404
MKG
174
175=item C<Type>
176
177One 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
208If you don't specify "Single" or "Multiple" in the type, you must specify
209C<MaxValues>.
210
211=item C<LookupType>
212
213Labeled in the CF admin page as "Applies to". This determines whether your CF
214is 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
af59614d 221 RT::Class-RT::Article # Articles
45030404
MKG
222
223Ticket CFs are the most common, meaning C<RT::Queue-RT::Ticket> is the most
224common C<LookupType>.
225
226=item C<RenderType>
227
228Only valid when C<Type> is "Select". Controls how the CF is displayed when
229editing it. Valid values are: C<Select box>, C<List>, and C<Dropdown>.
230
231C<List> is either a list of radio buttons or a list of checkboxes depending on
232C<MaxValues>.
233
234=item C<MaxValues>
235
236Determines whether this CF is a Single or Multiple type. 0 means multiple. 1
237means single.
238
239Make sure to set the C<MaxValues> field appropriately, otherwise you can end up
240with unsupported CF types like a "Select multiple dates" (it doesn't Just
241Work).
242
243You can also use old-style C<Type>s which end with "Single" or "Multiple", for
244example: SelectSingle, SelectMultiple, FreeformSingle, etc.
245
246=item C<Values>
247
248C<Values> should be an array ref (never a single value!) of hashrefs
249representing new L<RT::CustomFieldValue> objects to create for the new custom
250field. This only makes sense for "Select" CFs. An example:
251
252 my $i = 1;
253 push @CustomFields, {
45030404
MKG
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
265In order to ensure the same sorting of C<Values>, set C<SortOrder> inside each
266value. A clever way to do this easily is with a simple variable you increment
267each time (as above with C<$i>). You can use the same variable throughout the
268whole file, and don't need one per CF.
269
270=item C<BasedOn>
271
272Name or ID of another Select Custom Field. This makes the named CF the source
273of categories for your values.
274
275=item C<Pattern>
276
277The regular expression text (not C<qr//>!) used to validate values.
278
279=back
280
281Refer to the documentation and implementation of L<RT::CustomField/Create> and
282L<RT::CustomFieldValue/Create> for the full list of available fields and
283allowed values.
284
285=head2 C<@ACL>
286
287C<@ACL> is very useful for granting rights on your newly created records or
288setting up a standard system configuration. It is one of the most complex
289initialdata structures.
290
291=head3 Pick a Right
292
293All ACL definitions expect a key named C<Right> with the internal right name
294you want to grant. The internal right names are visible in RT's admin
295interface in grey next to the longer descriptions.
296
297=head3 Pick a level: on a queue, on a CF, or globally
298
299After picking a C<Right>, you need to specify on what object the right is
300granted. 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',
af59614d 307 LookupType => 'RT::User', # optional, in case you need to disambiguate
45030404
MKG
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
af59614d
MKG
318=item Granted on some other object (article Classes, etc)
319
320 ObjectType => 'RT::Class',
321 ObjectId => 'Name',
322
45030404
MKG
323=item Granted globally
324
325Specifying none of the above will get you a global right.
326
327=back
328
329There is currently no way to grant rights on a group or article class level.
330Note that you can grant rights B<to> a group; see below. If you need to grants
331rights on a group or article class level, you'll need to write an C<@Final>
332subref to handle it using the RT Perl API.
333
334=head3 Pick a Principal: User or Group or Role
335
336Finally you need to specify to what system group, system/queue role,
337user 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
370You'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
396Since you often want to grant a list of rights on the same object/level to the
397same role/group/user, we generally use Perl loops and operators to aid in the
398generation 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
412The best troubleshooting is often to see how the rights you define in C<@ACL>
413show up in the RT admin interface.
414
415=head2 C<@Scrips>
416
417Creates a new L<RT::Scrip> for each hashref. Refer to the documentation of
418L<RT::Scrip/Create> for the fields you can use.
419
420Additionally, the C<Queue> field is specially handled to make it easier to
421setup 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
441Creates a new L<RT::ScripAction> for each hashref. Refer to the documentation
442of L<RT::ScripAction/Create> for the fields you can use.
443
444=head2 C<@ScripConditions>
445
446Creates a new L<RT::ScripCondition> for each hashref. Refer to the
447documentation of L<RT::ScripCondition/Create> for the fields you can use.
448
449=head2 C<@Templates>
450
451Creates a new L<RT::Template> for each hashref. Refer to the documentation of
452L<RT::Template/Create> for the fields you can use.
453
454=head2 C<@Attributes>
455
456An array of L<RT::Attribute>s to create. You likely don't need to mess with
457this. If you do, know that the key C<Object> is expected to be an
458L<RT::Record> object on which to call C<AddAttribute>. If you don't provide
459C<Object> or it's undefined, C<< RT->System >> will be used.
460
461=head2 C<@Initial>
462
463=head2 C<@Final>
464
465C<@Initial> and C<@Final> are special and let you write your own processing
466code that runs before anything else or after everything else. They are
467expected to be arrays of subrefs (usually anonymous) like so:
468
469 our @Final = (sub {
470 RT->Logger->info("Finishing up!");
471 });
472
473You have the full power of RT's Perl libraries at your disposal. Be sure to do
474error checking and log any errors with C<< RT->Logger->error("...") >>!
475
476=head1 What's missing?
477
478There is currently no way, short of writing code in C<@Final> or C<@Initial>,
479to 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
485This may prompt you for a database password.
486
487=head1 Implementation details
488
489All the handling of initialdata files is done in C<< RT::Handle->InsertData >>.
490If you want to know B<exactly> what's happening with each array, your best bet
491is to start reading the code there.
492
493RT takes care of the ordering so that your new queues are created before it
494processes the new ACLs for those queues. This lets you refer to new queues you
495just created by Name.