Skip to content

Commit

Permalink
Add a dashboard notification when starred repo are being sync
Browse files Browse the repository at this point in the history
That notification will be gone once the sync is done OR after 1h, in case sync has some issues.
  • Loading branch information
j0k3r committed May 3, 2020
1 parent 2cd5a50 commit 817915e
Show file tree
Hide file tree
Showing 7 changed files with 94 additions and 13 deletions.
14 changes: 10 additions & 4 deletions app/Resources/views/default/dashboard.html.twig
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,12 @@
</div>
{% endif %}

{% if sync_status %}
<div class="alert info">
Your starred repos are being sync (this can happen <a href="#faq-check-starred-repo">many times per day</a>). It started <b>{{ sync_status|date|ago }}</b> and should be pretty fast depending on how many stars you have.
</div>
{% endif %}

<aside class="feed pure-u-lg-3-5 pure-u-md-4-5 pure-u-sm-5-5">
<p>You can grab your <b><a href="{{ url('rss_user', { uuid: app.user.uuid }) }}">feed link</a></b> and add it to your favorite feed reader. Every new release will show up in it.</p>
</aside>
Expand Down Expand Up @@ -100,23 +106,23 @@
<h2 class="content-head is-center">Got some questions? Here is a FAQ</h2>

<div>
<h4>
<h4 id="faq-check-new-release">
<i class="fa fa-clock-o"></i>
How often does the app check for new release?
</h4>
<p>
Banditore will check for new release <b>every 10 minutes</b>.
</p>

<h4>
<h4 id="faq-check-starred-repo">
<i class="fa fa-clock-o"></i>
How often does the app check for my starred repos?
</h4>
<p>
Banditore will sync your starred repos <b>every 5 minutes</b>. You can also force it by logged out / logged in.
</p>

<h4>
<h4 id="faq-dashboard">
<i class="fa fa-eye-slash"></i>
Why do I not see all my starred repos on the dashboard?
</h4>
Expand All @@ -125,7 +131,7 @@
Second, not all repos got tag or release (which is sad). In that case, they'll never show up on your dashboard.
</p>

<h4>
<h4 id="faq-other-question">
<i class="fa fa-question-circle-o"></i>
Another question?
</h4>
Expand Down
4 changes: 4 additions & 0 deletions app/config/config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -134,6 +134,10 @@ snc_redis:
type: predis
alias: doctrine_cache
dsn: "%redis_dsn_doctrine_cache%"
app_cache:
type: predis
alias: app_cache
dsn: "%redis_dsn_app_cache%"

# see https://github.com/symfony/symfony-standard/pull/1133
sensio_framework_extra:
Expand Down
1 change: 1 addition & 0 deletions app/config/parameters.yml.dist
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ parameters:

redis_dsn_guzzle_cache: redis://127.0.0.1:6379/2
redis_dsn_doctrine_cache: redis://127.0.0.1:6379/3
redis_dsn_app_cache: redis://127.0.0.1:6379/4

# used to generate url from the backend
project_host: banditore.com
Expand Down
3 changes: 3 additions & 0 deletions app/config/services.yml
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ services:
AppBundle\Controller\DefaultController:
arguments:
$diffInterval: "%status_minute_interval_before_alert%"
$redis: "@snc_redis.app_cache"

AppBundle\PubSubHubbub\Publisher:
arguments:
Expand All @@ -39,6 +40,8 @@ services:
# which will make a doctrine query on Travis because the default limit to Github will be reached
AppBundle\Consumer\SyncStarredRepos:
lazy: true
arguments:
$redis: "@snc_redis.app_cache"

AppBundle\Consumer\SyncVersions:
lazy: true
Expand Down
13 changes: 11 additions & 2 deletions src/AppBundle/Consumer/SyncStarredRepos.php
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
use AppBundle\Repository\StarRepository;
use AppBundle\Repository\UserRepository;
use Github\Client;
use Predis\ClientInterface as RedisClientInterface;
use Psr\Log\LoggerInterface;
use Swarrot\Broker\Message;
use Swarrot\Processor\ProcessorInterface;
Expand All @@ -28,24 +29,26 @@ class SyncStarredRepos implements ProcessorInterface

