837e15053aa3ca5869920003b9dbf9d3037d7dd5
[GitHub/WoltLab/com.woltlab.wcf.conversation.git] / files / lib / system / conversation / ConversationHandler.class.php
1 <?php
2 namespace wcf\system\conversation;
3 use wcf\system\database\util\PreparedStatementConditionBuilder;
4 use wcf\system\exception\NamedUserException;
5 use wcf\system\exception\PermissionDeniedException;
6 use wcf\system\flood\FloodControl;
7 use wcf\system\user\storage\UserStorageHandler;
8 use wcf\system\SingletonFactory;
9 use wcf\system\WCF;
10
11 /**
12 * Handles the number of conversations and unread conversations of the active user.
13 *
14 * @author Marcel Werk
15 * @copyright 2001-2019 WoltLab GmbH
16 * @license GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
17 * @package WoltLabSuite\Core\System\Conversation
18 */
19 class ConversationHandler extends SingletonFactory {
20 /**
21 * number of unread conversations
22 * @var integer[]
23 */
24 protected $unreadConversationCount = [];
25
26 /**
27 * number of conversations
28 * @var integer[]
29 */
30 protected $conversationCount = [];
31
32 /**
33 * Returns the number of unread conversations for given user.
34 *
35 * @param integer $userID
36 * @param boolean $skipCache
37 * @return integer
38 */
39 public function getUnreadConversationCount($userID = null, $skipCache = false) {
40 if ($userID === null) $userID = WCF::getUser()->userID;
41
42 if (!isset($this->unreadConversationCount[$userID]) || $skipCache) {
43 $this->unreadConversationCount[$userID] = 0;
44
45 // load storage data
46 UserStorageHandler::getInstance()->loadStorage([$userID]);
47
48 // get ids
49 $data = UserStorageHandler::getInstance()->getStorage([$userID], 'unreadConversationCount');
50
51 // cache does not exist or is outdated
52 if ($data[$userID] === null || $skipCache) {
53 $conditionBuilder = new PreparedStatementConditionBuilder();
54 $conditionBuilder->add('conversation.conversationID = conversation_to_user.conversationID');
55 $conditionBuilder->add('conversation_to_user.participantID = ?', [$userID]);
56 $conditionBuilder->add('conversation_to_user.hideConversation = 0');
57 $conditionBuilder->add('conversation_to_user.lastVisitTime < conversation.lastPostTime');
58 $conditionBuilder->add('conversation_to_user.leftAt = 0');
59
60 $sql = "SELECT COUNT(*) AS count
61 FROM wcf".WCF_N."_conversation_to_user conversation_to_user,
62 wcf".WCF_N."_conversation conversation
63 ".$conditionBuilder;
64 $statement = WCF::getDB()->prepareStatement($sql);
65 $statement->execute($conditionBuilder->getParameters());
66 $row = $statement->fetchArray();
67 $this->unreadConversationCount[$userID] = $row['count'];
68
69 // update storage data
70 UserStorageHandler::getInstance()->update($userID, 'unreadConversationCount', serialize($this->unreadConversationCount[$userID]));
71 }
72 else {
73 $this->unreadConversationCount[$userID] = unserialize($data[$userID]);
74 }
75 }
76
77 return $this->unreadConversationCount[$userID];
78 }
79
80 /**
81 * Returns the number of conversations for given user.
82 *
83 * @param integer $userID
84 * @return integer
85 */
86 public function getConversationCount($userID = null) {
87 if ($userID === null) $userID = WCF::getUser()->userID;
88
89 if (!isset($this->conversationCount[$userID])) {
90 $this->conversationCount[$userID] = 0;
91
92 // load storage data
93 UserStorageHandler::getInstance()->loadStorage([$userID]);
94
95 // get ids
96 $data = UserStorageHandler::getInstance()->getStorage([$userID], 'conversationCount');
97
98 // cache does not exist or is outdated
99 if ($data[$userID] === null) {
100 $conditionBuilder1 = new PreparedStatementConditionBuilder();
101 $conditionBuilder1->add('conversation_to_user.participantID = ?', [$userID]);
102 $conditionBuilder1->add('conversation_to_user.hideConversation IN (0,1)');
103 $conditionBuilder2 = new PreparedStatementConditionBuilder();
104 $conditionBuilder2->add('conversation.userID = ?', [$userID]);
105 $conditionBuilder2->add('conversation.isDraft = 1');
106
107 $sql = "SELECT (SELECT COUNT(*)
108 FROM wcf".WCF_N."_conversation_to_user conversation_to_user
109 ".$conditionBuilder1->__toString().")
110 +
111 (SELECT COUNT(*)
112 FROM wcf".WCF_N."_conversation conversation
113 ".$conditionBuilder2->__toString().") AS count";
114 $statement = WCF::getDB()->prepareStatement($sql);
115 $statement->execute(array_merge($conditionBuilder1->getParameters(), $conditionBuilder2->getParameters()));
116 $row = $statement->fetchArray();
117 $this->conversationCount[$userID] = $row['count'];
118
119 // update storage data
120 UserStorageHandler::getInstance()->update($userID, 'conversationCount', serialize($this->conversationCount[$userID]));
121 }
122 else {
123 $this->conversationCount[$userID] = unserialize($data[$userID]);
124 }
125 }
126
127 return $this->conversationCount[$userID];
128 }
129
130 /**
131 * Enforces the flood control.
132 */
133 public function enforceFloodControl() {
134 $limit = WCF::getSession()->getPermission('user.conversation.maxStartedConversationsPer24Hours');
135 if ($limit == -1) {
136 return;
137 }
138 else if ($limit == 0) {
139 // `0` is not a valid value, but the interface logic does not permit and exclusion
140 // while also allowing the special value `-1`. Therefore, `0` behaves like the
141 // 'canStartConversation' permission added in WoltLab Suite 5.2.
142 throw new PermissionDeniedException();
143 }
144
145 $count = FloodControl::getInstance()->countContent('com.woltlab.wcf.conversation', new \DateInterval('P1D'));
146 if ($count['count'] >= $limit) {
147 throw new NamedUserException(WCF::getLanguage()->getDynamicVariable('wcf.conversation.error.floodControl', [
148 'limit' => $count['count'],
149 'notBefore' => $count['earliestTime'] + 86400,
150 ]));
151 }
152 }
153 }