Skip to content

Commit

Permalink
Merge pull request #88 from Nessworthy/master
Browse files Browse the repository at this point in the history
W3Schools Plugin
  • Loading branch information
DaveRandom committed Oct 6, 2016
2 parents fb10066 + 1dbe4ab commit c7c8541
Show file tree
Hide file tree
Showing 2 changed files with 268 additions and 0 deletions.
126 changes: 126 additions & 0 deletions src/Plugins/AntiW3Schools.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,126 @@
<?php declare(strict_types=1);

namespace Room11\Jeeves\Plugins;

use Amp\Promise;
use Amp\Success;
use Room11\Jeeves\Chat\Client\ChatClient;
use Room11\Jeeves\Chat\Message\Message;

class AntiW3Schools extends BasePlugin
{

const BAD_HOST_PATTERN = 'w3schools\.com';
const W3S_CATEGORY_RESPONSES = [
'html' => '[Check the Mozilla Developer Network HTML documentation](https://developer.mozilla.org/docs/Web/HTML) for help with HTML.',
'css' => '[Check the Mozilla Developer Network CSS documentation](https://developer.mozilla.org/docs/Web/CSS) for help with CSS.',
'js' => '[Check the Mozilla Developer Network JS documentation](https://developer.mozilla.org/docs/Web/JavaScript) for help with JavaScript.',
'sql' => '[Check MySQL\'s official MySQL documentation](https://dev.mysql.com/doc/) for more information.',
'php' => '[Check the official PHP Documentation](https://secure.php.net/docs.php) for help with PHP.',
'bootstrap' => '[Check the official Bootstrap Documentation](https://getbootstrap.com/getting-started/) for help with the Bootstrap framework.',
'jquery' => '[Check the official jQuery API Documentation](https://api.jquery.com/) for help with the jQuery library.',
'angular' => '[Check the official AngularJS API Documentation](https://docs.angularjs.org/api) for help with the AngularJS framework.',
'xml'=> '[Check W3\'s documentation on XML](https://www.w3.org/standards/xml/core) for more information.',
'ajax' => '[Check the Mozilla Developer Network AJAX documentation](https://developer.mozilla.org/docs/AJAX) for more information.',
];

private $chatClient;

public function __construct(ChatClient $chatClient)
{
$this->chatClient = $chatClient;
}

/**
* @inheritDoc
*/
public function getName(): string
{
return 'AntiW3Schools';
}

/**
* @inheritDoc
*/
public function getDescription(): string
{
return 'A small monitoring plugin which bothers people when a w3schools link is detected.';
}

/**
* @inheritDoc
*/
public function getMessageHandler(): array
{
return [$this, 'handleMessage'];
}

/**
* Entry point for checking a message for w3schools links.
* @param Message $message
* @return Promise
*/
public function handleMessage(Message $message): Promise
{
return $this->containsTerribleUri($message->getText())
? $this->chatClient->postReply($message, $this->createReply($message))
: new Success();
}

/**
* Check if text contains a W3C link.
* @param string $text
* @return bool
*/
private function containsTerribleUri(string $text) : bool
{
return preg_match('#' . self::BAD_HOST_PATTERN . '#i', $text) === 1;
}

/**
* Create a suitable message to bother people about W3C.
* @param Message $message
* @return string
*/
private function createReply(Message $message) : string
{
$return = 'W3Schools should not be trusted as a reliable resource. [Click here to read why](http://www.w3fools.com/).';

$categories = $this->dissectCategoriesFromString($message->getText());

foreach($categories as $category) {
$return .= ' ' . self::W3S_CATEGORY_RESPONSES[$category];
}

return $return;

}

/**
* Retrieve W3S categories from a given string.
* @param string $text
* @return string[]
*/
private function dissectCategoriesFromString(string $text) {

// Extract the category from all W3S URIs found.
$categoryNames = array_keys(self::W3S_CATEGORY_RESPONSES);

$matchSets = [];
$categoryMatchPattern = '#' . self::BAD_HOST_PATTERN . '/(' . implode('|', $categoryNames) . ')/#i';
$matchResult = preg_match_all($categoryMatchPattern, $text, $matchSets);

if($matchResult === 0 || $matchResult === false) {
// If no matches were found (or the regex failed), return no results.
return [];
}

// Prevent multiple messages for the same category by only returning one of each type found.
return array_unique(
array_map(
'strtolower',
$matchSets[1]
)
);
}
}
142 changes: 142 additions & 0 deletions tests/src/Chat/Plugin/AntiW3SchoolsTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,142 @@
<?php declare(strict_types = 1);

