1 =head1 Summary of initialdata files
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.
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.
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.
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.
24 Extensions may also ship with database changes in such files. You may find
25 some in your install with:
27 find local/plugins -name initialdata -or -name content
29 =head1 What can be in an initialdata file?
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!
35 The basic template of a new initialdata file should look something like this:
41 # some definitions here
45 # some other definitions here
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
57 The complete list of possible arrays which can be used, along with
58 descriptions of the values to place in them, is below.
64 Password => 'changethis',
66 Timezone => 'America/Vancouver',
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.
76 For a full list of fields, read the documentation for L<RT::User/Create>.
81 Domain => 'UserDefined',
82 Name => 'Example Employees',
83 Description => 'All of the employees of my company',
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.
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
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:
101 add_members('My New Group Name' => qw(trs alex ruslan));
102 add_members('My Second Group' => qw(jesse kevin sunnavy jim));
106 my $group_name = shift;
109 my $group = RT::Group->new( RT->SystemUser );
110 $group->LoadUserDefinedGroup($group_name);
113 for my $name (@members) {
114 my $member = RT::User->new( RT->SystemUser );
115 $member->LoadByCols( Name => $name );
117 unless ($member->Id) {
118 RT->Logger->error("Unable to find user '$name'");
122 my ($ok, $msg) = $group->AddMember( $member->PrincipalObj->Id );
124 RT->Logger->info("Added member $name to $group_name");
126 RT->Logger->error("Unable to AddMember $name to $group_name: $msg");
130 RT->Logger->error("Unable to find group '$group_name'!");
138 CorrespondAddress => 'help@example.com',
139 CommentAddress => 'help-comment@example.com',
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.
145 =head2 C<@CustomFields>
147 push @CustomFields, {
149 Name => 'Favorite color',
150 Type => 'FreeformSingle',
151 LookupType => 'RT::Queue-RT::Ticket',
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:
161 The name of this CF as displayed in RT.
165 A short summary of what this CF is for.
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>.
174 One of the following on the left hand side:
176 SelectSingle # Select one value
177 SelectMultiple # Select multiple values
179 FreeformSingle # Enter one value
180 FreeformMultiple # Enter multiple values
182 Text # Fill in one text area
183 Wikitext # Fill in one wikitext area
185 BinarySingle # Upload one file
186 BinaryMultiple # Upload multiple files
188 ImageSingle # Upload one image
189 ImageMultiple # Upload multiple images
191 Combobox # Combobox: Select or enter one value
193 AutocompleteSingle # Enter one value with autocompletion
194 AutocompleteMultiple # Enter multiple values with autocompletion
197 DateTime # Select datetime
199 IPAddressSingle # Enter one IP address
200 IPAddressMultiple # Enter multiple IP addresses
202 IPAddressRangeSingle # Enter one IP address range
203 IPAddressRangeMultiple # Enter multiple IP address ranges
205 If you don't specify "Single" or "Multiple" in the type, you must specify
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:
213 RT::Queue-RT::Ticket # Tickets
214 RT::Queue-RT::Ticket-RT::Transaction # Transactions
219 Ticket CFs are the most common, meaning C<RT::Queue-RT::Ticket> is the most
220 common C<LookupType>.
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>.
227 C<List> is either a list of radio buttons or a list of checkboxes depending on
232 Determines whether this CF is a Single or Multiple type. 0 means multiple. 1
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
239 You can also use old-style C<Type>s which end with "Single" or "Multiple", for
240 example: SelectSingle, SelectMultiple, FreeformSingle, etc.
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:
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',
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...
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.
269 Name or ID of another Select Custom Field. This makes the named CF the source
270 of categories for your values.
274 The regular expression text (not C<qr//>!) used to validate values.
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
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.
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.
294 =head3 Pick a level: on a queue, on a CF, or globally
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.
301 =item Granted on a custom field by name (or ID), potentially a global or queue
305 =item Granted on a queue
309 =item Granted on a custom field applied to a specific queue
314 =item Granted globally
316 Specifying none of the above will get you a global right.
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.
325 =head3 Pick a Principal: User or Group or Role
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>.
332 =item An internal user group
334 GroupDomain => 'SystemInternal',
335 GroupType => 'Everyone, Privileged, or Unprivileged'
337 =item A system-level role
339 GroupDomain => 'RT::System-Role',
340 GroupType => 'Requestor, Owner, AdminCc, or Cc'
342 =item A queue-level role
344 GroupDomain => 'RT::Queue-Role',
346 GroupType => 'Requestor, Owner, AdminCc, or Cc',
348 =item A group you created
350 GroupDomain => 'UserDefined',
353 =item Individual user
355 UserId => 'Name or email or ID'
361 You're probably looking for definitions like these most of the time.
365 =item Grant a global right to a group you created
368 GroupDomain => 'UserDefined',
371 =item Grant a queue-level right to a group you created
375 GroupDomain => 'UserDefined',
378 =item Grant a CF-level right to a group you created
382 GroupDomain => 'UserDefined',
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.
391 # Give Requestors globally the right to see tickets, reply, and see the
392 # queue their ticket is in
396 GroupDomain => 'RT::System-Role',
397 GroupType => 'Requestor',
399 } qw(ShowTicket ReplyToTicket SeeQueue);
401 =head3 Troubleshooting
403 The best troubleshooting is often to see how the rights you define in C<@ACL>
404 show up in the RT admin interface.
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.
411 Additionally, the C<Queue> field is specially handled to make it easier to
412 setup the same Scrip on multiple queues:
422 Queue => 'General', # Name or ID
424 =item Multiple queues
426 Queue => ['General', 'Helpdesk', 13], # Array ref of Name or ID
430 =head2 C<@ScripActions>
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.
435 =head2 C<@ScripConditions>
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.
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.
445 =head2 C<@Attributes>
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.
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:
461 RT->Logger->info("Finishing up!");
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("...") >>!
467 =head1 What's missing?
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.
472 =head1 Running an initialdata file
474 sbin/rt-setup-database --action insert --datafile /path/to/your/initialdata
476 This may prompt you for a database password.
478 =head1 Implementation details
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.
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.