const DAYS_SINCE_LAST_UPDATE = 1;

private $logger;
private $doctrine;
private $userRepository;
private $starRepository;
private $repoRepository;
private $client;
private $logger;
private $redis;

/**
* Client parameter can be null when no available client were found by the Github Client Discovery.
*/
public function __construct(RegistryInterface $doctrine, UserRepository $userRepository, StarRepository $starRepository, RepoRepository $repoRepository, Client $client = null, LoggerInterface $logger)
public function __construct(RegistryInterface $doctrine, UserRepository $userRepository, StarRepository $starRepository, RepoRepository $repoRepository, Client $client = null, LoggerInterface $logger, RedisClientInterface $redis)
{
$this->doctrine = $doctrine;
$this->userRepository = $userRepository;
$this->starRepository = $starRepository;
$this->repoRepository = $repoRepository;
$this->client = $client;
$this->logger = $logger;
$this->redis = $redis;
}

public function process(Message $message, array $options)
Expand All @@ -68,6 +71,9 @@ public function process(Message $message, array $options)
return false;
}

// to be able to notify user about repos sync (will be remove after 1h to avoid infinite sync notification)
$this->redis->setex('banditore:user-sync:' . $user->getId(), 3600, time());

$this->logger->info('Consume banditore.sync_starred_repos message', ['user' => $user->getUsername()]);

$rateLimit = $this->getRateLimits($this->client, $this->logger);
Expand All @@ -85,6 +91,9 @@ public function process(Message $message, array $options)

$this->logger->notice('[' . $this->getRateLimits($this->client, $this->logger) . '] Synced repos: ' . $nbRepos, ['user' => $user->getUsername()]);

// sync is done, remove notification
$this->redis->del(['banditore:user-sync:' . $user->getId()]);

return true;
}

Expand Down
6 changes: 5 additions & 1 deletion src/AppBundle/Controller/DefaultController.php
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
use AshleyDawson\SimplePagination\Exception\InvalidPageNumberException;
use MarcW\RssWriter\Bridge\Symfony\HttpFoundation\RssStreamedResponse;
use MarcW\RssWriter\RssWriter;
use Predis\Client as RedisClient;
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\Routing\Annotation\Route;
Expand All @@ -25,8 +26,9 @@ class DefaultController extends Controller
private $rssGenerator;
private $rssWriter;
private $diffInterval;
private $redis;

