package WebGUI::Inbox; =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::Inbox::Message; =head1 NAME Package WebGUI::Inbox; =head1 DESCRIPTION This class provides a message routing system, which is primarily used by WebGUI's workflow engine. =head1 SYNOPSIS use WebGUI::Inbox; =head1 METHODS These methods are available from this class: =cut #------------------------------------------------------------------- =head2 addMessage ( properties ) Adds a new message to the inbox. =head3 properties See WebGUI::Inbox::Message::create() for details. =cut sub addMessage { my $self = shift; return WebGUI::Inbox::Message->create($self->session, @_); } #------------------------------------------------------------------- =head2 addPrivateMessage ( properties[, userToSend] ) Adds a new private message to the inbox if the user accepts private messages. =head3 properties See WebGUI::Inbox::Message::addMessage() for details. =cut sub addPrivateMessage { my $self = shift; my $messageData = shift; my $isReply = shift; my $userId = $messageData->{userId}; my $sentBy = $messageData->{sentBy} || $self->session->user->userId; return undef unless $userId; my $u = WebGUI::User->new($self->session,$userId); return undef unless ($isReply || $u->acceptsPrivateMessages($sentBy)); return $self->addMessage($messageData); } #------------------------------------------------------------------- =head2 canRead ( messageId [, user] ) Returns whether or not a user can view the message passed in. =head3 message A WebGUI::Inbox::Message object =head3 user WebGUI::User object to test against. Defaults to the current user. =cut sub canRead { my $self = shift; my $message = shift; my $user = shift || $self->session->user; unless (ref $message eq "WebGUI::Inbox::Message") { $self->session->log->warn("Message passed in was either empty or not a valid WebGUI::Inbox::Message. Got: ".(ref $message)); return 0 } my $userId = $message->get("userId"); my $groupId = $message->get("groupId"); return ($user->userId eq $userId || (defined $groupId && $user->isInGroup($groupId))); } #------------------------------------------------------------------- =head2 DESTROY ( ) Deconstructor. =cut sub DESTROY { my $self = shift; undef $self; } #------------------------------------------------------------------- =head2 getMessage ( messageId [, userId] ) Returns a WebGUI::Inbox::Message object. =head3 messageId The id of the message to retrieve. =head3 userId The id of the user to retrieve the message for. Defaults to the current user. =cut sub getMessage { my $self = shift; my $messageId = shift; my $userId = shift; return WebGUI::Inbox::Message->new($self->session, $messageId, $userId); } #------------------------------------------------------------------- =head2 getNextMessage ( message [, userId] ) Returns the message that was send after the message passed in for the user =head3 message The message to find the next message for =head3 user The WebGUI::User object of the user to retrieve the message for. Defaults to the current user. =cut sub getNextMessage { my $self = shift; my $session = $self->session; my $baseMessage = shift; my $user = shift || $session->user; my $sql = $self->getMessageSql($user,{ whereClause => "ibox.dateStamp > ".$baseMessage->get("dateStamp"), sortBy => "ibox.dateStamp", sortDir => "asc", limit => 1 }); my $message = $self->session->db->quickHashRef($sql); return $self->getMessage($message->{messageId}); } #------------------------------------------------------------------- =head2 getPreviousMessage ( message [, userId] ) Returns the message that was sent before the message passed in for the user =head3 message The message to find the previous message for =head3 user The WebGUI::User object of the user to retrieve the message for. Defaults to the current user. =cut sub getPreviousMessage { my $self = shift; my $session = $self->session; my $baseMessage = shift; my $user = shift || $session->user; my $sql = $self->getMessageSql($user,{ whereClause => "ibox.dateStamp < ".$baseMessage->get("dateStamp"), sortBy => "ibox.dateStamp", sortDir => "desc", limit => 1 }); my $message = $self->session->db->quickHashRef($sql); return $self->getMessage($message->{messageId}); } #------------------------------------------------------------------- =head2 getMessagesForUser ( user [ , limit, page, sortBy ] ) Returns an array reference containing the most recent message objects for a given user. =head3 user A user object. =head3 limit An integer indicating the number of messages to fetch. Defaults to 50. =head3 page An integer indication the page to return. Defaults to 1 =head3 sortby The column to sort by =cut sub getMessagesForUser { my $self = shift; my $user = shift; my $perpage = shift || 50; my $page = shift || 1; my $sortBy = shift; my $p = $self->getMessagesPaginator( $user , { sortBy => $sortBy, sortDir => "desc", paginateAfter => $perpage, pageNumber => $page }); return $self->getMessagesOnPage($p); } #------------------------------------------------------------------- =head2 getMessagesOnPage ( paginator ) Returns an array ref of WebGUI::Inbox::Message objects created from the current page of data. =head3 paginator The id of the message to retrieve. =cut sub getMessagesOnPage { my $self = shift; my $p = shift; my @messages = (); unless (defined $p and ref $p eq "WebGUI::Paginator") { $self->session->log->warn("Paginator was not defined"); return []; } foreach my $row (@{$p->getPageData}) { push @messages, $self->getMessage( $row->{messageId} ); } return \@messages; } #------------------------------------------------------------------- =head2 getMessagesPaginator ( user [, properties ] ) Returns an reference to a WebGUI::Paginator object filled with all the messages in a user's inbox =head3 user A user object. =head3 properties Properties which can be set to determine how many rows are returned, etc =head4 sortBy Column to sort the inbox by. Valid values are subject, sentBy, and dateStamp. Defaults to dateStamp if value is invalid. Defaults to status="pending" DESC, dateStamp DESC if value not set. =head4 sortDir Direction to sort the results by. Defaults to desc. This only works if a sortBy value is set. =head4 baseUrl The URL of the current page including attributes. The page number will be appended to this in all links generated by the paginator. Defaults to $session->url->pge =head4 paginateAfter The number of rows to display per page. If left blank it defaults to 25. =head4 formVar Specify the form variable the paginator should use in its links. Defaults to "pn". =head4 pageNumber By default the page number will be determined by looking at $self->session->form->process("pn"). If that is empty the page number will be defaulted to "1". If you'd like to override the page number specify it here. =cut sub getMessagesPaginator { my $self = shift; my $session = $self->session; my $user = shift || $session->user; my $properties = shift; my $userId = $user->userId; my $sortBy = $properties->{sortBy}; my $sortDir = $properties->{sortDir} || "desc"; my $baseUrl = $properties->{baseUrl} || $session->url->page; my $paginateAfter = $properties->{paginateAfter}; my $formVar = $properties->{formVar}; my $pageNumber = $properties->{pageNumber}; #Make sure a valid sortBy is passed in if($sortBy && !WebGUI::Utility::isIn($sortBy,qw( subject sentBy dateStamp status ))) { $sortBy = q{dateStamp} } #Sort by fullname if user wants to sort by who sent the message if ($sortBy eq "sentBy") { $sortBy = q{fullName}; } elsif ($sortBy eq "status") { $sortBy = q{messageStatus}; } elsif($sortBy) { $sortBy = qq{ibox.$sortBy}; } else { $sortBy = q{messageStatus='pending' DESC, dateStamp DESC}; $sortDir = q{}; } my $sql = $self->getMessageSql($user, { user => $user, sortBy => $sortBy, sortDir => $sortDir }); #$session->log->warn($sql); my $p = WebGUI::Paginator->new( $session, $baseUrl, $paginateAfter, $formVar, $pageNumber ); $p->setDataByQuery($sql,undef,undef); return $p; } #------------------------------------------------------------------- =head2 getMessageSql ( user, properties ) Returns the SQL used to return the messages in a user's inbox. =head3 user WebGUI::User object of user to get messages for. Defaults to current user. =head3 properties Hash reference of properties =head4 sortBy Column to sort by. Valid columns are: ibox.messageId, ibox.subject, ibox.sentBy, ibox.dateStamp, ibox.status, messageStatus, fullName =head4 sortDir Direction to sort by =head4 whereClause A where clause to use =head4 limit Column =cut sub getMessageSql { my $self = shift; my $session = $self->session; my $user = shift || $session->user; my $props = shift || {}; my $userId = $user->userId; my $sortBy = $props->{sortBy}; my $sortDir = $props->{sortDir}; my $whereClause = $props->{whereClause}; my $limit = $props->{limit}; if($sortBy) { $sortBy = qq{ORDER BY $sortBy $sortDir}; } if($whereClause) { $whereClause = qq{WHERE $whereClause}; } if($limit) { $limit = qq{LIMIT $limit}; } my $messageLimit = 20_000; my $limitHalf = $messageLimit / 2; my $limitQuarter = $messageLimit / 4; my $userGroups = $session->db->quoteAndJoin( $user->getGroupIdsRecursive ); $userGroups = "''" if $userGroups eq ""; # for performance purposes don't use datasets larger than 20000 no matter how man messages are in the inbox my $sql = qq{ SELECT ibox.messageId, ibox.subject, ibox.sentBy, ibox.dateStamp, (IF(ibox.status = 'completed' or ibox.status = 'pending',ibox.status,IF(inbox_messageState.repliedTo,'replied',IF(inbox_messageState.isRead,'read','unread')))) as messageStatus, (IF(userProfileData.firstName != '' and userProfileData.firstName is not null and userProfileData.lastName !='' and userProfileData.lastName is not null, concat(userProfileData.firstName,' ',userProfileData.lastName),users.username)) as fullName FROM ( ( SELECT messageId, subject, sentBy, dateStamp, status FROM inbox WHERE userId = '$userId' order by dateStamp desc limit $limitHalf) UNION ( SELECT messageId, subject, sentBy, dateStamp, status FROM inbox WHERE groupId IN ( $userGroups ) order by dateStamp desc limit $limitHalf ) ) AS ibox JOIN inbox_messageState on inbox_messageState.messageId=ibox.messageId and inbox_messageState.userId='$userId' and inbox_messageState.deleted=0 LEFT JOIN users on users.userId=ibox.sentBy LEFT JOIN userProfileData on userProfileData.userId=ibox.sentBy $whereClause $sortBy $limit }; #$session->log->warn($sql); return $sql; } #------------------------------------------------------------------- =head2 getUnreadMessageCount ( [userId] ) Returns the number of unread messages for the user passed in =head3 userId user to get unread message count for. Defaults to current user. =cut sub getUnreadMessageCount { my $self = shift; my $session = $self->session; my $userId = shift || $session->user->userId; return $session->db->quickScalar( qq{select count(*) from inbox_messageState where userId=? and deleted=0 and isRead=0 }, [$userId] ); } #------------------------------------------------------------------- =head2 new ( session ) Constructor. =head3 session A reference to the current session. =cut sub new { my $class = shift; my $session = shift; bless {_session=>$session}, $class; } #------------------------------------------------------------------- =head2 session ( ) Returns a reference to the current session. =cut sub session { my $self = shift; return $self->{_session}; } 1;