Check permissions before allowing users to use this import tool
[manu/RT-Extension-ImportCustomFieldValues.git] / html / Admin / CustomFields / ImportValues.html
1 <& /Admin/Elements/Header,
2     Title => $title,
3     &>
4 <& /Elements/Tabs &>
5 <& /Elements/ListActions, actions => \@results &>
6
7 <form method="post" enctype="multipart/form-data" action="ImportValues.html" name="ImportCFValues" id="ImportCFValues">
8 <input type="hidden" class="hidden" name="id" value="<% $id %>" />
9
10 % if ( $ARGS{Import} && $values ) {
11 % if ( $ARGS{ReplaceValues} ) {
12 <input type="hidden" class="hidden" name="ReplaceValues" value="1" />
13 <h2><&|/l&>The following values will replace existing ones:</&></h2>
14 % } else {
15 <h2><&|/l&>The following values will be added to existing ones:</&></h2>
16 % }
17 <table border="0" cellpadding="1" cellspacing="0" class="collection-as-table cf-csv-import">
18 <tr class="collection-as-table">
19     <th class="collection-as-table"><&|/l&>SortOrder</&></th>
20     <th class="collection-as-table"><&|/l&>Name</&></th>
21     <th class="collection-as-table"><&|/l&>Description</&></th>
22     <th class="collection-as-table"><&|/l&>Category</&></th>
23     <th class="collection-as-table"><&|/l&>Import</&></th>
24 </tr>
25 % my $i = 0;
26 % foreach my $value (@$values) {
27 <tr class="collection-as-table <% $i++ %2 ? 'oddline' : 'evenline'%>">
28     <td class="collection-as-table"><input name="row-<% $i %>-SortOrder" value="<% $value->{SortOrder} || '' %>" /></td>
29     <td class="collection-as-table"><input name="row-<% $i %>-Name" value="<% $value->{Name} || '' %>" /></td>
30     <td class="collection-as-table"><input name="row-<% $i %>-Description" value="<% $value->{Description} || '' %>" /></td>
31     <td class="collection-as-table"><input name="row-<% $i %>-Category" value="<% $value->{Category} || '' %>" /></td>
32     <td class="collection-as-table"><input type="checkbox" class="checkbox" name="row-<% $i %>-import" value="1" checked="checked" /></td>
33 </tr>
34 % }
35 </table>
36 <hr />
37 <div class="button-cancel">
38 <& /Elements/Submit, Name => 'Cancel', Label => loc('Cancel'), Class => "extra-buttons" &>
39 </div>
40 <& /Elements/Submit, Name => 'Confirm', Label => loc('Confirm') &>
41 % } else {
42 <h2><&|/l&>Please select a file with needed values using following format:</&></h2>
43 <p>
44 <&|/l&>- File encoding: UTF-8</&><br/>
45 <&|/l&>- Fields separated by ";"</&><br/>
46 <&|/l&>- No headers</&><br/>
47 <&|/l&>- Using the following columns and order: SortOrder, Name, Description, Category</&><br/>
48 <&|/l&>- Column "Name" is mandatory, other columns may be empty but must exists</&>
49 </p>
50 <hr />
51 <table>
52 <tr><td class="label"><&|/l&>CSV file</&></td><td>
53 <input type="file" name="<% $name %>" class="CF-<%$CustomField->id%>-Import" />
54 </td></tr>
55 <tr><td class="label"><&|/l&>Replace?</&>
56 <div class="hints"><&|/l&>Default is to add CSV values to existing ones</&></div>
57 </td><td>
58 <input type="checkbox" class="checkbox" id="cfvalues-replace" name="ReplaceValues" value="1" <% $ReplaceValuesChecked |n %> />
59 </td>
60 </td>
61 </tr>
62
63 </table>
64 <hr />
65 <div class="button-cancel">
66 <& /Elements/Submit, Name => 'Cancel', Label => loc('Cancel') &>
67 </div>
68 <& /Elements/Submit, Name => 'Import', Label => loc('Import') &>
69 % }
70
71 </form>
72 <%INIT>
73 my ($title, @results, $values);
74 my $CustomField = RT::CustomField->new( $session{'CurrentUser'} );
75 unless ( $CustomField->Load( $id ) ) {
76     Abort(loc("CustomField not found"));
77 }
78 unless ( $session{CurrentUser}->HasRight( Right => 'AdminCustomFieldValues', Object => $CustomField )
79          || $session{CurrentUser}->HasRight( Right => 'AdminCustomField', Object => $CustomField ) ) {
80     Abort(loc("No permissions to edit this customfield values"));
81 }
82 $title = loc( 'Importing values for CustomField [_1]', $CustomField->Name );
83 my $name =  'Import-'. $CustomField->Id . '-Values';
84
85 my $ReplaceValuesChecked = ( $ARGS{ReplaceValues} ) ? qq[checked="checked"] : '';
86
87 if ( $ARGS{Cancel} ) {
88     $ReplaceValuesChecked = '';
89     delete $ARGS{$name};
90 } elsif ( $ARGS{Import} && $ARGS{$name} ) {
91     my $cgi_object = $m->cgi_object;
92     my $filename = $cgi_object->param($name);
93     push @results, "Importing ". $filename;
94     my $fh = $cgi_object->upload($name);
95     if ( $fh ) {
96         binmode($fh);
97
98         require Text::CSV;
99         my $csv = Text::CSV->new ({ strict => 1, sep_char => ";", });
100         $values = $csv->csv (in => $fh, headers => [qw(SortOrder Name Description Category)], encoding => 'UTF-8', );
101         unless ( $values && ref($values) eq 'ARRAY' ) {
102             push @results, loc("[_1]: Wrong file format", $filename);
103         } else {
104             my $i = 0;
105             my $valid_values;
106             foreach my $value (@$values) {
107                 $i++;
108                 my $valid = 1;
109                 foreach my $field (qw(SortOrder Name Description Category)) {
110                     $value->{$field} =~ s/^\s+// if ( $value->{$field} );
111                     $value->{$field} =~ s/\s+$// if ( $value->{$field} );
112                 }
113                 if ( ! $value->{Name} ) {
114                     push @results, loc("Line [_1]: missing \"[_2]\"", $i, "Name"); 
115                     $valid = undef;
116                 }
117                 if ( $value->{SortOrder} && $value->{SortOrder} !~ m/^\d+$/ ) {
118                     push @results, loc("Line [_1]: \"[_2]\" must be numerical", $i, loc("SortOrder"));
119                     $valid = undef;
120                 }
121                 # FIXME: check Category against BasedOn object?
122                 if ( $valid ) {
123                     push @$valid_values, $value;
124                 }
125             }
126             $values = $valid_values;
127         }
128     } else {
129         push @results, loc("Unable to read file");
130     }
131 } elsif ( $ARGS{Confirm} ) {
132     # Prepare a new empty form
133     $ReplaceValuesChecked = '';
134     delete $ARGS{$name};
135     # Reconstructs values to import
136     my $submitted_values = ();
137     foreach my $key (keys %ARGS) {
138         next unless ( $key =~ m/^row-(\d+)-(.+)$/ );
139         $submitted_values->{$1}->{$2} = $ARGS{$key};
140     }
141     # Remove unwanted values
142     foreach my $i (keys %$submitted_values) {
143         if ( ! $submitted_values->{$i}->{import} || $submitted_values->{$i}->{import} eq "0" ) {
144             delete $submitted_values->{$i};
145         } elsif ( $submitted_values->{$i}->{import} ) {
146             delete $submitted_values->{$i}->{import};
147         }
148     }
149     unless ( $submitted_values && ref($submitted_values) eq 'HASH' && scalar(keys %$submitted_values) ) {
150         push @results, loc("No values to import");
151     } else {
152         if ( $ARGS{ReplaceValues} ) {
153             my $Values = $CustomField->Values;
154             while (my $Value = $Values->Next) {
155                 my $value_id = $Value->id;
156                 my ($val, $msg) = $Value->Delete;
157                 if ( $val ) {
158                     push @results, loc("Old value [_1] deleted", $value_id);
159                 } else {
160                     push @results, loc("Error deleting old value [_1]: [_2]", $value_id, $msg);
161                 }
162             }
163         }
164         foreach my $i (keys %$submitted_values) {
165             my ($val, $msg) = $CustomField->AddValue( %{$submitted_values->{$i}} );
166             if ( $val ) {
167                 push @results, loc("Line [_1]: successfully imported", $i);
168             } else  {
169                 push @results, loc("Line [_1]: import error: [_2]", $i, $msg);
170             }
171         }
172     }
173     
174 }
175
176 </%INIT>
177 <%ARGS>
178 $id => undef
179 </%ARGS>
180