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