Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

W3Schools Plugin #88

Merged
merged 3 commits into from
Oct 6, 2016
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
130 changes: 130 additions & 0 deletions src/Plugins/AntiW3Schools.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,130 @@
<?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](http://dev.mysql.com/doc/) for more information.',
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

https://dev.mysql.com/doc/

Also note that W3S "sql" chapter is not specific to MySQL, also covers other horrifyingly shit database engines as well \o/

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Indeed, I have no idea on what can be considered a good MySQL reference out there, initial searching didn't produce anything fantastic.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think the official manual is a good place to start with anything. There's also this for specifically PDO/mysql.

'php' => '[Check the official PHP Documentation](http://php.net/docs.php) for help with PHP.',
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

'bootstrap' => '[Check the official Bootstrap Documentation](http://getbootstrap.com/getting-started/) for help with the Bootstrap framework.',
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

'jquery' => '[Check the official jQuery API Documentation](http://api.jquery.com/) for help with the jQuery library.',
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

'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 = [];

if(
!preg_match_all(
'/' . self::BAD_HOST_PATTERN . '\/(' . implode('|', $categoryNames) . ')\//i',
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since you need to match literal slashes, why not use a different delimiter?

e.g. '#' . self::BAD_HOST_PATTERN . '/(' . implode('|', $categoryNames) . ')/#i'

$text,
$matchSets
) > 0
) {
// 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);
}
}