Added Newsletter Asset (Funded by United Knowledge)

This commit is contained in:
JT Smith 2007-06-16 19:33:12 +00:00
parent 245c7b947e
commit 9248570f79
16 changed files with 1295 additions and 149 deletions

View file

@ -35,7 +35,11 @@
- Added a simple Single Sign On mechanism.
- Added the SessionId macro.
- fix: Package deploy: hidden assets become visible (Yung Han Khoe, United Knowledge)
- RFE: Added Private Messaging to WebGUI (United Knowledge)
- Added Private Messaging (Funded by United Knowledge)
- Added Newsletter Asset (Funded by United Knowledge)
- Extended content profiling to CS Threads (Funded by United Knowledge)
- Added User Invitations (Funded by United Knowledge)
7.3.19
- Fixed a formatting problem in the workflow editor screen.

View file

@ -0,0 +1,90 @@
#PBtmpl0000000000000029
<a name="id<tmpl_var assetId>" id="id<tmpl_var assetId>"></a>
<tmpl_if preview.title>
<p><b><tmpl_var preview.title></b></p>
</tmpl_if>
<tmpl_if preview.content>
<p><tmpl_var preview.content></p>
</tmpl_if>
<h2><tmpl_var message.header.label></h2>
<tmpl_var form.header>
<table class="defaultPostForm">
<tmpl_if isNewPost>
<tmpl_if user.isVisitor>
<tr>
<td><tmpl_var visitorName.label></td>
<td><tmpl_var visitorName.form></td>
</tr>
</tmpl_if>
</tmpl_if>
<tr>
<td><tmpl_var subject.label></td>
<td><tmpl_var title.form></td>
</tr>
<tr>
<td><tmpl_var message.label></td>
<td><tmpl_var content.form></td>
</tr>
<tmpl_unless isReply>
<tmpl_loop meta_loop>
<tr>
<td><tmpl_var name></td>
<td><tmpl_var field></td>
</tr>
</tmpl_loop>
</tmpl_unless>
<tmpl_if attachment.form>
<tr>
<td><tmpl_var attachment.label></td>
<td><tmpl_var attachment.form></td>
</tr>
</tmpl_if>
<tmpl_if isNewPost>
<tmpl_unless user.isVisitor>
<tr>
<td><tmpl_var subscribe.label></td>
<td><tmpl_var subscribe.form></td>
</tr>
</tmpl_unless>
<tmpl_if isNewThread>
<tmpl_if user.isModerator>
<tr>
<td><tmpl_var lock.label></td>
<td><tmpl_var lock.form></td>
</tr>
<tr>
<td><tmpl_var stick.label></td>
<td><tmpl_var sticky.form></td>
</tr>
</tmpl_if>
</tmpl_if>
</tmpl_if>
<tr>
<td></td>
<td><tmpl_if usePreview><tmpl_var form.preview></tmpl_if><tmpl_var form.submit></td>
</tr>
</table>
<tmpl_var form.footer>
<tmpl_if isReply>
<p><b><tmpl_var reply.title></b></p>
<tmpl_var reply.content>
</tmpl_if>
~~~
<style type="text/css">
table.defaultPostForm td
{
font-family:arial;
font-size:9pt;
}
h2
{
font-family:arial;
}
</style>

View file

@ -0,0 +1,103 @@
#PBtmpl0000000000000068
<a name="id<tmpl_var assetId>" id="id<tmpl_var assetId>"></a>
<tmpl_if preview.title><p><b><tmpl_var preview.title></b></p></tmpl_if>
<tmpl_unless isReply><tmpl_if preview.synopsis><p><i><tmpl_var preview.synopsis></i></p></tmpl_if></tmpl_unless>
<tmpl_if preview.content><p><tmpl_var preview.content></p></tmpl_if>
<tmpl_if isReply>
<h1><tmpl_var message.header.label></h1>
<tmpl_else>
<h1><tmpl_var submission.header.label></h1>
</tmpl_if>
<tmpl_var form.header>
<table class="defaultSubmissionForm">
<tmpl_if isNewPost>
<tmpl_if user.isVisitor>
<tr>
<td><tmpl_var visitorName.label></td>
<td><tmpl_var visitorName.form></td>
</tr>
</tmpl_if>
</tmpl_if>
<tr>
<td><tmpl_var title.label></td>
<td><tmpl_var title.form></td>
</tr>
<tmpl_unless isReply>
<tr>
<td><tmpl_var synopsis.label></td>
<td><tmpl_var synopsis.form></td>
</tr>
</tmpl_unless>
<tr>
<td><tmpl_var body.label></td>
<td><tmpl_var content.form></td>
</tr>
<tmpl_unless isReply>
<tmpl_loop meta_loop>
<tr>
<td><tmpl_var name></td>
<td><tmpl_var field></td>
</tr>
</tmpl_loop>
<tmpl_if attachment.form>
<tr>
<td><tmpl_var attachment.label></td>
<td><tmpl_var attachment.form></td>
</tr>
</tmpl_if>
</tmpl_unless>
<tmpl_if isNewPost>
<tmpl_unless user.isVisitor>
<tr>
<td><tmpl_var subscribe.label></td>
<td><tmpl_var subscribe.form></td>
</tr>
</tmpl_unless>
<tmpl_if isNewThread>
<tmpl_if user.isModerator>
<tr>
<td><tmpl_var lock.label></td>
<td><tmpl_var lock.form></td>
</tr>
<tr>
<td><tmpl_var stick.label></td>
<td><tmpl_var sticky.form></td>
</tr>
</tmpl_if>
</tmpl_if>
</tmpl_if>
<tr>
<td></td>
<td><tmpl_if usePreview><tmpl_var form.preview></tmpl_if><tmpl_var form.submit></td>
</tr>
</table>
<tmpl_var form.footer>
<tmpl_if isReply>
<div class="defaultSubmissionFormContent">
<b><tmpl_var reply.title></b><br /><br />
<tmpl_var reply.content>
</div>
</tmpl_if>
~~~
<style type="text/css">
table.defaultSubmissionForm td
{
font-family:arial;
font-size:9pt;
}
.defaultSubmissionFormContent
{
font-family:arial;
font-size:9pt;
}
h2
{
font-family:arial;
}
</style>