namespace Room11\Jeeves\Tests\Chat\Plugin;

use Amp\Success;
use Room11\Jeeves\Chat\Message\Message;
use Room11\Jeeves\Plugins\AntiW3Schools;

class AntiW3SchoolsTest extends AbstractPluginTest
{
public function testCommandName()
{
$this->assertSame('AntiW3Schools', $this->plugin->getName());
$this->assertSame(
'A small monitoring plugin which bothers people when a w3schools link is detected.',
$this->plugin->getDescription()
);
$this->assertSame([], $this->plugin->getEventHandlers());
$this->assertSame([], $this->plugin->getCommandEndpoints());
}

public function testValidMessageHandler()
{
$result = $this->plugin->getMessageHandler();

$this->assertTrue(is_callable($result), 'Message handler expected to be callable, but wasn\'t.');
}

public function testNoMentionOfW3Schools()
{
/** @var AntiW3Schools $plugin */
$plugin = $this->plugin;

$message = $this->getMockBuilder(Message::class)
->disableOriginalConstructor()
->getMock();

$message
->expects($this->once())
->method('getText')
->will($this->returnValue('Happy Friday!'));

$result = $plugin->handleMessage($message);
$this->assertInstanceOf(Success::class, $result);
}

public function testBasicW3SchoolsMention()
{
/** @var AntiW3Schools $plugin */
$plugin = $this->plugin;
$client = $this->client;

$message = $this->getMockBuilder(Message::class)
->disableOriginalConstructor()
->getMock();

$message
->expects($this->exactly(2))
->method('getText')
->will($this->returnValue('What\'s wrong with w3schools.com?'));

$client
->expects($this->once())
->method('postReply')
->with(
$this->identicalTo($message),
$this->equalTo('W3Schools should not be trusted as a reliable resource. [Click here to read why](http://www.w3fools.com/).')
);

$plugin->handleMessage($message);

}

public function testSingleCategoryW3SchoolsMention()
{
/** @var AntiW3Schools $plugin */
$plugin = $this->plugin;
$client = $this->client;

$message = $this->getMockBuilder(Message::class)
->disableOriginalConstructor()
->getMock();

$message
->expects($this->exactly(2))
->method('getText')
->will($this->returnValue('How do I nest HTML elements like in http://www.w3schools.com/html/html_elements.asp?'));

$client
->expects($this->once())
->method('postReply')
->with(
$this->identicalTo($message),
$this->equalTo(
'W3Schools should not be trusted as a reliable resource. [Click here to read why](http://www.w3fools.com/).'
. ' [Check the Mozilla Developer Network HTML documentation](https://developer.mozilla.org/docs/Web/HTML) for help with HTML.'
)
);

$plugin->handleMessage($message);
}

public function testMultipleCategoryW3SchoolsMentions()
{
/** @var AntiW3Schools $plugin */
$plugin = $this->plugin;
$client = $this->client;

$message = $this->getMockBuilder(Message::class)
->disableOriginalConstructor()
->getMock();

$message
->expects($this->exactly(2))
->method('getText')
->will($this->returnValue('How do I nest HTML elements like in w3schools.com/html/html_elements.asp and styled like w3schools.com/css/fake_page.asp?'));

$client
->expects($this->once())
->method('postReply')
->with(
$this->identicalTo($message),
$this->equalTo(
'W3Schools should not be trusted as a reliable resource. [Click here to read why](http://www.w3fools.com/).'
. ' [Check the Mozilla Developer Network HTML documentation](https://developer.mozilla.org/docs/Web/HTML) for help with HTML.'
. ' [Check the Mozilla Developer Network CSS documentation](https://developer.mozilla.org/docs/Web/CSS) for help with CSS.'
)
);

$plugin->handleMessage($message);
}

/**
* @inheritdoc
*/
protected function setUp()
{
parent::setUp();

$this->plugin = new AntiW3Schools($this->client);
}
}

0 comments on commit c7c8541

Please sign in to comment.