root/trunk/Phergie/Plugin/Seen.php @ 290

Revision 290, 14.6 KB (checked in by tobias382, 5 years ago)

Fixes #67 Applied patch for limiting quote to the current channel

Line 
1<?php
2
3/**
4 * Handles requests for logged data pertaining to the ast actions taken or
5 * messages sent by a given user or posts sent containing a given search phrase.
6 */
7class Phergie_Plugin_Seen extends Phergie_Plugin_Abstract_Command
8{
9    /**
10     * Prepared statement for searching for the last logged action in which a
11     * particular user was mentioned
12     *
13     * @var PDOStatement
14     */
15    protected $search;
16
17    /**
18     * Prepared statement for searching for the last logged action originating
19     * from a particular user
20     *
21     * @var PDOStatement
22     */
23    protected $seen;
24
25    /**
26     * Prepared statement for searching for the last logged message originating
27     * from a particular user
28     *
29     * @var PDOStatement
30     */
31    protected $heard;
32
33    /**
34     * Prepared statement for searching for one or more time ranges during
35     * which a particular user is most likely to be present in a particular
36     * channel
37     *
38     * @var PDOStatement
39     */
40    protected $willsee;
41
42    /**
43     * Prepared statement for searching for a random logged message originating
44     * from a particular user
45     *
46     * @var PDOStatement
47     */
48    protected $quote;
49
50    /**
51     * Action descriptions corresponding to event constants
52     *
53     * @var array
54     */
55    protected $actions = array(
56        Phergie_Plugin_Logging::JOIN    => 'joining this channel',
57        Phergie_Plugin_Logging::PART    => 'leaving this channel because',
58        Phergie_Plugin_Logging::QUIT    => 'quitting',
59        Phergie_Plugin_Logging::PRIVMSG => 'saying',
60        Phergie_Plugin_Logging::ACTION  => 'doing the action',
61        Phergie_Plugin_Logging::NICK    => 'changing nick to',
62        Phergie_Plugin_Logging::KICK    => 'being kicked off because',
63        Phergie_Plugin_Logging::QUERY   => 'private messaging',
64    );
65
66    /**
67     * Initializes the database.
68     *
69     * @return void
70     */
71    public function onConnect()
72    {
73        try {
74            if (!Phergie_Plugin_Logging::databaseExists()) {
75                return;
76            }
77
78            // Initialize prepared statements for common operations
79            $this->search = Phergie_Plugin_Logging::prepare('
80                SELECT tstamp, type, chan, nick, message
81                FROM logs
82                WHERE nick LIKE :phrase ESCAPE "\\"
83                OR message LIKE :phrase ESCAPE "\\"
84                AND type NOT IN (:type, ' . Phergie_Plugin_Logging::MODE . ', ' . Phergie_Plugin_Logging::TOPIC . ')
85                ORDER BY tstamp DESC
86                LIMIT 1,:limit
87            ');
88
89            $this->seen = Phergie_Plugin_Logging::prepare('
90                SELECT tstamp, type, chan, message
91                FROM logs
92                WHERE LOWER(nick) = LOWER(:name)
93                AND type NOT IN (' . Phergie_Plugin_Logging::QUERY . ', ' . Phergie_Plugin_Logging::MODE . ', ' . Phergie_Plugin_Logging::TOPIC . ')
94                ORDER BY tstamp DESC
95                LIMIT :offset,1
96            ');
97
98            $this->heard = Phergie_Plugin_Logging::prepare('
99                SELECT tstamp, chan, message
100                FROM logs
101                WHERE type = ' . Phergie_Plugin_Logging::PRIVMSG . '
102                AND LOWER(nick) = LOWER(:name)
103                ORDER BY tstamp DESC
104                LIMIT :offset,1
105            ');
106
107            $this->willsee = Phergie_Plugin_Logging::prepare('
108                SELECT strftime("%H", tstamp) post_hour, COUNT(*) post_count
109                FROM logs
110                WHERE type IN (' . Phergie_Plugin_Logging::PRIVMSG . ', ' . Phergie_Plugin_Logging::ACTION . ')
111                AND LOWER(nick) = LOWER(:nick)
112                AND strftime("%w", tstamp) = strftime("%w", "now")
113                GROUP BY strftime("%H", tstamp)
114                ORDER BY 2 DESC, 1
115                LIMIT 1
116            ');
117
118            $this->quote = Phergie_Plugin_Logging::prepare('
119                SELECT tstamp, chan, message
120                FROM logs
121                WHERE type = ' . Phergie_Plugin_Logging::PRIVMSG . '
122                AND LOWER(nick) = LOWER(:name)
123                AND LOWER(chan) = LOWER(:chan)
124                ORDER BY RANDOM()
125                LIMIT :offset,1
126            ');
127        } catch (PDOException $e) { }
128    }
129
130    /**
131     * Returns whether or not the plugin's dependencies are met.
132     *
133     * @param Phergie_Driver_Abstract $client Client instance
134     * @param array $plugins List of short names for plugins that the
135     *                       bootstrap file intends to instantiate
136     * @see Phergie_Plugin_Abstract_Base::checkDependencies()
137     * @return bool TRUE if dependencies are met, FALSE otherwise
138     */
139    public static function checkDependencies(Phergie_Driver_Abstract $client, array $plugins)
140    {
141        if (!self::staticPluginLoaded('Logging', $client, $plugins)) {
142            return 'Logging plugin must be enabled';
143        }
144        return true;
145    }
146
147    /**
148     * Formats a timestamp for display purposes.
149     *
150     * @param string $timestamp Timestamp to format
151     * @return string Formatted timestamp
152     */
153    protected function formatTimestamp($timestamp)
154    {
155        return $this->getCountdown(time() - strtotime($timestamp));
156    }
157
158    /**
159     * Responds to requests for logged messages containing a particular search
160     * phrase.
161     *
162     * @param string $phrase Phrase to search for
163     * @return void
164     */
165    public function onDoSearch($phrase)
166    {
167        if (!Phergie_Plugin_Logging::databaseExists()) {
168            return;
169        }
170
171        $searchAll = false;
172        if (substr(strtolower($phrase), 0, 4) == '-all') {
173            $phrase = trim(substr($phrase, 4));
174            $searchAll = true;
175        } else if (substr(strtolower($phrase), 0, 2) == '-a') {
176            $phrase = trim(substr($phrase, 2));
177            $searchAll = true;
178        }
179        $searchAll = (!$this->fromAdmin(true) ? false : $searchAll);
180
181        $source = $this->event->getSource();
182        $target = $this->event->getNick();
183
184        $params = array(
185            ':phrase' => '%' . str_replace(array('\\', '%'), array('\\\\', '\\%'), $phrase) . '%',
186            ':limit' => ($source[0] == '#' ? 1 : 6),
187            ':type' => ($searchAll ? '0' : Phergie_Plugin_Logging::QUERY)
188        );
189
190        try {
191            $this->search->execute($params);
192            $rows = $this->search->fetchAll(PDO::FETCH_ASSOC);
193        } catch (PDOException $e) { }
194
195        if (count($rows) <= 0) {
196            $this->doNotice($target, 'I have no records for "' . $phrase . '"');
197            return;
198        }
199
200        foreach($rows as $row) {
201            $this->doPrivmsg(
202                $source,
203                sprintf(
204                    '%s%s was seen %s "%s" on %s (%s ago)',
205                    ($source[0] == '#' ? $target . ': ' : ''),
206                    $row['nick'],
207                    $this->actions[$row['type']],
208                    $row['message'],
209                    $row['chan'],
210                    $this->formatTimestamp($row['tstamp'])
211                )
212            );
213        }
214    }
215
216    /**
217     * Responds to requests for the last logged action originating from a
218     * particular user.
219     *
220     * @param string $user Nick of the user to search for
221     * @return void
222     */
223    public function onDoSeen($user)
224    {
225        if (!Phergie_Plugin_Logging::databaseExists()) {
226            return;
227        }
228
229        // Don't match if user has a space (obviously it's not a nick)
230        if (strpos($user, ' ') !== false) {
231            return;
232        }
233
234        $source = $this->event->getSource();
235        $target = $this->event->getNick();
236
237        // Handle cases where the bot is the subject
238        if (strtolower($user) == strtolower($this->getIni('nick'))) {
239            $this->doPrivmsg($source, $target . ': Are you blind? I\'m right here!');
240            return;
241        }
242
243        // Handle 'me' alias
244        if ($user == 'me') {
245            $user = $target;
246        }
247
248        // Get the last event from the specified user
249        $params = array(
250            ':name' => $user,
251            ':offset' => (strtolower($target) == strtolower($user) ? 1 : 0)
252        );
253
254        try {
255            $this->seen->execute($params);
256            $row = $this->seen->fetch(PDO::FETCH_ASSOC);
257        } catch (PDOException $e) { }
258
259        // Send the last action if available
260        if ($row) {
261            $this->doPrivmsg(
262                $source,
263                sprintf(
264                    '%s: %s was last seen %s "%s" on %s (%s ago)',
265                    $target,
266                    $user,
267                    $this->actions[$row['type']],
268                    $row['message'],
269                    $row['chan'],
270                    $this->formatTimestamp($row['tstamp'])
271                )
272            );
273        } else {
274            $this->doNotice($target, 'I have no records for ' . $user);
275        }
276    }
277
278    /**
279     * Responds to requests for the last logged message originating from a
280     * particular user.
281     *
282     * @param string $user Nick of the user to search for
283     * @return void
284     */
285    public function onDoHeard($user)
286    {
287        if (!Phergie_Plugin_Logging::databaseExists()) {
288            return;
289        }
290
291        // Don't match if user has a space (obviously it's not a nick)
292        if (strpos($user, ' ') !== false) {
293            return;
294        }
295
296        $source = $this->event->getSource();
297        $target = $this->event->getNick();
298
299        // Handle cases where the bot is the subject
300        if (strtolower($user) == strtolower($this->getIni('nick'))) {
301            $this->doPrivmsg($source, $target . ': Are you deaf? Can you not hear me?!');
302            return;
303        }
304
305        // Handle 'me' alias
306        if ($user == 'me') {
307            $user = $target;
308        }
309
310        // Get the last event from the specified user
311        $params = array(
312            ':name' => $user,
313            ':offset' => (strtolower($target) == strtolower($user) ? 1 : 0)
314        );
315
316        try {
317            $this->heard->execute($params);
318            $row = $this->heard->fetch(PDO::FETCH_ASSOC);
319        } catch (PDOException $e) { }
320
321        // Send the last action if available
322        if ($row) {
323            $this->doPrivmsg(
324                $source,
325                sprintf(
326                    '%s: %s was last seen %s "%s" on %s (%s ago)',
327                    $target,
328                    $user,
329                    $this->actions[Phergie_Plugin_Logging::PRIVMSG],
330                    $row['message'],
331                    $row['chan'],
332                    $this->formatTimestamp($row['tstamp'])
333                )
334            );
335        } else {
336            $this->doNotice($target, 'I have no records for ' . $user);
337        }
338    }
339
340    /**
341     * Responds to requests for a time range during which a particular user
342     * is most likely to be present in the channel from which the request
343     * originates.
344     *
345     * @param string $user Nick of the user to search for
346     * @return void
347     */
348    public function onDoWillsee($user)
349    {
350        if (!Phergie_Plugin_Logging::databaseExists()) {
351            return;
352        }
353
354        $source = $this->event->getSource();
355        $target = $this->event->getNick();
356
357        // Check to make sure the request came from a channel
358        if ($source[0] != '#') {
359            return;
360        }
361
362        // Don't match if user has a space (obviously it's not a nick)
363        if (strpos($user, ' ') !== false) {
364            return;
365        }
366
367        // Handle cases where the bot is the subject
368        if (strtolower($user) == strtolower($this->getIni('nick'))) {
369            $this->doPrivmsg($source, $target . ': What are you talking about? I\'m always here!');
370            return;
371        }
372
373        // Handle 'me' alias
374        if ($user == 'me') {
375            $user = $this->event->getNick();
376        }
377
378        // Perform the search
379        $params = array(
380            ':nick' => $user
381        );
382
383        try {
384            $this->willsee->execute($params);
385            $prediction = $this->willsee->fetchColumn();
386        } catch (PDOException $e) { }
387
388        // Return if no results are found
389        if ($prediction === false) {
390            $this->doNotice($target, 'I couldn\'t make a prediction for ' . $user);
391            return;
392        }
393
394        // Calculate a predicted time of arrival
395        $hour = date('H');
396        if ($hour > $prediction) {
397            $prediction = 24 - ($hour - $prediction);
398        } else {
399            $prediction = $prediction - $hour;
400        }
401
402        // Return with a message including the prediction
403        $message = $target . ': ' . $user . ' is most likely to be online ';
404        if ($prediction == 0) {
405            $message .= 'now!';
406        } elseif ($prediction == 1) {
407            $message .= 'in 1 hour.';
408        } else {
409            $message .= 'in ' . $prediction . ' hours.';
410        }
411        $this->doPrivmsg($source, $message);
412    }
413
414    /**
415     * Responds to requests for a random message originating from a particular
416     * user.
417     *
418     * @param string $user Nick of the user to search for
419     * @return void
420     */
421    public function onDoQuote($user)
422    {
423        if (!Phergie_Plugin_Logging::databaseExists()) {
424            return;
425        }
426
427        // Don't match if user has a space (obviously it's not a nick)
428        if (strpos($user, ' ') !== false) {
429            return;
430        }
431
432        $source = $this->event->getSource();
433        $target = $this->event->getNick();
434
435        // Handle cases where the bot is the subject
436        if (strtolower($user) == strtolower($this->getIni('nick'))) {
437            $this->doPrivmsg($source, $target . ': Everything I say is amazing, how can I choose just one?');
438            return;
439        }
440
441        // Handle 'me' alias
442        if ($user == 'me') {
443            $user = $target;
444        }
445
446        // Get the last event from the specified user
447        $params = array(
448            ':name' => $user,
449            ':chan' => $source,
450            ':offset' => (strtolower($target) == strtolower($user) ? 1 : 0)
451        );
452
453        try {
454            $this->quote->execute($params);
455            $row = $this->quote->fetch(PDO::FETCH_ASSOC);
456        } catch (PDOException $e) { }
457
458        // Send the last action if available
459        if ($row) {
460            $this->doPrivmsg(
461                $source,
462                sprintf(
463                    '%s: %s was quoted saying "%s" on %s (%s ago)',
464                    $target,
465                    $user,
466                    $row['message'],
467                    $row['chan'],
468                    $this->formatTimestamp($row['tstamp'])
469                )
470            );
471        } else {
472            $this->doNotice($target, 'I have no records for ' . $user);
473        }
474    }
475}
Note: See TracBrowser for help on using the browser.