public function __construct(VersionRepository $repoVersion, RepoRepository $repoRepo, StarRepository $repoStar, UserRepository $repoUser, Generator $rssGenerator, RssWriter $rssWriter, $diffInterval)
public function __construct(VersionRepository $repoVersion, RepoRepository $repoRepo, StarRepository $repoStar, UserRepository $repoUser, Generator $rssGenerator, RssWriter $rssWriter, $diffInterval, RedisClient $redis)
{
$this->repoVersion = $repoVersion;
$this->repoRepo = $repoRepo;
Expand All @@ -35,6 +37,7 @@ public function __construct(VersionRepository $repoVersion, RepoRepository $repo
$this->rssGenerator = $rssGenerator;
$this->rssWriter = $rssWriter;
$this->diffInterval = $diffInterval;
$this->redis = $redis;
}

/**
Expand Down Expand Up @@ -107,6 +110,7 @@ public function dashboardAction(Request $request)

return $this->render('default/dashboard.html.twig', [
'pagination' => $pagination,
'sync_status' => $this->redis->get('banditore:user-sync:' . $userId),
]);
}

Expand Down
66 changes: 60 additions & 6 deletions tests/AppBundle/Consumer/SyncStarredReposTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -50,13 +50,22 @@ public function testProcessNoUser()
$githubClient->expects($this->never())
->method('authenticate');

$redisClient = $this->getMockBuilder('Predis\Client')
->disableOriginalConstructor()
->getMock();

// will use `setex` & `del` but will be called dynamically by `_call`
$redisClient->expects($this->never())
->method('__call');

$processor = new SyncStarredRepos(
$doctrine,
$userRepository,
$starRepository,
$repoRepository,
$githubClient,
new NullLogger()
new NullLogger(),
$redisClient
);

$processor->process(new Message(json_encode(['user_id' => 123])), []);
Expand Down Expand Up @@ -149,13 +158,22 @@ public function testProcessSuccessfulMessage()
$logHandler = new TestHandler();
$logger->pushHandler($logHandler);

$redisClient = $this->getMockBuilder('Predis\Client')
->disableOriginalConstructor()
->getMock();

// will use `setex` & `del` but will be called dynamically by `_call`
$redisClient->expects($this->exactly(2))
->method('__call');

$processor = new SyncStarredRepos(
$doctrine,
$userRepository,
$starRepository,
$repoRepository,
$githubClient,
$logger
$logger,
$redisClient
);

$processor->process(new Message(json_encode(['user_id' => 123])), []);
Expand Down Expand Up @@ -245,13 +263,22 @@ public function testProcessUnexpectedError()

$githubClient = $this->getMockClient($responses);

$redisClient = $this->getMockBuilder('Predis\Client')
->disableOriginalConstructor()
->getMock();

// will use `setex` & `del` but will be called dynamically by `_call`
$redisClient->expects($this->once())
->method('__call');

$processor = new SyncStarredRepos(
$doctrine,
$userRepository,
$starRepository,
$repoRepository,
$githubClient,
new NullLogger()
new NullLogger(),
$redisClient
);

$processor->process(new Message(json_encode(['user_id' => 123])), []);
Expand Down Expand Up @@ -345,13 +372,22 @@ public function testProcessSuccessfulMessageNoStarToRemove()
$logHandler = new TestHandler();
$logger->pushHandler($logHandler);

$redisClient = $this->getMockBuilder('Predis\Client')
->disableOriginalConstructor()
->getMock();

// will use `setex` & `del` but will be called dynamically by `_call`
$redisClient->expects($this->exactly(2))
->method('__call');

$processor = new SyncStarredRepos(
$doctrine,
$userRepository,
$starRepository,
$repoRepository,
$githubClient,
$logger
$logger,
$redisClient
);

$processor->process(new Message(json_encode(['user_id' => 123])), []);
Expand Down Expand Up @@ -395,13 +431,22 @@ public function testProcessWithBadClient()
$logHandler = new TestHandler();
$logger->pushHandler($logHandler);

$redisClient = $this->getMockBuilder('Predis\Client')
->disableOriginalConstructor()
->getMock();

// will use `setex` & `del` but will be called dynamically by `_call`
$redisClient->expects($this->never())
->method('__call');

$processor = new SyncStarredRepos(
$doctrine,
$userRepository,
$starRepository,
$repoRepository,
null, // simulate a bad client
$logger
$logger,
$redisClient
);

$processor->process(new Message(json_encode(['user_id' => 123])), []);
Expand Down Expand Up @@ -467,13 +512,22 @@ public function testProcessWithRateLimitReached()
$logHandler = new TestHandler();
$logger->pushHandler($logHandler);

$redisClient = $this->getMockBuilder('Predis\Client')
->disableOriginalConstructor()
->getMock();

// will use `setex` & `del` but will be called dynamically by `_call`
$redisClient->expects($this->once())
->method('__call');

$processor = new SyncStarredRepos(
$doctrine,
$userRepository,
$starRepository,
$repoRepository,
$githubClient,
$logger
$logger,
$redisClient
);

$processor->process(new Message(json_encode(['user_id' => 123])), []);
Expand Down

0 comments on commit 817915e

Please sign in to comment.