From 6e948d17558d8b910c19dc2c696d997feb96ff2e Mon Sep 17 00:00:00 2001 From: Jeff Madsen Date: Tue, 5 Jul 2011 11:22:22 +0900 Subject: [PATCH] main messaging library --- application/config/mahana.php | 35 ++ application/language/english/mahana_lang.php | 17 + application/libraries/Mahana_messaging.php | 221 ++++++++++++ application/models/mahana_model.php | 334 +++++++++++++++++++ mahana.sql | 31 ++ 5 files changed, 638 insertions(+) create mode 100644 application/config/mahana.php create mode 100644 application/language/english/mahana_lang.php create mode 100644 application/libraries/Mahana_messaging.php create mode 100644 application/models/mahana_model.php create mode 100644 mahana.sql diff --git a/application/config/mahana.php b/application/config/mahana.php new file mode 100644 index 0000000..9d9fccf --- /dev/null +++ b/application/config/mahana.php @@ -0,0 +1,35 @@ +ci =& get_instance(); + require_once(APPPATH.'config/mahana.php'); + + $this->ci->load->model('mahana_model'); + $this->ci->load->helper('language'); + $this->ci->lang->load('mahana'); + + + } + + /* + function get_message() - will return a single message, including the status for specified user. + @parameters - $msg_id REQUIRED, $user_id REQUIRED + */ + + function get_message($msg_id, $user_id) + { + $status = array('err'=>1, 'code'=>MSG_ERR_GENERAL, 'msg'=>lang('mahana_'.MSG_ERR_GENERAL)); + + if (empty($msg_id)){$status = array('err'=>1, 'code'=>MSG_ERR_INVALID_MSG_ID, 'msg'=>lang('mahana_'.MSG_ERR_INVALID_MSG_ID));return $status;} + if (empty($user_id)){$status = array('err'=>1, 'code'=>MSG_ERR_INVALID_USER_ID, 'msg'=>lang('mahana_'.MSG_ERR_INVALID_USER_ID));return $status;} + + if ($message = $this->ci->mahana_model->get_message($msg_id, $user_id)) + { + return $status = array('err'=>0, 'code'=>MSG_SUCCESS, 'msg'=>lang('mahana_'.MSG_SUCCESS), 'retval'=>$message); + } + return $status; + } + + + /* + function get_full_thread() - will return a entire thread, including the status for specified user. + + @parameters - $thread_id REQUIRED, $user_id REQUIRED, $order_by OPTIONAL + - $full_thread - if true, user will also see messages from thread posted BEFORE user became participant + */ + + function get_full_thread($thread_id, $user_id, $full_thread=false, $order_by='asc') + { + $status = array('err'=>1, 'code'=>MSG_ERR_GENERAL, 'msg'=>lang('mahana_'.MSG_ERR_GENERAL)); + + if (empty($thread_id)){$status = array('err'=>1, 'code'=>MSG_ERR_INVALID_THREAD_ID, 'msg'=>lang('mahana_'.MSG_ERR_INVALID_THREAD_ID));return $status;} + if (empty($user_id)){$status = array('err'=>1, 'code'=>MSG_ERR_INVALID_USER_ID, 'msg'=>lang('mahana_'.MSG_ERR_INVALID_USER_ID));return $status;} + + if ($message = $this->ci->mahana_model->get_full_thread($thread_id, $user_id, $full_thread, $order_by)) + { + return $status = array('err'=>0, 'code'=>MSG_SUCCESS, 'msg'=>lang('mahana_'.MSG_SUCCESS), 'retval'=>$message); + } + return $status; + } + + /* + function get_all_threads() - will return all threads for user, including the status for specified user. + + @parameters - $user_id REQUIRED, $order_by OPTIONAL + - $full_thread - if true, user will also see messages from thread posted BEFORE user became participant + */ + + function get_all_threads($user_id, $full_thread=false, $order_by='asc') + { + $status = array('err'=>1, 'code'=>MSG_ERR_GENERAL, 'msg'=>lang('mahana_'.MSG_ERR_GENERAL)); + + if (empty($user_id)){$status = array('err'=>1, 'code'=>MSG_ERR_INVALID_USER_ID, 'msg'=>lang('mahana_'.MSG_ERR_INVALID_USER_ID));return $status;} + + if ($message = $this->ci->mahana_model->get_all_threads($user_id, $full_thread, $order_by)) + { + return $status = array('err'=>0, 'code'=>MSG_SUCCESS, 'msg'=>lang('mahana_'.MSG_SUCCESS), 'retval'=>$message); + } + return $status; + } + + + /* + function update_message_status() - will change status on message for particular user + + @parameters - $msg_id REQUIRED, $user_id REQUIRED, $status_id REQUIRED + - $status_id should come from config/mahana.php list of constants + */ + function update_message_status($msg_id, $user_id, $status_id ) + { + $status = array('err'=>1, 'code'=>MSG_ERR_GENERAL, 'msg'=>lang('mahana_'.MSG_ERR_GENERAL)); + + if (empty($msg_id)){$status = array('err'=>1, 'code'=>MSG_ERR_INVALID_MSG_ID, 'msg'=>lang('mahana_'.MSG_ERR_INVALID_MSG_ID));return $status;} + if (empty($user_id)){$status = array('err'=>1, 'code'=>MSG_ERR_INVALID_USER_ID, 'msg'=>lang('mahana_'.MSG_ERR_INVALID_USER_ID));return $status;} + if (empty($status_id)){$status = array('err'=>1, 'code'=>MSG_ERR_INVALID_STATUS_ID, 'msg'=>lang('mahana_'.MSG_ERR_INVALID_STATUS_ID));return $status;} + + if ($this->ci->mahana_model->update_message_status($msg_id, $user_id, $status_id )) + { + $status = array('err'=>0, 'code'=>MSG_SUCCESS, 'msg'=>lang('mahana_'.MSG_STATUS_UPDATE)); + } + return $status; + } + + /* + function add_participant() - adds user to existing thread + + @parameters - $thread_id REQUIRED, $user_id REQUIRED + */ + function add_participant($thread_id, $user_id) + { + $status = array('err'=>1, 'code'=>MSG_ERR_GENERAL, 'msg'=>lang('mahana_'.MSG_ERR_GENERAL)); + + if (empty($thread_id)){$status = array('err'=>1, 'code'=>MSG_ERR_INVALID_THREAD_ID, 'msg'=>lang('mahana_'.MSG_ERR_INVALID_THREAD_ID));return $status;} + if (empty($user_id)){$status = array('err'=>1, 'code'=>MSG_ERR_INVALID_USER_ID, 'msg'=>lang('mahana_'.MSG_ERR_INVALID_USER_ID));return $status;} + + if (!$this->ci->mahana_model->valid_new_participant($thread_id, $user_id)) + { + $status = array('err'=>1, 'code'=>1, 'msg'=>lang('mahana_'.MSG_ERR_PARTICIPANT_EXISTS)); + return $status; + } + + if (!$this->ci->mahana_model->application_user($user_id)) + { + $status = array('err'=>1, 'code'=>1, 'msg'=>lang('mahana_'.MSG_ERR_PARTICIPANT_NONSYSTEM)); + return $status; + } + + if ($this->ci->mahana_model->add_participant($thread_id, $user_id )) + { + $status = array('err'=>0, 'code'=>MSG_SUCCESS, 'msg'=>lang('mahana_'.MSG_PARTICIPANT_ADDED)); + } + return $status; + } + + /* + function remove_participant() - removes user from existing thread + + @parameters - $thread_id REQUIRED, $user_id REQUIRED + */ + function remove_participant($thread_id, $user_id) + { + $status = array('err'=>1, 'code'=>MSG_ERR_GENERAL, 'msg'=>lang('mahana_'.MSG_ERR_GENERAL)); + + if (empty($thread_id)){$status = array('err'=>1, 'code'=>MSG_ERR_INVALID_THREAD_ID, 'msg'=>lang('mahana_'.MSG_ERR_INVALID_THREAD_ID));return $status;} + if (empty($user_id)){$status = array('err'=>1, 'code'=>MSG_ERR_INVALID_USER_ID, 'msg'=>lang('mahana_'.MSG_ERR_INVALID_USER_ID));return $status;} + + if ($this->ci->mahana_model->remove_participant($thread_id, $user_id )) + { + $status = array('err'=>0, 'code'=>MSG_SUCCESS, 'msg'=>lang('mahana_'.MSG_PARTICIPANT_REMOVED)); + } + return $status; + } + + /* + function send_new_message() - sends new internal message. This function will create a new thread + + @parameters - $sender_id REQUIRED, $recipients REQUIRED + - $recipients may be either a single integer or an array of integers, representing user_ids + */ + function send_new_message($sender_id, $recipients, $subject='', $body='', $priority=PRIORITY_NORMAL){ + $status = array('err'=>1, 'code'=>MSG_ERR_GENERAL, 'msg'=>lang('mahana_'.MSG_ERR_GENERAL)); + + if (empty($sender_id)){$status = array('err'=>1, 'code'=>MSG_ERR_INVALID_SENDER_ID, 'msg'=>lang('mahana_'.MSG_ERR_INVALID_SENDER_ID));return $status;} + if (empty($recipients)){$status = array('err'=>1, 'code'=>MSG_ERR_INVALID_RECIPIENTS, 'msg'=>lang('mahana_'.MSG_ERR_INVALID_RECIPIENTS));return $status;} + + if ($this->ci->mahana_model->send_new_message($sender_id, $recipients, $subject, $body, $priority)) + { + $status = array('err'=>0, 'code'=>MSG_SUCCESS, 'msg'=>lang('mahana_'.MSG_MESSAGE_SENT)); + } + return $status; + } + + /* + function reply_to_message() - replies to internal message. This function will NOT create a new thread or participant list + + @parameters - $sender_id REQUIRED, $msg_id REQUIRED + */ + function reply_to_message($msg_id, $sender_id, $subject='', $body='', $priority=PRIORITY_NORMAL) + { + $status = array('err'=>1, 'code'=>MSG_ERR_GENERAL, 'msg'=>lang('mahana_'.MSG_ERR_GENERAL)); + + if (empty($sender_id)){$status = array('err'=>1, 'code'=>MSG_ERR_INVALID_SENDER_ID, 'msg'=>lang('mahana_'.MSG_ERR_INVALID_SENDER_ID));return $status;} + if (empty($msg_id)){$status = array('err'=>1, 'code'=>MSG_ERR_INVALID_MSG_ID, 'msg'=>lang('mahana_'.MSG_ERR_INVALID_MSG_ID));return $status;} + + if ($this->ci->mahana_model->reply_to_message($msg_id, $sender_id, $body, $priority)) + { + $status = array('err'=>0, 'code'=>MSG_SUCCESS, 'msg'=>lang('mahana_'.MSG_MESSAGE_SENT)); + } + return $status; + } + + /* + function get_participant_list() - returns list of participants on given thread. If sender_id set, sender_id will be left off list + + @parameters - $sender_id REQUIRED, $thread_id REQUIRED + */ + function get_participant_list($thread_id, $sender_id=0) + { + $status = array('err'=>1, 'code'=>MSG_ERR_GENERAL, 'msg'=>lang('mahana_'.MSG_ERR_GENERAL)); + + if (empty($thread_id)){$status = array('err'=>1, 'code'=>MSG_ERR_INVALID_THREAD_ID, 'msg'=>lang('mahana_'.MSG_ERR_INVALID_THREAD_ID));return $status;} + + if ($participants = $this->ci->mahana_model-> get_participant_list($thread_id, $sender_id)) + { + $status = array('err'=>0, 'code'=>MSG_SUCCESS, 'msg'=>lang('mahana_'.MSG_SUCCESS) ,'retval'=>$participants); + } + return $status; + } + +} \ No newline at end of file diff --git a/application/models/mahana_model.php b/application/models/mahana_model.php new file mode 100644 index 0000000..34c81a5 --- /dev/null +++ b/application/models/mahana_model.php @@ -0,0 +1,334 @@ +db->trans_start(); + + $thread_id = $this->_insert_thread($subject); + if ($this->db->trans_status() === false) + { + $this->db->trans_rollback(); + return false; + } + + $msg_id = $this->_insert_message($thread_id, $sender_id, $body, $priority); + if ($this->db->trans_status() === false) + { + $this->db->trans_rollback(); + return false; + } + + //create batch inserts + $participants[] = array('thread_id'=>$thread_id,'user_id'=> $sender_id); + $statuses[] = array('message_id'=>$msg_id, 'user_id'=> $sender_id,'status'=> MSG_STATUS_READ); + + if (!is_array($recipients)) + { + $participants[] = array('thread_id'=>$thread_id,'user_id'=>$recipients); + $statuses[] = array('message_id'=>$msg_id, 'user_id'=>$recipients, 'status'=>MSG_STATUS_UNREAD); + } + else + { + foreach ($recipients as $recipient) + { + $participants[] = array('thread_id'=>$thread_id,'user_id'=>$recipient); + $statuses[] = array('message_id'=>$msg_id, 'user_id'=>$recipient, 'status'=>MSG_STATUS_UNREAD); + } + } + $this->_insert_participants($participants); + if ($this->db->trans_status() === false) + { + $this->db->trans_rollback(); + return false; + } + + $this->_insert_statuses($statuses); + if ($this->db->trans_status() === false) + { + $this->db->trans_rollback(); + return false; + } + + $this->db->trans_complete(); + return true; + } + + //reply to message + function reply_to_message($reply_msg_id, $sender_id, $body, $priority) + { + $this->db->trans_start(); + + //get the thread id to keep messages together + if (!($thread_id = $this->_get_thread_id_from_message($reply_msg_id))) + { + return false; + } + + //add this message + $msg_id = $this->_insert_message($thread_id, $sender_id, $body, $priority); + if ($this->db->trans_status() === false) + { + $this->db->trans_rollback(); + return false; + } + + if ($recipients = $this->_get_thread_participants($thread_id, $sender_id)) + { + $statuses[] = array('message_id'=>$msg_id, 'user_id'=> $sender_id,'status'=> MSG_STATUS_READ); + foreach ($recipients as $recipient) + { + $statuses[] = array('message_id'=>$msg_id, 'user_id'=>$recipient['user_id'], 'status'=>MSG_STATUS_UNREAD); + } + $this->_insert_statuses($statuses); + if ($this->db->trans_status() === false) + { + $this->db->trans_rollback(); + return false; + } + } + + $this->db->trans_complete(); + return true; + } + + //get a single message + function get_message($msg_id, $user_id) + { + $sql = 'SELECT m.*, s.status, t.subject, '.USER_TABLE_USERNAME . + ' FROM msg_messages m ' . + ' JOIN msg_threads t ON (m.thread_id = t.id) ' . + ' JOIN ' .USER_TABLE_TABLENAME. ' ON ('.USER_TABLE_ID.' = m.sender_id) '. + ' JOIN msg_status s ON (s.message_id = m.id AND s.user_id = ? ) ' . + ' WHERE m.id = ? ' ; + + $query = $this->db->query($sql, array($user_id, $msg_id)); + return $query->result_array(); + } + + //get full thread + function get_full_thread($thread_id, $user_id, $full_thread = false, $order_by='asc'){ + $sql = 'SELECT m.*, s.status, t.subject, '.USER_TABLE_USERNAME . + ' FROM msg_participants p ' . + ' JOIN msg_threads t ON (t.id = p.thread_id) ' . + ' JOIN msg_messages m ON (m.thread_id = t.id) ' . + ' JOIN ' .USER_TABLE_TABLENAME. ' ON ('.USER_TABLE_ID.' = m.sender_id) '. + ' JOIN msg_status s ON (s.message_id = m.id AND s.user_id = ? ) ' . + ' WHERE p.user_id = ? ' . + ' AND p.thread_id = ? '; + if (!$full_thread) + { + $sql .= ' AND m.cdate >= p.cdate'; + } + $sql .= ' ORDER BY m.cdate '.$order_by; + + $query = $this->db->query($sql, array($user_id, $user_id, $thread_id)); //echo $this->db->last_query(); + return $query->result_array(); + } + + //get all threads + function get_all_threads($user_id, $full_thread = false, $order_by='asc'){ + $sql = 'SELECT m.*, s.status, t.subject, '.USER_TABLE_USERNAME . + ' FROM msg_participants p ' . + ' JOIN msg_threads t ON (t.id = p.thread_id) ' . + ' JOIN msg_messages m ON (m.thread_id = t.id) ' . + ' JOIN ' .USER_TABLE_TABLENAME. ' ON ('.USER_TABLE_ID.' = m.sender_id) '. + ' JOIN msg_status s ON (s.message_id = m.id AND s.user_id = ? ) ' . + ' WHERE p.user_id = ? ' ; + if (!$full_thread) + { + $sql .= ' AND m.cdate >= p.cdate'; + } + $sql .= ' ORDER BY t.id '.$order_by. ', m.cdate '.$order_by; + + $query = $this->db->query($sql, array($user_id, $user_id)); + return $query->result_array(); + } + + + //change message status + function update_message_status($msg_id, $user_id, $status_id ) + { + $this->db->where(array('message_id'=>$msg_id, 'user_id'=>$user_id )); + $this->db->update('msg_status', array('status'=>$status_id )); + return $this->db->affected_rows(); + } + + + //add participant + function add_participant($thread_id, $user_id) + { + $this->db->trans_start(); + + $participants[] = array('thread_id'=>$thread_id,'user_id'=>$user_id); + $this->_insert_participants($participants); + if ($this->db->trans_status() === false) + { + $this->db->trans_rollback(); + return false; + } + + //get messages by thread + $messages = $this->_get_messages_by_thread_id($thread_id); + + foreach ($messages as $message) + { + $statuses[] = array('message_id'=>$message['id'], 'user_id'=>$user_id, 'status'=>MSG_STATUS_UNREAD); + } + + $this->_insert_statuses($statuses); + if ($this->db->trans_status() === false) + { + $this->db->trans_rollback(); + return false; + } + + $this->db->trans_complete(); + return true; + } + + function remove_participant($thread_id, $user_id) + { + $this->db->trans_start(); + + $return = $this->_delete_participant($thread_id, $user_id); + if (($return === false) || $this->db->trans_status() === false) + { + $this->db->trans_rollback(); + return false; + } + + $this->_delete_statuses($thread_id, $user_id); + if ($this->db->trans_status() === false) + { + $this->db->trans_rollback(); + return false; + } + + $this->db->trans_complete(); + return true; + } + + // because of CodeIgniter's DB Class return style, it is safer to check for uniqueness first + function valid_new_participant($thread_id, $user_id) + { + $sql = 'SELECT COUNT(*) AS count ' . + ' FROM msg_participants p ' . + ' WHERE p.thread_id = ? ' . + ' AND p.user_id = ? '; + $query = $this->db->query($sql, array($thread_id, $user_id)); + if ($query->row()->count) + { + return false; + } + return true; + } + + function application_user($user_id) + { + $sql = 'SELECT COUNT(*) AS count ' . + ' FROM ' . USER_TABLE_TABLENAME . + ' WHERE ' . USER_TABLE_ID . ' = ?' ; + $query = $this->db->query($sql, array($user_id)); + if ($query->row()->count) + { + return true; + } + return false; + } + + function get_participant_list($thread_id, $sender_id =0) + { + if ($results = $this->_get_thread_participants($thread_id, $sender_id)) { + return $results; + } + return false; + } + + + // + //***** private functions *****// + // + + function _insert_thread($subject) + { + $insert_id = $this->db->insert('msg_threads', array('subject'=>$subject)); + return $this->db->insert_id(); + } + + function _insert_message($thread_id, $sender_id, $body, $priority) + { + $insert['thread_id'] = $thread_id; + $insert['sender_id'] = $sender_id; + $insert['body'] = $body; + $insert['priority'] = $priority; + + $insert_id = $this->db->insert('msg_messages', $insert); + return $this->db->insert_id(); + } + + function _insert_participants($participants) + { + return $this->db->insert_batch('msg_participants', $participants); + } + + function _insert_statuses($statuses) + { + return $this->db->insert_batch('msg_status', $statuses); + } + + function _get_thread_id_from_message($msg_id){ + $query = $this->db->select('thread_id')->get_where('msg_messages', array('id' => $msg_id)); + if ($query->num_rows()){ + return $query->row()->thread_id; + } + return 0; + } + + function _get_messages_by_thread_id($thread_id) + { + $query = $this->db->get_where('msg_messages', array('thread_id' => $thread_id)); + return $query->result_array(); + } + + + function _get_thread_participants($thread_id, $sender_id=0) + { + $array['thread_id'] = $thread_id; + if ($sender_id) //if $sender_id 0, no one to exclude + { + $array['user_id != '] = $sender_id; + } + + $this->db->select('user_id, '.USER_TABLE_USERNAME, false); + $this->db->join(USER_TABLE_TABLENAME,'msg_participants.user_id ='.USER_TABLE_ID); + $query = $this->db->get_where('msg_participants', $array); + + return $query->result_array(); + } + + function _delete_participant($thread_id, $user_id) + { + $this->db->delete('msg_participants', array('thread_id'=>$thread_id, 'user_id'=>$user_id)); + if ($this->db->affected_rows() > 0) + { + return true; + } + return false; + } + + function _delete_statuses($thread_id, $user_id) + { + $sql = 'DELETE s FROM msg_status s ' . + ' JOIN msg_messages m ON (m.id = s.message_id) ' . + ' WHERE m.thread_id = ? ' . + ' AND s.user_id = ? '; + $query = $this->db->query($sql, array($thread_id, $user_id)); + return true; + } +} + +/* end of file mahana_model.php */ \ No newline at end of file diff --git a/mahana.sql b/mahana.sql new file mode 100644 index 0000000..61314d1 --- /dev/null +++ b/mahana.sql @@ -0,0 +1,31 @@ +SET SQL_MODE="NO_AUTO_VALUE_ON_ZERO"; + +CREATE TABLE `msg_messages` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `thread_id` int(11) NOT NULL, + `body` text NOT NULL, + `priority` int(2) NOT NULL DEFAULT '0', + `sender_id` int(11) NOT NULL, + `cdate` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + PRIMARY KEY (`id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8; + +CREATE TABLE `msg_participants` ( + `user_id` int(11) NOT NULL, + `thread_id` int(11) NOT NULL, + `cdate` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + PRIMARY KEY (`user_id`,`thread_id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8; + +CREATE TABLE `msg_status` ( + `message_id` int(11) NOT NULL, + `user_id` int(11) NOT NULL, + `status` int(2) NOT NULL, + PRIMARY KEY (`message_id`,`user_id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8; + +CREATE TABLE `msg_threads` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `subject` text, + PRIMARY KEY (`id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8;