Compare commits
25 commits
picker-ser
...
master
Author | SHA1 | Date | |
---|---|---|---|
0f15cc65e0 | |||
f246a40d27 | |||
26751ae40c | |||
ee62ec9798 | |||
0fb5afaf58 | |||
c375390cbb | |||
d384398081 | |||
41b308f1b6 | |||
700bc784b1 | |||
ce3ce1e971 | |||
aa3e6960a3 | |||
fa56cf6908 | |||
4292cc3147 | |||
df9639e57c | |||
3e61221cf3 | |||
df80bdb0fb | |||
ac5a8323c6 | |||
a564aa85fa | |||
2417088e80 | |||
50d3fd71a6 | |||
dcf53f8b0f | |||
c030a9658d | |||
119afd9f24 | |||
40ef399b84 | |||
53e69067e4 |
10 changed files with 622 additions and 447 deletions
17
.travis.yml
Normal file
17
.travis.yml
Normal file
|
@ -0,0 +1,17 @@
|
|||
language: php
|
||||
|
||||
php:
|
||||
- 7.1
|
||||
- 7.2
|
||||
- 7.3
|
||||
|
||||
env:
|
||||
matrix:
|
||||
- COMPOSER_FLAGS="--prefer-lowest"
|
||||
- COMPOSER_FLAGS=""
|
||||
|
||||
before_script:
|
||||
- composer install --dev --prefer-source --no-interaction
|
||||
|
||||
script:
|
||||
- bin/phpunit
|
11
README.md
Normal file
11
README.md
Normal file
|
@ -0,0 +1,11 @@
|
|||
# Joind.in Winner Picker
|
||||
|
||||
[](https://travis-ci.org/opdavies/joindin-winner-picker-new)
|
||||
|
||||
WIP
|
||||
|
||||
## Usage
|
||||
|
||||
```
|
||||
bin/console app:pick-winner <tag>
|
||||
```
|
|
@ -5,6 +5,7 @@
|
|||
"php": "^7.1.3",
|
||||
"ext-ctype": "*",
|
||||
"ext-iconv": "*",
|
||||
"ext-json": "^1.5",
|
||||
"guzzlehttp/guzzle": "^6.3",
|
||||
"josephlavin/tap": "^1.0",
|
||||
"symfony/cache": "4.2.*",
|
||||
|
@ -61,6 +62,7 @@
|
|||
}
|
||||
},
|
||||
"require-dev": {
|
||||
"fzaninotto/faker": "^1.8",
|
||||
"symfony/maker-bundle": "^1.11",
|
||||
"symfony/test-pack": "^1.0",
|
||||
"symfony/var-dumper": "4.2.*"
|
||||
|
|
649
composer.lock
generated
649
composer.lock
generated
File diff suppressed because it is too large
Load diff
|
@ -2,6 +2,7 @@
|
|||
|
||||
namespace App\Command;
|
||||
|
||||
use App\Comment;
|
||||
use App\Service\Picker;
|
||||
use GuzzleHttp\Client;
|
||||
use Symfony\Component\Cache\Simple\FilesystemCache;
|
||||
|
@ -10,6 +11,7 @@ use Symfony\Component\Console\Input\InputArgument;
|
|||
use Symfony\Component\Console\Input\InputInterface;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
use Symfony\Component\Console\Style\SymfonyStyle;
|
||||
use Tightenco\Collect\Support\Collection;
|
||||
|
||||
class PickWinnerCommand extends Command
|
||||
{
|
||||
|
@ -20,6 +22,11 @@ class PickWinnerCommand extends Command
|
|||
*/
|
||||
private $client;
|
||||
|
||||
/**
|
||||
* @var \Symfony\Contracts\Cache\CacheInterface
|
||||
*/
|
||||
private $cache;
|
||||
|
||||
/**
|
||||
* @var \App\Service\Picker
|
||||
*/
|
||||
|
@ -35,6 +42,7 @@ class PickWinnerCommand extends Command
|
|||
{
|
||||
parent::__construct();
|
||||
$this->client = new Client();
|
||||
$this->cache = new FilesystemCache();
|
||||
$this->picker = $picker;
|
||||
}
|
||||
|
||||
|
@ -58,31 +66,122 @@ class PickWinnerCommand extends Command
|
|||
{
|
||||
$io = new SymfonyStyle($input, $output);
|
||||
|
||||
$io->title('Joind.in Winner Picker!');
|
||||
|
||||
$tag = $input->getArgument('tag');
|
||||
$startDate = (new \DateTime($input->getArgument('start')))->format('Y-m-d');
|
||||
$endDate = (new \DateTime($input->getArgument('end')))->format('Y-m-d');
|
||||
|
||||
var_dump([
|
||||
'tag' => $tag,
|
||||
'start date' => $startDate,
|
||||
'end date' => $endDate,
|
||||
]);
|
||||
$io->comment(vsprintf('Selecting from #%s events between %s and %s.', [
|
||||
$tag,
|
||||
$startDate,
|
||||
$endDate,
|
||||
]));
|
||||
|
||||
// $io->success('You have a new command! Now make it your own! Pass --help to see your options.');
|
||||
$cache = new FilesystemCache();
|
||||
$cacheKey = md5(collect([$tag, $startDate, $endDate])->implode('_'));
|
||||
$events = collect($this->getEventData($tag, $startDate, $endDate));
|
||||
$this->picker->setHosts($events);
|
||||
$this->picker->setComments($this->allComments($events));
|
||||
|
||||
if (!$events = $cache->get($cacheKey)) {
|
||||
$this->picker->getWinners(1)->each(function (Comment $comment) use ($io) {
|
||||
$io->section(vsprintf('%s (%s)', [
|
||||
$comment->getUserDisplayName(),
|
||||
$comment->getTalkTitle(),
|
||||
]));
|
||||
$io->text($comment->getText());
|
||||
$io->text($comment->getUri());
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all comments (talks and event) for the events.
|
||||
*
|
||||
* @param \Tightenco\Collect\Support\Collection $events
|
||||
* The retrieved events.
|
||||
*
|
||||
* @return \Tightenco\Collect\Support\Collection
|
||||
* The merged comments.
|
||||
*/
|
||||
private function allComments(Collection $events): Collection
|
||||
{
|
||||
return $events->map(function (\stdClass $event) {
|
||||
return $this
|
||||
->eventComments($event)
|
||||
->merge($this->talkComments($event))
|
||||
;
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the event comments.
|
||||
*
|
||||
* @param \stdClass $event
|
||||
* The event.
|
||||
*
|
||||
* @return \Tightenco\Collect\Support\Collection
|
||||
*/
|
||||
private function eventComments(\stdClass $event): Collection
|
||||
{
|
||||
// TODO: Cache this.
|
||||
$response = $this->client->get(
|
||||
$event->comments_uri,
|
||||
['query' => ['resultsperpage' => 1000]]
|
||||
)->getBody();
|
||||
|
||||
return collect(json_decode($response)->comments);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the talk comments.
|
||||
*
|
||||
* @param \stdClass $event
|
||||
* The event.
|
||||
*
|
||||
* @return \Tightenco\Collect\Support\Collection
|
||||
*/
|
||||
private function talkComments(\stdClass $event): Collection
|
||||
{
|
||||
// TODO: Cache this.
|
||||
$response = $this->client->get(
|
||||
$event->all_talk_comments_uri,
|
||||
['query' => ['resultsperpage' => 1000]]
|
||||
)->getBody();
|
||||
|
||||
return collect(json_decode($response)->comments);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the event data.
|
||||
*
|
||||
* @param string $tag
|
||||
* The tag to search for.
|
||||
* @param string $startDate
|
||||
* The start date limit.
|
||||
* @param string $endDate
|
||||
* The end date limit.
|
||||
*
|
||||
* @return array
|
||||
*
|
||||
* @throws \Psr\Cache\InvalidArgumentException
|
||||
* @throws \Psr\SimpleCache\InvalidArgumentException
|
||||
*/
|
||||
private function getEventData(string $tag, string $startDate, string $endDate): array
|
||||
{
|
||||
$cacheKey = md5(collect(['events:', $tag, $startDate, $endDate])->implode('_'));
|
||||
|
||||
if (!$events = $this->cache->get($cacheKey)) {
|
||||
$response = $this->client->get('http://api.joind.in/v2.1/events', [
|
||||
'query' => [
|
||||
'tags' => [$tag],
|
||||
'startdate' => $startDate,
|
||||
'enddate' => $endDate,
|
||||
'verbose' => 'yes',
|
||||
]
|
||||
],
|
||||
]);
|
||||
|
||||
$cache->set($cacheKey, json_decode($response->getBody())->events, 3600);
|
||||
$events = json_decode($response->getBody())->events;
|
||||
$this->cache->set($cacheKey, $events, 3600);
|
||||
}
|
||||
|
||||
return $events;
|
||||
}
|
||||
}
|
||||
|
|
106
src/Comment.php
Normal file
106
src/Comment.php
Normal file
|
@ -0,0 +1,106 @@
|
|||
<?php
|
||||
|
||||
namespace App;
|
||||
|
||||
class Comment
|
||||
{
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
private $text;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
private $userDisplayName;
|
||||
|
||||
/**
|
||||
* The URI for the comment.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
private $uri;
|
||||
|
||||
/**
|
||||
* The title of the talk that was commented on.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
private $talkTitle;
|
||||
|
||||
/**
|
||||
* Set the comment text.
|
||||
*
|
||||
* @param string $text
|
||||
*/
|
||||
public function setText(string $text): void
|
||||
{
|
||||
$this->text = $text;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the user's display name.
|
||||
*
|
||||
* @param string $name
|
||||
*/
|
||||
public function setUserDisplayName(string $name): void
|
||||
{
|
||||
$this->userDisplayName = $name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the URI for the comment.
|
||||
*
|
||||
* @param string $uri
|
||||
*/
|
||||
public function setUri(string $uri): void
|
||||
{
|
||||
$this->uri = $uri;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the talk title.
|
||||
*
|
||||
* @param string $talkTitle
|
||||
*/
|
||||
public function setTalkTitle(string $talkTitle): void
|
||||
{
|
||||
$this->talkTitle = $talkTitle;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getText(): string
|
||||
{
|
||||
return $this->text;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return mixed
|
||||
*/
|
||||
public function getUserDisplayName(): string
|
||||
{
|
||||
return $this->userDisplayName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the URI for the comment.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getUri(): string
|
||||
{
|
||||
return $this->uri;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the talk title.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getTalkTitle(): string
|
||||
{
|
||||
return $this->talkTitle;
|
||||
}
|
||||
}
|
|
@ -2,6 +2,7 @@
|
|||
|
||||
namespace App\Service;
|
||||
|
||||
use App\Comment;
|
||||
use Tightenco\Collect\Support\Collection;
|
||||
|
||||
class Picker
|
||||
|
@ -77,8 +78,16 @@ class Picker
|
|||
{
|
||||
$this->comments = $comments
|
||||
->flatten(1)
|
||||
->filter(function (array $comment) {
|
||||
return !$this->isUserAnEventHost($comment['user_display_name']);
|
||||
->filter(function (\stdClass $comment) {
|
||||
return !$this->isUserAnEventHost($comment->user_display_name);
|
||||
})
|
||||
->map(function (\stdClass $original) {
|
||||
return tap(new Comment(), function (Comment $comment) use ($original) {
|
||||
$comment->setText($original->comment);
|
||||
$comment->setUserDisplayName($original->user_display_name);
|
||||
$comment->setUri($original->uri);
|
||||
$comment->setTalkTitle($original->talk_title);
|
||||
});
|
||||
})
|
||||
->values();
|
||||
|
||||
|
|
|
@ -5,6 +5,9 @@
|
|||
"facebook/webdriver": {
|
||||
"version": "1.6.0"
|
||||
},
|
||||
"fzaninotto/faker": {
|
||||
"version": "v1.8.0"
|
||||
},
|
||||
"guzzlehttp/guzzle": {
|
||||
"version": "6.3.3"
|
||||
},
|
||||
|
@ -20,6 +23,9 @@
|
|||
"nikic/php-parser": {
|
||||
"version": "v4.2.0"
|
||||
},
|
||||
"php": {
|
||||
"version": "7.3"
|
||||
},
|
||||
"psr/cache": {
|
||||
"version": "1.0.1"
|
||||
},
|
||||
|
|
68
tests/Helpers/Factory/CommentFactory.php
Normal file
68
tests/Helpers/Factory/CommentFactory.php
Normal file
|
@ -0,0 +1,68 @@
|
|||
<?php
|
||||
|
||||
namespace App\Tests\Helpers\Factory;
|
||||
|
||||
use App\Comment;
|
||||
use Faker\Factory;
|
||||
use Tightenco\Collect\Support\Collection;
|
||||
|
||||
class CommentFactory
|
||||
{
|
||||
/**
|
||||
* @var \Faker\Factory
|
||||
*/
|
||||
private $faker;
|
||||
|
||||
/**
|
||||
* The number of comments to create.
|
||||
*
|
||||
* @var int
|
||||
*/
|
||||
private $commentCount = 0;
|
||||
|
||||
/**
|
||||
* CommentFactory constructor.
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
$this->faker = Factory::create();
|
||||
}
|
||||
|
||||
/**
|
||||
* Create new comments.
|
||||
*
|
||||
* @return \Tightenco\Collect\Support\Collection
|
||||
*/
|
||||
public function create(): Collection
|
||||
{
|
||||
$talkTitle = $this->faker->sentence;
|
||||
|
||||
return tap(collect(), function (Collection $data) use ($talkTitle) {
|
||||
if ($this->commentCount > 0) {
|
||||
foreach (range(1, $this->commentCount) as $i) {
|
||||
$comment = new \stdClass();
|
||||
$comment->talk_title = $talkTitle;
|
||||
$comment->comment = $this->faker->paragraph;
|
||||
$comment->uri = 'http://api.joind.in/v2.1/talk_comments/' . $this->faker->randomNumber(8);
|
||||
$comment->user_display_name = $this->faker->name;
|
||||
|
||||
$data->push($comment);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the number of comments to create.
|
||||
*
|
||||
* @param int $count
|
||||
*
|
||||
* @return \App\Tests\Helpers\Factory\CommentFactory
|
||||
*/
|
||||
public function setCount(int $count): self
|
||||
{
|
||||
$this->commentCount = $count;
|
||||
|
||||
return $this;
|
||||
}
|
||||
}
|
|
@ -2,7 +2,9 @@
|
|||
|
||||
namespace App\Tests\Service;
|
||||
|
||||
use App\Comment;
|
||||
use App\Service\Picker;
|
||||
use App\Tests\Helpers\Factory\CommentFactory;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
use Tightenco\Collect\Support\Collection;
|
||||
|
||||
|
@ -41,22 +43,8 @@ class PickerTest extends TestCase
|
|||
public function comments_for_multiple_events_are_flattened_and_combined()
|
||||
{
|
||||
$data = [
|
||||
[
|
||||
[
|
||||
'comment' => 'Great talk!',
|
||||
'user_display_name' => 'Dan Ackroyd',
|
||||
],
|
||||
[
|
||||
'comment' => 'Could be better.',
|
||||
'user_display_name' => 'Lucia Velasco',
|
||||
],
|
||||
],
|
||||
[
|
||||
[
|
||||
'comment' => 'Needs more cat pictures.',
|
||||
'user_display_name' => 'Rupert Jabelman',
|
||||
],
|
||||
],
|
||||
(new CommentFactory())->setCount(2)->create(),
|
||||
(new CommentFactory())->setCount(1)->create(),
|
||||
];
|
||||
|
||||
$comments = (new Picker())
|
||||
|
@ -70,58 +58,29 @@ class PickerTest extends TestCase
|
|||
/** @test */
|
||||
public function comments_from_event_hosts_cannot_be_picked()
|
||||
{
|
||||
$comments = (new CommentFactory())->setCount(3)->create();
|
||||
|
||||
$event = [
|
||||
'hosts' => [
|
||||
['host_name' => 'Oliver Davies'],
|
||||
['host_name' => $hostName = $comments[1]->user_display_name],
|
||||
],
|
||||
];
|
||||
|
||||
$comments = [
|
||||
[
|
||||
[
|
||||
'comment' => 'Great talk!',
|
||||
'user_display_name' => 'Peter Fisher',
|
||||
],
|
||||
[
|
||||
'comment' => 'Text on slides could be bigger.',
|
||||
'user_display_name' => 'Oliver Davies',
|
||||
],
|
||||
[
|
||||
'comment' => 'Speak slower.',
|
||||
'user_display_name' => 'Zan Baldwin',
|
||||
],
|
||||
],
|
||||
];
|
||||
|
||||
$comments = (new Picker())
|
||||
/** @var \Tightenco\Collect\Support\Collection $userNames */
|
||||
$userNames = (new Picker())
|
||||
->setHosts(collect([$event]))
|
||||
->setComments(collect($comments))
|
||||
->getComments();
|
||||
->getComments()
|
||||
->map->getUserDisplayName();
|
||||
|
||||
$this->assertCount(2, $comments);
|
||||
$this->assertSame('Peter Fisher', $comments[0]['user_display_name']);
|
||||
$this->assertSame('Zan Baldwin', $comments[1]['user_display_name']);
|
||||
$this->assertCount(2, $userNames);
|
||||
$this->assertFalse($userNames->contains($hostName));
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function winners_can_be_selected()
|
||||
{
|
||||
$comments = [
|
||||
[
|
||||
[
|
||||
'comment' => 'Great talk!',
|
||||
'user_display_name' => 'Peter Fisher',
|
||||
],
|
||||
[
|
||||
'comment' => 'Text on slides could be bigger.',
|
||||
'user_display_name' => 'Michael Bush',
|
||||
],
|
||||
[
|
||||
'comment' => 'Speak slower.',
|
||||
'user_display_name' => 'Zan Baldwin',
|
||||
],
|
||||
],
|
||||
];
|
||||
$comments = (new CommentFactory())->setCount(3)->create();
|
||||
|
||||
$picker = new Picker();
|
||||
$picker->setComments(collect($comments));
|
||||
|
@ -129,12 +88,17 @@ class PickerTest extends TestCase
|
|||
|
||||
tap($picker->getWinners(1), function (Collection $winners) use ($picker) {
|
||||
$this->assertCount(1, $winners);
|
||||
$this->assertInstanceOf(Comment::class, $winners->first());
|
||||
$this->assertTrue($picker->getComments()->contains($winners->first()));
|
||||
});
|
||||
|
||||
tap($picker->getWinners(2), function (Collection $winners) use ($picker) {
|
||||
$this->assertCount(2, $winners);
|
||||
|
||||
$this->assertInstanceOf(Comment::class, $winners->first());
|
||||
$this->assertTrue($picker->getComments()->contains($winners->first()));
|
||||
|
||||
$this->assertInstanceOf(Comment::class, $winners->last());
|
||||
$this->assertTrue($picker->getComments()->contains($winners->last()));
|
||||
});
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue