summaryrefslogtreecommitdiff
path: root/rt/etc
diff options
context:
space:
mode:
Diffstat (limited to 'rt/etc')
-rw-r--r--rt/etc/schema.mysql499
-rw-r--r--rt/etc/upgrade/3.9.1/content68
-rw-r--r--rt/etc/upgrade/3.9.2/content48
-rw-r--r--rt/etc/upgrade/3.9.3/schema.Oracle2
-rw-r--r--rt/etc/upgrade/3.9.3/schema.Pg2
-rw-r--r--rt/etc/upgrade/3.9.3/schema.mysql2
-rw-r--r--rt/etc/upgrade/3.9.5/backcompat1
-rw-r--r--rt/etc/upgrade/3.9.5/schema.Oracle20
-rw-r--r--rt/etc/upgrade/3.9.5/schema.Pg20
-rw-r--r--rt/etc/upgrade/3.9.5/schema.SQLite19
-rw-r--r--rt/etc/upgrade/3.9.5/schema.mysql20
-rw-r--r--rt/etc/upgrade/3.9.6/schema.Oracle1
-rw-r--r--rt/etc/upgrade/3.9.6/schema.Pg1
-rw-r--r--rt/etc/upgrade/3.9.6/schema.SQLite69
-rw-r--r--rt/etc/upgrade/3.9.6/schema.mysql1
-rw-r--r--rt/etc/upgrade/3.9.7/content82
-rw-r--r--rt/etc/upgrade/3.9.7/schema.Oracle6
-rw-r--r--rt/etc/upgrade/3.9.7/schema.Pg6
-rw-r--r--rt/etc/upgrade/3.9.7/schema.SQLite6
-rw-r--r--rt/etc/upgrade/3.9.7/schema.mysql6
-rw-r--r--rt/etc/upgrade/3.9.8/content24
-rw-r--r--rt/etc/upgrade/3.9.8/schema.Oracle65
-rw-r--r--rt/etc/upgrade/3.9.8/schema.Pg62
-rw-r--r--rt/etc/upgrade/3.9.8/schema.SQLite55
-rw-r--r--rt/etc/upgrade/3.9.8/schema.mysql58
-rw-r--r--rt/etc/upgrade/4.0.0rc2/schema.mysql10
-rw-r--r--rt/etc/upgrade/4.0.0rc4/schema.Oracle1
-rw-r--r--rt/etc/upgrade/4.0.0rc4/schema.Pg1
-rw-r--r--rt/etc/upgrade/4.0.0rc4/schema.mysql1
-rw-r--r--rt/etc/upgrade/4.0.0rc7/content21
-rw-r--r--rt/etc/upgrade/4.0.1/acl.Pg39
-rw-r--r--rt/etc/upgrade/4.0.1/content83
-rw-r--r--rt/etc/upgrade/4.0.3/content23
-rw-r--r--rt/etc/upgrade/4.0.4/content16
-rw-r--r--rt/etc/upgrade/sanity-check-stylesheets.pl87
-rwxr-xr-xrt/etc/upgrade/upgrade-articles264
-rw-r--r--rt/etc/upgrade/upgrade-articles.in264
37 files changed, 1953 insertions, 0 deletions
diff --git a/rt/etc/schema.mysql b/rt/etc/schema.mysql
new file mode 100644
index 000000000..c313aaf54
--- /dev/null
+++ b/rt/etc/schema.mysql
@@ -0,0 +1,499 @@
+
+CREATE TABLE Attachments (
+ id INTEGER NOT NULL AUTO_INCREMENT,
+ TransactionId integer NOT NULL ,
+ Parent integer NOT NULL DEFAULT 0 ,
+ MessageId varchar(160) CHARACTER SET ascii NULL ,
+ Subject varchar(255) NULL ,
+ Filename varchar(255) NULL ,
+ ContentType varchar(80) CHARACTER SET ascii NULL ,
+ ContentEncoding varchar(80) CHARACTER SET ascii NULL ,
+ Content LONGBLOB NULL ,
+ Headers LONGTEXT NULL ,
+ Creator integer NOT NULL DEFAULT 0 ,
+ Created DATETIME NULL ,
+ PRIMARY KEY (id)
+) ENGINE=InnoDB CHARACTER SET utf8;
+
+CREATE INDEX Attachments2 ON Attachments (TransactionId) ;
+CREATE INDEX Attachments3 ON Attachments (Parent, TransactionId) ;
+
+CREATE TABLE Queues (
+ id INTEGER NOT NULL AUTO_INCREMENT,
+ Name varchar(200) NOT NULL ,
+ Description varchar(255) NULL ,
+ CorrespondAddress varchar(120) CHARACTER SET ascii NULL,
+ CommentAddress varchar(120) CHARACTER SET ascii NULL,
+ Lifecycle varchar(32) CHARACTER SET ascii NULL,
+ SubjectTag varchar(120) NULL,
+ InitialPriority integer NOT NULL DEFAULT 0 ,
+ FinalPriority integer NOT NULL DEFAULT 0 ,
+ DefaultDueIn integer NOT NULL DEFAULT 0 ,
+ Creator integer NOT NULL DEFAULT 0 ,
+ Created DATETIME NULL ,
+ LastUpdatedBy integer NOT NULL DEFAULT 0 ,
+ LastUpdated DATETIME NULL ,
+ Disabled int2 NOT NULL DEFAULT 0 ,
+ PRIMARY KEY (id)
+) ENGINE=InnoDB CHARACTER SET utf8;
+
+CREATE UNIQUE INDEX Queues1 ON Queues (Name) ;
+CREATE INDEX Queues2 ON Queues (Disabled) ;
+
+
+
+CREATE TABLE Links (
+ id INTEGER NOT NULL AUTO_INCREMENT,
+ Base varchar(240) NULL,
+ Target varchar(240) NULL,
+ Type varchar(20) NOT NULL,
+ LocalTarget integer NOT NULL DEFAULT 0 ,
+ LocalBase integer NOT NULL DEFAULT 0 ,
+ LastUpdatedBy integer NOT NULL DEFAULT 0 ,
+ LastUpdated DATETIME NULL ,
+ Creator integer NOT NULL DEFAULT 0 ,
+ Created DATETIME NULL ,
+ PRIMARY KEY (id)
+) ENGINE=InnoDB CHARACTER SET ascii;
+
+CREATE INDEX Links2 ON Links (Base, Type) ;
+CREATE INDEX Links3 ON Links (Target, Type) ;
+CREATE INDEX Links4 ON Links (Type,LocalBase);
+
+
+
+CREATE TABLE Principals (
+ id INTEGER AUTO_INCREMENT not null,
+ PrincipalType VARCHAR(16) not null,
+ ObjectId integer, # foreign key to Users or Groups, depending
+ Disabled int2 NOT NULL DEFAULT 0 ,
+ PRIMARY KEY (id)
+) ENGINE=InnoDB CHARACTER SET ascii;
+
+CREATE INDEX Principals2 ON Principals (ObjectId);
+
+
+
+CREATE TABLE Groups (
+ id INTEGER NOT NULL AUTO_INCREMENT,
+ Name varchar(200) NULL ,
+ Description varchar(255) NULL ,
+ Domain varchar(64) CHARACTER SET ascii NULL,
+ Type varchar(64) CHARACTER SET ascii NULL,
+ Instance integer,
+ Creator integer NOT NULL DEFAULT 0 ,
+ Created DATETIME NULL ,
+ LastUpdatedBy integer NOT NULL DEFAULT 0 ,
+ LastUpdated DATETIME NULL ,
+ PRIMARY KEY (id)
+) ENGINE=InnoDB CHARACTER SET utf8;
+
+CREATE INDEX Groups1 ON Groups (Domain,Instance,Type,id);
+CREATE INDEX Groups2 On Groups (Type, Instance);
+
+
+
+CREATE TABLE ScripConditions (
+ id INTEGER NOT NULL AUTO_INCREMENT,
+ Name varchar(200) NULL ,
+ Description varchar(255) NULL ,
+ ExecModule varchar(60) CHARACTER SET ascii NULL,
+ Argument VARBINARY(255) NULL ,
+ ApplicableTransTypes varchar(60) CHARACTER SET ascii NULL ,
+
+ Creator integer NOT NULL DEFAULT 0 ,
+ Created DATETIME NULL ,
+ LastUpdatedBy integer NOT NULL DEFAULT 0 ,
+ LastUpdated DATETIME NULL ,
+ PRIMARY KEY (id)
+) ENGINE=InnoDB CHARACTER SET utf8;
+
+
+CREATE TABLE Transactions (
+ id INTEGER NOT NULL AUTO_INCREMENT,
+ ObjectType varchar(64) CHARACTER SET ascii NOT NULL,
+ ObjectId integer NOT NULL DEFAULT 0 ,
+ TimeTaken integer NOT NULL DEFAULT 0 ,
+ Type varchar(20) CHARACTER SET ascii NULL,
+ Field varchar(40) CHARACTER SET ascii NULL,
+ OldValue varchar(255) NULL ,
+ NewValue varchar(255) NULL ,
+ ReferenceType varchar(255) CHARACTER SET ascii NULL,
+ OldReference integer NULL ,
+ NewReference integer NULL ,
+ Data varchar(255) NULL ,
+
+ Creator integer NOT NULL DEFAULT 0 ,
+ Created DATETIME NULL ,
+ PRIMARY KEY (id)
+) ENGINE=InnoDB CHARACTER SET utf8;
+
+CREATE INDEX Transactions1 ON Transactions (ObjectType, ObjectId);
+
+
+
+CREATE TABLE Scrips (
+ id INTEGER NOT NULL AUTO_INCREMENT,
+ Description varchar(255),
+ ScripCondition integer NOT NULL DEFAULT 0 ,
+ ScripAction integer NOT NULL DEFAULT 0 ,
+ ConditionRules text NULL ,
+ ActionRules text NULL ,
+ CustomIsApplicableCode text NULL ,
+ CustomPrepareCode text NULL ,
+ CustomCommitCode text NULL ,
+ Stage varchar(32) CHARACTER SET ascii NULL ,
+ Queue integer NOT NULL DEFAULT 0 ,
+ Template integer NOT NULL DEFAULT 0 ,
+ Creator integer NOT NULL DEFAULT 0 ,
+ Created DATETIME NULL ,
+ LastUpdatedBy integer NOT NULL DEFAULT 0 ,
+ LastUpdated DATETIME NULL ,
+ PRIMARY KEY (id)
+) ENGINE=InnoDB CHARACTER SET utf8;
+
+
+CREATE TABLE ACL (
+ id INTEGER NOT NULL AUTO_INCREMENT,
+ PrincipalType varchar(25) CHARACTER SET ascii NOT NULL, #"User" "Group", "Owner", "Cc" "AdminCc", "Requestor"
+
+ PrincipalId integer NOT NULL DEFAULT 0 , #Foreign key to principals
+ RightName varchar(25) CHARACTER SET ascii NOT NULL,
+ ObjectType varchar(25) CHARACTER SET ascii NOT NULL,
+ ObjectId integer NOT NULL default 0,
+ Creator integer NOT NULL DEFAULT 0 ,
+ Created DATETIME NULL ,
+ LastUpdatedBy integer NOT NULL DEFAULT 0 ,
+ LastUpdated DATETIME NULL ,
+ PRIMARY KEY (id)
+) ENGINE=InnoDB CHARACTER SET utf8;
+
+CREATE INDEX ACL1 on ACL(RightName, ObjectType, ObjectId,PrincipalType,PrincipalId);
+
+
+
+CREATE TABLE GroupMembers (
+ id INTEGER NOT NULL AUTO_INCREMENT,
+ GroupId integer NOT NULL DEFAULT 0,
+ MemberId integer NOT NULL DEFAULT 0, #Foreign key to Principals
+ Creator integer NOT NULL DEFAULT 0 ,
+ Created DATETIME NULL ,
+ LastUpdatedBy integer NOT NULL DEFAULT 0 ,
+ LastUpdated DATETIME NULL ,
+ PRIMARY KEY (id)
+) ENGINE=InnoDB CHARACTER SET utf8;
+CREATE UNIQUE INDEX GroupMembers1 on GroupMembers (GroupId, MemberId);
+
+
+
+
+create table CachedGroupMembers (
+ id int auto_increment,
+ GroupId int, # foreign key to Principals
+ MemberId int, # foreign key to Principals
+ Via int, #foreign key to CachedGroupMembers. (may point to $self->id)
+ ImmediateParentId int, #foreign key to prinicpals.
+ # this points to the group that the member is
+ # a member of, for ease of deletes.
+ Disabled int2 NOT NULL DEFAULT 0 , # if this cached group member is a member of this group by way of a disabled
+ # group or this group is disabled, this will be set to 1
+ # this allows us to not find members of disabled subgroups when listing off
+ # group members recursively.
+ # Also, this allows us to have the ACL system elide members of disabled groups
+ PRIMARY KEY (id)
+) ENGINE=InnoDB CHARACTER SET utf8;
+
+CREATE INDEX DisGrouMem on CachedGroupMembers (GroupId,MemberId,Disabled);
+CREATE INDEX CachedGroupMembers3 on CachedGroupMembers (MemberId, ImmediateParentId);
+
+
+
+CREATE TABLE Users (
+ id INTEGER NOT NULL AUTO_INCREMENT,
+ Name varchar(200) NOT NULL ,
+ Password VARCHAR(256) NULL ,
+ AuthToken VARCHAR(16) CHARACTER SET ascii NULL ,
+ Comments TEXT NULL ,
+ Signature TEXT NULL ,
+ EmailAddress varchar(120) NULL ,
+ FreeformContactInfo TEXT NULL ,
+ Organization varchar(200) NULL ,
+ RealName varchar(120) NULL ,
+ NickName varchar(16) NULL ,
+ Lang varchar(16) NULL ,
+ EmailEncoding varchar(16) NULL ,
+ WebEncoding varchar(16) NULL ,
+ ExternalContactInfoId varchar(100) NULL ,
+ ContactInfoSystem varchar(30) NULL ,
+ ExternalAuthId varchar(100) NULL ,
+ AuthSystem varchar(30) NULL ,
+ Gecos varchar(16) NULL ,
+ HomePhone varchar(30) NULL ,
+ WorkPhone varchar(30) NULL ,
+ MobilePhone varchar(30) NULL ,
+ PagerPhone varchar(30) NULL ,
+ Address1 varchar(200) NULL ,
+ Address2 varchar(200) NULL ,
+ City varchar(100) NULL ,
+ State varchar(100) NULL ,
+ Zip varchar(16) NULL ,
+ Country varchar(50) NULL ,
+ Timezone varchar(50) NULL ,
+ PGPKey text NULL,
+
+ Creator integer NOT NULL DEFAULT 0 ,
+ Created DATETIME NULL ,
+ LastUpdatedBy integer NOT NULL DEFAULT 0 ,
+ LastUpdated DATETIME NULL ,
+ PRIMARY KEY (id)
+) ENGINE=InnoDB CHARACTER SET utf8;
+
+
+CREATE UNIQUE INDEX Users1 ON Users (Name) ;
+CREATE INDEX Users4 ON Users (EmailAddress);
+
+
+
+
+CREATE TABLE Tickets (
+ id INTEGER NOT NULL AUTO_INCREMENT,
+ EffectiveId integer NOT NULL DEFAULT 0 ,
+ Queue integer NOT NULL DEFAULT 0 ,
+ Type varchar(16) CHARACTER SET ascii NULL ,
+ IssueStatement integer NOT NULL DEFAULT 0 ,
+ Resolution integer NOT NULL DEFAULT 0 ,
+ Owner integer NOT NULL DEFAULT 0 ,
+ Subject varchar(200) NULL DEFAULT '[no subject]' ,
+ InitialPriority integer NOT NULL DEFAULT 0 ,
+ FinalPriority integer NOT NULL DEFAULT 0 ,
+ Priority integer NOT NULL DEFAULT 0 ,
+ TimeEstimated integer NOT NULL DEFAULT 0 ,
+ TimeWorked integer NOT NULL DEFAULT 0 ,
+ Status varchar(64) NULL ,
+ TimeLeft integer NOT NULL DEFAULT 0 ,
+ Told DATETIME NULL ,
+ Starts DATETIME NULL ,
+ Started DATETIME NULL ,
+ Due DATETIME NULL ,
+ Resolved DATETIME NULL ,
+
+
+ LastUpdatedBy integer NOT NULL DEFAULT 0 ,
+ LastUpdated DATETIME NULL ,
+ Creator integer NOT NULL DEFAULT 0 ,
+ Created DATETIME NULL ,
+ Disabled int2 NOT NULL DEFAULT 0 ,
+ PRIMARY KEY (id)
+) ENGINE=InnoDB CHARACTER SET utf8;
+
+CREATE INDEX Tickets1 ON Tickets (Queue, Status) ;
+CREATE INDEX Tickets2 ON Tickets (Owner) ;
+CREATE INDEX Tickets6 ON Tickets (EffectiveId, Type) ;
+
+
+
+CREATE TABLE ScripActions (
+ id INTEGER NOT NULL AUTO_INCREMENT,
+ Name varchar(200) NULL ,
+ Description varchar(255) NULL ,
+ ExecModule varchar(60) CHARACTER SET ascii NULL,
+ Argument VARBINARY(255) NULL ,
+ Creator integer NOT NULL DEFAULT 0 ,
+ Created DATETIME NULL ,
+ LastUpdatedBy integer NOT NULL DEFAULT 0 ,
+ LastUpdated DATETIME NULL ,
+ PRIMARY KEY (id)
+) ENGINE=InnoDB CHARACTER SET utf8;
+
+
+
+CREATE TABLE Templates (
+ id INTEGER NOT NULL AUTO_INCREMENT,
+ Queue integer NOT NULL DEFAULT 0 ,
+ Name varchar(200) NOT NULL ,
+ Description varchar(255) NULL ,
+ Type varchar(16) CHARACTER SET ascii NULL ,
+ Language varchar(16) CHARACTER SET ascii NULL ,
+ TranslationOf integer NOT NULL DEFAULT 0 ,
+ Content TEXT NULL ,
+ LastUpdated DATETIME NULL ,
+ LastUpdatedBy integer NOT NULL DEFAULT 0 ,
+ Creator integer NOT NULL DEFAULT 0 ,
+ Created DATETIME NULL ,
+ PRIMARY KEY (id)
+) ENGINE=InnoDB CHARACTER SET utf8;
+
+
+
+CREATE TABLE ObjectCustomFieldValues (
+ id INTEGER NOT NULL AUTO_INCREMENT,
+ CustomField int NOT NULL ,
+ ObjectType varchar(255) CHARACTER SET ascii NOT NULL, # Final target of the Object
+ ObjectId int NOT NULL , # New -- Replaces Ticket
+ SortOrder integer NOT NULL DEFAULT 0 , # New -- ordering for multiple values
+
+ Content varchar(255) NULL ,
+ LargeContent LONGBLOB NULL, # New -- to hold 255+ strings
+ ContentType varchar(80) CHARACTER SET ascii NULL, # New -- only text/* gets searched
+ ContentEncoding varchar(80) CHARACTER SET ascii NULL , # New -- for binary Content
+
+ Creator integer NOT NULL DEFAULT 0 ,
+ Created DATETIME NULL ,
+ LastUpdatedBy integer NOT NULL DEFAULT 0 ,
+ LastUpdated DATETIME NULL ,
+ Disabled int2 NOT NULL DEFAULT 0 , # New -- whether the value was current
+ PRIMARY KEY (id)
+) ENGINE=InnoDB CHARACTER SET utf8;
+
+CREATE INDEX ObjectCustomFieldValues1 ON ObjectCustomFieldValues (Content);
+CREATE INDEX ObjectCustomFieldValues2 ON ObjectCustomFieldValues (CustomField,ObjectType,ObjectId);
+
+
+
+CREATE TABLE CustomFields (
+ id INTEGER NOT NULL AUTO_INCREMENT,
+ Name varchar(200) NULL ,
+ Type varchar(200) CHARACTER SET ascii NULL , # Changed -- 'Single' and 'Multiple' is moved out
+ RenderType varchar(64) CHARACTER SET ascii NULL ,
+ MaxValues integer, # New -- was 'Single'(1) and 'Multiple'(0)
+ Pattern TEXT NULL , # New -- Must validate against this
+ Repeated int2 NOT NULL DEFAULT 0 , # New -- repeated table entry
+ BasedOn INTEGER NULL,
+ ValuesClass varchar(64) CHARACTER SET ascii NULL ,
+ Description varchar(255) NULL ,
+ SortOrder integer NOT NULL DEFAULT 0 ,
+ LookupType varchar(255) CHARACTER SET ascii NOT NULL,
+
+ Creator integer NOT NULL DEFAULT 0 ,
+ Created DATETIME NULL ,
+ LastUpdatedBy integer NOT NULL DEFAULT 0 ,
+ LastUpdated DATETIME NULL ,
+ Disabled int2 NOT NULL DEFAULT 0 ,
+ PRIMARY KEY (id)
+) ENGINE=InnoDB CHARACTER SET utf8;
+
+
+
+CREATE TABLE ObjectCustomFields (
+ id INTEGER NOT NULL AUTO_INCREMENT,
+ CustomField integer NOT NULL ,
+ ObjectId integer NOT NULL,
+ SortOrder integer NOT NULL DEFAULT 0 ,
+
+ Creator integer NOT NULL DEFAULT 0 ,
+ Created DATETIME NULL ,
+ LastUpdatedBy integer NOT NULL DEFAULT 0 ,
+ LastUpdated DATETIME NULL ,
+ PRIMARY KEY (id)
+) ENGINE=InnoDB CHARACTER SET utf8;
+
+
+
+CREATE TABLE CustomFieldValues (
+ id INTEGER NOT NULL AUTO_INCREMENT,
+ CustomField int NOT NULL ,
+ Name varchar(200) NULL ,
+ Description varchar(255) NULL ,
+ SortOrder integer NOT NULL DEFAULT 0 ,
+ Category VARCHAR(255) NULL,
+
+ Creator integer NOT NULL DEFAULT 0 ,
+ Created DATETIME NULL ,
+ LastUpdatedBy integer NOT NULL DEFAULT 0 ,
+ LastUpdated DATETIME NULL ,
+ PRIMARY KEY (id)
+) ENGINE=InnoDB CHARACTER SET utf8;
+
+CREATE INDEX CustomFieldValues1 ON CustomFieldValues (CustomField);
+
+
+
+
+CREATE TABLE Attributes (
+ id INTEGER NOT NULL AUTO_INCREMENT,
+ Name varchar(255) NULL ,
+ Description varchar(255) NULL ,
+ Content BLOB,
+ ContentType varchar(16) CHARACTER SET ascii,
+ ObjectType varchar(64) CHARACTER SET ascii,
+ ObjectId integer, # foreign key to anything
+ Creator integer NOT NULL DEFAULT 0 ,
+ Created DATETIME NULL ,
+ LastUpdatedBy integer NOT NULL DEFAULT 0 ,
+ LastUpdated DATETIME NULL ,
+ PRIMARY KEY (id)
+) ENGINE=InnoDB CHARACTER SET utf8;
+
+CREATE INDEX Attributes1 on Attributes(Name);
+CREATE INDEX Attributes2 on Attributes(ObjectType, ObjectId);
+
+
+
+# sessions is used by Apache::Session to keep sessions in the database.
+# We should have a reaper script somewhere.
+
+CREATE TABLE sessions (
+ id char(32) NOT NULL,
+ a_session LONGBLOB,
+ LastUpdated TIMESTAMP,
+ PRIMARY KEY (id)
+) ENGINE=InnoDB CHARACTER SET ascii;
+
+CREATE TABLE Classes (
+ id int(11) NOT NULL auto_increment,
+ Name varchar(255) NOT NULL default '',
+ Description varchar(255) NOT NULL default '',
+ SortOrder int(11) NOT NULL default '0',
+ Disabled int(2) NOT NULL default '0',
+ Creator int(11) NOT NULL default '0',
+ Created datetime default NULL,
+ LastUpdatedBy int(11) NOT NULL default '0',
+ LastUpdated datetime default NULL,
+ HotList int(2) NOT NULL default '0',
+ PRIMARY KEY (id)
+) ENGINE=InnoDB DEFAULT CHARSET=utf8;
+
+CREATE TABLE Articles (
+ id int(11) NOT NULL auto_increment,
+ Name varchar(255) NOT NULL default '',
+ Summary varchar(255) NOT NULL default '',
+ SortOrder int(11) NOT NULL default '0',
+ Class int(11) NOT NULL default '0',
+ Parent int(11) NOT NULL default '0',
+ URI varchar(255) character set ascii default NULL,
+ Creator int(11) NOT NULL default '0',
+ Created datetime default NULL,
+ LastUpdatedBy int(11) NOT NULL default '0',
+ LastUpdated datetime default NULL,
+ PRIMARY KEY (id)
+) ENGINE=InnoDB DEFAULT CHARSET=utf8;
+
+CREATE TABLE Topics (
+ id int(11) NOT NULL auto_increment,
+ Parent int(11) NOT NULL default '0',
+ Name varchar(255) NOT NULL default '',
+ Description varchar(255) NOT NULL default '',
+ ObjectType varchar(64) character set ascii NOT NULL default '',
+ ObjectId int(11) NOT NULL default '0',
+ PRIMARY KEY (id)
+) ENGINE=InnoDB DEFAULT CHARSET=utf8;
+
+CREATE TABLE ObjectTopics (
+ id int(11) NOT NULL auto_increment,
+ Topic int(11) NOT NULL default '0',
+ ObjectType varchar(64) character set ascii NOT NULL default '',
+ ObjectId int(11) NOT NULL default '0',
+ PRIMARY KEY (id)
+) ENGINE=InnoDB DEFAULT CHARSET=utf8;
+
+CREATE TABLE ObjectClasses (
+ id int(11) NOT NULL auto_increment,
+ Class int(11) NOT NULL default '0',
+ ObjectType varchar(255) character set ascii NOT NULL default '',
+ ObjectId int(11) NOT NULL default '0',
+ Creator int(11) NOT NULL default '0',
+ Created datetime default NULL,
+ LastUpdatedBy int(11) NOT NULL default '0',
+ LastUpdated datetime default NULL,
+ PRIMARY KEY (id)
+) ENGINE=InnoDB DEFAULT CHARSET=utf8;
diff --git a/rt/etc/upgrade/3.9.1/content b/rt/etc/upgrade/3.9.1/content
new file mode 100644
index 000000000..acdc0adb7
--- /dev/null
+++ b/rt/etc/upgrade/3.9.1/content
@@ -0,0 +1,68 @@
+@Initial = (
+ sub {
+ use strict;
+ $RT::Logger->debug('Make sure templates all have known types');
+
+ # We update all NULL rows, below. We want to find non-NULL
+ # rows, which weren't created by the current codebase running
+ # through earlier initialdatas. Type != 'Perl' enforces the
+ # non-NULL part, as well
+ my $templates = RT::Templates->new(RT->SystemUser);
+ $templates->Limit(
+ FIELD => 'Type',
+ OPERATOR => '!=',
+ VALUE => 'Perl',
+ );
+
+ if ($templates->Count) {
+ die "You have templates with Type already set. This will interfere with your upgrade because RT used to ignore the template Type field, but now uses it.";
+ }
+
+ $templates = RT::Templates->new(RT->SystemUser);
+ $templates->Limit(
+ FIELD => 'Type',
+ OPERATOR => 'IS',
+ VALUE => 'NULL',
+ );
+ while (my $template = $templates->Next) {
+ my ($status, $msg) = $template->SetType('Perl');
+ $RT::Logger->warning( "Couldn't change Type of Template #" . $template->Id . ": $msg" ) unless $status;
+ }
+ },
+ sub {
+ use strict;
+ $RT::Logger->debug('Adding ExecuteCode right to principals that currently have ModifyTemplate or ModifyScrips');
+
+ my $acl = RT::ACL->new(RT->SystemUser);
+ $acl->Limit(
+ FIELD => 'RightName',
+ OPERATOR => '=',
+ VALUE => 'ModifyTemplate',
+ ENTRYAGGREGATOR => 'OR',
+ );
+ $acl->Limit(
+ FIELD => 'RightName',
+ OPERATOR => '=',
+ VALUE => 'ModifyScrips',
+ ENTRYAGGREGATOR => 'OR',
+ );
+
+ while (my $ace = $acl->Next) {
+ my $principal = $ace->PrincipalObj;
+ next if $principal->HasRight(
+ Right => 'ExecuteCode',
+ Object => $RT::System,
+ );
+
+ my ($ok, $msg) = $principal->GrantRight(
+ Right => 'ExecuteCode',
+ Object => $RT::System,
+ );
+
+ if (!$ok) {
+ $RT::Logger->warn("Unable to grant ExecuteCode on principal " . $principal->id . ": $msg");
+ }
+ }
+ },
+);
+
diff --git a/rt/etc/upgrade/3.9.2/content b/rt/etc/upgrade/3.9.2/content
new file mode 100644
index 000000000..d0dbbfd0a
--- /dev/null
+++ b/rt/etc/upgrade/3.9.2/content
@@ -0,0 +1,48 @@
+@Initial = (
+ sub {
+ use strict;
+ $RT::Logger->debug('Removing all delegated rights');
+
+ my $acl = RT::ACL->new(RT->SystemUser);
+ $acl->Limit( CLAUSE => 'search',
+ FIELD => 'DelegatedBy',
+ OPERATOR => '>',
+ VALUE => '0'
+ );
+ $acl->Limit( CLAUSE => 'search',
+ FIELD => 'DelegatedFrom',
+ OPERATOR => '>',
+ VALUE => '0',
+ ENTRYAGGREGATOR => 'OR',
+ );
+
+ while ( my $ace = $acl->Next ) {
+ my ( $ok, $msg ) = $ace->Delete();
+
+ if ( !$ok ) {
+ $RT::Logger->warn(
+ "Unable to delete ACE " . $ace->id . ": " . $msg );
+ }
+ }
+
+ my $groups = RT::Groups->new(RT->SystemUser);
+ $groups->Limit( FIELD => 'Domain',
+ OPERATOR => '=',
+ VALUE => 'Personal'
+ );
+ while ( my $group = $groups->Next ) {
+ my $members = $group->MembersObj();
+ while ( my $member = $members->Next ) {
+ my ( $ok, $msg ) = $group->DeleteMember( $member->MemberId );
+ if ( !$ok ) {
+ $RT::Logger->warn( "Unable to remove group member "
+ . $member->id . ": "
+ . $msg );
+ }
+ }
+ $group->PrincipalObj->Delete;
+ $group->RT::Record::Delete();
+ }
+ },
+);
+
diff --git a/rt/etc/upgrade/3.9.3/schema.Oracle b/rt/etc/upgrade/3.9.3/schema.Oracle
new file mode 100644
index 000000000..4ee50c446
--- /dev/null
+++ b/rt/etc/upgrade/3.9.3/schema.Oracle
@@ -0,0 +1,2 @@
+ALTER TABLE ACL DROP COLUMN DelegatedBy;
+ALTER TABLE ACL DROP COLUMN DelegatedFrom;
diff --git a/rt/etc/upgrade/3.9.3/schema.Pg b/rt/etc/upgrade/3.9.3/schema.Pg
new file mode 100644
index 000000000..4ee50c446
--- /dev/null
+++ b/rt/etc/upgrade/3.9.3/schema.Pg
@@ -0,0 +1,2 @@
+ALTER TABLE ACL DROP COLUMN DelegatedBy;
+ALTER TABLE ACL DROP COLUMN DelegatedFrom;
diff --git a/rt/etc/upgrade/3.9.3/schema.mysql b/rt/etc/upgrade/3.9.3/schema.mysql
new file mode 100644
index 000000000..4ee50c446
--- /dev/null
+++ b/rt/etc/upgrade/3.9.3/schema.mysql
@@ -0,0 +1,2 @@
+ALTER TABLE ACL DROP COLUMN DelegatedBy;
+ALTER TABLE ACL DROP COLUMN DelegatedFrom;
diff --git a/rt/etc/upgrade/3.9.5/backcompat b/rt/etc/upgrade/3.9.5/backcompat
new file mode 100644
index 000000000..611ab5186
--- /dev/null
+++ b/rt/etc/upgrade/3.9.5/backcompat
@@ -0,0 +1 @@
+RT::ACE LastUpdated LastUpdatedBy Creator Created
diff --git a/rt/etc/upgrade/3.9.5/schema.Oracle b/rt/etc/upgrade/3.9.5/schema.Oracle
new file mode 100644
index 000000000..065776dfb
--- /dev/null
+++ b/rt/etc/upgrade/3.9.5/schema.Oracle
@@ -0,0 +1,20 @@
+alter Table CustomFieldValues ADD Category varchar2(255);
+
+UPDATE CustomFieldValues SET Category = (SELECT Content FROM Attributes WHERE
+Name = 'Category' AND ObjectType = 'RT::CustomFieldValue'
+AND CustomFieldValues.id = Attributes.ObjectId);
+
+DELETE FROM Attributes WHERE Name = 'Category' AND ObjectType = 'RT::CustomFieldValue';
+
+ALTER TABLE Groups ADD Creator NUMBER(11,0) DEFAULT 0 NOT NULL;
+ALTER TABLE Groups ADD Created DATE;
+ALTER TABLE Groups ADD LastUpdatedBy NUMBER(11,0) DEFAULT 0 NOT NULL;
+ALTER TABLE Groups ADD LastUpdated DATE;
+ALTER TABLE GroupMembers ADD Creator NUMBER(11,0) DEFAULT 0 NOT NULL;
+ALTER TABLE GroupMembers ADD Created DATE;
+ALTER TABLE GroupMembers ADD LastUpdatedBy NUMBER(11,0) DEFAULT 0 NOT NULL;
+ALTER TABLE GroupMembers ADD LastUpdated DATE;
+ALTER TABLE ACL ADD Creator NUMBER(11,0) DEFAULT 0 NOT NULL;
+ALTER TABLE ACL ADD Created DATE;
+ALTER TABLE ACL ADD LastUpdatedBy NUMBER(11,0) DEFAULT 0 NOT NULL;
+ALTER TABLE ACL ADD LastUpdated DATE;
diff --git a/rt/etc/upgrade/3.9.5/schema.Pg b/rt/etc/upgrade/3.9.5/schema.Pg
new file mode 100644
index 000000000..cea2c4410
--- /dev/null
+++ b/rt/etc/upgrade/3.9.5/schema.Pg
@@ -0,0 +1,20 @@
+alter Table CustomFieldValues ADD Column Category varchar(255);
+
+UPDATE CustomFieldValues SET Category = (SELECT Content FROM Attributes WHERE
+Name = 'Category' AND ObjectType = 'RT::CustomFieldValue'
+AND CustomFieldValues.id = Attributes.ObjectId);
+
+DELETE FROM Attributes WHERE Name = 'Category' AND ObjectType = 'RT::CustomFieldValue';
+
+ALTER TABLE Groups ADD COLUMN Creator integer NOT NULL DEFAULT 0;
+ALTER TABLE Groups ADD COLUMN Created TIMESTAMP NULL;
+ALTER TABLE Groups ADD COLUMN LastUpdatedBy integer NOT NULL DEFAULT 0;
+ALTER TABLE Groups ADD COLUMN LastUpdated TIMESTAMP NULL;
+ALTER TABLE GroupMembers ADD COLUMN Creator integer NOT NULL DEFAULT 0;
+ALTER TABLE GroupMembers ADD COLUMN Created TIMESTAMP NULL;
+ALTER TABLE GroupMembers ADD COLUMN LastUpdatedBy integer NOT NULL DEFAULT 0;
+ALTER TABLE GroupMembers ADD COLUMN LastUpdated TIMESTAMP NULL;
+ALTER TABLE ACL ADD COLUMN Creator integer NOT NULL DEFAULT 0;
+ALTER TABLE ACL ADD COLUMN Created TIMESTAMP NULL;
+ALTER TABLE ACL ADD COLUMN LastUpdatedBy integer NOT NULL DEFAULT 0;
+ALTER TABLE ACL ADD COLUMN LastUpdated TIMESTAMP NULL;
diff --git a/rt/etc/upgrade/3.9.5/schema.SQLite b/rt/etc/upgrade/3.9.5/schema.SQLite
new file mode 100644
index 000000000..c23f89bc7
--- /dev/null
+++ b/rt/etc/upgrade/3.9.5/schema.SQLite
@@ -0,0 +1,19 @@
+ALTER TABLE CustomFieldValues ADD Column Category varchar(255);
+UPDATE CustomFieldValues SET Category = (SELECT Content FROM Attributes WHERE
+Name = 'Category' AND ObjectType = 'RT::CustomFieldValue'
+AND CustomFieldValues.id = Attributes.ObjectId);
+
+DELETE FROM Attributes WHERE Name = 'Category' AND ObjectType = 'RT::CustomFieldValue';
+
+ALTER TABLE Groups ADD COLUMN Creator integer NOT NULL DEFAULT 0;
+ALTER TABLE Groups ADD COLUMN Created DATETIME NULL;
+ALTER TABLE Groups ADD COLUMN LastUpdatedBy integer NOT NULL DEFAULT 0;
+ALTER TABLE Groups ADD COLUMN LastUpdated DATETIME NULL;
+ALTER TABLE GroupMembers ADD COLUMN Creator integer NOT NULL DEFAULT 0;
+ALTER TABLE GroupMembers ADD COLUMN Created DATETIME NULL;
+ALTER TABLE GroupMembers ADD COLUMN LastUpdatedBy integer NOT NULL DEFAULT 0;
+ALTER TABLE GroupMembers ADD COLUMN LastUpdated DATETIME NULL;
+ALTER TABLE ACL ADD COLUMN Creator integer NOT NULL DEFAULT 0;
+ALTER TABLE ACL ADD COLUMN Created DATETIME NULL;
+ALTER TABLE ACL ADD COLUMN LastUpdatedBy integer NOT NULL DEFAULT 0;
+ALTER TABLE ACL ADD COLUMN LastUpdated DATETIME NULL;
diff --git a/rt/etc/upgrade/3.9.5/schema.mysql b/rt/etc/upgrade/3.9.5/schema.mysql
new file mode 100644
index 000000000..4bd0907c0
--- /dev/null
+++ b/rt/etc/upgrade/3.9.5/schema.mysql
@@ -0,0 +1,20 @@
+alter Table CustomFieldValues ADD Column Category varchar(255);
+
+UPDATE CustomFieldValues SET Category = (SELECT Content FROM Attributes WHERE
+Name = 'Category' AND ObjectType = 'RT::CustomFieldValue'
+AND CustomFieldValues.id = Attributes.ObjectId);
+
+DELETE FROM Attributes WHERE Name = 'Category' AND ObjectType = 'RT::CustomFieldValue';
+
+ALTER TABLE Groups ADD COLUMN Creator integer NOT NULL DEFAULT 0;
+ALTER TABLE Groups ADD COLUMN Created DATETIME NULL;
+ALTER TABLE Groups ADD COLUMN LastUpdatedBy integer NOT NULL DEFAULT 0;
+ALTER TABLE Groups ADD COLUMN LastUpdated DATETIME NULL;
+ALTER TABLE GroupMembers ADD COLUMN Creator integer NOT NULL DEFAULT 0;
+ALTER TABLE GroupMembers ADD COLUMN Created DATETIME NULL;
+ALTER TABLE GroupMembers ADD COLUMN LastUpdatedBy integer NOT NULL DEFAULT 0;
+ALTER TABLE GroupMembers ADD COLUMN LastUpdated DATETIME NULL;
+ALTER TABLE ACL ADD COLUMN Creator integer NOT NULL DEFAULT 0;
+ALTER TABLE ACL ADD COLUMN Created DATETIME NULL;
+ALTER TABLE ACL ADD COLUMN LastUpdatedBy integer NOT NULL DEFAULT 0;
+ALTER TABLE ACL ADD COLUMN LastUpdated DATETIME NULL;
diff --git a/rt/etc/upgrade/3.9.6/schema.Oracle b/rt/etc/upgrade/3.9.6/schema.Oracle
new file mode 100644
index 000000000..ecec972f4
--- /dev/null
+++ b/rt/etc/upgrade/3.9.6/schema.Oracle
@@ -0,0 +1 @@
+ALTER TABLE Tickets MODIFY Status VARCHAR2(64);
diff --git a/rt/etc/upgrade/3.9.6/schema.Pg b/rt/etc/upgrade/3.9.6/schema.Pg
new file mode 100644
index 000000000..f4f909edc
--- /dev/null
+++ b/rt/etc/upgrade/3.9.6/schema.Pg
@@ -0,0 +1 @@
+ALTER TABLE Tickets ALTER Status TYPE varchar(64);
diff --git a/rt/etc/upgrade/3.9.6/schema.SQLite b/rt/etc/upgrade/3.9.6/schema.SQLite
new file mode 100644
index 000000000..2e7b6d307
--- /dev/null
+++ b/rt/etc/upgrade/3.9.6/schema.SQLite
@@ -0,0 +1,69 @@
+BEGIN TRANSACTION;
+CREATE TEMPORARY TABLE Tickets_backup (
+ id INTEGER PRIMARY KEY ,
+ EffectiveId integer NULL ,
+ Queue integer NULL ,
+ Type varchar(16) NULL ,
+ IssueStatement integer NULL ,
+ Resolution integer NULL ,
+ Owner integer NULL ,
+ Subject varchar(200) NULL DEFAULT '[no subject]' ,
+ InitialPriority integer NULL ,
+ FinalPriority integer NULL ,
+ Priority integer NULL ,
+ TimeEstimated integer NULL ,
+ TimeWorked integer NULL ,
+ Status varchar(64) NULL ,
+ TimeLeft integer NULL ,
+ Told DATETIME NULL ,
+ Starts DATETIME NULL ,
+ Started DATETIME NULL ,
+ Due DATETIME NULL ,
+ Resolved DATETIME NULL ,
+ LastUpdatedBy integer NULL ,
+ LastUpdated DATETIME NULL ,
+ Creator integer NULL ,
+ Created DATETIME NULL ,
+ Disabled int2 NOT NULL DEFAULT 0
+);
+
+INSERT INTO Tickets_backup SELECT * FROM Tickets;
+DROP TABLE Tickets;
+
+CREATE TABLE Tickets (
+ id INTEGER PRIMARY KEY ,
+ EffectiveId integer NULL ,
+ Queue integer NULL ,
+ Type varchar(16) NULL ,
+ IssueStatement integer NULL ,
+ Resolution integer NULL ,
+ Owner integer NULL ,
+ Subject varchar(200) NULL DEFAULT '[no subject]' ,
+ InitialPriority integer NULL ,
+ FinalPriority integer NULL ,
+ Priority integer NULL ,
+ TimeEstimated integer NULL ,
+ TimeWorked integer NULL ,
+ Status varchar(64) NULL ,
+ TimeLeft integer NULL ,
+ Told DATETIME NULL ,
+ Starts DATETIME NULL ,
+ Started DATETIME NULL ,
+ Due DATETIME NULL ,
+ Resolved DATETIME NULL ,
+ LastUpdatedBy integer NULL ,
+ LastUpdated DATETIME NULL ,
+ Creator integer NULL ,
+ Created DATETIME NULL ,
+ Disabled int2 NOT NULL DEFAULT 0
+);
+
+CREATE INDEX Tickets1 ON Tickets (Queue, Status) ;
+CREATE INDEX Tickets2 ON Tickets (Owner) ;
+CREATE INDEX Tickets3 ON Tickets (EffectiveId) ;
+CREATE INDEX Tickets4 ON Tickets (id, Status) ;
+CREATE INDEX Tickets5 ON Tickets (id, EffectiveId) ;
+
+INSERT INTO Tickets SELECT * FROM Tickets_backup;
+DROP TABLE Tickets_backup;
+COMMIT;
diff --git a/rt/etc/upgrade/3.9.6/schema.mysql b/rt/etc/upgrade/3.9.6/schema.mysql
new file mode 100644
index 000000000..b0a9eaf9f
--- /dev/null
+++ b/rt/etc/upgrade/3.9.6/schema.mysql
@@ -0,0 +1 @@
+ALTER TABLE Tickets Modify Status varchar(64);
diff --git a/rt/etc/upgrade/3.9.7/content b/rt/etc/upgrade/3.9.7/content
new file mode 100644
index 000000000..504ddf18f
--- /dev/null
+++ b/rt/etc/upgrade/3.9.7/content
@@ -0,0 +1,82 @@
+my $move_attributes = sub {
+ my ($table, $type, $column) = @_;
+ my $query = "UPDATE $table SET $column = (SELECT Content FROM Attributes WHERE"
+ ." Name = ? AND ObjectType = ? AND $table.id = Attributes.ObjectId)";
+
+ my $res = $RT::Handle->SimpleQuery( $query, $column, $type );
+ unless ( $res ) {
+ $RT::Logger->error("Failed to move $column on $type from Attributes into $table table");
+ return;
+ }
+
+ $query = 'DELETE FROM Attributes WHERE Name = ? AND ObjectType = ?';
+ $res = $RT::Handle->SimpleQuery( $query, $column, $type );
+ unless ( $res ) {
+ $RT::Logger->error("Failed to delete $column on $type from Attributes");
+ return;
+ }
+ return 1;
+};
+
+@Initial = (
+ sub {
+ return $move_attributes->( 'Users', 'RT::User', 'AuthToken');
+ },
+ sub {
+ return $move_attributes->( 'CustomFields', 'RT::CustomField', 'RenderType');
+ },
+ sub {
+ my $cfs = RT::CustomFields->new($RT::SystemUser);
+ $cfs->UnLimit;
+ $cfs->FindAllRows;
+ while ( my $cf = $cfs->Next ) {
+ # Explicitly remove 'ORDER BY id asc' to emulate the
+ # previous functionality, where Pg might return the the
+ # rows in arbitrary order
+ $cf->Attributes->OrderByCols();
+
+ my $attr = $cf->FirstAttribute('BasedOn');
+ next unless $attr;
+ $cf->SetBasedOn($attr->Content);
+ }
+ $query = 'DELETE FROM Attributes WHERE Name = ? AND ObjectType = ?';
+ $res = $RT::Handle->SimpleQuery( $query, 'BasedOn', 'RT::CustomField' );
+ unless ( $res ) {
+ $RT::Logger->error("Failed to delete BasedOn CustomFields from Attributes");
+ return;
+ }
+ return 1;
+ },
+ sub {
+ $move_attributes->( 'CustomFields', 'RT::CustomField', 'ValuesClass')
+ or return;
+
+ my $query = "UPDATE CustomFields SET ValuesClass = NULL WHERE ValuesClass = ?";
+ my $res = $RT::Handle->SimpleQuery( $query, 'RT::CustomFieldValues' );
+ unless ( $res ) {
+ $RT::Logger->error("Failed to replace default with NULLs");
+ return;
+ }
+ return 1;
+ },
+ sub {
+ my $attr = RT->System->FirstAttribute('BrandedSubjectTag');
+ return 1 unless $attr;
+
+ my $map = $attr->Content || {};
+ while ( my ($qid, $tag) = each %$map ) {
+ my $queue = RT::Queue->new( RT->SystemUser );
+ $queue->Load( $qid );
+ unless ( $queue->id ) {
+ $RT::Logger->warning("Couldn't load queue #$qid. Skipping...");
+ next;
+ }
+
+ my ($status, $msg) = $queue->SetSubjectTag($tag);
+ unless ( $status ) {
+ $RT::Logger->error("Couldn't set subject tag for queue #$qid: $msg");
+ next;
+ }
+ }
+ },
+);
diff --git a/rt/etc/upgrade/3.9.7/schema.Oracle b/rt/etc/upgrade/3.9.7/schema.Oracle
new file mode 100644
index 000000000..3c75c917d
--- /dev/null
+++ b/rt/etc/upgrade/3.9.7/schema.Oracle
@@ -0,0 +1,6 @@
+ALTER TABLE Users ADD AuthToken VARCHAR2(16) NULL;
+ALTER TABLE CustomFields ADD BasedOn NUMBER(11,0) NULL;
+ALTER TABLE CustomFields ADD RenderType VARCHAR2(64) NULL;
+ALTER TABLE CustomFields ADD ValuesClass VARCHAR2(64) NULL;
+ALTER TABLE Queues ADD SubjectTag VARCHAR2(120) NULL;
+ALTER TABLE Queues ADD Lifecycle VARCHAR2(32) NULL;
diff --git a/rt/etc/upgrade/3.9.7/schema.Pg b/rt/etc/upgrade/3.9.7/schema.Pg
new file mode 100644
index 000000000..1704fa673
--- /dev/null
+++ b/rt/etc/upgrade/3.9.7/schema.Pg
@@ -0,0 +1,6 @@
+ALTER TABLE Users ADD COLUMN AuthToken VARCHAR(16) NULL;
+ALTER TABLE CustomFields ADD COLUMN BasedOn INTEGER NULL;
+ALTER TABLE CustomFields ADD COLUMN RenderType VARCHAR(64) NULL;
+ALTER TABLE CustomFields ADD COLUMN ValuesClass VARCHAR(64) NULL;
+ALTER TABLE Queues ADD COLUMN SubjectTag VARCHAR(120) NULL;
+ALTER TABLE Queues ADD COLUMN Lifecycle VARCHAR(32) NULL;
diff --git a/rt/etc/upgrade/3.9.7/schema.SQLite b/rt/etc/upgrade/3.9.7/schema.SQLite
new file mode 100644
index 000000000..1704fa673
--- /dev/null
+++ b/rt/etc/upgrade/3.9.7/schema.SQLite
@@ -0,0 +1,6 @@
+ALTER TABLE Users ADD COLUMN AuthToken VARCHAR(16) NULL;
+ALTER TABLE CustomFields ADD COLUMN BasedOn INTEGER NULL;
+ALTER TABLE CustomFields ADD COLUMN RenderType VARCHAR(64) NULL;
+ALTER TABLE CustomFields ADD COLUMN ValuesClass VARCHAR(64) NULL;
+ALTER TABLE Queues ADD COLUMN SubjectTag VARCHAR(120) NULL;
+ALTER TABLE Queues ADD COLUMN Lifecycle VARCHAR(32) NULL;
diff --git a/rt/etc/upgrade/3.9.7/schema.mysql b/rt/etc/upgrade/3.9.7/schema.mysql
new file mode 100644
index 000000000..1be165647
--- /dev/null
+++ b/rt/etc/upgrade/3.9.7/schema.mysql
@@ -0,0 +1,6 @@
+ALTER TABLE Users ADD COLUMN AuthToken VARCHAR(16) CHARACTER SET ascii NULL;
+ALTER TABLE CustomFields ADD COLUMN BasedOn INTEGER NULL;
+ALTER TABLE CustomFields ADD COLUMN RenderType VARCHAR(64) NULL;
+ALTER TABLE CustomFields ADD COLUMN ValuesClass VARCHAR(64) CHARACTER SET ascii NULL;
+ALTER TABLE Queues ADD COLUMN SubjectTag VARCHAR(120) NULL;
+ALTER TABLE Queues ADD COLUMN Lifecycle VARCHAR(32) NULL;
diff --git a/rt/etc/upgrade/3.9.8/content b/rt/etc/upgrade/3.9.8/content
new file mode 100644
index 000000000..d759db9cd
--- /dev/null
+++ b/rt/etc/upgrade/3.9.8/content
@@ -0,0 +1,24 @@
+@Initial = sub {
+ my $dbh = $RT::Handle->dbh;
+ my $sth = $dbh->table_info( '', undef, undef, "'TABLE'");
+ my $found_fm_tables = {};
+ while ( my $table = $sth->fetchrow_hashref ) {
+ my $name = $table->{TABLE_NAME} || $table->{table_name};
+ next unless $name =~ /^fm_/i;
+ $found_fm_tables->{lc $name}++;
+ }
+
+ return unless %$found_fm_tables;
+
+ unless ( $found_fm_tables->{fm_topics} && $found_fm_tables->{fm_objecttopics} ) {
+ $RT::Logger->error("You appear to be upgrading from RTFM 2.0 - We don't support upgrading this old of an RTFM yet");
+ }
+
+ $RT::Logger->error("We found RTFM tables in your database. Checking for content.");
+
+ my $result = $dbh->selectall_arrayref("SELECT count(*) AS articlecount FROM FM_Articles", { Slice => {} } );
+
+ if ($result->[0]{articlecount} > 0) {
+ $RT::Logger->error("You appear to have RTFM Articles. You can upgrade using the etc/upgrade/upgrade-articles script. Read more about it in UPGRADING");
+ }
+};
diff --git a/rt/etc/upgrade/3.9.8/schema.Oracle b/rt/etc/upgrade/3.9.8/schema.Oracle
new file mode 100644
index 000000000..4f823731f
--- /dev/null
+++ b/rt/etc/upgrade/3.9.8/schema.Oracle
@@ -0,0 +1,65 @@
+CREATE SEQUENCE Classes_seq;
+CREATE TABLE Classes (
+id NUMBER(11,0)
+ CONSTRAINT Classes_key PRIMARY KEY,
+Name varchar2(255) DEFAULT '',
+Description varchar2(255) DEFAULT '',
+SortOrder NUMBER(11,0) DEFAULT 0 NOT NULL,
+Disabled NUMBER(11,0) DEFAULT 0 NOT NULL,
+Creator NUMBER(11,0) DEFAULT 0 NOT NULL,
+Created DATE,
+LastUpdatedBy NUMBER(11,0) DEFAULT 0 NOT NULL,
+LastUpdated DATE,
+HotList NUMBER(11,0) DEFAULT 0 NOT NULL
+);
+
+CREATE SEQUENCE Articles_seq;
+CREATE TABLE Articles (
+id NUMBER(11,0)
+ CONSTRAINT Articles_key PRIMARY KEY,
+Name varchar2(255) DEFAULT '',
+Summary varchar2(255) DEFAULT '',
+SortOrder NUMBER(11,0) DEFAULT 0 NOT NULL,
+Class NUMBER(11,0) DEFAULT 0 NOT NULL,
+Parent NUMBER(11,0) DEFAULT 0 NOT NULL,
+URI varchar2(255),
+Creator NUMBER(11,0) DEFAULT 0 NOT NULL,
+Created DATE,
+LastUpdatedBy NUMBER(11,0) DEFAULT 0 NOT NULL,
+LastUpdated DATE
+);
+
+
+CREATE SEQUENCE Topics_seq;
+CREATE TABLE Topics (
+id NUMBER(11,0)
+ CONSTRAINT Topics_key PRIMARY KEY,
+Parent NUMBER(11,0) DEFAULT 0 NOT NULL,
+Name varchar2(255) DEFAULT '',
+Description varchar2(255) DEFAULT '',
+ObjectType varchar2(64) DEFAULT '' NOT NULL,
+ObjectId NUMBER(11,0) NOT NULL
+);
+
+
+CREATE SEQUENCE ObjectTopics_seq;
+CREATE TABLE ObjectTopics (
+id NUMBER(11,0)
+ CONSTRAINT ObjectTopics_key PRIMARY KEY,
+Topic NUMBER(11,0) NOT NULL,
+ObjectType varchar2(64) DEFAULT '' NOT NULL,
+ObjectId NUMBER(11,0) NOT NULL
+);
+
+CREATE SEQUENCE ObjectClasses_seq;
+CREATE TABLE ObjectClasses (
+id NUMBER(11,0)
+ CONSTRAINT ObjectClasses_key PRIMARY KEY,
+Class NUMBER(11,0) NOT NULL,
+ObjectType varchar2(255) DEFAULT '' NOT NULL,
+ObjectId NUMBER(11,0) NOT NULL,
+Creator NUMBER(11,0) DEFAULT 0 NOT NULL,
+Created DATE,
+LastUpdatedBy NUMBER(11,0) DEFAULT 0 NOT NULL,
+LastUpdated DATE
+);
diff --git a/rt/etc/upgrade/3.9.8/schema.Pg b/rt/etc/upgrade/3.9.8/schema.Pg
new file mode 100644
index 000000000..d12e27a73
--- /dev/null
+++ b/rt/etc/upgrade/3.9.8/schema.Pg
@@ -0,0 +1,62 @@
+CREATE TABLE Classes (
+id SERIAL,
+Name varchar(255) NOT NULL DEFAULT '',
+Description varchar(255) NOT NULL DEFAULT '',
+SortOrder integer NOT NULL DEFAULT 0,
+Disabled smallint NOT NULL DEFAULT 0,
+Creator integer NOT NULL DEFAULT 0,
+Created TIMESTAMP NULL,
+LastUpdatedBy integer NOT NULL DEFAULT 0,
+LastUpdated TIMESTAMP NULL,
+HotList smallint NOT NULL DEFAULT 0,
+PRIMARY KEY (id)
+);
+
+CREATE TABLE Articles (
+id SERIAL,
+Name varchar(255) NOT NULL DEFAULT '',
+Summary varchar(255) NOT NULL DEFAULT '',
+SortOrder integer NOT NULL DEFAULT 0,
+Class integer NOT NULL DEFAULT 0,
+Parent integer NOT NULL DEFAULT 0,
+URI varchar(255),
+Creator integer NOT NULL DEFAULT 0,
+Created TIMESTAMP NULL,
+LastUpdatedBy integer NOT NULL DEFAULT 0,
+LastUpdated TIMESTAMP NULL,
+PRIMARY KEY (id)
+);
+
+
+CREATE TABLE Topics (
+id SERIAL,
+Parent integer NOT NULL DEFAULT 0,
+Name varchar(255) NOT NULL DEFAULT '',
+Description varchar(255) NOT NULL DEFAULT '',
+ObjectType varchar(64) NOT NULL DEFAULT '',
+ObjectId integer NOT NULL,
+PRIMARY KEY (id)
+);
+
+
+CREATE TABLE ObjectTopics (
+id SERIAL,
+Topic integer NOT NULL,
+ObjectType varchar(64) NOT NULL DEFAULT '',
+ObjectId integer NOT NULL,
+PRIMARY KEY (id)
+);
+
+
+CREATE TABLE ObjectClasses (
+id SERIAL,
+Class integer NOT NULL,
+ObjectType varchar(255) NOT NULL DEFAULT '',
+ObjectId integer NOT NULL,
+Creator integer NOT NULL DEFAULT 0,
+Created TIMESTAMP NULL,
+LastUpdatedBy integer NOT NULL DEFAULT 0,
+LastUpdated TIMESTAMP NULL,
+PRIMARY KEY (id)
+);
+
diff --git a/rt/etc/upgrade/3.9.8/schema.SQLite b/rt/etc/upgrade/3.9.8/schema.SQLite
new file mode 100644
index 000000000..29ed7e87a
--- /dev/null
+++ b/rt/etc/upgrade/3.9.8/schema.SQLite
@@ -0,0 +1,55 @@
+CREATE TABLE Classes (
+id INTEGER PRIMARY KEY,
+Name varchar(255) NOT NULL DEFAULT '',
+Description varchar(255) NOT NULL DEFAULT '',
+SortOrder integer NOT NULL DEFAULT 0,
+Disabled smallint NOT NULL DEFAULT 0,
+Creator integer NOT NULL DEFAULT 0,
+Created TIMESTAMP NULL,
+LastUpdatedBy integer NOT NULL DEFAULT 0,
+LastUpdated TIMESTAMP NULL,
+HotList smallint NOT NULL DEFAULT 0
+);
+
+CREATE TABLE Articles (
+id INTEGER PRIMARY KEY,
+Name varchar(255) NOT NULL DEFAULT '',
+Summary varchar(255) NOT NULL DEFAULT '',
+SortOrder integer NOT NULL DEFAULT 0,
+Class integer NOT NULL DEFAULT 0,
+Parent integer NOT NULL DEFAULT 0,
+URI varchar(255),
+Creator integer NOT NULL DEFAULT 0,
+Created TIMESTAMP NULL,
+LastUpdatedBy integer NOT NULL DEFAULT 0,
+LastUpdated TIMESTAMP NULL
+);
+
+
+CREATE TABLE Topics (
+id INTEGER PRIMARY KEY,
+Parent integer NOT NULL DEFAULT 0,
+Name varchar(255) NOT NULL DEFAULT '',
+Description varchar(255) NOT NULL DEFAULT '',
+ObjectType varchar(64) NOT NULL DEFAULT '',
+ObjectId integer NOT NULL
+);
+
+
+CREATE TABLE ObjectTopics (
+id INTEGER PRIMARY KEY,
+Topic integer NOT NULL,
+ObjectType varchar(64) NOT NULL DEFAULT '',
+ObjectId integer NOT NULL
+);
+
+CREATE TABLE ObjectClasses (
+id INTEGER PRIMARY KEY,
+Class integer NOT NULL,
+ObjectType varchar(64) NOT NULL DEFAULT '',
+ObjectId integer NOT NULL,
+Creator integer NOT NULL DEFAULT 0,
+Created TIMESTAMP NULL,
+LastUpdatedBy integer NOT NULL DEFAULT 0,
+LastUpdated TIMESTAMP NULL
+);
diff --git a/rt/etc/upgrade/3.9.8/schema.mysql b/rt/etc/upgrade/3.9.8/schema.mysql
new file mode 100644
index 000000000..e7ed84de7
--- /dev/null
+++ b/rt/etc/upgrade/3.9.8/schema.mysql
@@ -0,0 +1,58 @@
+CREATE TABLE Classes (
+ id int(11) NOT NULL auto_increment,
+ Name varchar(255) NOT NULL default '',
+ Description varchar(255) NOT NULL default '',
+ SortOrder int(11) NOT NULL default '0',
+ Disabled int(2) NOT NULL default '0',
+ Creator int(11) NOT NULL default '0',
+ Created datetime default NULL,
+ LastUpdatedBy int(11) NOT NULL default '0',
+ LastUpdated datetime default NULL,
+ HotList int(2) NOT NULL default '0',
+ PRIMARY KEY (id)
+) ENGINE=InnoDB DEFAULT CHARSET=utf8;
+
+CREATE TABLE Articles (
+ id int(11) NOT NULL auto_increment,
+ Name varchar(255) NOT NULL default '',
+ Summary varchar(255) NOT NULL default '',
+ SortOrder int(11) NOT NULL default '0',
+ Class int(11) NOT NULL default '0',
+ Parent int(11) NOT NULL default '0',
+ URI varchar(255) character set ascii default NULL,
+ Creator int(11) NOT NULL default '0',
+ Created datetime default NULL,
+ LastUpdatedBy int(11) NOT NULL default '0',
+ LastUpdated datetime default NULL,
+ PRIMARY KEY (id)
+) ENGINE=InnoDB DEFAULT CHARSET=utf8;
+
+CREATE TABLE Topics (
+ id int(11) NOT NULL auto_increment,
+ Parent int(11) NOT NULL default '0',
+ Name varchar(255) NOT NULL default '',
+ Description varchar(255) NOT NULL default '',
+ ObjectType varchar(64) character set ascii NOT NULL default '',
+ ObjectId int(11) NOT NULL default '0',
+ PRIMARY KEY (id)
+) ENGINE=InnoDB DEFAULT CHARSET=utf8;
+
+CREATE TABLE ObjectTopics (
+ id int(11) NOT NULL auto_increment,
+ Topic int(11) NOT NULL default '0',
+ ObjectType varchar(64) character set ascii NOT NULL default '',
+ ObjectId int(11) NOT NULL default '0',
+ PRIMARY KEY (id)
+) ENGINE=InnoDB DEFAULT CHARSET=utf8;
+
+CREATE TABLE ObjectClasses (
+ id int(11) NOT NULL auto_increment,
+ Class int(11) NOT NULL default '0',
+ ObjectType varchar(255) character set ascii NOT NULL default '',
+ ObjectId int(11) NOT NULL default '0',
+ Creator int(11) NOT NULL default '0',
+ Created datetime default NULL,
+ LastUpdatedBy int(11) NOT NULL default '0',
+ LastUpdated datetime default NULL,
+ PRIMARY KEY (id)
+) ENGINE=InnoDB DEFAULT CHARSET=utf8;
diff --git a/rt/etc/upgrade/4.0.0rc2/schema.mysql b/rt/etc/upgrade/4.0.0rc2/schema.mysql
new file mode 100644
index 000000000..9431213ec
--- /dev/null
+++ b/rt/etc/upgrade/4.0.0rc2/schema.mysql
@@ -0,0 +1,10 @@
+
+DROP TABLE IF EXISTS sessions;
+
+CREATE TABLE sessions (
+ id char(32) NOT NULL,
+ a_session LONGBLOB,
+ LastUpdated TIMESTAMP,
+ PRIMARY KEY (id)
+) ENGINE=InnoDB CHARACTER SET ascii;
+
diff --git a/rt/etc/upgrade/4.0.0rc4/schema.Oracle b/rt/etc/upgrade/4.0.0rc4/schema.Oracle
new file mode 100644
index 000000000..0df9d65c2
--- /dev/null
+++ b/rt/etc/upgrade/4.0.0rc4/schema.Oracle
@@ -0,0 +1 @@
+ALTER TABLE Users MODIFY Password VARCHAR2(256);
diff --git a/rt/etc/upgrade/4.0.0rc4/schema.Pg b/rt/etc/upgrade/4.0.0rc4/schema.Pg
new file mode 100644
index 000000000..728081041
--- /dev/null
+++ b/rt/etc/upgrade/4.0.0rc4/schema.Pg
@@ -0,0 +1 @@
+ALTER TABLE Users ALTER Password TYPE varchar(256);
diff --git a/rt/etc/upgrade/4.0.0rc4/schema.mysql b/rt/etc/upgrade/4.0.0rc4/schema.mysql
new file mode 100644
index 000000000..2f562bd4d
--- /dev/null
+++ b/rt/etc/upgrade/4.0.0rc4/schema.mysql
@@ -0,0 +1 @@
+ALTER TABLE Users MODIFY Password varchar(256);
diff --git a/rt/etc/upgrade/4.0.0rc7/content b/rt/etc/upgrade/4.0.0rc7/content
new file mode 100644
index 000000000..d0d210b7b
--- /dev/null
+++ b/rt/etc/upgrade/4.0.0rc7/content
@@ -0,0 +1,21 @@
+@Initial = (
+ sub {
+ $RT::Logger->debug("Going to set lifecycle for approvals");
+
+ my $queue = RT::Queue->new( RT->SystemUser );
+ $queue->Load('___Approvals');
+ unless ( $queue->id ) {
+ $RT::Logger->warning("There is no ___Approvals queue in the DB");
+ return 1;
+ }
+
+ return 1 if $queue->Lifecycle->Name eq 'approvals';
+
+ my ($status, $msg) = $queue->SetLifecycle('approvals');
+ unless ( $status ) {
+ $RT::Logger->error("Couldn't set lifecycle for '___Approvals' queue: $msg");
+ return 0;
+ }
+ return 1;
+ },
+);
diff --git a/rt/etc/upgrade/4.0.1/acl.Pg b/rt/etc/upgrade/4.0.1/acl.Pg
new file mode 100644
index 000000000..6b0e7bb3d
--- /dev/null
+++ b/rt/etc/upgrade/4.0.1/acl.Pg
@@ -0,0 +1,39 @@
+
+sub acl {
+ my $dbh = shift;
+
+ my @acls;
+
+ my @tables = qw (
+ classes_id_seq
+ Classes
+ articles_id_seq
+ Articles
+ topics_id_seq
+ Topics
+ objecttopics_id_seq
+ ObjectTopics
+ objectclasses_id_seq
+ ObjectClasses
+ );
+
+ my $db_user = RT->Config->Get('DatabaseUser');
+
+ my $sequence_right
+ = ( $dbh->{pg_server_version} >= 80200 )
+ ? "USAGE, SELECT, UPDATE"
+ : "SELECT, UPDATE";
+
+ foreach my $table (@tables) {
+ # Tables are upper-case, sequences are lowercase
+ if ( $table =~ /^[a-z]/ ) {
+ push @acls, "GRANT $sequence_right ON $table TO \"$db_user\";"
+ }
+ else {
+ push @acls, "GRANT SELECT, INSERT, UPDATE, DELETE ON $table TO \"$db_user\";"
+ }
+ }
+ return (@acls);
+}
+
+1;
diff --git a/rt/etc/upgrade/4.0.1/content b/rt/etc/upgrade/4.0.1/content
new file mode 100644
index 000000000..9b74ff1a8
--- /dev/null
+++ b/rt/etc/upgrade/4.0.1/content
@@ -0,0 +1,83 @@
+@Initial = (
+ sub {
+ use strict;
+ $RT::Logger->debug('Removing all delegated rights');
+
+ my $acl = RT::ACL->new(RT->SystemUser);
+ my $groupjoin = $acl->NewAlias('Groups');
+ $acl->Join( ALIAS1 => 'main',
+ FIELD1 => 'PrincipalId',
+ ALIAS2 => $groupjoin,
+ FIELD2 => 'id'
+ );
+ $acl->Limit( ALIAS => $groupjoin,
+ FIELD => 'Domain',
+ OPERATOR => '=',
+ VALUE => 'Personal',
+ );
+
+ while ( my $ace = $acl->Next ) {
+ my ( $ok, $msg ) = $ace->Delete();
+
+ if ( !$ok ) {
+ $RT::Logger->warn( "Unable to delete ACE " . $ace->id . ": " . $msg );
+ }
+ }
+
+ my $groups = RT::Groups->new(RT->SystemUser);
+ $groups->Limit( FIELD => 'Domain',
+ OPERATOR => '=',
+ VALUE => 'Personal'
+ );
+ while ( my $group = $groups->Next ) {
+ my $members = $group->MembersObj();
+ while ( my $member = $members->Next ) {
+ my ( $ok, $msg ) = $group->DeleteMember( $member->MemberId );
+ if ( !$ok ) {
+ $RT::Logger->warn( "Unable to remove group member "
+ . $member->id . ": "
+ . $msg );
+ }
+ }
+ $group->PrincipalObj->Delete;
+ $group->RT::Record::Delete();
+ }
+ },
+ sub {
+ use strict;
+ $RT::Logger->debug('Removing all Delegate and PersonalGroup rights');
+
+ my $acl = RT::ACL->new(RT->SystemUser);
+ for my $right (qw/AdminOwnPersonalGroups AdminAllPersonalGroups DelegateRights/) {
+ $acl->Limit( FIELD => 'RightName', VALUE => $right );
+ }
+
+ while ( my $ace = $acl->Next ) {
+ my ( $ok, $msg ) = $ace->Delete();
+ $RT::Logger->debug("Removing ACE ".$ace->id." for right ".$ace->__Value('RightName'));
+
+ if ( !$ok ) {
+ $RT::Logger->warn( "Unable to delete ACE " . $ace->id . ": " . $msg );
+ }
+ }
+ },
+ sub {
+ use strict;
+ $RT::Logger->debug('Removing unimplemented RejectTicket and ModifyTicketStatus rights');
+
+ my $acl = RT::ACL->new(RT->SystemUser);
+ for my $right (qw/RejectTicket ModifyTicketStatus/) {
+ $acl->Limit( FIELD => 'RightName', VALUE => $right );
+ }
+
+ while ( my $ace = $acl->Next ) {
+ my ( $ok, $msg ) = $ace->Delete();
+ $RT::Logger->debug("Removing ACE ".$ace->id." for right ".$ace->__Value('RightName'));
+
+ if ( !$ok ) {
+ $RT::Logger->warn( "Unable to delete ACE " . $ace->id . ": " . $msg );
+ }
+ }
+ },
+);
+
diff --git a/rt/etc/upgrade/4.0.3/content b/rt/etc/upgrade/4.0.3/content
new file mode 100644
index 000000000..3e06c89d0
--- /dev/null
+++ b/rt/etc/upgrade/4.0.3/content
@@ -0,0 +1,23 @@
+@ScripConditions = (
+ {
+
+ Name => 'On Forward', # loc
+ Description => 'Whenever a ticket or transaction is forwarded', # loc
+ ApplicableTransTypes => 'Forward Transaction,Forward Ticket',
+ ExecModule => 'AnyTransaction', },
+
+ {
+
+ Name => 'On Forward Ticket', # loc
+ Description => 'Whenever a ticket is forwarded', # loc
+ ApplicableTransTypes => 'Forward Ticket',
+ ExecModule => 'AnyTransaction', },
+
+ {
+
+ Name => 'On Forward Transaction', # loc
+ Description => 'Whenever a transaction is forwarded', # loc
+ ApplicableTransTypes => 'Forward Transaction',
+ ExecModule => 'AnyTransaction', },
+
+);
diff --git a/rt/etc/upgrade/4.0.4/content b/rt/etc/upgrade/4.0.4/content
new file mode 100644
index 000000000..fdfcb3e27
--- /dev/null
+++ b/rt/etc/upgrade/4.0.4/content
@@ -0,0 +1,16 @@
+@Initial = (
+ sub {
+ use strict;
+ my $templates = RT::Templates->new(RT->SystemUser);
+ $templates->Limit(
+ FIELD => 'Type',
+ OPERATOR => 'IS',
+ VALUE => 'NULL',
+ );
+ while (my $template = $templates->Next) {
+ my ($status, $msg) = $template->SetType('Perl');
+ $RT::Logger->warning( "Couldn't change Type of Template #" . $template->Id . ": $msg" ) unless $status;
+ }
+ },
+);
+
diff --git a/rt/etc/upgrade/sanity-check-stylesheets.pl b/rt/etc/upgrade/sanity-check-stylesheets.pl
new file mode 100644
index 000000000..eff469fd6
--- /dev/null
+++ b/rt/etc/upgrade/sanity-check-stylesheets.pl
@@ -0,0 +1,87 @@
+# BEGIN BPS TAGGED BLOCK {{{
+#
+# COPYRIGHT:
+#
+# This software is Copyright (c) 1996-2012 Best Practical Solutions, LLC
+# <sales@bestpractical.com>
+#
+# (Except where explicitly superseded by other copyright notices)
+#
+#
+# LICENSE:
+#
+# This work is made available to you under the terms of Version 2 of
+# the GNU General Public License. A copy of that license should have
+# been provided with this software, but in any event can be snarfed
+# from www.gnu.org.
+#
+# This work is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+# 02110-1301 or visit their web page on the internet at
+# http://www.gnu.org/licenses/old-licenses/gpl-2.0.html.
+#
+#
+# CONTRIBUTION SUBMISSION POLICY:
+#
+# (The following paragraph is not intended to limit the rights granted
+# to you to modify and distribute this software under the terms of
+# the GNU General Public License and is only of importance to you if
+# you choose to contribute your changes and enhancements to the
+# community by submitting them to Best Practical Solutions, LLC.)
+#
+# By intentionally submitting any modifications, corrections or
+# derivatives to this work, or any other work intended for use with
+# Request Tracker, to Best Practical Solutions, LLC, you confirm that
+# you are the copyright holder for those contributions and you grant
+# Best Practical Solutions, LLC a nonexclusive, worldwide, irrevocable,
+# royalty-free, perpetual, license to use, copy, create derivative
+# works based on those contributions, and sublicense and distribute
+# those contributions and any derivatives thereof.
+#
+# END BPS TAGGED BLOCK }}}
+use strict;
+use warnings;
+
+use RT;
+RT::LoadConfig();
+RT->Config->Set('LogToScreen' => 'debug');
+RT::Init();
+
+$| = 1;
+
+use RT::Users;
+my $users = RT::Users->new( $RT::SystemUser );
+$users->UnLimit();
+
+my @comp_roots = RT::Interface::Web->ComponentRoots;
+my %comp_root_check_cache;
+sub stylesheet_exists {
+ my $stylesheet = shift;
+
+ return $comp_root_check_cache{$stylesheet}
+ if exists $comp_root_check_cache{$stylesheet};
+
+ for my $comp_root (@comp_roots) {
+ return ++$comp_root_check_cache{$stylesheet}
+ if -d "$comp_root/NoAuth/css/$stylesheet";
+ }
+
+ return $comp_root_check_cache{$stylesheet} = 0;
+}
+
+my $system_stylesheet = RT->Config->Get('WebDefaultStylesheet');
+
+while (my $u = $users->Next) {
+ my $stylesheet = RT->Config->Get('WebDefaultStylesheet', $u);
+ unless (stylesheet_exists $stylesheet) {
+ my $prefs = $u->Preferences($RT::System);
+ $prefs->{WebDefaultStylesheet} = $system_stylesheet;
+ $u->SetPreferences($RT::System, $prefs);
+ }
+}
diff --git a/rt/etc/upgrade/upgrade-articles b/rt/etc/upgrade/upgrade-articles
new file mode 100755
index 000000000..eef00aa67
--- /dev/null
+++ b/rt/etc/upgrade/upgrade-articles
@@ -0,0 +1,264 @@
+#!/usr/bin/perl
+# BEGIN BPS TAGGED BLOCK {{{
+#
+# COPYRIGHT:
+#
+# This software is Copyright (c) 1996-2012 Best Practical Solutions, LLC
+# <sales@bestpractical.com>
+#
+# (Except where explicitly superseded by other copyright notices)
+#
+#
+# LICENSE:
+#
+# This work is made available to you under the terms of Version 2 of
+# the GNU General Public License. A copy of that license should have
+# been provided with this software, but in any event can be snarfed
+# from www.gnu.org.
+#
+# This work is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+# 02110-1301 or visit their web page on the internet at
+# http://www.gnu.org/licenses/old-licenses/gpl-2.0.html.
+#
+#
+# CONTRIBUTION SUBMISSION POLICY:
+#
+# (The following paragraph is not intended to limit the rights granted
+# to you to modify and distribute this software under the terms of
+# the GNU General Public License and is only of importance to you if
+# you choose to contribute your changes and enhancements to the
+# community by submitting them to Best Practical Solutions, LLC.)
+#
+# By intentionally submitting any modifications, corrections or
+# derivatives to this work, or any other work intended for use with
+# Request Tracker, to Best Practical Solutions, LLC, you confirm that
+# you are the copyright holder for those contributions and you grant
+# Best Practical Solutions, LLC a nonexclusive, worldwide, irrevocable,
+# royalty-free, perpetual, license to use, copy, create derivative
+# works based on those contributions, and sublicense and distribute
+# those contributions and any derivatives thereof.
+#
+# END BPS TAGGED BLOCK }}}
+use strict;
+use warnings;
+
+use lib "/opt/rt3/local/lib";
+use lib "/opt/rt3/lib";
+
+use RT;
+RT::LoadConfig();
+RT->Config->Set('LogToScreen' => 'debug');
+RT::Init();
+
+$| = 1;
+
+my $db_name = RT->Config->Get('DatabaseName');
+my $db_type = RT->Config->Get('DatabaseType');
+
+my $dbh = $RT::Handle->dbh;
+
+my $sth = $dbh->table_info( '', undef, undef, "'TABLE'");
+my $found_fm_tables;
+while ( my $table = $sth->fetchrow_hashref ) {
+ my $name = $table->{TABLE_NAME} || $table->{'table_name'}; # Oracle's table_info affected by NAME_lc
+ next unless $name =~ /^fm_/i;
+ $found_fm_tables->{lc $name}++;
+}
+
+unless ( $found_fm_tables->{fm_topics} && $found_fm_tables->{fm_objecttopics} ) {
+ warn "Couldn't find topics tables, it appears you have RTFM 2.0 or earlier.";
+ warn "This script cannot yet upgrade RTFM versions which are that old";
+ exit;
+}
+
+{ # port over Articles
+ my @columns = qw(id Name Summary SortOrder Class Parent URI Creator Created LastUpdatedBy LastUpdated);
+ copy_tables('FM_Articles','Articles',\@columns);
+
+}
+
+
+{ # port over Classes
+ my @columns = qw(id Name Description SortOrder Disabled Creator Created LastUpdatedBy LastUpdated);
+ if ( grep lc($_) eq 'hotlist', $RT::Handle->Fields('FM_Classes') ) {
+ push @columns, 'HotList';
+ }
+ copy_tables('FM_Classes','Classes',\@columns);
+}
+
+{ # port over Topics
+ my @columns = qw(id Parent Name Description ObjectType ObjectId);
+ copy_tables('FM_Topics','Topics',\@columns);
+}
+
+{ # port over ObjectTopics
+ my @columns = qw(id Topic ObjectType ObjectId);
+ copy_tables('FM_ObjectTopics','ObjectTopics',\@columns);
+}
+
+sub copy_tables {
+ my ($source, $dest, $columns) = @_;
+ my $column_list = join(', ',@$columns);
+ my $sql;
+ # SQLite: http://www.sqlite.org/lang_insert.html
+ if ( $db_type eq 'mysql' || $db_type eq 'SQLite' ) {
+ $sql = "insert into $dest ($column_list) select $column_list from $source";
+ }
+ # Oracle: http://www.adp-gmbh.ch/ora/sql/insert/select_and_subquery.html
+ elsif ( $db_type eq 'Pg' || $db_type eq 'Oracle' ) {
+ $sql = "insert into $dest ($column_list) (select $column_list from $source)";
+ }
+ $RT::Logger->debug($sql);
+ $dbh->do($sql);
+}
+
+{ # create ObjectClasses
+ # this logic will need updating when folks have an FM_ObjectClasses table
+ use RT::Classes;
+ use RT::ObjectClass;
+
+ my $classes = RT::Classes->new(RT->SystemUser);
+ $classes->UnLimit;
+ while ( my $class = $classes->Next ) {
+ my $objectclass = RT::ObjectClass->new(RT->SystemUser);
+ my ($ret, $msg ) = $objectclass->Create( Class => $class->Id, ObjectType => 'RT::System', ObjectId => 0 );
+ if ($ret) {
+ warn("Applied Class '".$class->Name."' globally");
+ } else {
+ warn("Couldn't create linkage for Class ".$class->Name.": $msg");
+ }
+ }
+}
+
+{ # update ACLs
+ use RT::ACL;
+ my $acl = RT::ACL->new(RT->SystemUser);
+ $acl->Limit( FIELD => 'ObjectType', VALUE => 'RT::FM::Class' );
+ $acl->Limit( FIELD => 'ObjectType', VALUE => 'RT::FM::System' );
+ while ( my $ace = $acl->Next ) {
+ if ( $ace->__Value('ObjectType') eq 'RT::FM::Class' ) {
+ my ($ret, $msg ) = $ace->__Set( Field => 'ObjectType', Value => 'RT::Class');
+ warn "Fixing ACL ".$ace->Id." to refer to RT::Class: $msg";
+ } elsif ( $ace->__Value('ObjectType') eq 'RT::FM::System' ) {
+ my ($ret, $msg) = $ace->__Set(Field => 'ObjectType', Value => 'RT::System');
+ warn "Fixing ACL ".$ace->Id." to refer to RT::System: $msg";
+ }
+ }
+
+
+}
+
+{ # update CustomFields
+ use RT::CustomFields;
+ my $cfs = RT::CustomFields->new(RT->SystemUser);
+ $cfs->Limit( FIELD => 'LookupType', VALUE => 'RT::FM::Class-RT::FM::Article' );
+ while ( my $cf = $cfs->Next ) {
+ my ($ret, $msg) = $cf->__Set( Field => 'LookupType', Value => 'RT::Class-RT::Article' );
+ warn "Update Custom Field LookupType for CF.".$cf->Id." $msg";
+ }
+}
+
+{ # update ObjectCustomFieldValues
+ use RT::ObjectCustomFieldValues;
+ my $ocfvs = RT::ObjectCustomFieldValues->new(RT->System);
+ $ocfvs->Limit( FIELD => 'ObjectType', VALUE => 'RT::FM::Article' );
+ while ( my $ocfv = $ocfvs->Next ) {
+ my ($ret, $msg) = $ocfv->__Set( Field => 'ObjectType', Value => 'RT::Article' );
+ warn "Updated CF ".$ocfv->__Value('CustomField')." Value for Article ".$ocfv->__Value('ObjectId');
+ }
+
+}
+
+{ # update Topics
+ use RT::Topics;
+ my $topics = RT::Topics->new(RT->SystemUser);
+ $topics->Limit( FIELD => 'ObjectType', VALUE => 'RT::FM::Class' );
+ $topics->Limit( FIELD => 'ObjectType', VALUE => 'RT::FM::System' );
+ while ( my $topic = $topics->Next ) {
+ if ( $topic->__Value('ObjectType') eq 'RT::FM::Class' ) {
+ my ($ret, $msg ) = $topic->__Set( Field => 'ObjectType', Value => 'RT::Class');
+ warn "Fixing Topic ".$topic->Id." to refer to RT::Class: $msg";
+ } elsif ( $topic->__Value('ObjectType') eq 'RT::FM::System' ) {
+ my ($ret, $msg) = $topic->__Set(Field => 'ObjectType', Value => 'RT::System');
+ warn "Fixing Topic ".$topic->Id." to refer to RT::System: $msg";
+ }
+ }
+}
+
+{ # update ObjectTopics
+ use RT::ObjectTopics;
+ my $otopics = RT::ObjectTopics->new(RT->SystemUser);
+ $otopics->UnLimit;
+ while ( my $otopic = $otopics->Next ) {
+ if ( $otopic->ObjectType eq 'RT::FM::Article' ) {
+ my ($ret, $msg) = $otopic->SetObjectType('RT::Article');
+ warn "Fixing Topic ".$otopic->Topic." to apply to article: $msg";
+ }
+ }
+}
+
+{ # update Links
+ use RT::Links;
+ my $links = RT::Links->new(RT->SystemUser);
+ $links->Limit(FIELD => 'Base', VALUE => 'rtfm', OPERATOR => 'LIKE', SUBCLAUSE => 'stopanding', ENTRYAGGREGATOR => 'OR');
+ $links->Limit(FIELD => 'Target', VALUE => 'rtfm', OPERATOR => 'LIKE', SUBCLAUSE => 'stopanding', ENTRYAGGREGATOR => 'OR' );
+ while ( my $link = $links->Next ) {
+ my $base = $link->__Value('Base');
+ my $target = $link->__Value('Target');
+ if ( $base =~ s/rtfm/article/i ) {
+ my ($ret, $msg) = $link->__Set( Field => 'Base', Value => $base );
+ warn "Updating base to $base: $msg for link ".$link->id;
+ }
+ if ( $target =~ s/rtfm/article/i ) {
+ my ($ret, $msg) = $link->__Set( Field => 'Target', Value => $target );
+ warn "Updating target to $target: $msg for link ".$link->id;
+ }
+
+ }
+}
+
+{ # update Transactions
+ # we only keep article transactions at this point
+ no warnings 'once';
+ use RT::Transactions;
+ # Next calls Type to check readability and Type calls _Accessible
+ # which called CurrentUserCanSee which calls Object which tries to instantiate
+ # an RT::FM::Article. Rather than a shim RT::FM::Article class, I'm just avoiding
+ # the ACL check since we're running around as the superuser.
+ local *RT::Transaction::Type = sub { shift->__Value('Type') };
+ my $transactions = RT::Transactions->new(RT->SystemUser);
+ $transactions->Limit( FIELD => 'ObjectType', VALUE => 'RT::FM::Article' );
+ while ( my $t = $transactions->Next ) {
+ my ($ret, $msg) = $t->__Set( Field => 'ObjectType', Value => 'RT::Article' );
+ warn "Updated Transaction ".$t->Id." to point to RT::Article";
+ }
+
+ # we also need to change links that point to articles
+ $transactions = RT::Transactions->new(RT->SystemUser);
+ $transactions->Limit( FIELD => 'Type', VALUE => 'AddLink' );
+ $transactions->Limit( FIELD => 'NewValue', VALUE => 'rtfm', OPERATOR => 'LIKE' );
+ while ( my $t = $transactions->Next ) {
+ my $value = $t->__Value('NewValue');
+ $value =~ s/rtfm/article/;
+ my ($ret, $msg) = $t->__Set( Field => 'NewValue', Value => $value );
+ warn "Updated Transaction ".$t->Id." to link to $value";
+ }
+}
+
+{ # update Attributes
+ # these are all things we should make real columns someday
+ use RT::Attributes;
+ my $attributes = RT::Attributes->new(RT->SystemUser);
+ $attributes->Limit( FIELD => 'ObjectType', VALUE => 'RT::FM::Class' );
+ while ( my $a = $attributes->Next ) {
+ my ($ret,$msg) = $a->__Set( Field => 'ObjectType', Value => 'RT::Class' );
+ warn "Updating Attribute ".$a->Name." to point to RT::Class";
+ }
+}
diff --git a/rt/etc/upgrade/upgrade-articles.in b/rt/etc/upgrade/upgrade-articles.in
new file mode 100644
index 000000000..b0f13d674
--- /dev/null
+++ b/rt/etc/upgrade/upgrade-articles.in
@@ -0,0 +1,264 @@
+#!@PERL@
+# BEGIN BPS TAGGED BLOCK {{{
+#
+# COPYRIGHT:
+#
+# This software is Copyright (c) 1996-2012 Best Practical Solutions, LLC
+# <sales@bestpractical.com>
+#
+# (Except where explicitly superseded by other copyright notices)
+#
+#
+# LICENSE:
+#
+# This work is made available to you under the terms of Version 2 of
+# the GNU General Public License. A copy of that license should have
+# been provided with this software, but in any event can be snarfed
+# from www.gnu.org.
+#
+# This work is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+# 02110-1301 or visit their web page on the internet at
+# http://www.gnu.org/licenses/old-licenses/gpl-2.0.html.
+#
+#
+# CONTRIBUTION SUBMISSION POLICY:
+#
+# (The following paragraph is not intended to limit the rights granted
+# to you to modify and distribute this software under the terms of
+# the GNU General Public License and is only of importance to you if
+# you choose to contribute your changes and enhancements to the
+# community by submitting them to Best Practical Solutions, LLC.)
+#
+# By intentionally submitting any modifications, corrections or
+# derivatives to this work, or any other work intended for use with
+# Request Tracker, to Best Practical Solutions, LLC, you confirm that
+# you are the copyright holder for those contributions and you grant
+# Best Practical Solutions, LLC a nonexclusive, worldwide, irrevocable,
+# royalty-free, perpetual, license to use, copy, create derivative
+# works based on those contributions, and sublicense and distribute
+# those contributions and any derivatives thereof.
+#
+# END BPS TAGGED BLOCK }}}
+use strict;
+use warnings;
+
+use lib "@LOCAL_LIB_PATH@";
+use lib "@RT_LIB_PATH@";
+
+use RT;
+RT::LoadConfig();
+RT->Config->Set('LogToScreen' => 'debug');
+RT::Init();
+
+$| = 1;
+
+my $db_name = RT->Config->Get('DatabaseName');
+my $db_type = RT->Config->Get('DatabaseType');
+
+my $dbh = $RT::Handle->dbh;
+
+my $sth = $dbh->table_info( '', undef, undef, "'TABLE'");
+my $found_fm_tables;
+while ( my $table = $sth->fetchrow_hashref ) {
+ my $name = $table->{TABLE_NAME} || $table->{'table_name'}; # Oracle's table_info affected by NAME_lc
+ next unless $name =~ /^fm_/i;
+ $found_fm_tables->{lc $name}++;
+}
+
+unless ( $found_fm_tables->{fm_topics} && $found_fm_tables->{fm_objecttopics} ) {
+ warn "Couldn't find topics tables, it appears you have RTFM 2.0 or earlier.";
+ warn "This script cannot yet upgrade RTFM versions which are that old";
+ exit;
+}
+
+{ # port over Articles
+ my @columns = qw(id Name Summary SortOrder Class Parent URI Creator Created LastUpdatedBy LastUpdated);
+ copy_tables('FM_Articles','Articles',\@columns);
+
+}
+
+
+{ # port over Classes
+ my @columns = qw(id Name Description SortOrder Disabled Creator Created LastUpdatedBy LastUpdated);
+ if ( grep lc($_) eq 'hotlist', $RT::Handle->Fields('FM_Classes') ) {
+ push @columns, 'HotList';
+ }
+ copy_tables('FM_Classes','Classes',\@columns);
+}
+
+{ # port over Topics
+ my @columns = qw(id Parent Name Description ObjectType ObjectId);
+ copy_tables('FM_Topics','Topics',\@columns);
+}
+
+{ # port over ObjectTopics
+ my @columns = qw(id Topic ObjectType ObjectId);
+ copy_tables('FM_ObjectTopics','ObjectTopics',\@columns);
+}
+
+sub copy_tables {
+ my ($source, $dest, $columns) = @_;
+ my $column_list = join(', ',@$columns);
+ my $sql;
+ # SQLite: http://www.sqlite.org/lang_insert.html
+ if ( $db_type eq 'mysql' || $db_type eq 'SQLite' ) {
+ $sql = "insert into $dest ($column_list) select $column_list from $source";
+ }
+ # Oracle: http://www.adp-gmbh.ch/ora/sql/insert/select_and_subquery.html
+ elsif ( $db_type eq 'Pg' || $db_type eq 'Oracle' ) {
+ $sql = "insert into $dest ($column_list) (select $column_list from $source)";
+ }
+ $RT::Logger->debug($sql);
+ $dbh->do($sql);
+}
+
+{ # create ObjectClasses
+ # this logic will need updating when folks have an FM_ObjectClasses table
+ use RT::Classes;
+ use RT::ObjectClass;
+
+ my $classes = RT::Classes->new(RT->SystemUser);
+ $classes->UnLimit;
+ while ( my $class = $classes->Next ) {
+ my $objectclass = RT::ObjectClass->new(RT->SystemUser);
+ my ($ret, $msg ) = $objectclass->Create( Class => $class->Id, ObjectType => 'RT::System', ObjectId => 0 );
+ if ($ret) {
+ warn("Applied Class '".$class->Name."' globally");
+ } else {
+ warn("Couldn't create linkage for Class ".$class->Name.": $msg");
+ }
+ }
+}
+
+{ # update ACLs
+ use RT::ACL;
+ my $acl = RT::ACL->new(RT->SystemUser);
+ $acl->Limit( FIELD => 'ObjectType', VALUE => 'RT::FM::Class' );
+ $acl->Limit( FIELD => 'ObjectType', VALUE => 'RT::FM::System' );
+ while ( my $ace = $acl->Next ) {
+ if ( $ace->__Value('ObjectType') eq 'RT::FM::Class' ) {
+ my ($ret, $msg ) = $ace->__Set( Field => 'ObjectType', Value => 'RT::Class');
+ warn "Fixing ACL ".$ace->Id." to refer to RT::Class: $msg";
+ } elsif ( $ace->__Value('ObjectType') eq 'RT::FM::System' ) {
+ my ($ret, $msg) = $ace->__Set(Field => 'ObjectType', Value => 'RT::System');
+ warn "Fixing ACL ".$ace->Id." to refer to RT::System: $msg";
+ }
+ }
+
+
+}
+
+{ # update CustomFields
+ use RT::CustomFields;
+ my $cfs = RT::CustomFields->new(RT->SystemUser);
+ $cfs->Limit( FIELD => 'LookupType', VALUE => 'RT::FM::Class-RT::FM::Article' );
+ while ( my $cf = $cfs->Next ) {
+ my ($ret, $msg) = $cf->__Set( Field => 'LookupType', Value => 'RT::Class-RT::Article' );
+ warn "Update Custom Field LookupType for CF.".$cf->Id." $msg";
+ }
+}
+
+{ # update ObjectCustomFieldValues
+ use RT::ObjectCustomFieldValues;
+ my $ocfvs = RT::ObjectCustomFieldValues->new(RT->System);
+ $ocfvs->Limit( FIELD => 'ObjectType', VALUE => 'RT::FM::Article' );
+ while ( my $ocfv = $ocfvs->Next ) {
+ my ($ret, $msg) = $ocfv->__Set( Field => 'ObjectType', Value => 'RT::Article' );
+ warn "Updated CF ".$ocfv->__Value('CustomField')." Value for Article ".$ocfv->__Value('ObjectId');
+ }
+
+}
+
+{ # update Topics
+ use RT::Topics;
+ my $topics = RT::Topics->new(RT->SystemUser);
+ $topics->Limit( FIELD => 'ObjectType', VALUE => 'RT::FM::Class' );
+ $topics->Limit( FIELD => 'ObjectType', VALUE => 'RT::FM::System' );
+ while ( my $topic = $topics->Next ) {
+ if ( $topic->__Value('ObjectType') eq 'RT::FM::Class' ) {
+ my ($ret, $msg ) = $topic->__Set( Field => 'ObjectType', Value => 'RT::Class');
+ warn "Fixing Topic ".$topic->Id." to refer to RT::Class: $msg";
+ } elsif ( $topic->__Value('ObjectType') eq 'RT::FM::System' ) {
+ my ($ret, $msg) = $topic->__Set(Field => 'ObjectType', Value => 'RT::System');
+ warn "Fixing Topic ".$topic->Id." to refer to RT::System: $msg";
+ }
+ }
+}
+
+{ # update ObjectTopics
+ use RT::ObjectTopics;
+ my $otopics = RT::ObjectTopics->new(RT->SystemUser);
+ $otopics->UnLimit;
+ while ( my $otopic = $otopics->Next ) {
+ if ( $otopic->ObjectType eq 'RT::FM::Article' ) {
+ my ($ret, $msg) = $otopic->SetObjectType('RT::Article');
+ warn "Fixing Topic ".$otopic->Topic." to apply to article: $msg";
+ }
+ }
+}
+
+{ # update Links
+ use RT::Links;
+ my $links = RT::Links->new(RT->SystemUser);
+ $links->Limit(FIELD => 'Base', VALUE => 'rtfm', OPERATOR => 'LIKE', SUBCLAUSE => 'stopanding', ENTRYAGGREGATOR => 'OR');
+ $links->Limit(FIELD => 'Target', VALUE => 'rtfm', OPERATOR => 'LIKE', SUBCLAUSE => 'stopanding', ENTRYAGGREGATOR => 'OR' );
+ while ( my $link = $links->Next ) {
+ my $base = $link->__Value('Base');
+ my $target = $link->__Value('Target');
+ if ( $base =~ s/rtfm/article/i ) {
+ my ($ret, $msg) = $link->__Set( Field => 'Base', Value => $base );
+ warn "Updating base to $base: $msg for link ".$link->id;
+ }
+ if ( $target =~ s/rtfm/article/i ) {
+ my ($ret, $msg) = $link->__Set( Field => 'Target', Value => $target );
+ warn "Updating target to $target: $msg for link ".$link->id;
+ }
+
+ }
+}
+
+{ # update Transactions
+ # we only keep article transactions at this point
+ no warnings 'once';
+ use RT::Transactions;
+ # Next calls Type to check readability and Type calls _Accessible
+ # which called CurrentUserCanSee which calls Object which tries to instantiate
+ # an RT::FM::Article. Rather than a shim RT::FM::Article class, I'm just avoiding
+ # the ACL check since we're running around as the superuser.
+ local *RT::Transaction::Type = sub { shift->__Value('Type') };
+ my $transactions = RT::Transactions->new(RT->SystemUser);
+ $transactions->Limit( FIELD => 'ObjectType', VALUE => 'RT::FM::Article' );
+ while ( my $t = $transactions->Next ) {
+ my ($ret, $msg) = $t->__Set( Field => 'ObjectType', Value => 'RT::Article' );
+ warn "Updated Transaction ".$t->Id." to point to RT::Article";
+ }
+
+ # we also need to change links that point to articles
+ $transactions = RT::Transactions->new(RT->SystemUser);
+ $transactions->Limit( FIELD => 'Type', VALUE => 'AddLink' );
+ $transactions->Limit( FIELD => 'NewValue', VALUE => 'rtfm', OPERATOR => 'LIKE' );
+ while ( my $t = $transactions->Next ) {
+ my $value = $t->__Value('NewValue');
+ $value =~ s/rtfm/article/;
+ my ($ret, $msg) = $t->__Set( Field => 'NewValue', Value => $value );
+ warn "Updated Transaction ".$t->Id." to link to $value";
+ }
+}
+
+{ # update Attributes
+ # these are all things we should make real columns someday
+ use RT::Attributes;
+ my $attributes = RT::Attributes->new(RT->SystemUser);
+ $attributes->Limit( FIELD => 'ObjectType', VALUE => 'RT::FM::Class' );
+ while ( my $a = $attributes->Next ) {
+ my ($ret,$msg) = $a->__Set( Field => 'ObjectType', Value => 'RT::Class' );
+ warn "Updating Attribute ".$a->Name." to point to RT::Class";
+ }
+}