Page Menu
Home
DevCentral
Search
Configure Global Search
Log In
Files
F3770050
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Award Token
Flag For Later
Size
24 KB
Referenced Files
None
Subscribers
None
View Options
diff --git a/app/Analyzers/GitHubPayloadAnalyzer.php b/app/Analyzers/GitHubPayloadAnalyzer.php
index 739709f..b38cfd3 100644
--- a/app/Analyzers/GitHubPayloadAnalyzer.php
+++ b/app/Analyzers/GitHubPayloadAnalyzer.php
@@ -1,314 +1,315 @@
<?php
namespace Nasqueron\Notifications\Analyzers;
use Config;
+use Storage;
class GitHubPayloadAnalyzer {
///
/// Private members
///
/**
* The project name, used to load specific configuration and offer defaults
* @var string
*/
private $project;
/**
* The GitHub event triggering this request
* @var string
*/
private $event;
/**
* The request content, as a structured data
* @var stdClass
*/
private $payload;
/**
* The configuration for the payload analyzer
* @var GitHubPayloadAnalyzerConfiguration;
*/
private $configuration;
///
/// Constructor
///
/**
* Creates a new GitHubPayloadAnalyzer instance.
*
* @param string $project
* @param string $event
* @param stdClass $payload
*/
public function __construct($project, $event, $payload) {
$this->project = $project;
$this->event = $event;
$this->payload = $payload;
$this->loadConfiguration($project);
}
///
/// Configuration
///
const CONFIG_DEFAULT_FILE = 'default.json';
public function getConfigurationFileName () {
$dir = Config::get('services.github.analyzer.configDir');
$filename = $dir . '/' . $this->project . '.json';
- if (!file_exists($filename)) {
+ if (!Storage::has($filename)) {
return $dir . '/' . static::CONFIG_DEFAULT_FILE;
}
return $filename;
}
public function loadConfiguration () {
$fileName = $this->getConfigurationFileName();
$mapper = new \JsonMapper();
$this->configuration = $mapper->map(
- json_decode(file_get_contents($fileName)),
+ json_decode(Storage::get($fileName)),
new GitHubPayloadAnalyzerConfiguration()
);
}
///
/// Properties
///
public function getRepository () {
if ($this->isAdministrativeEvent()) {
return '';
}
return $this->payload->repository->name;
}
///
/// Qualification of the payload
///
public function isAdministrativeEvent () {
$administrativeEvents = [
'membership', // Member added to team
'ping', // Special ping ponf event, fired on new hook
'repository', // Repository created
];
return in_array($this->event, $administrativeEvents);
}
/**
* Gets the group for a specific payload
*
* @return string the group, central part of the routing key
*/
public function getGroup () {
// Some events are organization-level only and can't be mapped to an
// existing repository.
if ($this->isAdministrativeEvent()) {
return $this->configuration->administrativeGroup;
}
// If the payload is about some repository matching a table of
// symbols, we need to sort it to the right group.
$repository = $this->getRepository();
foreach ($this->configuration->repositoryMapping as $mapping) {
if ($mapping->doesRepositoryBelong($repository)) {
return $mapping->group;
}
}
// By default, fallback group is the project name or a specified value.
if (empty($this->configuration->defaultGroup)) {
return strtolower($this->project);
}
return $this->configuration->defaultGroup;
}
///
/// Description of the payload
///
/**
* Gets repository and branch information
*
* @return string
*/
public function getWhere () {
$repo = $this->payload->repository->name;
$branch = $this->payload->ref;
return static::getRepositoryAndBranch($repo, $branch);
}
/**
* Gets a repository and branch information string
*
* @param string $repo The repository
* @param string $branch The branch
* @return string "<repo>" or "<repo> (branch <branch>)" when branch isn't master
*/
public static function getRepositoryAndBranch ($repo = "", $branch = "") {
if ($repo === "") {
return "";
}
if (starts_with($branch, "refs/heads/")) {
$branch = substr($branch, 11);
}
if ($branch === "" || $branch === "master") {
return $repo;
}
return "$repo (branch $branch)";
}
/**
* Gets the title of the head commit
*
* @return string
*/
private function getHeadCommitTitle () {
return static::getCommitTitle($this->payload->head_commit->message);
}
/**
* Extracts the commit title from the whole commit message.
*
* @param string $message The commit message
* @return string The commit title
*/
public static function getCommitTitle ($message) {
// Discards extra lines
$pos = strpos($message, "\n");
if ($pos > 0) {
$message = substr($message, 0, $pos);
}
// Short messages are returned as is
$len = strlen($message);
if ($len <= 72) {
return $message;
}
// Longer messages are truncated
return substr($message, 0, 71) . '…';
}
/**
* Gets the description text for the head commit.
*
* @return string
*/
private function getHeadCommitDescription () {
$commit = $this->payload->head_commit;
$title = $this->getHeadCommitTitle();
$committer = $commit->committer->username;
$author = $commit->author->username;
$message = "$committer committed $title";
if ($committer !== $author) {
$message .= " (authored by $author)";
}
return $message;
}
/**
* Gets a short textual description of the event
*
* @return string
*/
public function getDescription () {
switch ($this->event) {
case "create":
$repository = $this->payload->repository->full_name;
$type = $this->payload->ref_type;
$ref = $this->payload->ref;
if ($type == "tag" || $type == "branch") {
return "New $type on $repository: $ref";
}
return "Unknown create: $type $ref";
case "ping":
$quote = $this->payload->zen;
return "« $quote » — GitHub Webhooks ping zen aphorism.";
case "push":
$n = count($this->payload->commits);
if ($n == 1) {
return $this->getHeadCommitDescription();
}
$repoAndBranch = $this->getWhere();
$user = $this->payload->pusher->name;
return "$user pushed $n commits to $repoAndBranch";
case "repository":
$repository = $this->payload->repository->full_name;
$message = "New repository $repository";
if ($this->payload->repository->fork) {
$message .= " (fork)";
}
if ($description = $this->payload->repository->description) {
$message .= " — $description";
}
return $message;
case "status":
return $this->payload->description
. " — "
. $this->payload->context;
default:
return "Some $this->event happened";
}
}
/**
* Gets a link to view the event on GitHub
*
* @return string The most relevant URL
*/
public function getLink () {
switch ($this->event) {
case "create":
$type = $this->payload->ref_type;
$ref = $this->payload->ref;
$url = $this->payload->repository->html_url;
if ($type == "tag") {
$url .= "/releases/tag/" . $ref;
} elseif ($type == "branch") {
$url .= "/tree/" . $ref;
}
return $url;
case "push":
$n = count($this->payload->commits);
if ($n == 1) {
return $this->payload->head_commit->url;
}
return $this->payload->compare;
case "repository":
return $this->payload->repository->html_url;
case "status":
return $this->payload->target_url;
default:
return "";
}
}
}
diff --git a/app/Analyzers/PhabricatorPayloadAnalyzer.php b/app/Analyzers/PhabricatorPayloadAnalyzer.php
index eab5abf..d043717 100644
--- a/app/Analyzers/PhabricatorPayloadAnalyzer.php
+++ b/app/Analyzers/PhabricatorPayloadAnalyzer.php
@@ -1,122 +1,123 @@
<?php
namespace Nasqueron\Notifications\Analyzers;
use Nasqueron\Notifications\Phabricator\PhabricatorStory;
use Config;
+use Storage;
class PhabricatorPayloadAnalyzer {
///
/// Private members
///
/**
* The project name, used to load specific configuration and offer defaults
* @var string
*/
private $project;
/**
* The story
* @var PhabricatorStory
*/
private $story;
/**
* The configuration for the payload analyzer
* @var PhabricatorPayloadAnalyzerConfiguration;
*/
private $configuration;
///
/// Constructor
///
/**
* Creates a new GitHubPayloadAnalyzer instance.
*
* @param string $project
* @param string $event
* @param stdClass $payload
*/
public function __construct($project, PhabricatorStory $story) {
$this->project = $project;
$this->story = $story;
$this->loadConfiguration($project);
}
///
/// Configuration
///
const CONFIG_DEFAULT_FILE = 'default.json';
public function getConfigurationFileName () {
$dir = Config::get('services.phabricator.analyzer.configDir');
$filename = $dir . '/' . $this->project . '.json';
- if (!file_exists($filename)) {
+ if (!Storage::has($filename)) {
return $dir . '/' . static::CONFIG_DEFAULT_FILE;
}
return $filename;
}
public function loadConfiguration () {
$fileName = $this->getConfigurationFileName();
$mapper = new \JsonMapper();
$this->configuration = $mapper->map(
- json_decode(file_get_contents($fileName)),
+ json_decode(Storage::get($fileName)),
new PhabricatorPayloadAnalyzerConfiguration()
);
}
///
/// Qualification of the story
///
public function isAdministrativeEvent () {
//TODO: determine events who qualify as administrative
return false;
}
/**
* Gets the group for a specific story
*
* @return string the group, central part of the routing key
*/
public function getGroup () {
// Some events are organization-level only and can't be mapped
// to projects.
if ($this->isAdministrativeEvent()) {
return $this->configuration->administrativeGroup;
}
// If the payload is about some repository matching a table of
// symbols, we need to sort it to the right group.
foreach ($this->configuration->groupsMapping as $mapping) {
foreach ($this->story->getProjects() as $project) {
if ($mapping->doesProjectBelong($project)) {
return $mapping->group;
}
}
}
// Words
foreach ($this->configuration->groupsMapping as $mapping) {
if ($mapping->doesStoryBelong($this->story)) {
return $mapping->group;
}
}
// By default, fallback group is the project name or a specified value.
if (empty($this->configuration->defaultGroup)) {
return strtolower($this->project);
}
return $this->configuration->defaultGroup;
}
}
diff --git a/app/Console/Commands/PhabricatorGetProjectsMap.php b/app/Console/Commands/PhabricatorGetProjectsMap.php
index 30fb683..9822eea 100644
--- a/app/Console/Commands/PhabricatorGetProjectsMap.php
+++ b/app/Console/Commands/PhabricatorGetProjectsMap.php
@@ -1,62 +1,63 @@
<?php
namespace Nasqueron\Notifications\Console\Commands;
use Illuminate\Console\Command;
+use Storage;
use Nasqueron\Notifications\Phabricator\ProjectsMap;
class PhabricatorGetProjectsMap extends Command {
/**
* The name and signature of the console command.
*
* @var string
*/
protected $signature = 'phabricator:projectsmap';
/**
* The console command description.
*
* @var string
*/
protected $description = 'Regerate the projects map for each Phabricator instances';
/**
* Create a new command instance.
*
* @return void
*/
public function __construct() {
parent::__construct();
}
/**
* Execute the console command.
*
* @return mixed
*/
public function handle() {
foreach ($this->getServicesCredentials() as $service) {
if ($service->gate == "Phabricator") {
$this->info("Querying projects map for " . $service->instance);
$map = ProjectsMap::fetch($service->instance);
$map->saveToCache();
$this->table(
['PHID', 'Project name'],
$map->toArray()
);
}
}
}
/**
* Gets service credentials
*
* @return stdClass the services credentials
*/
protected function getServicesCredentials () {
$path = config('services.gate.credentials');
- $data = json_decode(file_get_contents($path));
+ $data = json_decode(Storage::get($path));
return $data->services;
}
}
diff --git a/app/Http/Controllers/Gate/GateController.php b/app/Http/Controllers/Gate/GateController.php
index 1b80231..c045c21 100644
--- a/app/Http/Controllers/Gate/GateController.php
+++ b/app/Http/Controllers/Gate/GateController.php
@@ -1,128 +1,129 @@
<?php
namespace Nasqueron\Notifications\Http\Controllers\Gate;
use Nasqueron\Notifications\Features;
use Nasqueron\Notifications\Http\Controllers\Controller;
use Report;
+use Storage;
/**
* Represents a controller handling an entry-point for API payloads
*/
class GateController extends Controller {
///
/// Private members
///
/**
* @var string
*/
protected $door;
///
/// Requests
///
/**
* Handles GET requests
*/
public function onGet () {
// Virtually all the push APIs will send they payloads
// using a POST request, so we can provide a sensible
// default GET error message.
return view('gate/ispostonly');
}
/**
* Logs the request
*/
protected function logRequest () {
Log::info('[Gate] New payload.', [
'service' => static::SERVICE_NAME,
'door' => $this->door,
]);
}
///
/// Reports
///
/**
* Initializes the report and registers it
*/
protected function initializeReport () {
if (Features::isEnabled('ActionsReport')) {
Report::attachToGate(static::SERVICE_NAME, $this->door);
}
}
/**
* Renders the report
*
* @return Illuminate\Http\Response|null
*/
protected function renderReport () {
if (Features::isEnabled('ActionsReport')) {
return Report::render();
}
}
///
/// Credentials
///
/**
* Gets services credentials
*
* @return stdClass the services credentials
*/
protected function getServicesCredentials () {
$path = config('services.gate.credentials');
- $data = json_decode(file_get_contents($path));
+ $data = json_decode(Storage::get($path));
return $data->services;
}
/**
* Determines if a service definition matches this current gate and door.
*
* @param stdClass $service the service to check
* @return true if the service matches our gate and door; otherwise, false.
*/
protected function doesServiceMatch ($service) {
return $service->gate == static::SERVICE_NAME
&& $service->door == $this->door;
}
/**
* Gets service credentials for this gate and door
*
* @return stdClass the service credentials
*/
public function getService () {
foreach ($this->getServicesCredentials() as $service) {
if ($this->doesServiceMatch($service)) {
return $service;
}
}
return null;
}
/**
* Gets secret for this service and door.
*
* @return string the secret, or if unknown, an empty string
*/
protected function getSecret () {
$service= $this->getService();
if ($service !== null) {
return $service->secret;
}
return "";
}
}
diff --git a/app/Phabricator/PhabricatorAPI.php b/app/Phabricator/PhabricatorAPI.php
index fbac06a..e151f68 100644
--- a/app/Phabricator/PhabricatorAPI.php
+++ b/app/Phabricator/PhabricatorAPI.php
@@ -1,163 +1,165 @@
<?php
namespace Nasqueron\Notifications\Phabricator;
+use Storage;
+
class PhabricatorAPI {
///
/// Private members
///
/**
* The Phabricator main URL
*
* @var string
*/
private $instance;
/**
* The token generated at /settings/panel/apitokens/ to query the API
*
* @var string
*/
private $apiToken;
///
/// Constructors
///
/**
* Initializes a new instance of the Phabricator API class
*
* @param string $instance The Phabricator main URL, without trailing slash
* @param string $apiToken The token generated at /settings/panel/apitokens/
*/
public function __construct ($instance, $apiToken) {
$this->instance = $instance;
$this->apiToken = $apiToken;
}
public static function forInstance ($instance) {
$service = self::getServiceForInstance($instance);
if ($service === null) {
throw new \RuntimeException("No credentials for Phabricator instance $instance.");
}
return new self($service->instance, $service->secret);
}
/**
* Gets an API instance for the specify project
*
* @param string $project The name of the project (this matches the door parameter in credentials.json)
* @return PhabricatorAPI|null A PhabricatorAPI instance for the project if found; otherwise, null.
*/
public static function forProject ($project) {
$service = self::getServiceForProject($project);
if ($service === null) {
return null;
}
return new self($service->instance, $service->secret);
}
///
/// Helper methods for static constructors
///
private static function getServices () {
$path = config('services.gate.credentials');
- $data = json_decode(file_get_contents($path));
+ $data = json_decode(Storage::get($path));
return $data->services;
}
private static function getServiceForInstance ($instance) {
foreach (self::getServices() as $service) {
if ($service->gate === "Phabricator" && $service->instance === $instance) {
return $service;
}
}
return null;
}
private static function getServiceForProject ($project) {
foreach (self::getServices() as $service) {
if ($service->gate === "Phabricator" && $service->door === $project) {
return $service;
}
}
return null;
}
///
/// Public methods
///
/**
* Calls a Conduit API method
*
* @param $method The method to call (e.g. repository.create)
* @param $arguments The arguments to use
*/
public function call ($method, $arguments = []) {
$url = $this->instance . '/api/' . $method;
$arguments['api.token'] = $this->apiToken;
$reply = json_decode(static::post($url, $arguments));
if ($reply->error_code !== NULL) {
throw new PhabricatorAPIException(
$reply->error_code,
$reply->error_info
);
}
return $reply->result;
}
/**
* Gets the first result of an API reply
*
* @param Traversable|array $reply
* @return mixed
*/
public static function getFirstResult ($reply) {
if (is_object($reply) && property_exists($reply, 'data')) {
$reply = $reply->data;
}
foreach ($reply as $value) {
return $value;
}
}
///
/// CURL session
///
protected static function getPostFields ($arguments) {
$items = [];
foreach ($arguments as $key => $value) {
$items[] = urlencode($key) . '=' . urlencode($value);
}
return implode('&', $items);
}
protected static function post ($url, $arguments) {
$options = [
CURLOPT_URL => $url,
CURLOPT_HEADER => false,
CURLOPT_RETURNTRANSFER => true,
CURLOPT_FOLLOWLOCATION => 1,
CURLOPT_POSTFIELDS => static::getPostFields($arguments),
];
$ch = curl_init();
curl_setopt_array($ch, $options);
$result = curl_exec($ch);
curl_close($ch);
return $result;
}
}
diff --git a/config/services.php b/config/services.php
index 452af52..1963d23 100644
--- a/config/services.php
+++ b/config/services.php
@@ -1,54 +1,54 @@
<?php
return [
/*
|--------------------------------------------------------------------------
| Third Party Services
|--------------------------------------------------------------------------
|
| This file is for storing the credentials for third party services such
| as Stripe, Mailgun, Mandrill, and others. This file provides a sane
| default location for this type of information, allowing packages
| to have a conventional place to find your various credentials.
|
*/
'mailgun' => [
'domain' => env('MAILGUN_DOMAIN'),
'secret' => env('MAILGUN_SECRET'),
],
'mandrill' => [
'secret' => env('MANDRILL_SECRET'),
],
'ses' => [
'key' => env('SES_KEY'),
'secret' => env('SES_SECRET'),
'region' => 'us-east-1',
],
'stripe' => [
'model' => Nasqueron\Notifications\User::class,
'key' => env('STRIPE_KEY'),
'secret' => env('STRIPE_SECRET'),
],
'github' => [
'analyzer' => [
- 'configDir' => storage_path(env('GITHUB_ANALYZER_CONFIG_DIR', 'app/GitHubPayloadAnalyzer'))
+ 'configDir' => env('GITHUB_ANALYZER_CONFIG_DIR', 'GitHubPayloadAnalyzer')
]
],
'phabricator' => [
'analyzer' => [
- 'configDir' => storage_path(env('PHABRICATOR_ANALYZER_CONFIG_DIR', 'app/PhabricatorPayloadAnalyzer'))
+ 'configDir' => env('PHABRICATOR_ANALYZER_CONFIG_DIR', 'PhabricatorPayloadAnalyzer')
]
],
'gate' => [
- 'credentials' => storage_path(env('CREDENTIALS', 'app/credentials.json')),
+ 'credentials' => env('CREDENTIALS', 'credentials.json'),
]
];
File Metadata
Details
Attached
Mime Type
text/x-diff
Expires
Mon, Nov 25, 18:53 (7 h, 5 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
2260763
Default Alt Text
(24 KB)
Attached To
Mode
rNOTIF Notifications center
Attached
Detach File
Event Timeline
Log In to Comment