View file

@ -0,0 +1,18 @@
#newsletter000000000001
#url: newsletterdefaulttemplate
#title: Summary Newsletter (default)
#menuTitle: Summary Newsletter
#namespace:newsletter
#create
<p><tmpl_var header></p>
<tmpl_loop thread_loop>
<p>
<a href="<tmpl_var url>"><tmpl_var title></a><br />
<p><tmpl_var synopsis></p>
</p>
</tmpl_loop>
<p><tmpl_var footer></p>

View file

@ -0,0 +1,67 @@
#newslettercs0000000001
#url: newslettercstemplate
#title: Newsletter Manager (default)
#menuTitle: Newsletter Manager
#namespace:Collaboration
#create
<a name="id<tmpl_var assetId>" id="id<tmpl_var assetId>"></a>
<tmpl_if session.var.adminOn>
<p><tmpl_var controls></p>
</tmpl_if>
<tmpl_if displayTitle>
<h2><tmpl_var title></h2>
</tmpl_if>
<tmpl_if description>
<tmpl_var description>
</tmpl_if>
<p class="pagination">
<tmpl_if user.canPost>
<a href="<tmpl_var add.url>"><tmpl_var add.label></a>
|
</tmpl_if>
<tmpl_unless user.isVisitor>
<a href="<tmpl_var mySubscriptionsUrl>">^International("my subscriptions","Asset_Newsletter");</a>
|
</tmpl_unless>
<a href="<tmpl_var search.url>"><tmpl_var search.label></a>
</p>
<p />
<tmpl_loop post_loop>
<p><b><a href="<tmpl_var url>"><tmpl_var title></a></b><br />
<tmpl_var synopsis></p>
</tmpl_loop>
<tmpl_if pagination.pageCount.isMultiple>
<div class="pagination">
<tmpl_var pagination.previousPage> &bull; <tmpl_var pagination.pageList.upTo10> &bull; <tmpl_var pagination.nextPage>
</div>
</tmpl_if>
~~~
<style type="text/css">
.pagination {
-moz-box-sizing:border-box;
background:#676767;
color:#C0C0C0;
width:100%;
text-align:right;
padding:3px;
font-size:9pt;
font-family:arial;
}
.pagination a {
color:white;
font-size:8pt;
text-decoration:underline;
}
.pagination a:hover {
text-decoration:none;
}
</style>

View file

@ -0,0 +1,22 @@
#newslettersubscrip0001
#url: newslettermysubscriptionstemplate
#title: My Subscriptions (default)
#menuTitle: My Subscriptions
#namespace:newsletter/mysubscriptions
#create
<h1>^International("my subscriptions","Asset_Newsletter");</h1>
<tmpl_var formHeader>
<h2>^International("newsletter categories","Asset_Newsletter");</h2>
<tmpl_loop categoriesLoop>
<p><b><tmpl_var categoryName></b><br />
<blockquote>
<tmpl_loop optionsLoop>
<label><tmpl_var optionForm> <tmpl_var optionName></label><br />
</tmpl_loop>
</blockquote></p>
</tmpl_loop>
<tmpl_var formSubmit>
<tmpl_var formFooter>

View file

