Upgrade to 4.0.10.
[usit-rt.git] / lib / RT / ObjectCustomField.pm
CommitLineData
84fb5b46
MKG
1# BEGIN BPS TAGGED BLOCK {{{
2#
3# COPYRIGHT:
4#
403d7b0b 5# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC
84fb5b46
MKG
6# <sales@bestpractical.com>
7#
8# (Except where explicitly superseded by other copyright notices)
9#
10#
11# LICENSE:
12#
13# This work is made available to you under the terms of Version 2 of
14# the GNU General Public License. A copy of that license should have
15# been provided with this software, but in any event can be snarfed
16# from www.gnu.org.
17#
18# This work is distributed in the hope that it will be useful, but
19# WITHOUT ANY WARRANTY; without even the implied warranty of
20# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
21# General Public License for more details.
22#
23# You should have received a copy of the GNU General Public License
24# along with this program; if not, write to the Free Software
25# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
26# 02110-1301 or visit their web page on the internet at
27# http://www.gnu.org/licenses/old-licenses/gpl-2.0.html.
28#
29#
30# CONTRIBUTION SUBMISSION POLICY:
31#
32# (The following paragraph is not intended to limit the rights granted
33# to you to modify and distribute this software under the terms of
34# the GNU General Public License and is only of importance to you if
35# you choose to contribute your changes and enhancements to the
36# community by submitting them to Best Practical Solutions, LLC.)
37#
38# By intentionally submitting any modifications, corrections or
39# derivatives to this work, or any other work intended for use with
40# Request Tracker, to Best Practical Solutions, LLC, you confirm that
41# you are the copyright holder for those contributions and you grant
42# Best Practical Solutions, LLC a nonexclusive, worldwide, irrevocable,
43# royalty-free, perpetual, license to use, copy, create derivative
44# works based on those contributions, and sublicense and distribute
45# those contributions and any derivatives thereof.
46#
47# END BPS TAGGED BLOCK }}}
48
49package RT::ObjectCustomField;
50
51use strict;
52use warnings;
53
54
55use RT::CustomField;
56use base 'RT::Record';
57
58sub Table {'ObjectCustomFields'}
59
60
61
62
63
64
65sub Create {
66 my $self = shift;
67 my %args = (
68 CustomField => 0,
69 ObjectId => 0,
70 SortOrder => undef,
71 @_
72 );
73
74 my $cf = $self->CustomFieldObj( $args{'CustomField'} );
75 unless ( $cf->id ) {
76 $RT::Logger->error("Couldn't load '$args{'CustomField'}' custom field");
77 return 0;
78 }
79
80 #XXX: Where is ACL check for 'AssignCustomFields'?
81
82 my $ObjectCFs = RT::ObjectCustomFields->new($self->CurrentUser);
83 $ObjectCFs->LimitToObjectId( $args{'ObjectId'} );
84 $ObjectCFs->LimitToCustomField( $cf->id );
85 $ObjectCFs->LimitToLookupType( $cf->LookupType );
86 if ( my $first = $ObjectCFs->First ) {
87 $self->Load( $first->id );
88 return $first->id;
89 }
90
91 unless ( defined $args{'SortOrder'} ) {
92 my $ObjectCFs = RT::ObjectCustomFields->new( RT->SystemUser );
93 $ObjectCFs->LimitToObjectId( $args{'ObjectId'} );
94 $ObjectCFs->LimitToObjectId( 0 ) if $args{'ObjectId'};
95 $ObjectCFs->LimitToLookupType( $cf->LookupType );
96 $ObjectCFs->OrderBy( FIELD => 'SortOrder', ORDER => 'DESC' );
97 if ( my $first = $ObjectCFs->First ) {
98 $args{'SortOrder'} = $first->SortOrder + 1;
99 } else {
100 $args{'SortOrder'} = 0;
101 }
102 }
103
104 return $self->SUPER::Create(
105 CustomField => $args{'CustomField'},
106 ObjectId => $args{'ObjectId'},
107 SortOrder => $args{'SortOrder'},
108 );
109}
110
111sub Delete {
112 my $self = shift;
113
114 my $ObjectCFs = RT::ObjectCustomFields->new($self->CurrentUser);
115 $ObjectCFs->LimitToObjectId($self->ObjectId);
116 $ObjectCFs->LimitToLookupType($self->CustomFieldObj->LookupType);
117
118 # Move everything below us up
119 my $sort_order = $self->SortOrder;
120 while (my $OCF = $ObjectCFs->Next) {
121 my $this_order = $OCF->SortOrder;
122 next if $this_order <= $sort_order;
123 $OCF->SetSortOrder($this_order - 1);
124 }
125
126 $self->SUPER::Delete;
127}
128
129
130=head2 CustomFieldObj
131
132Returns the CustomField Object which has the id returned by CustomField
133
134
135=cut
136
137sub CustomFieldObj {
138 my $self = shift;
139 my $id = shift || $self->CustomField;
140
141 # To find out the proper context object to load the CF with, we need
142 # data from the CF -- namely, the record class. Go find that as the
143 # system user first.
144 my $system_CF = RT::CustomField->new( RT->SystemUser );
145 $system_CF->Load( $id );
146 my $class = $system_CF->RecordClassFromLookupType;
147
148 my $obj = $class->new( $self->CurrentUser );
149 $obj->Load( $self->ObjectId );
150
151 my $CF = RT::CustomField->new( $self->CurrentUser );
152 $CF->SetContextObject( $obj );
153 $CF->Load( $id );
154 return $CF;
155}
156
157=head2 Sorting custom fields applications
158
159Custom fields sorted on multiple layers. First of all custom
160fields with different lookup type are sorted independently. All
161global custom fields have fixed order for all objects, but you
162can insert object specific custom fields between them. Object
163specific custom fields can be applied to several objects and
164be on different place. For example you have GCF1, GCF2, LCF1,
165LCF2 and LCF3 that applies to tickets. You can place GCF2
166above GCF1, but they will be in the same order in all queues.
167However, LCF1 and other local can be placed at any place
168for particular queue: above global, between them or below.
169
170=head3 MoveUp
171
172Moves custom field up. See </Sorting custom fields applications>.
173
174=cut
175
176sub MoveUp {
177 my $self = shift;
178
179 my $ocfs = RT::ObjectCustomFields->new( $self->CurrentUser );
180
181 my $oid = $self->ObjectId;
182 $ocfs->LimitToObjectId( $oid );
183 if ( $oid ) {
184 $ocfs->LimitToObjectId( 0 );
185 }
186
187 my $cf = $self->CustomFieldObj;
188 $ocfs->LimitToLookupType( $cf->LookupType );
189
190 $ocfs->Limit( FIELD => 'SortOrder', OPERATOR => '<', VALUE => $self->SortOrder );
191 $ocfs->OrderByCols( { FIELD => 'SortOrder', ORDER => 'DESC' } );
192
193 my @above = ($ocfs->Next, $ocfs->Next);
194 unless ($above[0]) {
195 return (0, "Can not move up. It's already at the top");
196 }
197
198 my $new_sort_order;
199 if ( $above[0]->ObjectId == $self->ObjectId ) {
200 $new_sort_order = $above[0]->SortOrder;
201 my ($status, $msg) = $above[0]->SetSortOrder( $self->SortOrder );
202 unless ( $status ) {
203 return (0, "Couldn't move custom field");
204 }
205 }
206 elsif ( $above[1] && $above[0]->SortOrder == $above[1]->SortOrder + 1 ) {
207 my $move_ocfs = RT::ObjectCustomFields->new( RT->SystemUser );
208 $move_ocfs->LimitToLookupType( $cf->LookupType );
209 $move_ocfs->Limit(
210 FIELD => 'SortOrder',
211 OPERATOR => '>=',
212 VALUE => $above[0]->SortOrder,
213 );
214 $move_ocfs->OrderByCols( { FIELD => 'SortOrder', ORDER => 'DESC' } );
215 while ( my $record = $move_ocfs->Next ) {
216 my ($status, $msg) = $record->SetSortOrder( $record->SortOrder + 1 );
217 unless ( $status ) {
218 return (0, "Couldn't move custom field");
219 }
220 }
221 $new_sort_order = $above[0]->SortOrder;
222 } else {
223 $new_sort_order = $above[0]->SortOrder - 1;
224 }
225
226 my ($status, $msg) = $self->SetSortOrder( $new_sort_order );
227 unless ( $status ) {
228 return (0, "Couldn't move custom field");
229 }
230
231 return (1,"Moved custom field up");
232}
233
234=head3 MoveDown
235
236Moves custom field down. See </Sorting custom fields applications>.
237
238=cut
239
240sub MoveDown {
241 my $self = shift;
242
243 my $ocfs = RT::ObjectCustomFields->new( $self->CurrentUser );
244
245 my $oid = $self->ObjectId;
246 $ocfs->LimitToObjectId( $oid );
247 if ( $oid ) {
248 $ocfs->LimitToObjectId( 0 );
249 }
250
251 my $cf = $self->CustomFieldObj;
252 $ocfs->LimitToLookupType( $cf->LookupType );
253
254 $ocfs->Limit( FIELD => 'SortOrder', OPERATOR => '>', VALUE => $self->SortOrder );
255 $ocfs->OrderByCols( { FIELD => 'SortOrder', ORDER => 'ASC' } );
256
257 my @below = ($ocfs->Next, $ocfs->Next);
258 unless ($below[0]) {
259 return (0, "Can not move down. It's already at the bottom");
260 }
261
262 my $new_sort_order;
263 if ( $below[0]->ObjectId == $self->ObjectId ) {
264 $new_sort_order = $below[0]->SortOrder;
265 my ($status, $msg) = $below[0]->SetSortOrder( $self->SortOrder );
266 unless ( $status ) {
267 return (0, "Couldn't move custom field");
268 }
269 }
270 elsif ( $below[1] && $below[0]->SortOrder + 1 == $below[1]->SortOrder ) {
271 my $move_ocfs = RT::ObjectCustomFields->new( RT->SystemUser );
272 $move_ocfs->LimitToLookupType( $cf->LookupType );
273 $move_ocfs->Limit(
274 FIELD => 'SortOrder',
275 OPERATOR => '<=',
276 VALUE => $below[0]->SortOrder,
277 );
278 $move_ocfs->OrderByCols( { FIELD => 'SortOrder', ORDER => 'ASC' } );
279 while ( my $record = $move_ocfs->Next ) {
280 my ($status, $msg) = $record->SetSortOrder( $record->SortOrder - 1 );
281 unless ( $status ) {
282 return (0, "Couldn't move custom field");
283 }
284 }
285 $new_sort_order = $below[0]->SortOrder;
286 } else {
287 $new_sort_order = $below[0]->SortOrder + 1;
288 }
289
290 my ($status, $msg) = $self->SetSortOrder( $new_sort_order );
291 unless ( $status ) {
292 return (0, "Couldn't move custom field");
293 }
294
295 return (1,"Moved custom field down");
296}
297
298
299=head2 id
300
301Returns the current value of id.
302(In the database, id is stored as int(11).)
303
304
305=cut
306
307
308=head2 CustomField
309
310Returns the current value of CustomField.
311(In the database, CustomField is stored as int(11).)
312
313
314
315=head2 SetCustomField VALUE
316
317
318Set CustomField to VALUE.
319Returns (1, 'Status message') on success and (0, 'Error Message') on failure.
320(In the database, CustomField will be stored as a int(11).)
321
322
323=cut
324
325
326=head2 ObjectId
327
328Returns the current value of ObjectId.
329(In the database, ObjectId is stored as int(11).)
330
331
332
333=head2 SetObjectId VALUE
334
335
336Set ObjectId to VALUE.
337Returns (1, 'Status message') on success and (0, 'Error Message') on failure.
338(In the database, ObjectId will be stored as a int(11).)
339
340
341=cut
342
343
344=head2 SortOrder
345
346Returns the current value of SortOrder.
347(In the database, SortOrder is stored as int(11).)
348
349
350
351=head2 SetSortOrder VALUE
352
353
354Set SortOrder to VALUE.
355Returns (1, 'Status message') on success and (0, 'Error Message') on failure.
356(In the database, SortOrder will be stored as a int(11).)
357
358
359=cut
360
361
362=head2 Creator
363
364Returns the current value of Creator.
365(In the database, Creator is stored as int(11).)
366
367
368=cut
369
370
371=head2 Created
372
373Returns the current value of Created.
374(In the database, Created is stored as datetime.)
375
376
377=cut
378
379
380=head2 LastUpdatedBy
381
382Returns the current value of LastUpdatedBy.
383(In the database, LastUpdatedBy is stored as int(11).)
384
385
386=cut
387
388
389=head2 LastUpdated
390
391Returns the current value of LastUpdated.
392(In the database, LastUpdated is stored as datetime.)
393
394
395=cut
396
397
398
399sub _CoreAccessible {
400 {
401
402 id =>
403 {read => 1, sql_type => 4, length => 11, is_blob => 0, is_numeric => 1, type => 'int(11)', default => ''},
404 CustomField =>
405 {read => 1, write => 1, sql_type => 4, length => 11, is_blob => 0, is_numeric => 1, type => 'int(11)', default => ''},
406 ObjectId =>
407 {read => 1, write => 1, sql_type => 4, length => 11, is_blob => 0, is_numeric => 1, type => 'int(11)', default => ''},
408 SortOrder =>
409 {read => 1, write => 1, sql_type => 4, length => 11, is_blob => 0, is_numeric => 1, type => 'int(11)', default => '0'},
410 Creator =>
411 {read => 1, auto => 1, sql_type => 4, length => 11, is_blob => 0, is_numeric => 1, type => 'int(11)', default => '0'},
412 Created =>
413 {read => 1, auto => 1, sql_type => 11, length => 0, is_blob => 0, is_numeric => 0, type => 'datetime', default => ''},
414 LastUpdatedBy =>
415 {read => 1, auto => 1, sql_type => 4, length => 11, is_blob => 0, is_numeric => 1, type => 'int(11)', default => '0'},
416 LastUpdated =>
417 {read => 1, auto => 1, sql_type => 11, length => 0, is_blob => 0, is_numeric => 0, type => 'datetime', default => ''},
418
419 }
420};
421
422RT::Base->_ImportOverlays();
423
4241;