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
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.
78 For a full list of fields, read the documentation for L<RT::User/Create>.
83 Domain => 'UserDefined',
84 Name => 'Example Employees',
85 Description => 'All of the employees of my company',
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.
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
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:
103 add_members('My New Group Name' => qw(trs alex ruslan));
104 add_members('My Second Group' => qw(jesse kevin sunnavy jim));
108 my $group_name = shift;
111 my $group = RT::Group->new( RT->SystemUser );
112 $group->LoadUserDefinedGroup($group_name);
115 for my $name (@members) {
116 my $member = RT::User->new( RT->SystemUser );
117 $member->LoadByCols( Name => $name );
119 unless ($member->Id) {
120 RT->Logger->error("Unable to find user '$name'");
124 my ($ok, $msg) = $group->AddMember( $member->PrincipalObj->Id );
126 RT->Logger->info("Added member $name to $group_name");
128 RT->Logger->error("Unable to AddMember $name to $group_name: $msg");
132 RT->Logger->error("Unable to find group '$group_name'!");
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
144 CorrespondAddress => 'help@example.com',
145 CommentAddress => 'help-comment@example.com',
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.
154 =head2 C<@CustomFields>
156 push @CustomFields, {
157 Name => 'Favorite color',
158 Type => 'FreeformSingle',
159 LookupType => 'RT::Queue-RT::Ticket',
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:
169 The name of this CF as displayed in RT.
173 A short summary of what this CF is for.
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.
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>.
187 One of the following on the left hand side:
189 SelectSingle # Select one value
190 SelectMultiple # Select multiple values
192 FreeformSingle # Enter one value
193 FreeformMultiple # Enter multiple values
195 Text # Fill in one text area
196 Wikitext # Fill in one wikitext area
198 BinarySingle # Upload one file
199 BinaryMultiple # Upload multiple files
201 ImageSingle # Upload one image
202 ImageMultiple # Upload multiple images
204 Combobox # Combobox: Select or enter one value
206 AutocompleteSingle # Enter one value with autocompletion
207 AutocompleteMultiple # Enter multiple values with autocompletion
210 DateTime # Select datetime
212 IPAddressSingle # Enter one IP address
213 IPAddressMultiple # Enter multiple IP addresses
215 IPAddressRangeSingle # Enter one IP address range
216 IPAddressRangeMultiple # Enter multiple IP address ranges
218 If you don't specify "Single" or "Multiple" in the type, you must specify
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:
226 RT::Queue-RT::Ticket # Tickets
227 RT::Queue-RT::Ticket-RT::Transaction # Transactions
231 RT::Class-RT::Article # Articles
233 Ticket CFs are the most common, meaning C<RT::Queue-RT::Ticket> is the most
234 common C<LookupType>.
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>.
241 C<List> is either a list of radio buttons or a list of checkboxes depending on
246 Determines whether this CF is a Single or Multiple type. 0 means multiple. 1
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
253 You can also use old-style C<Type>s which end with "Single" or "Multiple", for
254 example: SelectSingle, SelectMultiple, FreeformSingle, etc.
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:
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',
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...
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.
282 Name or ID of another Select Custom Field. This makes the named CF the source
283 of categories for your values.
287 The regular expression text (not C<qr//>!) used to validate values.
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
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
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.
305 =head3 Pick one or more C<Right>s
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.
312 =head3 Pick a level: on a queue, on a CF, or globally
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.
319 =item Granted on a custom field by name (or ID), potentially a global or queue
322 LookupType => 'RT::User', # optional, in case you need to disambiguate
324 =item Granted on a queue
328 =item Granted on a custom field applied to a specific queue
333 =item Granted on a custom field applied to some other object
335 # This finds the CF named "Name" applied to Articles in the
338 LookupType => RT::Article->CustomFieldLookupType,
339 ObjectId => 'Responses',
341 =item Granted on some other object (article Classes, etc)
343 ObjectType => 'RT::Class',
346 =item Granted globally
348 Specifying none of the above will get you a global right.
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.
357 =head3 Pick a Principal: User or Group or Role
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>.
364 =item An internal user group
366 GroupDomain => 'SystemInternal',
367 GroupType => 'Everyone, Privileged, or Unprivileged'
369 =item A system-level role
371 GroupDomain => 'RT::System-Role',
372 GroupType => 'Requestor, Owner, AdminCc, or Cc'
374 =item A queue-level role
376 GroupDomain => 'RT::Queue-Role',
378 GroupType => 'Requestor, Owner, AdminCc, or Cc',
380 =item A group you created
382 GroupDomain => 'UserDefined',
385 =item Individual user
387 UserId => 'Name or email or ID'
393 You're probably looking for definitions like these most of the time.
397 =item Grant a global right to a group you created
400 GroupDomain => 'UserDefined',
403 =item Grant a queue-level right to a group you created
407 GroupDomain => 'UserDefined',
410 =item Grant a CF-level right to a group you created
414 GroupDomain => 'UserDefined',
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.
423 # Give Requestors globally the right to see tickets, reply, and see the
424 # queue their ticket is in
428 GroupDomain => 'RT::System-Role',
429 GroupType => 'Requestor',
431 } qw(ShowTicket ReplyToTicket SeeQueue);
433 =head3 Troubleshooting
435 The best troubleshooting is often to see how the rights you define in C<@ACL>
436 show up in the RT admin interface.
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.
443 Additionally, the C<Queue> field is specially handled to make it easier to
444 setup the same Scrip on multiple queues:
454 Queue => 'General', # Name or ID
456 =item Multiple queues
458 Queue => ['General', 'Helpdesk', 13], # Array ref of Name or ID
462 =head2 C<@ScripActions>
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.
467 =head2 C<@ScripConditions>
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.
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.
477 =head2 C<@Attributes>
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.
485 Here is an example of using a subroutine reference as a value for Object:
488 Name => 'SavedSearch',
489 Description => 'New Tickets in SomeQueue',
491 my $GroupName = 'SomeQueue Group';
492 my $group = RT::Group->new( RT->SystemUser );
494 my( $ret, $msg ) = $group->LoadUserDefinedGroup( $GroupName );
495 die $msg unless $ret;
500 Format => <<' END_OF_FORMAT',
503 Query => "Status = 'new' AND Queue = 'SomeQueue'",
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:
518 RT->Logger->info("Finishing up!");
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("...") >>!
524 =head1 What's missing?
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.
529 =head1 Running an initialdata file
531 /opt/rt4/sbin/rt-setup-database --action insert --datafile /path/to/your/initialdata
533 This may prompt you for a database password.
535 =head1 Implementation details
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.
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.