webgui/lib/WebGUI/Inbox/Message.pm

722 lines
20 KiB
Perl

package WebGUI::Inbox::Message;
=head1 LEGAL
-------------------------------------------------------------------
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
-------------------------------------------------------------------
=cut
use strict;
use WebGUI::Mail::Send;
use WebGUI::International;
=head1 NAME
Package WebGUI::Inbox::Message;
=head1 DESCRIPTION
This package provides an API for working with inbox messages.
=head1 SYNOPSIS
use WebGUI::Inbox::Message;
my $message = WebGUI::Inbox::Message->new($session, $messageId);
=head1 METHODS
These methods are available from this class:
=cut
#-------------------------------------------------------------------
=head2 create ( session, properties )
Creates a new message.
=head2 session
A reference to the current session.
=head3 properties
A hash reference containing the properties to update.
=head4 message
The content of this message.
=head4 subject
The topic of this message. Defaults to 'Notification'.
=head4 status
May be "unread", "pending", or "completed". Defaults to "pending".
You should set this to "pending" if the message requires an action which will later be completed.
WebGUI::Inbox::Message->create( $session, { status => "pending"} )
You should set this to "unread" if this is a message without an action, such as a notification.
WebGUI::Inbox::Message->create( $session, { status => "unread" } );
You should only set this to "completed" if this is an action that would normally be "pending" but for some reason
requries no further action. For instance, if the user submitting some content is also the approver you may choose
to simply set the status immediately to completed.
=head4 userId
A userId of a user attached to this message.
=head4 groupId
A groupId of a group attached to this message.
=head4 sentBy
A userId that created this message. Defaults to '3' (Admin).
=head4 emailMessage
Email message to use rather than inbox message contents.
=head4 emailSubject
Email subject to use rather than inbox message subject.
=head4 smsMessage
SMS notification message to send to C<smsAddress>
=head4 smsSubject
SMS notification subject (typically used for SMS Gateway authentication)
=head4 smsAddress
Email address that SMS notification is sent to (typically the user's C<cellPhone> C<@> C<smsGateway>)
=head3 options
A hash reference containing options for handling the message.
=head4 no_email
If no_email is true, then no email will be made or sent. Only
the inbox message will be made.
=head4 no_sms
If no_sms is true, then no attempt to sms notifications will be sent.
=head4 overridePerUserDelivery
If true, then the C<isInbox> flag will not be passed to L<WebGUI::Mail::Send::Create>, and thus the
per-user settings for email delivery will not be used. Useful if you want to force this message to
be sent as an Email rather than allowing the user's C<receiveInboxEmailNotifications> setting to
take effect.
=head4 extraHeaders
A hash ref containing extra header information to send to WebGUI::Message::create valid headers include:
cc, bcc, replyTo, returnPath, contentType, messageId, and inReplyTo. See WebGUI::Message::create for more details.
=cut
sub create {
my $class = shift;
my $session = shift;
my $properties = shift;
my $options = shift || {};
my $self = {};
my $i18n = WebGUI::International->new($session);
$self->{_properties}{messageId} = "new";
$self->{_properties}{status} = $properties->{status} || "pending";
$self->{_properties}{subject} = $properties->{subject} || $i18n->get(523,'WebGUI');
$self->{_properties}{message} = $properties->{message};
$self->{_properties}{dateStamp} = time();
$self->{_properties}{userId} = $properties->{userId};
$self->{_properties}{groupId} = $properties->{groupId};
$self->{_properties}{sentBy} = $properties->{sentBy} || 3;
unless ( $self->{_properties}{userId} || $self->{_properties}{groupId} ) {
$self->{_properties}{userId} = $session->user->userId;
}
my $status = $self->{_properties}{status};
my $smsMessage = $properties->{smsMessage};
my $smsSubject = $properties->{smsSubject};
my $smsAddress = $properties->{smsAddress};
if ($status eq "completed") {
$self->{_properties}{completedBy} = $session->user->userId;
$self->{_properties}{completedOn} = time();
}
elsif($status ne "pending") {
$self->{_properties}{status} = "active";
}
$self->{_messageId} = $self->{_properties}{messageId} = $session->db->setRow("inbox","messageId",$self->{_properties});
$self->{_userId } = $self->{_properties}{userId};
$self->{_inbox } = $self->{_properties};
#Add the message state row for individual user passed in
if($self->{_properties}{userId}) {
$session->db->write(
q{ REPLACE INTO inbox_messageState (messageId,userId) VALUES (?,?) },
[$self->{_messageId},$self->{_properties}{userId}]
);
}
#Add the message state row for every user in the group
if($self->{_properties}{groupId}) {
my $g = WebGUI::Group->new($session,$self->{_properties}{groupId});
my $users = $g->getAllUsers;
foreach my $userId (@{$users}) {
$session->db->write(
q{ REPLACE INTO inbox_messageState (messageId,userId) VALUES (?,?) },
[$self->{_messageId},$userId]
);
}
}
unless ( $options->{ no_email } ) {
my $subject = (defined $properties->{emailSubject}) ? $properties->{emailSubject} : $self->{_properties}{subject};
#Set default mail headers
my $mailHeaders = {
toUser=>$self->{_properties}{userId},
toGroup=>$self->{_properties}{groupId},
subject=>$subject,
};
#Add extraHeaders if they are passsed in as options
if($options->{ extraHeaders } && ref $options->{ extraHeaders } eq 'HASH') {
%{$mailHeaders} = (%{$mailHeaders},%{$options->{ extraHeaders }});
}
#Get inbox override flag
my $overridePerUserDelivery = $options->{overridePerUserDelivery} ? undef : 'isInbox';
#Create the mail message
my $mail = WebGUI::Mail::Send->create($session,$mailHeaders,$overridePerUserDelivery);
my $preface = "";
my $fromUser = WebGUI::User->new($session, $properties->{sentBy});
#Don't append prefaces to the visitor users or messages that don't specify a user (default case)
unless ($fromUser->isVisitor || $fromUser->userId eq 3) { #Can't use isAdmin because it will not send prefaces from normal users who in the admin group
$preface = sprintf($i18n->get('from user preface', 'Inbox_Message'), $fromUser->username);
}
my $msg = (defined $properties->{emailMessage}) ? $properties->{emailMessage} : $self->{_properties}{message};
$msg = '<p>' . $preface . '</p><br />'.$msg if($preface ne "");
$mail->addHtml($msg);
$mail->addFooter;
$mail->queue;
}
unless ( $options->{ no_sms } ) {
# If smsAddress provided, send smsMessage too
if ( $smsAddress && $smsMessage) {
my $sms = WebGUI::Mail::Send->create(
$session,
{ to => $smsAddress,
subject => $smsSubject,
}
);
if ($sms) {
$sms->addText($smsMessage);
$sms->queue;
}
}
}
$self->{_session} = $session;
bless $self, $class;
}
#-------------------------------------------------------------------
=head2 delete ( userId )
Deletes this message from the inbox for the user passed in
=head3 userId
User to delete message for. If no user is passed in, the current user will be used.
=cut
sub delete {
my $self = shift;
my $session = $self->session;
my $db = $session->db;
my $messageId = $self->getId;
my $userId = shift || $self->{_userId};
$self->setDeleted($userId);
my $isActive = $db->quickScalar(
q{ select count(*) from inbox_messageState where messageId=? and deleted=0 },
[$messageId]
);
#Delete the message from the database if everyone who was sent the message has deleted it
unless ($isActive) {
$self->purge;
}
}
#-------------------------------------------------------------------
=head2 get ( property )
Returns the value of a property.
=head3 property
The name of any property of an inbox message. See create() for details. In addition to those settable by create, you may also retrieve these:
=head4 dateStamp
The date the message was created.
=head4 completedBy
The userId of the user that completed the action associated with this message.
=head4 completedOn
An epoch date representing when the action associated with this message was completed.
=cut
sub get {
my $self = shift;
my $name = shift;
if($name eq "status") {
my $status = $self->{_properties}{status};
if($status eq "active") {
return "read" if($self->{_properties}{isRead});
return "replied" if($self->{_properties}{repliedTo});
return "unread";
}
return $status;
}
return $self->{_properties}{$name};
}
#-------------------------------------------------------------------
=head2 getId ( )
Returns the ID of this message.
=cut
sub getId {
my $self = shift;
return $self->{_messageId};
}
#-------------------------------------------------------------------
=head2 getStatus ( [ userId ] )
Gets the current status of the message for the user passed in
=head3 userId
The id of the user to get the status of the message for. Defaults to the current user.
=cut
sub getStatus {
my $self = shift;
my $userId = shift || $self->{_userId};
my $status = $self->{_properties}{status};
my $statusCodes = $self->statusCodes;
if($status eq "active") {
return $statusCodes->{"replied"} if($self->{_properties}{repliedTo});
return $statusCodes->{"read" } if($self->{_properties}{isRead});
return $statusCodes->{"unread" };
}
return $statusCodes->{$self->get("status")};
}
#-------------------------------------------------------------------
=head2 isRead ( )
Returns whether or not the message has been read.
=cut
sub isRead {
my $self = shift;
return $self->{_properties}{isRead};
}
#-------------------------------------------------------------------
=head2 isValidStatus ( status )
Returns whether or not the status passed in is valid. Can be called as a class or instance method
=head4 status
The id of the user that replied to this message. Defaults to the current user.
=cut
sub isValidStatus {
my $self = shift;
my $status = shift;
return (exists $self->statusCodes->{$status});
}
#-------------------------------------------------------------------
=head2 new ( session, messageId )
Constructor used to access existing messages. Use create for making
new messages.
=head3 session
A reference to the current session.
=head3 messageId
The unique id of a message.
=head3 userId
The userId for this message. Defaults to the current user.
=cut
sub new {
my $class = shift;
my $session = shift;
my $messageId = shift;
my $userId = shift || $session->user->userId;
#Don't bother going on if a messageId wasn't passed in
return undef unless $messageId;
my $inbox = $session->db->getRow("inbox","messageId",$messageId);
#Don't return messages that don't exist
return undef unless (scalar(keys %{$inbox}));
my $statusValues = $session->db->quickHashRef(
q{ select isRead, repliedTo, deleted from inbox_messageState where messageId=? and userId=? },
[$messageId,$userId]
);
#Don't return deleted messages
return undef if($statusValues->{deleted});
my $self = {};
my %properties = (%{$inbox},%{$statusValues});
bless {_properties=>\%properties, _inbox=>$inbox, _session=>$session, _messageId=>$messageId, _userId=>$userId}, $class;
}
#-------------------------------------------------------------------
=head2 purge
Completely deletes a message from the inbox.
=cut
sub purge {
my $self = shift;
my $db = $self->session->db;
my $messageId = $self->getId;
$db->write("delete from inbox where messageId=?",[$messageId]);
$db->write("delete from inbox_messageState where messageId=?",[$messageId]);
}
#-------------------------------------------------------------------
=head2 session
Returns a reference to the current session.
=cut
sub session {
my $self = shift;
return $self->{_session};
}
#-------------------------------------------------------------------
=head2 setCompleted ( [ userId ] )
Marks a message completed.
=head4 userId
The id of the user that completed this task. Defaults to the current user.
=cut
sub setCompleted {
my $self = shift;
my $userId = shift || $self->session->user->userId;
$self->{_properties}{status} = "completed";
$self->{_properties}{completedBy} = $userId;
$self->{_properties}{completedOn} = time();
$self->{_inbox}{status} = "completed";
$self->{_inbox}{completedBy} = $userId;
$self->{_inbox}{completedOn} = time();
$self->session->db->setRow("inbox","messageId",$self->{_inbox});
#Completed messages should also be marked read for all users connected to this message
$self->setReadAll;
}
#-------------------------------------------------------------------
=head2 setDeleted ( [ userId ] )
Marks a message deleted.
=head4 userId
The id of the user that deleted this message. Defaults to the current user.
=cut
sub setDeleted {
my $self = shift;
my $userId = shift || $self->session->user->userId;
$self->session->db->write(
q{update inbox_messageState set deleted=1 where messageId=? and userId=?},
[$self->getId,$userId]
);
}
#-------------------------------------------------------------------
=head2 setRead ( [ userId ] )
Marks a message read.
=head4 userId
The id of the user that reads this message. Defaults to the current user.
=cut
sub setRead {
my $self = shift;
my $userId = shift || $self->session->user->userId;
$self->session->db->write(
q{update inbox_messageState set isRead=1 where messageId=? and userId=?},
[$self->getId,$userId]
);
}
#-------------------------------------------------------------------
=head2 setReadAll ( )
Marks a message read for all users who are connected to this message
=cut
sub setReadAll {
my $self = shift;
$self->session->db->write(
q{update inbox_messageState set isRead=1 where messageId=?},
[$self->getId]
);
}
#-------------------------------------------------------------------
=head2 setReplied ( [ userId ] )
Marks a message replied.
=head4 userId
The id of the user that replied to this message. Defaults to the current user.
=cut
sub setReplied {
my $self = shift;
my $userId = shift || $self->session->user->userId;
$self->session->db->write(
q{update inbox_messageState set repliedTo=1, isRead=1 where messageId=? and userId=?},
[$self->getId,$userId]
);
}
#-------------------------------------------------------------------
=head2 setStatus ( status,[ userId ] )
Sets the current status of the message
There are two levels of status for any inbox message:
Global Message Status - This is the status of the entire message and holds true for everyone who received the message. These status values are as follows:
pending - indicates that there is some action for one of the users who received this message to act on.
active - indicates that this is a message that requires no action by any users who received this message.
completed - indicates that the action that was required is now completed.
Individual Message Status - This is the status of the message for each individual who received it. If you send a message to a group, each person who received the message will be able to see the message in one of the following states:
unread - indicates that this message has not be read by the current user
read - indicates that this message has been read by the current user
replied - indicates that the user has replied to this message
It is important to note that there is one more status not listed here which is deleted. This is a special state which cannot be set through this method. You should use the setDeleted method in this class if you wish to delete a message for a user.
=head4 status
Status to mark the message
=head4 userId
The id of the user that completed this task. Defaults to the current user.
=cut
sub setStatus {
my $self = shift;
my $status = shift;
my $session = $self->session;
my $userId = shift || $session->user->userId;
unless ($status) {
$session->log->warn("No status passed in for message. Exit without update");
return undef;
}
unless($self->isValidStatus($status)) {
$self->session->log->warn("Invalid status $status passed in for message. Exit without update");
return undef;
}
if($status eq "completed") {
$self->setCompleted($userId);
return undef;
}
elsif($status eq "read") {
$self->setRead($userId);
}
elsif($status eq "unread") {
$self->setUnread($userId);
}
elsif($status eq "replied") {
$self->setReplied($userId);
}
#Only let completed stuff go back to pending
if ( $status eq "pending" && $self->{_properties}{status} eq "completed") {
$self->{_properties}{status} = "pending";
$self->{_inbox}{status} = "pending"
}
$self->session->db->setRow("inbox","messageId",$self->{_inbox});
return undef;
}
#-------------------------------------------------------------------
=head2 setUnread ( [ userId ] )
Marks a message unread.
=head4 userId
The id of the user that reads this message. Defaults to the current user.
=cut
sub setUnread {
my $self = shift;
my $userId = shift || $self->session->user->userId;
$self->session->db->write(
q{update inbox_messageState set isRead=0 where messageId=? and userId=?},
[$self->getId,$userId]
);
}
#-------------------------------------------------------------------
=head2 statusCodes ( session )
Returns a hash ref of valid status values. Can be called as a class or instance method:
WebGUI::Inbox::Message->statusCodes($session);
my $message = WebGUI::Inbox::Message->new($session, $messageId);
my $statusCodes = $inbox->statusCodes;
There are two levels of status for any inbox message:
Global Message Status - This is the status of the entire message and holds true for everyone who received the message. These status values are as follows:
pending - indicates that there is some action for one of the users who received this message to act on.
active - indicates that this is a message that requires no action by any users who received this message.
completed - indicates that the action that was required is now completed.
Individual Message Status - This is the status of the message for each individual who received it. If you send a message to a group, each person who received the message will be able to see the message in one of the following states:
unread - indicates that this message has not be read by the current user
read - indicates that this message has been read by the current user
replied - indicates that the user has replied to this message
It is important to note that there is one more status not listed here which is deleted. This is a special state and you should use the setDeleted method in this class if you wish to delete a message for a user.
=head4 session
The current session object.
=cut
sub statusCodes {
my $self = shift;
my $session = shift;
if(ref $self eq "WebGUI::Inbox::Message") {
$session = $self->session;
}
my $i18n = WebGUI::International->new($session);
return {
"active" => $i18n->get("inbox message status active"),
"pending" => $i18n->get(552),
"completed" => $i18n->get(350),
"unread" => $i18n->get("private message status unread"),
"read" => $i18n->get("private message status read"),
"replied" => $i18n->get("private message status replied"),
}
}
1;