<?php
/**
* @version	$Id: post_eh.php 16515 2017-01-20 14:12:04Z alex $
* @package	In-Bulletin
* @copyright	Copyright (C) 1997 - 2009 Intechnic. All rights reserved.
* @license      GNU/GPL
* In-Portal is Open Source software.
* This means that this software may have been modified pursuant
* the GNU General Public License, and as distributed it includes
* or is derivative of works licensed under the GNU General Public License
* or other free or open source software licenses.
* See http://www.in-portal.org/license for copyright notices and details.
*/

	defined('FULL_PATH') or die('restricted access!');

	class PostEventHandler extends kDBEventHandler {

		/**
		 * Checks topic-post modify and delete permissions
		 *
		 * @param kEvent $event
		 * @return bool
		 * @access public
		 */
		public function CheckPermission(kEvent $event)
		{
			$events = Array ('OnUpdate', 'OnDelete');

			if ( in_array($event->Name, $events) ) {
				return true;
			}

			return parent::CheckPermission($event);
		}

		/**
		 * Sets default values
		 *
		 * @param kEvent $event
		 * @return void
		 * @access protected
		 */
		protected function OnBeforeItemCreate(kEvent $event)
		{
			parent::OnBeforeItemCreate($event);

			/** @var kDBItem $object */
			$object = $event->getObject();

			$user_id = $this->Application->RecallVar('user_id');

			$now = adodb_mktime();

			$object->SetDBField('CreatedById', $user_id);
			$object->SetDBField('CreatedOn_date', $now);
			$object->SetDBField('CreatedOn_time', $now);

			$object->SetDBField('ModifiedById', $user_id);
			$object->SetDBField('Modified_date', $now);
			$object->SetDBField('Modified_time', $now);

			$object->SetDBField('IPAddress', $this->Application->getClientIp());

			$sql = 'SELECT Username
					FROM ' . TABLE_PREFIX . 'Users
					WHERE PortalUserId = ' . $user_id;
			$object->SetDBField('PosterAlias', $this->Conn->GetOne($sql));

			// set post options
			/** @var PostHelper $post_helper */
			$post_helper = $this->Application->recallObject('PostHelper');

			$options_map = $post_helper->getOptionsMap();
			$post_options = $object->GetDBField('Options');
			foreach ($options_map as $option_name => $field_name) {
				$option_value = $object->GetDBField($field_name);
				$post_helper->SetPostOption($option_name, $option_value, $post_options);
			}
			$object->SetDBField('Options', $post_options);

			$table_info = $object->getLinkedInfo($event->Special, true);
			$object->SetDBField($table_info['ForeignKey'], $table_info['ParentId']);
		}

		/**
		 * Checks if user has permission on post
		 *
		 * @param kEvent $event
		 * @param string $permissions
		 */
		function checkPostPermission($event, $permissions)
		{
			/** @var kDBItem $object */
			$object = $event->getObject();

			$sql = 'SELECT ci.CategoryId, p.CreatedById
					FROM '.$object->TableName.' p
					LEFT JOIN '.TABLE_PREFIX.'Topic t ON t.TopicId = p.TopicId
					LEFT JOIN '.TABLE_PREFIX.'CategoryItems ci ON ci.ItemResourceId = t.ResourceId AND ci.PrimaryCat = 1
					WHERE p.'.$object->IDField.' = '.$object->GetID();
			$post_info = $this->Conn->GetRow($sql);

			/** @var kPermissionsHelper $perm_helper */
			$perm_helper = $this->Application->recallObject('PermissionsHelper');

			$is_owner = $post_info['CreatedById'] == $this->Application->RecallVar('user_id');
			$params['permissions'] = 'TOPIC.REPLY.MODIFY|TOPIC.REPLY.OWNER.MODIFY';
			$params['cat_id'] = $post_info['CategoryId'];
			return $perm_helper->TagPermissionCheck($params, $is_owner);
		}

		/**
		 * Sets post options before post update
		 * Ensures, that only user with permission will update topic
		 *
		 * @param kEvent $event
		 * @return void
		 * @access protected
		 */
		protected function OnBeforeItemUpdate(kEvent $event)
		{
			parent::OnBeforeItemUpdate($event);

			/** @var kDBItem $object */
			$object = $event->getObject();

			$perm_status = $this->checkPostPermission($event, 'TOPIC.REPLY.MODIFY|TOPIC.REPLY.OWNER.MODIFY');
			if ( !$perm_status ) {
				$event->status = kEvent::erFAIL;
				return;
			}

			/** @var PostHelper $post_helper */
			$post_helper = $this->Application->recallObject('PostHelper');

			$options_map = $post_helper->getOptionsMap();
			$post_options = $object->GetDBField('Options');
			foreach ($options_map as $option_name => $field_name) {
				$option_value = $object->GetDBField($field_name);
				$post_helper->SetPostOption($option_name, $option_value, $post_options);
			}
			$object->SetDBField('Options', $post_options);
		}

		/**
		 * Notifies admin about post change
		 *
		 * @param kEvent $event
		 * @return void
		 * @access protected
		 */
		protected function OnAfterItemUpdate(kEvent $event)
		{
			parent::OnAfterItemUpdate($event);

			$this->Application->emailAdmin('POST.MODIFY');
		}

		/**
		 * Checks, that user can delete post
		 *
		 * @param kEvent $event
		 * @return void
		 * @access protected
		 */
		protected function OnBeforeItemDelete(kEvent $event)
		{
			parent::OnBeforeItemDelete($event);

			/** @var kDBItem $object */
			$object = $event->getObject();

			if ( !$this->checkPostPermission($event, 'TOPIC.REPLY.OWNER.DELETE|TOPIC.REPLY.DELETE') ) {
				$event->status = kEvent::erFAIL;
			}
		}

		/**
		 * Sets post options to virtual fields
		 *
		 * @param kEvent $event
		 * @return void
		 * @access protected
		 */
		protected function OnAfterItemLoad(kEvent $event)
		{
			parent::OnAfterItemLoad($event);

			/** @var kDBItem $object */
			$object = $event->getObject();

			/** @var PostHelper $post_helper */
			$post_helper = $this->Application->recallObject('PostHelper');

			$options_map = $post_helper->getOptionsMap();
			$post_options = $object->GetDBField('Options');

			foreach ($options_map as $option_name => $field_name) {
				$option_value = $post_helper->GetPostOption($option_name, $post_options);
				$object->SetDBField($field_name, (int)$option_value);
			}
		}

		/**
		 * Updates cached post counter in topic
		 *
		 * @param kEvent $event
		 * @return void
		 * @access protected
		 */
		protected function OnAfterItemCreate(kEvent $event)
		{
			parent::OnAfterItemCreate($event);

			/** @var kDBItem $object */
			$object = $event->getObject();

			$parent_prefix = $this->Application->getUnitOption($event->Prefix, 'ParentPrefix');

			/** @var kCatDBItem $main_object */
			$main_object = $this->Application->recallObject($parent_prefix);

			if ( $this->Application->LoggedIn() ) {
				// Update user posts counter.
				$user_posts = $this->Application->RecallPersistentVar('bb_posts');
				$this->Application->StorePersistentVar('bb_posts', $user_posts + 1);
			}

			/** @var PostHelper $post_helper */
			$post_helper = $this->Application->recallObject('PostHelper');

			$category_id = $this->Application->GetVar('m_cat_id');
			$post_helper->PropagateCategoryField($category_id, 'Modified', $object->GetDBField('CreatedOn'));

			if ( !$this->Application->isAdmin && $main_object->GetDBField('Posts') ) {
				// don't send any email events when in admin OR new topic just added (0 posts)

				$user_notified = false; // don't send POST.ADD event twice to same user (in case if owner adds new post)
				if ( $main_object->GetDBField('NotifyOwnerOnChanges') ) {
					$user_notified = $main_object->GetDBField('OwnerId');
					$this->Application->emailUser('POST.ADD', $user_notified);
				}

				$post_owner_id = $object->GetDBField('CreatedById');
				if ( ($post_owner_id > 0) && ($user_notified != $post_owner_id) ) {
					$this->Application->emailUser('POST.ADD', $post_owner_id);
				}

				$this->Application->emailAdmin('POST.ADD');
			}

			$post_helper->updateTodayPostsCount($main_object, $object->GetDBField('CreatedOn'), +1);
			$this->updateTopicInfo($event, $main_object);

			$topic_id = $object->GetDBField('TopicId');
			$posts_count = $post_helper->updatePostCount($topic_id, +1);
			$main_object->SetDBField('Posts', $posts_count);

			// auto-lock topic after N number of posts (if option enabled)
			$auto_lock = $this->Application->ConfigValue('AutoTopicLockPosts');

			if ( (int)$auto_lock > 0 ) {
				if ( $posts_count >= $auto_lock ) {
					// user has unlocked topic after $auto_lock and posts again -> ensure that topic will be locked again
					$this->Application->HandleEvent(new kEvent($parent_prefix . ':OnTopicLockToggle'));
				}
			}
		}

		/**
		 * Update last post info in topic
		 *
		 * @param kEvent $event
		 * @param kCatDBItem $main_object
		 */
		function updateTopicInfo($event, &$main_object)
		{
			/** @var kDBItem $object */
			$object = $event->getObject();

			$main_object->SetDBField('Modified_date', $object->GetDBField('Modified'));
			$main_object->SetDBField('Modified_time', $object->GetDBField('Modified'));

			$main_object->SetDBField('LastPostId', $object->GetID());

			$main_object->SetDBField('LastPostDate_date', $object->GetDBField('CreatedOn'));
			$main_object->SetDBField('LastPostDate_time', $object->GetDBField('CreatedOn'));

			$main_object->Update();
		}

		/**
		 * Goes to next_template after post creation
		 *
		 * @param kEvent $event
		 * @return void
		 * @access protected
		 */
		protected function OnCreate(kEvent $event)
		{
			parent::OnCreate($event);

			if ( $event->status == kEvent::erSUCCESS && !$this->Application->isAdmin ) {
				$event->SetRedirectParam('opener', 's');
				$event->redirect = $this->Application->GetVar('next_template');
			}
		}

		/**
		 * Goes to next_template after post editing
		 *
		 * @param kEvent $event
		 * @return void
		 * @access protected
		 */
		protected function OnUpdate(kEvent $event)
		{
			parent::OnUpdate($event);

			if ($event->status == kEvent::erSUCCESS && !$this->Application->isAdmin) {
				$event->SetRedirectParam('opener', 's');
				$event->redirect = $this->Application->GetVar('next_template');
				$event->SetRedirectParam('pass', 'm,bb');
			}
		}

		/**
		 * Moves reference to last post in topic, when it is deleted
		 *
		 * @param kEvent $event
		 * @return void
		 * @access protected
		 */
		protected function OnAfterItemDelete(kEvent $event)
		{
			parent::OnAfterItemDelete($event);

			/** @var kDBItem $object */
			$object = $event->getObject();

			$topic_id = $object->GetDBField('TopicId');
			if ( !$topic_id ) {
				// deleting post from non-existing topic
				return;
			}

			/** @var PostHelper $post_helper */
			$post_helper = $this->Application->recallObject('PostHelper');

			// update posts count in topic
			$post_helper->updatePostCount($topic_id, -1);

			// update post owner posts counter
			$sql = 'UPDATE ' . TABLE_PREFIX . 'UserPersistentSessionData
					SET VariableValue = IF (VariableValue > 0, VariableValue - 1, 0)
					WHERE (PortalUserId = ' . $object->GetDBField('CreatedById') . ') AND (VariableName = "bb_posts")';
			$this->Conn->Query($sql);


			/** @var kCatDBItem $main_object */
			$main_object = $this->Application->recallObject('bb.-item', null, Array ('skip_autoload' => true));

			$main_object->Load($topic_id);

			if ( !$main_object->isLoaded() ) {
				// this is topic deletion proccess, when all it's posts are deleted too
				return;
			}

			$post_helper->updateTodayPostsCount($main_object, $object->GetDBField('CreatedOn'), -1);

			if ( $main_object->GetDBField('LastPostId') == $object->GetID() ) {
				$sql = 'SELECT PostingId, CreatedOn
						FROM ' . $object->TableName . '
						WHERE TopicId = ' . $topic_id . '
						ORDER BY PostingId DESC';
				$last_post = $this->Conn->GetRow($sql);

				$fields_hash = Array (
					'LastPostId' => $last_post['PostingId'],
					'LastPostDate' => $last_post['CreatedOn'],
				);
				$this->Conn->doUpdate($fields_hash, $main_object->TableName, $main_object->IDField . ' = ' . $topic_id);
			}
		}

		/**
		 * Sets default values to posting options based on persistent session
		 *
		 * @param kEvent $event
		 * @return void
		 * @access protected
		 */
		protected function OnAfterConfigRead(kEvent $event)
		{
			parent::OnAfterConfigRead($event);

			if ( !$this->Application->LoggedIn() ) {
				return;
			}

			$virtual_fields = $this->Application->getUnitOption($event->Prefix, 'VirtualFields');
			$virtual_fields['DisableBBCodes']['default'] = (int)!$this->Application->RecallPersistentVar('bbcode');
			$virtual_fields['DisableSmileys']['default'] = (int)!$this->Application->RecallPersistentVar('smileys');
			$virtual_fields['ShowSignatures']['default'] = (int)$this->Application->RecallPersistentVar('show_sig');
			$this->Application->setUnitOption($event->Prefix, 'VirtualFields', $virtual_fields);
		}

		/**
		 * Deletes items & preserves clean env
		 *
		 * @param kEvent $event
		 * @return void
		 * @access protected
		 */
		protected function OnDelete(kEvent $event)
		{
			parent::OnDelete($event);

			if ( $event->status == kEvent::erSUCCESS && !$this->Application->isAdmin ) {
				$parent_prefix = $this->Application->getUnitOption($event->Prefix, 'ParentPrefix');
				$event->SetRedirectParam('pass', 'm,' . $parent_prefix);
			}
		}

		/**
		 * Prepares new reply form
		 *
		 * @param kEvent $event
		 * @return void
		 * @access protected
		 */
		protected function OnNew(kEvent $event)
		{
			parent::OnNew($event);

			$reply_to = $this->Application->GetVar('reply_to');

			if ( $reply_to > 0 ) {
				/** @var kDBItem $object */
				$object = $event->getObject();

				/** @var kDBItem $source_post */
				$source_post = $this->Application->recallObject($event->Prefix . '.-item', null, Array ('skip_autoload' => true));

				$source_post->Load($reply_to);

				$object->SetDBField('Subject', 'Re: ' . $source_post->GetDBField('Subject'));
				$object->SetDBField('PostingText', '[quote id=' . $reply_to . ']' . $source_post->GetDBField('PostingText') . '[/quote]');
			}
		}
	}
