diff --git a/docs/changelog/7.x.x.txt b/docs/changelog/7.x.x.txt index ecf1432e6..972c0d1a8 100644 --- a/docs/changelog/7.x.x.txt +++ b/docs/changelog/7.x.x.txt @@ -25,6 +25,7 @@ - fixed #10925: Wrong message in i18n - relabel Help in the Admin Console to Template Help - fixed #10928: EMS Print Ticket -- Time not processed for timezone + - added Subscribable AssetAspect to Wiki 7.7.19 - fixed #10838: Forwarded forum post email to new CS adds reply to original thread diff --git a/docs/upgrades/packages-7.8.0/default-wiki-front-page.wgpkg b/docs/upgrades/packages-7.8.0/default-wiki-front-page.wgpkg new file mode 100644 index 000000000..b868f20c4 Binary files /dev/null and b/docs/upgrades/packages-7.8.0/default-wiki-front-page.wgpkg differ diff --git a/docs/upgrades/packages-7.8.0/default-wiki-page.wgpkg b/docs/upgrades/packages-7.8.0/default-wiki-page.wgpkg new file mode 100644 index 000000000..e449eced7 Binary files /dev/null and b/docs/upgrades/packages-7.8.0/default-wiki-page.wgpkg differ diff --git a/docs/upgrades/packages-7.8.0/home_untitled_default-asset-subscription.wgpkg b/docs/upgrades/packages-7.8.0/home_untitled_default-asset-subscription.wgpkg new file mode 100644 index 000000000..555bd2860 Binary files /dev/null and b/docs/upgrades/packages-7.8.0/home_untitled_default-asset-subscription.wgpkg differ diff --git a/docs/upgrades/upgrade_7.7.19-7.8.0.pl b/docs/upgrades/upgrade_7.7.19-7.8.0.pl index 37d6204b4..c7c757ade 100644 --- a/docs/upgrades/upgrade_7.7.19-7.8.0.pl +++ b/docs/upgrades/upgrade_7.7.19-7.8.0.pl @@ -33,6 +33,7 @@ my $session = start(); # this line required # upgrade functions go here reorganizeAdSpaceProperties($session); fixTemplateSettingsFromShunt($session); +addSubscribableAspect( $session ); finish($session); # this line required @@ -46,6 +47,26 @@ finish($session); # this line required # print "DONE!\n" unless $quiet; #} +#---------------------------------------------------------------------------- +# Add tables for the subscribable aspect +sub addSubscribableAspect { + my $session = shift; + print "\tAdding Subscribable aspect..." unless $quiet; + + $session->db->write( <<'ESQL' ); +CREATE TABLE assetAspect_Subscribable ( + assetId CHAR(22) BINARY NOT NULL, + revisionDate BIGINT NOT NULL, + subscriptionGroupId CHAR(22) BINARY, + subscriptionTemplateId CHAR(22) BINARY, + skipNotification INT, + PRIMARY KEY ( assetId, revisionDate ) +) +ESQL + + print "DONE!\n" unless $quiet; +} + #---------------------------------------------------------------------------- # Describe what our function does sub reorganizeAdSpaceProperties { diff --git a/lib/WebGUI/Asset/WikiPage.pm b/lib/WebGUI/Asset/WikiPage.pm index e5a423229..fce1f881b 100644 --- a/lib/WebGUI/Asset/WikiPage.pm +++ b/lib/WebGUI/Asset/WikiPage.pm @@ -12,7 +12,11 @@ package WebGUI::Asset::WikiPage; use strict; use Class::C3; -use base qw(WebGUI::AssetAspect::Comments WebGUI::Asset); +use base qw( + WebGUI::AssetAspect::Subscribable + WebGUI::AssetAspect::Comments + WebGUI::Asset +); use Tie::IxHash; use WebGUI::International; use WebGUI::Utility; @@ -236,6 +240,73 @@ sub getEditForm { #------------------------------------------------------------------- +=head2 getSubscriptionTemplate ( ) + +=cut + +sub getSubscriptionTemplate { + my ( $self ) = @_; + return $self->getParent->getSubscriptionTemplate; +} + +#------------------------------------------------------------------- + +=head2 getTemplateVars ( ) + +Get the common template vars for this asset + +=cut + +sub getTemplateVars { + my ( $self ) = @_; + my $i18n = WebGUI::International->new($self->session, "Asset_WikiPage"); + my $wiki = $self->getWiki; + my $owner = WebGUI::User->new( $self->session, $self->get('ownerUserId') ); + my $keywords = WebGUI::Keyword->new($self->session)->getKeywordsForAsset({ + asset => $self, + asArrayRef => 1, + }); + my @keywordsLoop = (); + foreach my $word (@{$keywords}) { + push @keywordsLoop, { + keyword => $word, + url => $wiki->getUrl("func=byKeyword;keyword=".$word), + }; + } + my $var = { + %{ $self->get }, + url => $self->getUrl, + keywordsLoop => \@keywordsLoop, + viewLabel => $i18n->get("viewLabel"), + editLabel => $i18n->get("editLabel"), + historyLabel => $i18n->get("historyLabel"), + wikiHomeLabel => $i18n->get("wikiHomeLabel", "Asset_WikiMaster"), + searchLabel => $i18n->get("searchLabel", "Asset_WikiMaster"), + searchUrl => $wiki->getUrl("func=search"), + recentChangesUrl => $wiki->getUrl("func=recentChanges"), + recentChangesLabel => $i18n->get("recentChangesLabel", "Asset_WikiMaster"), + mostPopularUrl => $wiki->getUrl("func=mostPopular"), + mostPopularLabel => $i18n->get("mostPopularLabel", "Asset_WikiMaster"), + wikiHomeUrl => $wiki->getUrl, + historyUrl => $self->getUrl("func=getHistory"), + editContent => $self->getEditForm, + allowsAttachments => $wiki->get("allowAttachments"), + comments => $self->getFormattedComments(), + canEdit => $self->canEdit, + content => $wiki->autolinkHtml( + $self->scrubContent, + {skipTitles => [$self->get('title')]}, + ), + isSubscribed => $self->isSubscribed, + subscribeUrl => $self->getSubscribeUrl, + unsubscribeUrl => $self->getUnsubscribeUrl, + owner => $owner->get('alias'), + }; + return $var; +} + +#------------------------------------------------------------------- + =head2 getWiki Returns an object referring to the wiki that contains this page. If it is not a WikiMaster, @@ -438,43 +509,7 @@ Renders this asset. sub view { my $self = shift; - my $i18n = WebGUI::International->new($self->session, "Asset_WikiPage"); - my $keywords = WebGUI::Keyword->new($self->session)->getKeywordsForAsset({ - asset=>$self, - asArrayRef=>1, - }); - my $wiki = $self->getWiki; - my @keywordsLoop = (); - foreach my $word (@{$keywords}) { - push(@keywordsLoop, { - keyword=>$word, - url=>$wiki->getUrl("func=byKeyword;keyword=".$word), - }); - } - my $var = { - keywordsLoop => \@keywordsLoop, - viewLabel => $i18n->get("viewLabel"), - editLabel => $i18n->get("editLabel"), - historyLabel => $i18n->get("historyLabel"), - wikiHomeLabel => $i18n->get("wikiHomeLabel", "Asset_WikiMaster"), - searchLabel => $i18n->get("searchLabel", "Asset_WikiMaster"), - searchUrl => $self->getParent->getUrl("func=search"), - recentChangesUrl => $self->getParent->getUrl("func=recentChanges"), - recentChangesLabel => $i18n->get("recentChangesLabel", "Asset_WikiMaster"), - mostPopularUrl => $self->getParent->getUrl("func=mostPopular"), - mostPopularLabel => $i18n->get("mostPopularLabel", "Asset_WikiMaster"), - wikiHomeUrl => $self->getParent->getUrl, - historyUrl => $self->getUrl("func=getHistory"), - editContent => $self->getEditForm, - allowsAttachments => $self->getWiki->get("allowAttachments"), - comments => $self->getFormattedComments(), - canEdit => $self->canEdit, - content => $self->getWiki->autolinkHtml( - $self->scrubContent, - {skipTitles => [$self->get('title')]}, - ), - }; - return $self->processTemplate($var, $self->getWiki->get("pageTemplateId")); + return $self->processTemplate($self->getTemplateVars, $self->getWiki->get("pageTemplateId")); } #------------------------------------------------------------------- diff --git a/lib/WebGUI/Asset/Wobject/WikiMaster.pm b/lib/WebGUI/Asset/Wobject/WikiMaster.pm index 6fb0b6385..fa4e9a409 100644 --- a/lib/WebGUI/Asset/Wobject/WikiMaster.pm +++ b/lib/WebGUI/Asset/Wobject/WikiMaster.pm @@ -11,7 +11,11 @@ package WebGUI::Asset::Wobject::WikiMaster; #------------------------------------------------------------------- use Class::C3; -use base qw(WebGUI::AssetAspect::RssFeed WebGUI::Asset::Wobject); +use base qw( + WebGUI::AssetAspect::Subscribable + WebGUI::AssetAspect::RssFeed + WebGUI::Asset::Wobject +); use strict; use Tie::IxHash; use WebGUI::International; @@ -444,6 +448,36 @@ sub getRssFeedItems { return $var; } +#---------------------------------------------------------------------------- + +=head2 getTemplateVars ( ) + +Get the common template variables for all views of the wiki. + +=cut + +sub getTemplateVars { + my ( $self ) = @_; + my $i18n = WebGUI::International->new($self->session, "Asset_WikiMaster"); + my $var = { %{$self->get}, + url => $self->getUrl, + searchLabel => $i18n->get("searchLabel"), + mostPopularUrl => $self->getUrl("func=mostPopular"), + mostPopularLabel => $i18n->get("mostPopularLabel"), + addPageLabel => $i18n->get("addPageLabel"), + addPageUrl => $self->getUrl("func=add;class=WebGUI::Asset::WikiPage"), + recentChangesUrl => $self->getUrl("func=recentChanges"), + recentChangesLabel => $i18n->get("recentChangesLabel"), + restoreLabel => $i18n->get("restoreLabel"), + canAdminister => $self->canAdminister, + isSubscribed => $self->isSubscribed, + subscribeUrl => $self->getSubscribeUrl, + unsubscribeUrl => $self->getUnsubscribeUrl, + }; + + return $var; +} + #------------------------------------------------------------------- =head2 prepareView @@ -492,6 +526,19 @@ sub processPropertiesFromFormPost { #------------------------------------------------------------------- +=head2 shouldSkipNotification ( ) + +WikiMasters do not send notification + +=cut + +sub shouldSkipNotification { + my ( $self ) = @_; + return 1; +} + +#------------------------------------------------------------------- + =head2 view Render the front page of the wiki. @@ -500,23 +547,13 @@ Render the front page of the wiki. sub view { my $self = shift; - my $i18n = WebGUI::International->new($self->session, "Asset_WikiMaster"); - my $var = { - description => $self->autolinkHtml($self->get('description')), - searchLabel=>$i18n->get("searchLabel"), - mostPopularUrl=>$self->getUrl("func=mostPopular"), - mostPopularLabel=>$i18n->get("mostPopularLabel"), - addPageLabel=>$i18n->get("addPageLabel"), - addPageUrl=>$self->getUrl("func=add;class=WebGUI::Asset::WikiPage"), - recentChangesUrl=>$self->getUrl("func=recentChanges"), - recentChangesLabel=>$i18n->get("recentChangesLabel"), - restoreLabel => $i18n->get("restoreLabel"), - canAdminister => $self->canAdminister, - keywordCloud => WebGUI::Keyword->new($self->session)->generateCloud({ - startAsset=>$self, - displayFunc=>"byKeyword", - }), - }; + my $var = $self->getTemplateVars; + $var->{ description } = $self->autolinkHtml( $var->{ description } ); + $var->{ keywordCloud } + = WebGUI::Keyword->new($self->session)->generateCloud({ + startAsset=>$self, + displayFunc=>"byKeyword", + }); my $template = $self->{_frontPageTemplate}; $self->appendSearchBoxVars($var); $self->appendRecentChanges($var, $self->get('recentChangesCountFront')); diff --git a/lib/WebGUI/AssetAspect/Subscribable.pm b/lib/WebGUI/AssetAspect/Subscribable.pm new file mode 100644 index 000000000..6e2026762 --- /dev/null +++ b/lib/WebGUI/AssetAspect/Subscribable.pm @@ -0,0 +1,514 @@ +package WebGUI::AssetAspect::Subscribable; + +use strict; +use Class::C3; + +=head1 NAME + +WebGUI::AssetAspect::Subscribable - Let users subscribe to your asset + +=head1 SYNOPSIS + + +=head1 DESCRIPTION + + +=head1 METHODS + +#---------------------------------------------------------------------------- + +=head2 definition ( session [, definition ] ) + +=cut + +sub definition { + my $class = shift; + my $session = shift; + my $definition = shift; + my $i18n = __PACKAGE__->i18n($session); + + tie my %properties, 'Tie::IxHash', ( + subscriptionGroupId => { + tab => "security", + fieldType => "subscriptionGroup", + label => $i18n->echo("Subscription Group"), + hoverHelp => $i18n->echo("The users who are subscribed to recieve e-mail alerts for this asset"), + defaultValue => undef, + noFormPost => 1, + }, + subscriptionTemplateId => { + tab => "display", + fieldType => "template", + namespace => $class->getSubscriptionTemplateNamespace, + label => $i18n->echo("Subscription Template"), + hoverHelp => $i18n->echo("The template to use to send out e-mail notifications"), + }, + skipNotification => { + autoGenerate => 0, + noFormPost => 1, + fieldType => 'yesNo', + }, + ); + + push @{ $definition }, { + autoGenerateForms => 1, + tableName => "assetAspect_Subscribable", + properties => \%properties, + }; + + return $class->maybe::next::method( $session, $definition ); +} + +#---------------------------------------------------------------------------- + +=head2 addRevision ( properties [, revisionDate, options ] ) + +Override addRevision to set skipNotification to 0 for each new revision. + +=cut + +sub addRevision { + my $self = shift; + my $properties = shift; + + $properties->{ skipNotification } = 0; + + return $self->maybe::next::method( $properties, @_ ); +} + +#---------------------------------------------------------------------------- + +=head2 canSubscribe ( [userId ] ) + +Returns true if the user is allowed to subscribe to this asset. C is +a userId to check, defaults to the current user. + +By default, Visitors are not allowed to subscribe. Anyone else who canView, +canSubscribe. + +=cut + +sub canSubscribe { + my $self = shift; + my $userId = shift || $self->session->user->userId; + + return 0 if $userId eq "1"; + return $self->canView( $userId ); +} + +#---------------------------------------------------------------------------- + +=head2 commit ( ) + +By default, send the notification out when the asset is committed. Override +this if you don't want this asset to send out notifications (but you still +want to be able to subscribe to children) + +=cut + +sub commit { + my ( $self, @args ) = @_; + $self->maybe::next::method( @args ); + if ( !$self->shouldSkipNotification ) { + $self->notifySubscribers; + } + return; +} + +#---------------------------------------------------------------------------- + +=head2 createSubscriptionGroup ( ) + +Create a group to hold subscribers to this asset, if there is not one already. + +=cut + +sub createSubscriptionGroup { + my $self = shift; + + if ( my $groupId = $self->get('subscriptionGroupId') ) { + return WebGUI::Group->new( $self->session, $groupId ); + } + else { + my $group = WebGUI::Group->new($self->session, "new"); + $group->name( "Subscription " . $self->getTitle ); + $group->description( "Subscription Group for " . $self->getTitle . "(" . $self->getId . ")" ); + $group->isEditable( 0 ); + $group->showInForms( 0 ); + $group->deleteGroups( [ "3" ] ); # admins don't want to be auto subscribed to this thing + $self->update({ + subscriptionGroupId => $group->getId + }); + + return $group; + } +} + +#---------------------------------------------------------------------------- + +=head2 DOES ( role ) + +Returns true if the asset does the specified role. This mixin does the +"Subscribable" role. + +=cut + +sub DOES { + my $self = shift; + my $role = shift; + + return 1 if ( lc $role eq "subscribable" ); + return $self->maybe::next::method( $role ); +} + +#---------------------------------------------------------------------------- + +=head2 getSubscriptionContent ( ) + +Get the content to send to subscribers. By default, will process the template +from C with the variables from C or +C. + +=cut + +sub getSubscriptionContent { + my $self = shift; + my $template = $self->getSubscriptionTemplate; + my $var; + if ( $self->can("getTemplateVars") ) { + # Rely on getTemplateVars sub judgement + $var = $self->getTemplateVars; + } + else { + # Try to make sense of the asset properties + $var = { + %{ $self->get }, + url => $self->session->url->getSiteURL . $self->getUrl, + } + } + + return $template->process( $var ); +} + +#---------------------------------------------------------------------------- + +=head2 getSubscriptionGroup ( ) + +Gets the WebGUI::Group for the subscribers group. + +=cut + +sub getSubscriptionGroup { + my $self = shift; + my $groupId = $self->get( "subscriptionGroupId" ); + my $group = $groupId ? WebGUI::Group->new( $self->session, $groupId ) : $self->createSubscriptionGroup; + return $group; +} + +#---------------------------------------------------------------------------- + +=head2 getSubscriptionTemplate ( ) + +Get a WebGUI::Asset::Template object for the subscription template. + +=cut + +sub getSubscriptionTemplate { + my $self = shift; + my $templateId = $self->get( "subscriptionTemplateId" ); + my $template = WebGUI::Asset::Template->new( $self->session, $templateId ); # This should throw if we don't + return $template; +} + +#---------------------------------------------------------------------------- + +=head2 getSubscriptionTemplateNamespace ( ) + +Get the namespace for the subscription template. + +=cut + +sub getSubscriptionTemplateNamespace { + return "AssetAspect/Subscribable"; +} + +#---------------------------------------------------------------------------- + +=head2 getSubscribeUrl ( ) + +Get the URL to subscribe to this asset. + +=cut + +sub getSubscribeUrl { + my $self = shift; + return $self->getUrl( 'func=subscribe' ); +} + +#---------------------------------------------------------------------------- + +=head2 getUnsubscribeUrl ( ) + +Get the URL to unsubscribe from this asset. + +=cut + +sub getUnsubscribeUrl { + my $self = shift; + return $self->getUrl( 'func=unsubscribe' ); +} + +#---------------------------------------------------------------------------- + +=head2 i18n ( ) + +Get the i18n for RSSCapable + +=cut + +sub i18n { + my $class = shift; + my $session = shift; + + return WebGUI::International->new( $session ); +} + +#---------------------------------------------------------------------------- + +=head2 isSubscribed ( [userId] ) + +Returns true if the user is subscribed to the asset. C is a userId to +check, defaults to the current user. + +=cut + +sub isSubscribed { + my $self = shift; + my $userId = shift; + my $user = $userId + ? WebGUI::User->new( $self->session, $userId ) + : $self->session->user + ; + my $group = $self->getSubscriptionGroup; + # TODO: Make WebGUI::Group throw error if group not found + if ( !$group ) { + return 0; + } + else { + return $user->isInGroup( $group->getId ); + } +} + +#---------------------------------------------------------------------------- + +=head2 _makeMessageId ( string ) + +Make the message ID following proper RFC2822. C is a unique identifier +for the message. + +=cut + +sub _makeMessageId { + my $self = shift; + my $string = shift; + my $domain = $self->session->config->get( "sitename" )->[ 0 ]; + return "wg-" . $string . "@" . $domain; +} + +#---------------------------------------------------------------------------- + +=head2 notifySubscribers ( [options] ) + +Notify all the subscribers of this asset. C is a hash reference of +options with the following keys: + + content -> Content to send to the subscribers. Defaults to getSubscriptionContent + subject -> E-mail subject. Defaults to the asset title. + from -> E-mail address this message is from. Defaults to the e-mail address of + the owner of this asset, or the Company E-Mail from settings + replyTo -> E-mail address to reply to. Defaults to the listAddress, the Mail + Return Path from settings, or the Company E-Mail from settings + inReplyTo -> Asset ID of the asset this subscription message is replying to + listAddress -> The address of the mailing list this is being sent from, if necessary + +=cut + +sub notifySubscribers { + my $self = shift; + my $opt = shift; + my $session = $self->session; + my $setting = $self->session->setting; + my $companyEmail = $setting->get( "companyEmail" ); + my $mailReturnPath = $setting->get( "mailReturnPath" ); + + $opt->{ subject } ||= $self->getTitle; + $opt->{ content } ||= $self->getSubscriptionContent; + WebGUI::Macro::process( $self->session, \$opt->{content} ); + + if ( !$opt->{ from } ) { + my $owner = WebGUI::User->new( $self->session, $self->get( "ownerUserId" ) ); + $opt->{ from } = $owner->profileField( "email" ) || $opt->{ listAddress } || $companyEmail; + } + + if ( !$opt->{ replyTo } ) { + $opt->{ replyTo } = $opt->{listAddress} || $mailReturnPath || $companyEmail; + } + + $opt->{ returnPath } = $mailReturnPath || $opt->{listAddress} || $companyEmail || $opt->{ from }; + + my $messageId = $self->_makeMessageId( $self->getId ); + + ### Get all the people we need to send to + # Any parent asset that does subscribable + # First asset in this list is the topmost parent, and is the list ID + my @assets = ( $self ); + my $parentAsset = $self->getParent; + while ( $parentAsset ) { + last if !$parentAsset->DOES( "subscribable" ); + unshift @assets, $parentAsset; + $parentAsset = $parentAsset->getParent; + } + + ### Prepare the actual sender address (the address of the process sending, + # not the address of the user who initiated the sending) + my $sender = $opt->{listAddress} || $companyEmail || $opt->{from}; + my $siteurl = $session->url->getSiteURL; + # XXX This doesnt seem right... + my $listId = $sender; + $listId =~ s/\@/\./; + + for my $asset ( @assets ) { + my $group = $asset->getSubscriptionGroup; + my $mail + = WebGUI::Mail::Send->create( $self->session, { + from => '<' . $opt->{ from } . '>', + returnPath => '<' . $opt->{ returnPath } . '>', + replyTo => '<' . $opt->{ replyTo } . '>', + toGroup => $group->getId, + subject => $opt->{ subject }, + messageId => '<' . $messageId . '>', + } ); + + # Add threading headers + if ( $opt->{ inReplyTo } ) { + $mail->addHeaderField( "In-Reply-To", '<' . $opt->{inReplyTo} . '>' ); + $mail->addHeaderField( "References", '<' . $opt->{inReplyTo} . '>' ); + } + + $mail->addHeaderField("List-ID", $assets[0]->getTitle." <".$listId.">"); + $mail->addHeaderField("List-Help", ", <".$setting->get("companyURL").">"); + $mail->addHeaderField("List-Owner", ", <".$setting->get("companyURL")."> (".$setting->get("companyName").")"); + $mail->addHeaderField("Sender", "<".$sender.">"); + $mail->addHeaderField("List-Unsubscribe", "<".$siteurl.$asset->getUnsubscribeUrl.">"); + $mail->addHeaderField("X-Unsubscribe-Web", "<".$siteurl.$asset->getUnsubscribeUrl.">"); + $mail->addHeaderField("List-Subscribe", "<".$siteurl.$asset->getSubscribeUrl.">"); + $mail->addHeaderField("X-Subscribe-Web", "<".$siteurl.$asset->getSubscribeUrl.">"); + $mail->addHeaderField("List-Archive", "<".$siteurl.$assets[0]->getUrl.">"); + $mail->addHeaderField("X-Archives", "<".$siteurl.$assets[0]->getUrl.">"); + if ( $opt->{listAddress} ) { + $mail->addHeaderField("List-Post", "{listAddress}.">"); + } + else { + $mail->addHeaderField("List-Post", "No"); + } + $mail->addHtml($opt->{content}); + $mail->addFooter; + $mail->queue; + } +} + +#---------------------------------------------------------------------------- + +=head2 setSkipNotification ( ) + +Set a flag so that this asset does not send out notifications for this +revision. + +=cut + +sub setSkipNotification { + my $self = shift; + my $value = shift; + $value = defined $value ? $value : 1; + + $self->update( { + skipNotification => $value, + } ); + + return; +} + +#---------------------------------------------------------------------------- + +=head2 shouldSkipNotification ( ) + +Returns true if the asset should skip notifications. + +=cut + +sub shouldSkipNotification { + my $self = shift; + return $self->get( "skipNotification" ) ? 1 : 0; +} + +#---------------------------------------------------------------------------- + +=head2 subscribe ( [userId] ) + +Subscribe a user to this asset. C is a userId to subscribe, defaults +to the current user. + +=cut + +sub subscribe { + my $self = shift; + my $userId = shift || $self->session->user->userId; + $self->getSubscriptionGroup->addUsers( [$userId] ); + return; +} + +#---------------------------------------------------------------------------- + +=head2 unsubscribe ( [userId] ) + +Unsubscribe a user from this asset. C is a userId to unsubscribe, +defaults to the current user. + +=cut + +sub unsubscribe { + my $self = shift; + my $userId = shift || $self->session->user->userId; + $self->getSubscriptionGroup->deleteUsers( [$userId] ); + return; +} + +#---------------------------------------------------------------------------- + +=head2 www_subscribe ( ) + +Subscribe the current user to this asset. + +=cut + +sub www_subscribe { + my $self = shift; + $self->subscribe if $self->canSubscribe; + return $self->www_view; +} + +#---------------------------------------------------------------------------- + +=head2 www_unsubscribe ( ) + +Unsubscribe the current user from this asset. + +=cut + +sub www_unsubscribe { + my $self = shift; + $self->unsubscribe; + return $self->www_view; +} + +1; # You can't handle the truth diff --git a/lib/WebGUI/Help/Asset_WikiMaster.pm b/lib/WebGUI/Help/Asset_WikiMaster.pm index 987a8b5b5..3c4d3d8ec 100644 --- a/lib/WebGUI/Help/Asset_WikiMaster.pm +++ b/lib/WebGUI/Help/Asset_WikiMaster.pm @@ -146,6 +146,18 @@ our $HELP = { { 'name' => 'useContentFilter', }, { 'name' => 'filterCode', }, { 'name' => 'maxImageSize', }, + { + name => 'isSubscribed', + description => 'help isSubscribed', + }, + { + name => 'subscribeUrl', + description => 'help subscribeUrl', + }, + { + name => 'unsubscribeUrl', + description => 'help unsubscribeUrl', + }, ], fields => [], related => [], diff --git a/lib/WebGUI/Help/Asset_WikiPage.pm b/lib/WebGUI/Help/Asset_WikiPage.pm index 3f81fe097..36354c338 100644 --- a/lib/WebGUI/Help/Asset_WikiPage.pm +++ b/lib/WebGUI/Help/Asset_WikiPage.pm @@ -76,6 +76,22 @@ our $HELP = { }, { 'name' => 'editContent', }, { 'name' => 'content', }, + { + name => 'isSubscribed', + description => 'help isSubscribed', + }, + { + name => 'subscribeUrl', + description => 'help subscribeUrl', + }, + { + name => 'unsubscribeUrl', + description => 'help unsubscribeUrl', + }, + { + name => 'owner', + description => 'help owner', + }, ], related => [], }, @@ -110,6 +126,17 @@ our $HELP = { related => [], }, + + 'subscription template' => { + title => 'help subscription title', + body => 'help subscription body', + isa => [ + { + tag => 'view template', + namespace => 'Asset_WikiPage', + }, + ], + }, }; 1; diff --git a/lib/WebGUI/i18n/English/AssetAspect_Subscribable.pm b/lib/WebGUI/i18n/English/AssetAspect_Subscribable.pm new file mode 100644 index 000000000..41ba60bfc --- /dev/null +++ b/lib/WebGUI/i18n/English/AssetAspect_Subscribable.pm @@ -0,0 +1,14 @@ +package WebGUI::i18n::English::AssetAspect_Subscribable; + +use strict; + +our $I18N = { + "new post" => { + message => 'has posted to one of your subscriptions', + lastUpdated => 0, + context => 'Title of the e-mail that is sent for subscriptions', + }, +}; + +1; +#vim:ft=perl diff --git a/lib/WebGUI/i18n/English/Asset_WikiMaster.pm b/lib/WebGUI/i18n/English/Asset_WikiMaster.pm index 121e21db9..8fca0288b 100644 --- a/lib/WebGUI/i18n/English/Asset_WikiMaster.pm +++ b/lib/WebGUI/i18n/English/Asset_WikiMaster.pm @@ -494,6 +494,35 @@ listing of pages that are related to a specific keyword?| }, lastUpdated => 1166848379, }, + 'help isSubscribed' => { + message => q{This variable is true if the user is subscribed to the entire wiki}, + lastUpdated => 0, + context => q{Help for template variable}, + }, + + 'help subscribeUrl' => { + message => q{The URL to subscribe to the entire wiki}, + lastUpdated => 0, + context => q{Help for template variable}, + }, + + 'help unsubscribeUrl' => { + message => q{The URL to unsubscribe from the entire wiki}, + lastUpdated => 0, + context => q{Help for template variable}, + }, + + 'subscribe' => { + message => q{Subscribe}, + lastUpdated => 0, + context => q{Label for link to subscribe to e-mail notifications}, + }, + + 'unsubscribe' => { + message => q{Unsubscribe}, + lastUpdated => 0, + context => q{Label for link to unsubscribe from e-mail notifications}, + }, }; 1; diff --git a/lib/WebGUI/i18n/English/Asset_WikiPage.pm b/lib/WebGUI/i18n/English/Asset_WikiPage.pm index 6949d85c8..bd13bddf4 100644 --- a/lib/WebGUI/i18n/English/Asset_WikiPage.pm +++ b/lib/WebGUI/i18n/English/Asset_WikiPage.pm @@ -268,6 +268,41 @@ our $I18N = lastUpdated => 1169141075, }, + 'help isSubscribed' => { + message => q{This variable is true if the user is subscribed to this wiki page}, + lastUpdated => 0, + context => q{Help for template variable}, + }, + + 'help subscribeUrl' => { + message => q{The URL to subscribe to this wiki page}, + lastUpdated => 0, + context => q{Help for template variable}, + }, + + 'help unsubscribeUrl' => { + message => q{The URL to unsubscribe from this wiki page}, + lastUpdated => 0, + context => q{Help for template variable}, + }, + + 'help owner' => { + message => q{The username of the owner of the page}, + lastUpdated => 0, + context => q{Help for template variable}, + }, + + 'help subscription title' => { + message => q{Wiki Page Subscription E-mail}, + lastUpdated => 0, + context => 'Title for help page', + }, + + 'help subscription body' => { + message => q{The template to send via e-mail to the people subscribed to the wiki}, + lastUpdated => 0, + context => 'Body text for help page', + }, }; 1; diff --git a/t/Asset/WikiPage/subscribable.t b/t/Asset/WikiPage/subscribable.t new file mode 100644 index 000000000..468a83cd8 --- /dev/null +++ b/t/Asset/WikiPage/subscribable.t @@ -0,0 +1,57 @@ +# vim:syntax=perl +#------------------------------------------------------------------- +# 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 +#------------------------------------------------------------------ + +# Test the subscribable features of the Wiki +# +# + +use FindBin; +use strict; +use lib "$FindBin::Bin/../../lib"; +use Test::More; +use WebGUI::Test; # Must use this before any other WebGUI modules +use WebGUI::Session; + +#---------------------------------------------------------------------------- +# Init +my $session = WebGUI::Test->session; +my $import = WebGUI::Asset->getImportNode( $session ); +my $wiki + = $import->addChild( { + className => 'WebGUI::Asset::Wobject::WikiMaster', + subscriptionTemplateId => 'limMkk80fMB3fqNZVf162w', + groupIdView => '7', # Everyone + } ); + +my $page + = $wiki->addChild( { + className => 'WebGUI::Asset::WikiPage', + }, undef, undef, { skipAutoCommitWorkflows => 1 } ); + +WebGUI::Test->tagsToRollback( WebGUI::VersionTag->getWorking( $session ) ); + +#---------------------------------------------------------------------------- +# Tests + +plan tests => 4; # Increment this number for each test you create + +#---------------------------------------------------------------------------- +# Test subscribable methods +ok( $page->DOES('subscribable'), 'WikiMaster is subscribable' ); + +ok( my $template = $page->getSubscriptionTemplate, 'getSubscriptionTemplate returns something' ); +isa_ok( $template, 'WebGUI::Asset::Template', 'getSubscriptionTemplate' ); +is( $template->getId, 'limMkk80fMB3fqNZVf162w', 'getSubscriptionTemplate gets wikimaster template' ); + +#---------------------------------------------------------------------------- +# Cleanup + +#vim:ft=perl diff --git a/t/Asset/Wobject/WikiMaster/subscribable.t b/t/Asset/Wobject/WikiMaster/subscribable.t new file mode 100644 index 000000000..2fbff29d7 --- /dev/null +++ b/t/Asset/Wobject/WikiMaster/subscribable.t @@ -0,0 +1,98 @@ +# vim:syntax=perl +#------------------------------------------------------------------- +# 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 +#------------------------------------------------------------------ + +# Test the subscribable features of the Wiki +# +# + +use FindBin; +use strict; +use lib "$FindBin::Bin/../../../lib"; +use Test::More; +use WebGUI::Test; # Must use this before any other WebGUI modules +use WebGUI::Session; + +#---------------------------------------------------------------------------- +# Init +my $session = WebGUI::Test->session; +my $import = WebGUI::Asset->getImportNode( $session ); +my $wiki + = $import->addChild( { + className => 'WebGUI::Asset::Wobject::WikiMaster', + subscriptionTemplateId => 'limMkk80fMB3fqNZVf162w', + groupIdView => '7', # Everyone + } ); + +WebGUI::Test->tagsToRollback( WebGUI::VersionTag->getWorking( $session ) ); + +#---------------------------------------------------------------------------- +# Tests + +plan tests => 17; # Increment this number for each test you create + +#---------------------------------------------------------------------------- +# Test subscribable methods +ok( $wiki->DOES('subscribable'), 'WikiMaster is subscribable' ); +ok( $wiki->shouldSkipNotification, "WikiMaster never notifies" ); + +ok( my $template = $wiki->getSubscriptionTemplate, 'getSubscriptionTemplate returns something' ); +isa_ok( $template, 'WebGUI::Asset::Template', 'getSubscriptionTemplate' ); + +is( $wiki->getSubscriptionTemplateNamespace, 'AssetAspect/Subscribable', 'getSubscriptionNamespace' ); + +ok( my $subgroup = $wiki->getSubscriptionGroup, 'getSubscriptionGroup returns something' ); +isa_ok( $subgroup, 'WebGUI::Group', 'getSubscriptionGroup' ); + +is( $wiki->getSubscribeUrl, $wiki->getUrl('func=subscribe'), 'getSubscribeUrl' ); +is( $wiki->getUnsubscribeUrl, $wiki->getUrl('func=unsubscribe'), 'getUnsubscribeUrl' ); + + +#---------------------------------------------------------------------------- +# canSubscribe permissions +$session->user({ userId => '1' }); +ok( !$wiki->canSubscribe, 'Visitor cannot subscribe' ); +ok( $wiki->canSubscribe( '3' ), 'Admin can subscribe' ); + +# subscribe +$wiki->subscribe('3'); +ok( + WebGUI::User->new( $session, '3' )->isInGroup( $wiki->getSubscriptionGroup->getId ), + 'subscribe' +); + +# isSubscribed +ok( $wiki->isSubscribed( '3' ), 'isSubscribed' ); + +# unsubscribe +$wiki->unsubscribe('3'); +ok( + !WebGUI::User->new( $session, '3' )->isInGroup( $wiki->getSubscriptionGroup->getId ), + 'unsubscribe' +); + + +#---------------------------------------------------------------------------- +# skip notification +ok( !$wiki->get('skipNotification'), 'skipNotification defaults to false' ); +$wiki->setSkipNotification(1); +ok( $wiki->get('skipNotification'), 'setSkipNotification sets skipNotification' ); + +# add revision +my $new_rev = $wiki->addRevision({},time+1); +ok( !$new_rev->get('skipNotification'), 'addRevision resets skipNotification to false' ); + +# notify subscribers +# subscription content + +#---------------------------------------------------------------------------- +# Cleanup + +#vim:ft=perl