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 Name => 'Example Employees',
82 Description => 'All of the employees of my company',
85 Creates a new L<RT::Group> for each hashref. In almost all cases you'll want
86 to follow the example above to create a group just as if you had done it from
89 Additionally, the C<MemberOf> field is specially handled to make it easier to
90 add the new group to other groups. C<MemberOf> may be a single value or an
91 array ref. Each value should be a user-defined group name or hashref to pass
92 into L<RT::Group/LoadByCols>. Each group found will have the new group
95 Unfortunately you can't specify the I<members> of a group at this time. As a
96 workaround, you can push a subref into C<@Final> which adds members to your new
97 groups. An example, using a convenience function to avoid repeating yourself:
100 add_members('My New Group Name' => qw(trs alex ruslan));
101 add_members('My Second Group' => qw(jesse kevin sunnavy jim));
105 my $group_name = shift;
108 my $group = RT::Group->new( RT->SystemUser );
109 $group->LoadUserDefinedGroup($group_name);
112 for my $name (@members) {
113 my $member = RT::User->new( RT->SystemUser );
114 $member->LoadByCols( Name => $name );
116 unless ($member->Id) {
117 RT->Logger->error("Unable to find user '$name'");
121 my ($ok, $msg) = $group->AddMember( $member->PrincipalObj->Id );
123 RT->Logger->info("Added member $name to $group_name");
125 RT->Logger->error("Unable to AddMember $name to $group_name: $msg");
129 RT->Logger->error("Unable to find group '$group_name'!");
137 CorrespondAddress => 'help@example.com',
138 CommentAddress => 'help-comment@example.com',
141 Creates a new L<RT::Queue> for each hashref. Refer to the documentation of
142 L<RT::Queue/Create> for the fields you can use.
144 =head2 C<@CustomFields>
146 push @CustomFields, {
147 Name => 'Favorite color',
148 Type => 'FreeformSingle',
149 LookupType => 'RT::Queue-RT::Ticket',
152 Creates a new L<RT::CustomField> for each hashref. It is the most complex of
153 the initialdata structures. The most commonly used fields are:
159 The name of this CF as displayed in RT.
163 A short summary of what this CF is for.
167 May be a single value, or an array reference of such; each should be
168 either an ID or Name. If omitted, the CF is applied globally. This
169 should not be used for User or Group custom fields.
171 This argument may also be passed via C<Queue>, for backwards
172 compatibility, which also defaults the C<LookupType> to
173 C<RT::Queue-RT::Ticket>.
177 One of the following on the left hand side:
179 SelectSingle # Select one value
180 SelectMultiple # Select multiple values
182 FreeformSingle # Enter one value
183 FreeformMultiple # Enter multiple values
185 Text # Fill in one text area
186 Wikitext # Fill in one wikitext area
188 BinarySingle # Upload one file
189 BinaryMultiple # Upload multiple files
191 ImageSingle # Upload one image
192 ImageMultiple # Upload multiple images
194 Combobox # Combobox: Select or enter one value
196 AutocompleteSingle # Enter one value with autocompletion
197 AutocompleteMultiple # Enter multiple values with autocompletion
200 DateTime # Select datetime
202 IPAddressSingle # Enter one IP address
203 IPAddressMultiple # Enter multiple IP addresses
205 IPAddressRangeSingle # Enter one IP address range
206 IPAddressRangeMultiple # Enter multiple IP address ranges
208 If you don't specify "Single" or "Multiple" in the type, you must specify
213 Labeled in the CF admin page as "Applies to". This determines whether your CF
214 is for Tickets, Transactions, Users, Groups, or Queues. Possible values:
216 RT::Queue-RT::Ticket # Tickets
217 RT::Queue-RT::Ticket-RT::Transaction # Transactions
221 RT::Class-RT::Article # Articles
223 Ticket CFs are the most common, meaning C<RT::Queue-RT::Ticket> is the most
224 common C<LookupType>.
228 Only valid when C<Type> is "Select". Controls how the CF is displayed when
229 editing it. Valid values are: C<Select box>, C<List>, and C<Dropdown>.
231 C<List> is either a list of radio buttons or a list of checkboxes depending on
236 Determines whether this CF is a Single or Multiple type. 0 means multiple. 1
239 Make sure to set the C<MaxValues> field appropriately, otherwise you can end up
240 with unsupported CF types like a "Select multiple dates" (it doesn't Just
243 You can also use old-style C<Type>s which end with "Single" or "Multiple", for
244 example: SelectSingle, SelectMultiple, FreeformSingle, etc.
248 C<Values> should be an array ref (never a single value!) of hashrefs
249 representing new L<RT::CustomFieldValue> objects to create for the new custom
250 field. This only makes sense for "Select" CFs. An example:
253 push @CustomFields, {
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',
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...
265 In order to ensure the same sorting of C<Values>, set C<SortOrder> inside each
266 value. A clever way to do this easily is with a simple variable you increment
267 each time (as above with C<$i>). You can use the same variable throughout the
268 whole file, and don't need one per CF.
272 Name or ID of another Select Custom Field. This makes the named CF the source
273 of categories for your values.
277 The regular expression text (not C<qr//>!) used to validate values.
281 Refer to the documentation and implementation of L<RT::CustomField/Create> and
282 L<RT::CustomFieldValue/Create> for the full list of available fields and
287 C<@ACL> is very useful for granting rights on your newly created records or
288 setting up a standard system configuration. It is one of the most complex
289 initialdata structures.
293 All ACL definitions expect a key named C<Right> with the internal right name
294 you want to grant. The internal right names are visible in RT's admin
295 interface in grey next to the longer descriptions.
297 =head3 Pick a level: on a queue, on a CF, or globally
299 After picking a C<Right>, you need to specify on what object the right is
300 granted. This is B<different> than the user/group/role receiving the right.
304 =item Granted on a custom field by name (or ID), potentially a global or queue
307 LookupType => 'RT::User', # optional, in case you need to disambiguate
309 =item Granted on a queue
313 =item Granted on a custom field applied to a specific queue
318 =item Granted on some other object (article Classes, etc)
320 ObjectType => 'RT::Class',
323 =item Granted globally
325 Specifying none of the above will get you a global right.
329 There is currently no way to grant rights on a group or article class level.
330 Note that you can grant rights B<to> a group; see below. If you need to grants
331 rights on a group or article class level, you'll need to write an C<@Final>
332 subref to handle it using the RT Perl API.
334 =head3 Pick a Principal: User or Group or Role
336 Finally you need to specify to what system group, system/queue role,
337 user defined group, or user you want to grant the right B<to>.
341 =item An internal user group
343 GroupDomain => 'SystemInternal',
344 GroupType => 'Everyone, Privileged, or Unprivileged'
346 =item A system-level role
348 GroupDomain => 'RT::System-Role',
349 GroupType => 'Requestor, Owner, AdminCc, or Cc'
351 =item A queue-level role
353 GroupDomain => 'RT::Queue-Role',
355 GroupType => 'Requestor, Owner, AdminCc, or Cc',
357 =item A group you created
359 GroupDomain => 'UserDefined',
362 =item Individual user
364 UserId => 'Name or email or ID'
370 You're probably looking for definitions like these most of the time.
374 =item Grant a global right to a group you created
377 GroupDomain => 'UserDefined',
380 =item Grant a queue-level right to a group you created
384 GroupDomain => 'UserDefined',
387 =item Grant a CF-level right to a group you created
391 GroupDomain => 'UserDefined',
396 Since you often want to grant a list of rights on the same object/level to the
397 same role/group/user, we generally use Perl loops and operators to aid in the
398 generation of C<@ACL> without repeating ourselves.
400 # Give Requestors globally the right to see tickets, reply, and see the
401 # queue their ticket is in
405 GroupDomain => 'RT::System-Role',
406 GroupType => 'Requestor',
408 } qw(ShowTicket ReplyToTicket SeeQueue);
410 =head3 Troubleshooting
412 The best troubleshooting is often to see how the rights you define in C<@ACL>
413 show up in the RT admin interface.
417 Creates a new L<RT::Scrip> for each hashref. Refer to the documentation of
418 L<RT::Scrip/Create> for the fields you can use.
420 Additionally, the C<Queue> field is specially handled to make it easier to
421 setup the same Scrip on multiple queues:
431 Queue => 'General', # Name or ID
433 =item Multiple queues
435 Queue => ['General', 'Helpdesk', 13], # Array ref of Name or ID
439 =head2 C<@ScripActions>
441 Creates a new L<RT::ScripAction> for each hashref. Refer to the documentation
442 of L<RT::ScripAction/Create> for the fields you can use.
444 =head2 C<@ScripConditions>
446 Creates a new L<RT::ScripCondition> for each hashref. Refer to the
447 documentation of L<RT::ScripCondition/Create> for the fields you can use.
451 Creates a new L<RT::Template> for each hashref. Refer to the documentation of
452 L<RT::Template/Create> for the fields you can use.
454 =head2 C<@Attributes>
456 An array of L<RT::Attribute>s to create. You likely don't need to mess with
457 this. If you do, know that the key C<Object> is expected to be an
458 L<RT::Record> object on which to call C<AddAttribute>. If you don't provide
459 C<Object> or it's undefined, C<< RT->System >> will be used.
465 C<@Initial> and C<@Final> are special and let you write your own processing
466 code that runs before anything else or after everything else. They are
467 expected to be arrays of subrefs (usually anonymous) like so:
470 RT->Logger->info("Finishing up!");
473 You have the full power of RT's Perl libraries at your disposal. Be sure to do
474 error checking and log any errors with C<< RT->Logger->error("...") >>!
476 =head1 What's missing?
478 There is currently no way, short of writing code in C<@Final> or C<@Initial>,
479 to easily create B<Classes>, B<Topics>, or B<Articles> from initialdata files.
481 =head1 Running an initialdata file
483 sbin/rt-setup-database --action insert --datafile /path/to/your/initialdata
485 This may prompt you for a database password.
487 =head1 Implementation details
489 All the handling of initialdata files is done in C<< RT::Handle->InsertData >>.
490 If you want to know B<exactly> what's happening with each array, your best bet
491 is to start reading the code there.
493 RT takes care of the ordering so that your new queues are created before it
494 processes the new ACLs for those queues. This lets you refer to new queues you
495 just created by Name.