@ -28,10 +28,41 @@ addAttachmentsToEvents($session);
addMetaDataPostsToCS($session);
addUserInvitations($session);
addPrivateMessaging($session);
addNewsletter($session);
finish($session); # this line required
#-------------------------------------------------
sub addNewsletter {
my $session = shift;
print "\tAdding a newsletter management system.\n" unless ($quiet);
$session->config->addToArray("assets","WebGUI::Asset::Wobject::Collaboration::Newsletter");
my $db = $session->db;
$db->write("create table Newsletter (
assetId varchar(22) binary not null,
revisionDate bigint not null,
newsletterTemplateId varchar(22) binary not null default 'newsletter000000000001',
mySubscriptionsTemplateId varchar(22) binary not null default 'newslettersubscrip0001',
newsletterHeader mediumtext,
newsletterFooter mediumtext,
newsletterCategories text,
primary key (assetId, revisionDate)
)");
$db->write("create table Newsletter_subscriptions (
assetId varchar(22) binary not null,
userId varchar(22) binary not null,
subscriptions text,
lastTimeSent bigint not null default 0,
primary key (assetId, userId)
)");
$db->write("alter table Newsletter_subscriptions add index lastTimeSent_assetId_userId
(lastTimeSent,assetId,userId)");
my $workflow = WebGUI::Workflow->new($session, "pbworkflow000000000002");
my $activity = $workflow->addActivity("WebGUI::Workflow::Activity::SendNewsletters","newslettersendactivity");
$activity->set("title","Send Newsletters For Newsletter Assets");
}
#-------------------------------------------------
sub addRealtimeWorkflow {
my $session = shift;

View file

@ -1694,10 +1694,11 @@ anything.
sub processPropertiesFromFormPost {
my $self = shift;
my %data;
my $form = $self->session->form;
foreach my $definition (@{$self->definition($self->session)}) {
foreach my $property (keys %{$definition->{properties}}) {
if ($definition->{properties}{$property}{noFormPost}) {
if ($self->session->form->process("assetId") eq "new" && $self->get($property) eq "") {
if ($form->process("assetId") eq "new" && $self->get($property) eq "") {
$data{$property} = $definition->{properties}{$property}{defaultValue};
}
next;
@ -1705,7 +1706,7 @@ sub processPropertiesFromFormPost {
my %params = %{$definition->{properties}{$property}};
$params{name} = $property;
$params{value} = $self->get($property);
$data{$property} = $self->session->form->process(
$data{$property} = $form->process(
$property,
$definition->{properties}{$property}{fieldType},
$definition->{properties}{$property}{defaultValue},
@ -1713,11 +1714,13 @@ sub processPropertiesFromFormPost {
);
}
}
foreach my $form ($self->session->form->param) {
if ($form =~ /^metadata_(.*)$/) {
$self->updateMetaData($1,$self->session->form->process($form));
}
}
if ($self->session->setting->get("metaDataEnabled")) {
my $meta = $self->getMetaDataFields;
foreach my $field (keys %{$meta}) {
my $value = $form->process("metadata_".$field, $meta->{$field}{fieldType}, $meta->{$field}{defaultValue});
$self->updateMetaData($field, $value);
}
}
$self->session->db->beginTransaction;
$self->update(\%data);
$self->session->db->commit;

View file

@ -24,6 +24,54 @@ use WebGUI::Asset::RSSCapable;
use base 'WebGUI::Asset::RSSCapable';
use base 'WebGUI::Asset::Wobject';
#-------------------------------------------------------------------
sub _computePostCount {
my $self = shift;
return scalar @{$self->getLineage(['descendants'], {includeOnlyClasses => ['WebGUI::Asset::Post']})};
}
#-------------------------------------------------------------------
sub _computeThreadCount {
my $self = shift;
return scalar @{$self->getLineage(['children'], {includeOnlyClasses => ['WebGUI::Asset::Post::Thread']})};
}
#-------------------------------------------------------------------
# format the date according to rfc 822 (for RSS export)
my @_months = qw(Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec);
sub _get_rfc822_date {
my $self = shift;
my ($time) = @_;
my ($year, $mon, $mday, $hour, $min, $sec) = $self->session->datetime->localtime($time);
my $month = $_months[$mon - 1];
return sprintf("%02d %s %04d %02d:%02d:%02d GMT",
$mday, $month, $year, $hour, $min, $sec);
}
#-------------------------------------------------------------------
sub _visitorCacheKey {
my $self = shift;
my $pn = $self->session->form->process('pn');
return "view_".$self->getId."?pn=".$pn;
}
#-------------------------------------------------------------------
sub _visitorCacheOk {
my $self = shift;
return ($self->session->user->userId eq '1'
&& !$self->session->form->process('sortBy'));
}
#-------------------------------------------------------------------
# encode a string to include in xml (for RSS export)
sub _xml_encode {
my $text = shift;
$text =~ s/&/&amp;/g;
$text =~ s/</&lt;/g;
$text =~ s/\]\]>/\]\]&gt;/g;
return $text;
}
#-------------------------------------------------------------------
sub addChild {
my $self = shift;
@ -554,7 +602,7 @@ sub definition {
fieldType=>"template",
namespace=>"Collaboration/Notification",
defaultValue=>'PBtmpl0000000000000027',
tab=>'display',
tab=>'mail',
label=>$i18n->get('notification template'),
hoverHelp=>$i18n->get('notification template description'),
},
@ -664,6 +712,27 @@ sub duplicate {
return $newAsset;
}
#-------------------------------------------------------------------
sub getEditTabs {
my $self = shift;
my $i18n = WebGUI::International->new($self->session,"Asset_Collaboration");
return (['mail', $i18n->get('mail'), 9]);
}
#-------------------------------------------------------------------
=head2 getNewThreadUrl( )
Formats the url to start a new thread.
=cut
sub getNewThreadUrl {
my $self = shift;
$self->getUrl("func=add;class=WebGUI::Asset::Post::Thread");
}
#-------------------------------------------------------------------
sub getRssItems {
my $self = shift;
@ -726,27 +795,6 @@ SQL
return @posts;
}
#-------------------------------------------------------------------
sub getEditTabs {
my $self = shift;
my $i18n = WebGUI::International->new($self->session,"Asset_Collaboration");
return (['mail', $i18n->get('mail'), 9]);
}
#-------------------------------------------------------------------
=head2 getNewThreadUrl( )
Formats the url to start a new thread.
=cut
sub getNewThreadUrl {
my $self = shift;
$self->getUrl("func=add;class=WebGUI::Asset::Post::Thread");
}
#-------------------------------------------------------------------
=head2 getSearchUrl ( )
@ -806,14 +854,78 @@ sub getUnsubscribeUrl {
#-------------------------------------------------------------------
sub _computeThreadCount {
sub getViewTemplateVars {
my $self = shift;
return scalar @{$self->getLineage(['children'], {includeOnlyClasses => ['WebGUI::Asset::Post::Thread']})};
}
sub _computePostCount {
my $self = shift;
return scalar @{$self->getLineage(['descendants'], {includeOnlyClasses => ['WebGUI::Asset::Post']})};
my $scratchSortBy = $self->getId."_sortBy";
my $scratchSortOrder = $self->getId."_sortDir";
my $sortBy = $self->session->form->process("sortBy") || $self->session->scratch->get($scratchSortBy) || $self->get("sortBy");
my $sortOrder = $self->session->scratch->get($scratchSortOrder) || $self->get("sortOrder");
if ($sortBy ne $self->session->scratch->get($scratchSortBy) && $self->session->form->process("func") ne "editSave") {
$self->session->scratch->set($scratchSortBy,$self->session->form->process("sortBy"));
} elsif ($self->session->form->process("sortBy") && $self->session->form->process("func") ne "editSave") {
if ($sortOrder eq "asc") {
$sortOrder = "desc";
} else {
$sortOrder = "asc";
}
$self->session->scratch->set($scratchSortOrder, $sortOrder);
}
$sortBy ||= "dateUpdated";
$sortOrder ||= "desc";
my %var;
$var{'user.canPost'} = $self->canPost;
$var{"add.url"} = $self->getNewThreadUrl;
$var{"rss.url"} = $self->getRssUrl;
$var{'user.isModerator'} = $self->canModerate;
$var{'user.isVisitor'} = ($self->session->user->userId eq '1');
$var{'user.isSubscribed'} = $self->isSubscribed;
$var{'sortby.title.url'} = $self->getSortByUrl("title");
$var{'sortby.username.url'} = $self->getSortByUrl("username");
$var{'karmaIsEnabled'} = $self->session->setting->get("useKarma");
$var{'sortby.karmaRank.url'} = $self->getSortByUrl("karmaRank");
$var{'sortby.date.url'} = $self->getSortByUrl("dateSubmitted");
$var{'sortby.lastreply.url'} = $self->getSortByUrl("lastPostDate");
$var{'sortby.views.url'} = $self->getSortByUrl("views");
$var{'sortby.replies.url'} = $self->getSortByUrl("replies");
$var{'sortby.rating.url'} = $self->getSortByUrl("rating");
$var{"search.url"} = $self->getSearchUrl;
$var{"subscribe.url"} = $self->getSubscribeUrl;
$var{"unsubscribe.url"} = $self->getUnsubscribeUrl;
$var{"collaborationAssetId"} = $self->getId;
my $sql = "
select
asset.assetId,
asset.className,
assetData.revisionDate as revisionDate
from Thread
left join asset on Thread.assetId=asset.assetId
left join Post on Post.assetId=Thread.assetId and Thread.revisionDate = Post.revisionDate
left join assetData on assetData.assetId=Thread.assetId and Thread.revisionDate = assetData.revisionDate
where
asset.parentId=".$self->session->db->quote($self->getId)."
and asset.state='published'
and asset.className='WebGUI::Asset::Post::Thread'
and assetData.revisionDate=(
select
max(revisionDate)
from
assetData
where
assetData.assetId=asset.assetId
and (status='approved' or status='archived')
)
and status='approved'
group by
assetData.assetId
order by
Thread.isSticky desc,
".$sortBy."
".$sortOrder;
my $p = WebGUI::Paginator->new($self->session,$self->getUrl,$self->get("threadsPerPage"));
$p->setDataByQuery($sql);
$self->appendPostListTemplateVars(\%var, $p);
$self->appendTemplateLabels(\%var);
return \%var;
}
#-------------------------------------------------------------------
@ -1053,18 +1165,6 @@ sub unsubscribe {
#-------------------------------------------------------------------
sub _visitorCacheOk {
my $self = shift;
return ($self->session->user->userId eq '1'
&& !$self->session->form->process('sortBy'));
}
sub _visitorCacheKey {
my $self = shift;
my $pn = $self->session->form->process('pn');
return "view_".$self->getId."?pn=".$pn;
}
sub view {
my $self = shift;
if ($self->_visitorCacheOk) {
@ -1072,87 +1172,16 @@ sub view {
$self->session->errorHandler->debug("HIT") if $out;
return $out if $out;
}
my $scratchSortBy = $self->getId."_sortBy";
my $scratchSortOrder = $self->getId."_sortDir";
my $sortBy = $self->session->form->process("sortBy") || $self->session->scratch->get($scratchSortBy) || $self->get("sortBy");
my $sortOrder = $self->session->scratch->get($scratchSortOrder) || $self->get("sortOrder");
if ($sortBy ne $self->session->scratch->get($scratchSortBy) && $self->session->form->process("func") ne "editSave") {
$self->session->scratch->set($scratchSortBy,$self->session->form->process("sortBy"));
} elsif ($self->session->form->process("sortBy") && $self->session->form->process("func") ne "editSave") {
if ($sortOrder eq "asc") {
$sortOrder = "desc";
} else {
$sortOrder = "asc";
}
$self->session->scratch->set($scratchSortOrder, $sortOrder);
}
$sortBy ||= "dateUpdated";
$sortOrder ||= "desc";
my %var;
$var{'user.canPost'} = $self->canPost;
$var{"add.url"} = $self->getNewThreadUrl;
$var{"rss.url"} = $self->getRssUrl;
$var{'user.isModerator'} = $self->canModerate;
$var{'user.isVisitor'} = ($self->session->user->userId eq '1');
$var{'user.isSubscribed'} = $self->isSubscribed;
$var{'sortby.title.url'} = $self->getSortByUrl("title");
$var{'sortby.username.url'} = $self->getSortByUrl("username");
$var{'karmaIsEnabled'} = $self->session->setting->get("useKarma");
$var{'sortby.karmaRank.url'} = $self->getSortByUrl("karmaRank");
$var{'sortby.date.url'} = $self->getSortByUrl("dateSubmitted");
$var{'sortby.lastreply.url'} = $self->getSortByUrl("lastPostDate");
$var{'sortby.views.url'} = $self->getSortByUrl("views");
$var{'sortby.replies.url'} = $self->getSortByUrl("replies");
$var{'sortby.rating.url'} = $self->getSortByUrl("rating");
$var{"search.url"} = $self->getSearchUrl;
$var{"subscribe.url"} = $self->getSubscribeUrl;
$var{"unsubscribe.url"} = $self->getUnsubscribeUrl;
$var{"collaborationAssetId"} = $self->getId;
my $sql = "
select
asset.assetId,
asset.className,
assetData.revisionDate as revisionDate
from Thread
left join asset on Thread.assetId=asset.assetId
left join Post on Post.assetId=Thread.assetId and Thread.revisionDate = Post.revisionDate
left join assetData on assetData.assetId=Thread.assetId and Thread.revisionDate = assetData.revisionDate
where
asset.parentId=".$self->session->db->quote($self->getId)."
and asset.state='published'
and asset.className='WebGUI::Asset::Post::Thread'
and assetData.revisionDate=(
select
max(revisionDate)
from
assetData
where
assetData.assetId=asset.assetId
and (status='approved' or status='archived')
)
and status='approved'
group by
assetData.assetId
order by
Thread.isSticky desc,
".$sortBy."
".$sortOrder;
my $p = WebGUI::Paginator->new($self->session,$self->getUrl,$self->get("threadsPerPage"));
$p->setDataByQuery($sql);
$self->appendPostListTemplateVars(\%var, $p);
$self->appendTemplateLabels(\%var);
# If the asset is not called through the normal prepareView/view cycle, first call prepareView.
# This happens for instance in the viewDetail method in the Matrix. In that case the Collaboration
# is called through the api.
$self->prepareView unless ($self->{_viewTemplate});
my $out = $self->processTemplate(\%var,undef,$self->{_viewTemplate});
my $out = $self->processTemplate($self->getViewTemplateVars,undef,$self->{_viewTemplate});
if ($self->_visitorCacheOk) {
WebGUI::Cache->new($self->session,$self->_visitorCacheKey)
->set($out,$self->get("visitorCacheTimeout"));
$self->session->errorHandler->debug("MISS");
WebGUI::Cache->new($self->session,$self->_visitorCacheKey)->set($out,$self->get("visitorCacheTimeout"));
}
return $out;
return $out;
}
#-------------------------------------------------------------------
@ -1221,28 +1250,6 @@ sub www_unsubscribe {
return $self->www_view;
}
#-------------------------------------------------------------------
# format the date according to rfc 822 (for RSS export)
my @_months = qw(Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec);
sub _get_rfc822_date {
my $self = shift;
my ($time) = @_;
my ($year, $mon, $mday, $hour, $min, $sec) = $self->session->datetime->localtime($time);
my $month = $_months[$mon - 1];
return sprintf("%02d %s %04d %02d:%02d:%02d GMT",
$mday, $month, $year, $hour, $min, $sec);
}
#-------------------------------------------------------------------
# encode a string to include in xml (for RSS export)
sub _xml_encode {
my $text = shift;
$text =~ s/&/&amp;/g;
$text =~ s/</&lt;/g;
$text =~ s/\]\]>/\]\]&gt;/g;
return $text;
}
#-------------------------------------------------------------------
sub www_view {
my $self = shift;

View file

@ -0,0 +1,242 @@
package WebGUI::Asset::Wobject::Collaboration::Newsletter;
#-------------------------------------------------------------------
# WebGUI is Copyright 2001-2006 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 strict;
use Tie::IxHash;
use WebGUI::Form;
use WebGUI::International;
use WebGUI::Utility;
use base 'WebGUI::Asset::Wobject::Collaboration';
#-------------------------------------------------------------------
=head2 definition ( )
defines wobject properties for Newsletter instances. You absolutely need
this method in your new Wobjects. If you choose to "autoGenerateForms", the
getEditForm method is unnecessary/redundant/useless.
=cut
sub definition {
my $class = shift;
my $session = shift;
my $definition = shift;
my $i18n = WebGUI::International->new($session, 'Asset_Newsletter');
my %properties;
tie %properties, 'Tie::IxHash';
%properties = (
newsletterHeader => {
defaultValue=>undef,
fieldType=>"HTMLArea",
tab=>"mail",
label=>$i18n->get("newsletter header"),
hoverHelp=>$i18n->get("newsletter header help"),
},
newsletterFooter => {
defaultValue=>undef,
fieldType=>"HTMLArea",
tab=>"mail",
label=>$i18n->get("newsletter footer"),
hoverHelp=>$i18n->get("newsletter footer help"),
},
newsletterTemplateId => {
defaultValue=>'newsletter000000000001',
fieldType=>"template",
namespace=>"newsletter",
tab=>"mail",
label=>$i18n->get("newsletter template"),
hoverHelp=>$i18n->get("newsletter template help"),
},
mySubscriptionsTemplateId => {
defaultValue=>'newslettersubscrip0001',
fieldType=>"template",
namespace=>"newsletter/mysubscriptions",
tab=>"display",
label=>$i18n->get("my subscriptions template"),
hoverHelp=>$i18n->get("my subscriptions template help"),
},
);
if ($session->setting->get("metaDataEnabled")) {
$properties{newsletterCategories} = {
defaultValue=>undef,
fieldType=>"checkList",
tab=>"properties",
options=>$session->db->buildHashRef("select fieldId, fieldName from metaData_properties where
fieldType in ('selectBox', 'checkList', 'radioList') order by fieldName"),
label=>$i18n->get("newsletter categories"),
hoverHelp=>$i18n->get("newsletter categories help"),
vertical=>1,
};
}
else {
$properties{newsletterCategories} = {
fieldType=>"readOnly",
value=>'<b style="color: #800000;">'.$i18n->get("content profiling needed").'</b>',
};
}
push(@{$definition}, {
assetName=>$i18n->get('assetName'),
icon=>'newsletter.gif',
autoGenerateForms=>1,
tableName=>'Newsletter',
className=>'WebGUI::Asset::Wobject::Collaboration::Newsletter',
properties=>\%properties
});
return $class->SUPER::definition($session, $definition);
}
#-------------------------------------------------------------------
=head2 duplicate ( )
duplicates a Newsletter. This method is unnecessary, but if you have
auxiliary, ancillary, or "collateral" data or files related to your
wobject instances, you will need to duplicate them here.
=cut
sub duplicate {
my $self = shift;
my $newAsset = $self->SUPER::duplicate(@_);
return $newAsset;
}
#-------------------------------------------------------------------
sub getUserSubscriptions {
my $self = shift;
my $userId = shift || $self->session->user->userId;
my ($subscriptionString) = $self->session->db->quickArray("select subscriptions from Newsletter_subscriptions where
assetId=? and userId=?", [$self->getId, $userId]);
return split("\n", $subscriptionString);
}
#-------------------------------------------------------------------
sub getViewTemplateVars {
my $self = shift;
my $var = $self->SUPER::getViewTemplateVars;
$var->{mySubscriptionsUrl} = $self->getUrl("func=mySubscriptions");
return $var;
}
#-------------------------------------------------------------------
sub purge {
my $self = shift;
$self->session->db->write("delete from Newsletter_subscriptions where assetId=?", [$self->getId]);
$self->SUPER::purge(@_);
}
#-------------------------------------------------------------------
sub setUserSubscriptions {
my $self = shift;
my $subscriptions = shift;
my $userId = shift || $self->session->user->userId;
$self->session->db->write("replace into Newsletter_subscriptions (assetId, userId, subscriptions, lastSendTime)
values (?,?,?,?)", [$self->getId, $userId, $subscriptions, time()]);
}
#-------------------------------------------------------------------
=head2 view ( )
method called by the www_view method. Returns a processed template
to be displayed within the page style.
=cut
sub view {
my $self = shift;
my $session = $self->session;
#This automatically creates template variables for all of your wobject's properties.
my $var = $self->getViewTemplateVars;
#This is an example of debugging code to help you diagnose problems.
#WebGUI::ErrorHandler::warn($self->get("templateId"));
return $self->processTemplate($var, undef, $self->{_viewTemplate});
}
#-------------------------------------------------------------------
=head2 www_edit ( )
Web facing method which is the default edit page. This method is entirely
optional. Take it out unless you specifically want to set a submenu in your
adminConsole views.
=cut
sub www_edit {
my $self = shift;
return $self->session->privilege->insufficient() unless $self->canEdit;
return $self->session->privilege->locked() unless $self->canEditIfLocked;
my $i18n = WebGUI::International->new($self->session, "Asset_Newsletter");
return $self->getAdminConsole->render($self->getEditForm->print, $i18n->get("edit title"));
}
#-------------------------------------------------------------------
sub www_mySubscriptions {
my $self = shift;
return $self->session->privilege->insufficient unless ($self->canView && $self->session->user->userId ne "1");
my %var = ();
my $meta = $self->getMetaDataFields;
my @categories = ();
my @userPrefs = $self->getUserSubscriptions;
foreach my $id (keys %{$meta}) {
my @options = ();
if (isIn($id, split("\n", $self->get("newsletterCategories")))) {
foreach my $option (split("\n", $meta->{$id}{possibleValues})) {
$option =~ s/\s+$//; # remove trailing spaces
next if $option eq ""; # skip blank values
my $preferenceName = $id."~".$option;
push(@options, {
optionName => $option,
optionForm => WebGUI::Form::checkbox($self->session, {
name => "subscriptions",
value => $preferenceName,
checked => isIn($preferenceName, @userPrefs),
})
});
}
push (@categories, {
categoryName => $meta->{$id}{fieldName},
optionsLoop => \@options
});
}
}
$var{categoriesLoop} = \@categories;
if (scalar(@categories)) {
$var{formHeader} = WebGUI::Form::formHeader($self->session, {action=>$self->getUrl, method=>"post"})
.WebGUI::Form::hidden($self->session, {name=>"func", value=>"mySubscriptionsSave"});
$var{formFooter} = WebGUI::Form::formFooter($self->session);
$var{formSubmit} = WebGUI::Form::submit($self->session);
}
return $self->processStyle($self->processTemplate(\%var, $self->get("mySubscriptionsTemplateId")));
}
#-------------------------------------------------------------------
sub www_mySubscriptionsSave {
my $self = shift;
return $self->session->privilege->insufficient unless ($self->canView && $self->session->user->userId ne "1");
my $subscriptions = $self->session->form->process("subscriptions", "checkList");
$self->setUserSubscriptions($subscriptions);
return $self->www_view;
}
1;

View file

@ -60,7 +60,7 @@ wasting space in the db for this field.
=head3 fieldType
The form field type for metaData, select list, text, integer.
The form field type for metaData: selectBox, text, integer, or checkList, yesNo, radioList.
=head3 possibleValues
@ -251,13 +251,14 @@ sub www_editMetaDataField {
-name=>"description",
-label=>$i18n->get(85),
-hoverHelp=>$i18n->get('Metadata Description description'),
-value=>$fieldInfo->{description});
-value=>$fieldInfo->{description}
);
$f->fieldType(
-name=>"fieldType",
-label=>$i18n->get(486),
-hoverHelp=>$i18n->get('Data Type description'),
-value=>$fieldInfo->{fieldType} || "text",
-types=> [ qw /text integer yesNo selectList radioList/ ]
-types=> [ qw /text integer yesNo selectBox radioList checkList/ ]
);
$f->textarea(
-name=>"possibleValues",
@ -265,6 +266,12 @@ sub www_editMetaDataField {
-hoverHelp=>$i18n->get('Possible Values description'),
-value=>$fieldInfo->{possibleValues}
);
$f->textarea(
-name=>"defaultValue",
-label=>$i18n->get('default value'),
-hoverHelp=>$i18n->get('default value description'),
-value=>$fieldInfo->{defaultValue}
);
$f->submit();
$ac->setHelp("metadata edit property","Asset");
return $ac->render($f->print, $i18n->get('Edit Metadata'));

View file

@ -82,7 +82,7 @@ sub AUTOLOAD {
my $name = ucfirst((split /::/, $AUTOLOAD)[-1]);
my %params = @_;
$params{uiLevelOverride} ||= $self->{_uiLevelOverride};
$params{rowClass} = $self->{_class};
$params{rowClass} ||= $self->{_class};
my $cmd = "use WebGUI::Form::".$name;
eval ($cmd);
if ($@) {

View file

@ -0,0 +1,128 @@
package WebGUI::Help::Asset_Newsletter; ## Be sure to change the package name to match your filename.
##Stub document for creating help documents.
our $HELP = { ##hashref of hashes
'newsletter add/edit' => {
title => 'newsletter add/edit',
body => 'newsletter add/edit desc',
isa => [
{
tag => 'collaboration add/edit',
namespace => 'Asset_Collaboration',
},
],
fields => [
{
title => 'newsletter header',
description => 'newsletter header help',
namespace => 'Asset_Newsletter',
},
{
title => 'newsletter footer',
description => 'newsletter footer help',
namespace => 'Asset_Newsletter',
},
{
title => 'newsletter template',
description => 'newsletter template help',
namespace => 'Asset_Newsletter',
},
{
title => 'my subscriptions template',
description => 'my subscriptions template help',
namespace => 'Asset_Newsletter',
},
{
title => 'newsletter categories',
description => 'newsletter categories help',
namespace => 'Asset_Newsletter',
},
],
variables => [
{
name => "mySubscriptionsUrl",
},
],
},
'my subscriptions template' => {
title => 'my subscriptions template',
body => 'my subscriptions template help',
variables => [
{
name => "formHeader",
},
{
name => "formFooter",
},
{
name => "formSubmit",
},
{
name => "categoriesLoop",
variables => [
{
name => "categoryName",
},
{
name => "optionsLoop",
variables => [
{
name => "optionName",
},
{
name => "optionForm",
},
],
},
],
},
},
'newsletter template' => {
title => 'newsletter template',
body => 'newsletter template help',
variables => [
{
name => "title",
description => "newsletterTitle",
},
{
name => "description",
description => "newsletterDescription",
},
{
name => "header",
description => "newsletter header",
},
{
name => "footer",
description => "newsletter header",
},
{
name => "thread_loop",
variables => [
{
name => "title",
description => "threadTitle",
},
{
name => "synopsis",
description => "threadSynopsis",
},
{
name => "body",
description => "threadBody",
},
{
name => "url",
description => "threadUrl",
},
],
},
},
};
1; ##All perl modules must return true

View file

@ -0,0 +1,207 @@
package WebGUI::Workflow::Activity::SendNewsletters;
=head1 LEGAL
-------------------------------------------------------------------
WebGUI is Copyright 2001-2006 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
-------------------------------------------------------------------
=cut
use strict;
use base 'WebGUI::Workflow::Activity';
use WebGUI::Asset;
use WebGUI::Mail::Send;
=head1 NAME
Package WebGUI::Workflow::Activity::Skeleton
=head1 DESCRIPTION
Tell a little about what this activity does.
=head1 SYNOPSIS
See WebGUI::Workflow::Activity for details on how to use any activity.
=head1 METHODS
These methods are available from this class:
=cut
#-------------------------------------------------------------------
=head2 definition ( session, definition )
See WebGUI::Workflow::Activity::defintion() for details.
=cut
sub definition {
my $class = shift;
my $session = shift;
my $definition = shift;
my $i18n = WebGUI::International->new($session, "Asset_Newsletter");
push(@{$definition}, {
name=>$i18n->get("send activity name"),
properties=> { }
});
return $class->SUPER::definition($session,$definition);
}
#-------------------------------------------------------------------
=head2 execute ( [ object ] )
See WebGUI::Workflow::Activity::execute() for details.
=cut
sub execute {
my $self = shift;
my $object = shift;
my $instance = shift;
my ($db,$eh) = $self->session->quick(qw(db errorHandler));
my $time = time();
my $newsletter = undef;
$eh->info("Getting subscriptions");
my $subscriptionResultSet = $db->read("select assetId, userId, subscriptions, lastTimeSent
from Newsletter_subscriptions where lastTimeSent < unix_timestamp() - 60*60*23
order by assetId, userId"); # only sending to people who haven't been sent to in the past 23 hours
while (my ($assetId, $userId, $subscriptions, $lastTimeSent) = $subscriptionResultSet->array) {
# get user object
$eh->info("Getting user $userId");
my $user = WebGUI::User->new($self->session, $userId);
next if ($user->userId eq "1");
my $emailAddress = $user->profileField("email");
next if ($emailAddress eq "");
# get newsletter asset
unless (defined $newsletter && $newsletter->getId eq $assetId) { # cache newsletter object
$eh->info("Getting newsletter asset $assetId");
$newsletter = WebGUI::Asset->new($self->session, $assetId);
}
# find matching threads
my @threads = ();
$eh->info("Find threads in $assetId matching $userId subscriptions.");
foreach my $subscription (split("\n", $subscriptions)) {
$eh->info("Found subscription $subscription");
my ($fieldId, $value) = split("~", $subscription);
$eh->info("Searching for threads that match $subscription");
my $matchingThreads = $db->read("select metaData_values.assetId from metaData_values
left join asset using (assetId) where fieldId=? and value like ? and creationDate > ?
and className like ? and lineage like ?",
[$fieldId, '%'.$value.'%', $lastTimeSent, 'WebGUI::Asset::Post::Thread%', $newsletter->get("lineage").'%']);
while (my ($threadId) = $matchingThreads->array) {
my $thread = WebGUI::Asset->new($self->session, $threadId);
if (defined $thread) {
$eh->info("Found thread $threadId");
push(@threads, $thread);
}
else {
$eh->error("Couldn't instanciate thread $threadId");
}
}
}
unless (scalar(@threads)) { # don't send a message if there aren't matching threads
$eh->info("No threads found matching $userId subscriptions.");
next;
}
# build newsletter
$eh->info("Building newsletter for $userId.");
my $siteurl = $self->session->url->getSiteURL();
my @threadLoop = ();
foreach my $thread (@threads) {
push(@threadLoop, {
title => $thread->getTitle,
synopsis => $thread->get("synopsis"),
body => $thread->get("body"),
url => $siteurl.$thread->getUrl,
});
}
my %var = (
title => $newsletter->getTitle,
description => $newsletter->get("description"),
header => $newsletter->get("newsletterHeader"),
footer => $newsletter->get("newsletterFooter"),
thread_loop => \@threadLoop,
);
my $template = WebGUI::Asset->new($self->session, $newsletter->get("newsletterTemplateId"));
my $content = $template->process(\%var);
# send newsletter
$eh->info("Sending newsletter for $userId.");
my $setting = $self->session->setting;
my $returnAddress = $setting->get("mailReturnPath");
my $companyAddress = $setting->get("companyEmail");
my $listAddress = $newsletter->get("mailAddress");
my $from = $listAddress || $companyAddress;
my $replyTo = $listAddress || $returnAddress || $companyAddress;
my $sender = $listAddress || $companyAddress;
my $returnPath = $returnAddress || $sender;
my $listId = $sender;
$listId =~ s/\@/\./;
my $domain = $newsletter->get("mailAddress");
$domain =~ s/.*\@(.*)/$1/;
my $messageId = "cs-".$self->getId.'@'.$domain;
my $subject = $newsletter->get("mailPrefix").$newsletter->getTitle;
my $mail = WebGUI::Mail::Send->create($self->session, {
to => "<".$emailAddress.">",
from => "<".$from.">",
returnPath => "<".$returnPath.">",
replyTo => "<".$replyTo.">",
subject => $subject,
messageId => '<'.$messageId.'>'
});
$mail->addHeaderField("List-ID", $newsletter->getTitle." <".$listId.">");
$mail->addHeaderField("List-Help", "<mailto:".$companyAddress.">, <".$setting->get("companyURL").">");
$mail->addHeaderField("List-Unsubscribe", "<".$siteurl.$newsletter->getUrl("func=mySubscriptions").">");
$mail->addHeaderField("List-Owner", "<mailto:".$companyAddress.">, <".$setting->get("companyURL")."> (".$setting->get("companyName").")");
$mail->addHeaderField("Sender", "<".$sender.">");
if ($listAddress eq "") {
$mail->addHeaderField("List-Post", "No");
} else {
$mail->addHeaderField("List-Post", "<mailto:".$listAddress.">");
}
$mail->addHeaderField("List-Archive", "<".$siteurl.$newsletter->getUrl.">");
$mail->addHeaderField("X-Unsubscribe-Web", "<".$siteurl.$newsletter->getUrl("func=mySubscriptions").">");
$mail->addHeaderField("X-Archives", "<".$siteurl.$newsletter->getUrl.">");
$mail->addHtml($content);
$mail->queue;
# mark sent
$eh->info("Email sent.");
$db->write("update Newsletter_subscriptions set lastTimeSent = ?", [time()]);
# timeout if we're taking too long
if (time() - $time > 50) {
$eh->info("Oops. Ran out of time. Will continue building newsletters in a bit.");
$subscriptionResultSet->finish;
return $self->WAITING;
}
}
return $self->COMPLETE;
}
1;

View file

@ -723,6 +723,15 @@ each asset under the tab &quot;Meta&quot; in the asset properties.</p>
lastUpdated => 1031514049,
message => q|Possible Values|
},
'default value' => {
lastUpdated => 0,
message => q|Default Value(s)|
},
'default value description' => {
lastUpdated => 0,
message => q|The default value for this field. If there are multiple default values, as in the
case of the check box list, then enter one per line.|
},
'Depth' => {
lastUpdated => 1089039511,
context => q|Field label for the Export Page operation|,

View file

@ -0,0 +1,208 @@
package WebGUI::i18n::English::Asset_Newsletter;
our $I18N = {
'newsletterTitle' => {
message => q|Whatever this newsletter is called.|,
lastUpdated => 0,
context => q|newsletter template variable|
},
'newsletterDescription' => {
message => q|Whatever is in the description field of this newsletter.|,
lastUpdated => 0,
context => q|newsletter template variable|
},
'thread_loop' => {
message => q|A loop containing all the matching threads for this user's personalized newsletter.|,
lastUpdated => 0,
context => q|newsletter template variable|
},
'threadTitle' => {
message => q|The title of this thread.|,
lastUpdated => 0,
context => q|newsletter template variable|
},
'threadSynopsis' => {
message => q|The short version of this story.|,
lastUpdated => 0,
context => q|newsletter template variable|
},
'threadBody' => {
message => q|The full version of this story.|,
lastUpdated => 0,
context => q|newsletter template variable|
},
'threadUrl' => {
message => q|The fully qualified URL that points to this thread.|,
lastUpdated => 0,
context => q|newsletter template variable|
},
'categoriesLoop' => {
message => q|A loop containing all the categories of data the users may choose from.|,
lastUpdated => 0,
context => q|template variable|
},
'optionsLoop' => {
message => q|A loop containing all the options in a given category.|,
lastUpdated => 0,
context => q|template variable|
},
'categoryName' => {
message => q|The name of this specific category within the loop.|,
lastUpdated => 0,
context => q|template variable|
},
'optionName' => {
message => q|The name of this specific option within this category.|,
lastUpdated => 0,
context => q|template variable|
},
'optionForm' => {
message => q|The checkbox form control for this specific option within this category.|,
lastUpdated => 0,
context => q|template variable|
},
'formSubmit' => {
message => q|The save button for the form.|,
lastUpdated => 0,
context => q|template variable|
},
'formHeader' => {
message => q|The top of the subscription form.|,
lastUpdated => 0,
context => q|template variable|
},
'formFooter' => {
message => q|The bottom of the subscription form.|,
lastUpdated => 0,
context => q|template variable|
},
'newsletter add/edit' => {
message => q|Newsletter, Add/Edit|,
lastUpdated => 0,
context => q|help title|
},
'newsletter add/edit desc' => {
message => q|The Newsletter asset is used to create news stories and then send subscribed users an email
based upon their chosen interests. This asset requires content profiling to be enabled in order to
function.|,
lastUpdated => 0,
context => q|help description|
},
'mySubscriptionsUrl' => {
message => q|The URL for a user to click on to manage their subscriptions.|,
lastUpdated => 0,
context => q|newsletter template variable|
},
'content profiling needed' => {
message => q|WARNING: You need to enable content profiling for this asset to work.|,
lastUpdated => 0,
context => q|title for edit screen|
},
'edit title' => {
message => q|Edit Newsletter|,
lastUpdated => 0,
context => q|title for edit screen|
},
'newsletter categories' => {
message => q|Newsletter Categories|,
lastUpdated => 0,
context => q|asset property|
},
'newsletter categories help' => {
message => q|Choose the metadata fields you wish to use as categories. Only select box, check list, and
radio list categories may be used.|,
lastUpdated => 0,
context => q|help for asset property|
},
'newsletter template' => {
message => q|Newsletter Template|,
lastUpdated => 0,
context => q|asset property|
},
'newsletter template help' => {
message => q|Which template would you like to use for the newsletter when it is sent out to users?|,
lastUpdated => 0,
context => q|help for asset property|
},
'my subscriptions' => {
message => q|My Subscriptions|,
lastUpdated => 0,
context => q|label for user to click on to manage their subscriptions|
},
'my subscriptions template' => {
message => q|My Subscriptions Template|,
lastUpdated => 0,
context => q|asset property|
},
'my subscriptions template help' => {
message => q|Which template would you like to use for users selecting which cateogries they will subscribe
to?|,
lastUpdated => 0,
context => q|help for asset property|
},
'newsletter header' => {
message => q|Newsletter Header|,
lastUpdated => 0,
context => q|asset property|
},
'newsletteer header help' => {
message => q|A message the will be placed at the top of the newsletter; like a greeting.|,
lastUpdated => 0,
context => q|help for asset property|
},
'newsletter footer' => {
message => q|Newsletter Footer|,
lastUpdated => 0,
context => q|asset property|
},
'newsletteer footer help' => {
message => q|A message the will be placed at the bottom of the newsletter; like a salutation.|,
lastUpdated => 0,
context => q|help for asset property|
},
'send activity name' => {
message => q|Send Newsletters|,
lastUpdated => 0,
context => q|the name of the workflow activity that sends out the newsletters|
},
'assetName' => {
message => q|Newsletter|,
lastUpdated => 1131394072,
},
};
1;