diff --git a/docs/changelog/7.x.x.txt b/docs/changelog/7.x.x.txt index 2a1d087d0..c3f8f856a 100644 --- a/docs/changelog/7.x.x.txt +++ b/docs/changelog/7.x.x.txt @@ -1,6 +1,7 @@ 7.7.11 - Fixed a bug where empty version tags were not deleted. (Martin Kamerbeek / Oqapi) - fixed: deploying a package doesn't commit version tag with autocommit on + - fixed rfe #76: group delete causes problems 7.7.10 - Made a change to LDAP auth that adds an OR to that query so that it also searches for a row with fieldData REGEXP '^uid=(value-from-ldap-directory-server),'. (Wes Morgan) diff --git a/lib/WebGUI/Group.pm b/lib/WebGUI/Group.pm index ddc8a9137..1ef8b65a4 100644 --- a/lib/WebGUI/Group.pm +++ b/lib/WebGUI/Group.pm @@ -19,6 +19,8 @@ use Tie::CPHash; use WebGUI::LDAPLink; use WebGUI::Macro; use WebGUI::Utility; +use WebGUI::Pluggable; +use WebGUI::International; =head1 NAME @@ -261,12 +263,13 @@ Deletes this group from the group related tables in the database and calls clear =cut sub delete { - my $self = shift; - $self->clearCaches; - $self->session->db->write("delete from groups where groupId=?", [$self->getId]); - $self->session->db->write("delete from groupings where groupId=?", [$self->getId]); - $self->session->db->write("delete from groupGroupings where inGroup=? or groupId=?", [$self->getId, $self->getId]); - undef $self; + my $self = shift; + $self->resetGroupFields; + $self->clearCaches; + $self->session->db->write("delete from groups where groupId=?", [$self->getId]); + $self->session->db->write("delete from groupings where groupId=?", [$self->getId]); + $self->session->db->write("delete from groupGroupings where inGroup=? or groupId=?", [$self->getId, $self->getId]); + undef $self; } #------------------------------------------------------------------- @@ -1139,6 +1142,117 @@ sub new { } +#------------------------------------------------------------------- + +=head2 resetGroupFields ( ) + +Looks through WebGUI and resets any group field that it can find, that uses this group, +to the admin group, 3. Called internally by delete. + +Currently handes these areas: + +=over 4 + +=item * + +Anything in an Asset definition that is labeled as type group. JSON data is not handled. + +=item * + +Everything in Operation/Settings, from its definition subroutine. + +=item * + +Settings fields hand picked from Shop/Admin and Account/FriendManager. + +=item * + +Any Workflow Activity data from the definition that is labeled as type group. + +=back + +=cut + +sub resetGroupFields { + my $self = shift; + my $gid = $self->getId; + my $session = $self->session; + my $db = $session->db; + my $config = $session->config; + my $assets = $config->get('assets'); + my $tableCache = {}; + + ##Note, I did assets in SQL instead of using the API because you would have to + ##instanciate every version of the asset that used the group. This should be much quicker + ASSET: foreach my $asset (keys %{ $assets }) { + my $definition = WebGUI::Pluggable::instanciate($asset, 'definition', [$session]); + SUBDEF: foreach my $subdef (@{ $definition }) { + next SUBDEF if exists $tableCache->{$subdef->{tableName}}; + PROP: while (my ($fieldName, $properties) = each %{ $subdef->{properties} }) { + next PROP unless $properties->{fieldType} eq 'group'; + push @{ $tableCache->{$subdef->{tableName}} }, $fieldName; + } + } + } + ##VersionTags + $tableCache->{assetVersionTag} = ['groupToUse']; + $tableCache->{adSpace} = ['groupToPurchase']; + foreach my $tableName (keys %{ $tableCache }) { + foreach my $fieldName (@{ $tableCache->{$tableName} }) { + my $sql = sprintf 'UPDATE %s SET %s=3 where %s=?', + $db->dbh->quote_identifier($tableName), + (($db->dbh->quote_identifier($fieldName)) x 2); + $db->write($sql, [ $gid ]); + } + } + + SETTINGS: { + my $setting = $session->setting; + my $i18n = WebGUI::International->new($session); + my $definition = WebGUI::Pluggable::run('WebGUI::Operation::Settings', 'definition', [$session, $i18n]); + FIELD: foreach my $field (@{ $definition }) { + next FIELD unless $field->{fieldType} eq 'group' + and $setting->get($field->{name}) eq $gid; + $setting->set($field->{name}, 3); + } + } + ##Settings in the settings table not from Operation/Settings. These should all + ##be moved to definition style subroutines for future auto-probing. + AUX_SETTINGS: { + ##These are extra fields + my $setting = $session->setting; + my @extraFields = qw/groupIdCashier groupIdAdminCommerce/; ##Shop/Admin + push @extraFields, qw/groupIdAdminFriends groupsToManageFriends/; ##Account/FriendManager + FIELD: foreach my $field (@extraFields) { + next FIELD unless $setting->get($field) eq $gid; + $setting->set($field, 3); + } + } + ACTIVITY: { + my $workflowActivities = $config->get('workflowActivities'); + my @activities; + foreach my $wfActivities (values %{ $workflowActivities} ) { + push @activities, @{ $wfActivities }; + } + use Data::Dumper; + warn Dumper \@activities; + foreach my $activity (@activities) { + my $definition = WebGUI::Pluggable::instanciate($activity, 'definition', [$session]); + my $sth = $db->prepare('UPDATE WorkflowActivityData set value=3 where name=? and value=?'); + SUBDEF: foreach my $subdef (@{ $definition }) { + PROP: while (my ($fieldName, $properties) = each %{ $subdef->{properties} }) { + next PROP unless $properties->{fieldType} eq 'group'; + warn $fieldName; + warn $gid; + $sth->execute([$fieldName, $gid]); + } + } + } + } + ##Inbox messages, inbox table + return 1; +} + #------------------------------------------------------------------- =head2 scratchFilter ( [ value ] ) diff --git a/t/Group/resetGroupFields.t b/t/Group/resetGroupFields.t new file mode 100644 index 000000000..04611b665 --- /dev/null +++ b/t/Group/resetGroupFields.t @@ -0,0 +1,179 @@ +#------------------------------------------------------------------- +# WebGUI is Copyright 2001-2009 Plain Black Corporation. +#------------------------------------------------------------------- +# Please read the legal notices (docs/legal.txt) and the license +# (docs/license.txt) that came with this distribution before using +# this software. +#------------------------------------------------------------------- +# http://www.plainblack.com info@plainblack.com +#------------------------------------------------------------------- + +use FindBin; +use strict; +use lib "$FindBin::Bin/../lib"; + +use WebGUI::Test; +use WebGUI::Session; +use WebGUI::Asset; +use WebGUI::Group; + +use Test::More; +use Test::Deep; + +plan tests => 10; + +my $session = WebGUI::Test->session; + +my $assetGroup = WebGUI::Group->new($session, 'new'); +WebGUI::Test->groupsToDelete($assetGroup); + +my $settingGroup = WebGUI::Group->new($session, 'new'); +WebGUI::Test->groupsToDelete($settingGroup); + +my $activityGroup = WebGUI::Group->new($session, 'new'); +WebGUI::Test->groupsToDelete($activityGroup); + +my $home = WebGUI::Asset->getDefault($session); + +my $snippet1 = $home->addChild({ + className => 'WebGUI::Asset::Snippet', + groupIdEdit => $assetGroup->getId, + groupIdView => 7, + snippet => 'one', +}); + +my $snippet2 = $home->addChild({ + className => 'WebGUI::Asset::Snippet', + groupIdEdit => 7, + groupIdView => 7, + snippet => 'two', +}); + +my $snippet3 = $home->addChild({ + className => 'WebGUI::Asset::Snippet', + groupIdEdit => $assetGroup->getId, + groupIdView => $assetGroup->getId, + snippet => 'three', +}); + +my $gallery1 = $home->addChild({ + className => 'WebGUI::Asset::Wobject::Gallery', + groupIdView => 7, + groupIdEdit => $assetGroup->getId, + groupIdAddComment => $assetGroup->getId, +}); + +cmp_deeply( + $gallery1->get, + superhashof({ + groupIdEdit => $assetGroup->getId, + groupIdView => 7, + groupIdAddComment => $assetGroup->getId, + }), + 'gallery set up correctly' +); + +cmp_deeply( + $snippet1->get, + superhashof({ + groupIdEdit => $assetGroup->getId, + groupIdView => 7, + }), + 'groupIdEdit updated on test snippet' +); + +my $workflow = WebGUI::Workflow->create($session, + { + enabled => 1, + objectType => 'User', + mode => 'realtime', + }, +); + +WebGUI::Test->originalConfig('workflowActivities'); +$session->config->addToArray('workflowActivities/User', 'WebGUI::Workflow::Activity::AddUserToGroup'); + +my $userActivity = $workflow->addActivity('WebGUI::Workflow::Activity::AddUserToGroup'); +$userActivity->set('className', 'WebGUI::Workflow::Activity::AddUserToGroup'); +$userActivity->set('groupId', $activityGroup->getId); +is($userActivity->get('groupId'), $activityGroup->getId, 'group in Workflow Activity set to test group'); + +################################################################### +# +# Asset tests +# +################################################################### + +$assetGroup->delete; + +my $newSnippet1 = WebGUI::Asset->newByDynamicClass($session, $snippet1->getId); + +cmp_deeply( + $newSnippet1->get, + superhashof({ + groupIdEdit => 3, + groupIdView => 7, + }), + 'groupIdEdit updated on test snippet' +); + +my $newSnippet2 = WebGUI::Asset->newByDynamicClass($session, $snippet2->getId); + +cmp_deeply( + $newSnippet2->get, + superhashof({ + groupIdEdit => 7, + groupIdView => 7, + }), + 'other snippet not touched' +); + +my $newSnippet3 = WebGUI::Asset->newByDynamicClass($session, $snippet3->getId); + +cmp_deeply( + $newSnippet3->get, + superhashof({ + groupIdEdit => 3, + groupIdView => 3, + }), + 'multiple fields updated' +); + +my $newGallery1 = WebGUI::Asset->newByDynamicClass($session, $gallery1->getId); + +cmp_deeply( + $newGallery1->get, + superhashof({ + groupIdEdit => 3, + groupIdView => 7, + groupIdAddComment => 3, + }), + 'multiple fields and tables updated' +); + +################################################################### +# +# Setting tests +# +################################################################### + +$session->setting->set('groupIdAdminUser', $settingGroup->getId); + +is($session->setting->get('groupIdAdminUser'), $settingGroup->getId, 'group in Setting set up'); + +$settingGroup->delete; + +is($session->setting->get('groupIdAdminUser'), 3, 'group in Setting reset to Admin'); + +################################################################### +# +# Workflow Activity tests +# +################################################################### + +$activityGroup->delete; + +my $userActivity2 = WebGUI::Workflow::Activity->new($session, $userActivity->getId); +is ($userActivity2->get('groupId'), 3, 'group in Workflow Activity set to Admin'); + +WebGUI::Test->tagsToRollback(WebGUI::VersionTag->getWorking($session));