From b5b60fff453c96e3c5551505557e5aec5d614583 Mon Sep 17 00:00:00 2001 From: James Brooks Date: Sat, 28 Nov 2015 17:35:49 +0000 Subject: [PATCH 1/4] Added update checking, part of #109 --- app/GitHub/Release.php | 70 +++++++++++++++++++ .../Controllers/Dashboard/ApiController.php | 35 ++++++++++ app/Http/Routes/DashboardRoutes.php | 1 + app/Providers/GitHubServiceProvider.php | 45 ++++++++++++ config/app.php | 1 + config/services.php | 4 ++ public/build/dist/js/all-29dc2bf4b8.js | 16 ----- .../{all-a7eebd3275.js => all-9ed1a73f72.js} | 2 +- public/build/rev-manifest.json | 2 +- resources/assets/js/app.js | 13 ++++ resources/lang/en/cachet.php | 4 ++ resources/views/dashboard/index.blade.php | 5 ++ 12 files changed, 180 insertions(+), 18 deletions(-) create mode 100644 app/GitHub/Release.php create mode 100644 app/Providers/GitHubServiceProvider.php delete mode 100755 public/build/dist/js/all-29dc2bf4b8.js rename public/build/dist/js/{all-a7eebd3275.js => all-9ed1a73f72.js} (99%) diff --git a/app/GitHub/Release.php b/app/GitHub/Release.php new file mode 100644 index 00000000..6a04c454 --- /dev/null +++ b/app/GitHub/Release.php @@ -0,0 +1,70 @@ +cache = $cache; + $this->config = $config; + } + + /** + * Returns the latest GitHub release. + * + * @return string + */ + public function latest() + { + $release = $this->cache->remember('version', 720, function () { + $headers = ['Accept' => 'application/vnd.github.v3+json']; + + // We can re-use the Emoji token here, if we have it. + if ($token = $this->config->get('services.github.token')) { + $headers['OAUTH-TOKEN'] = $token; + } + + return json_decode((new Client())->get('https://api.github.com/repos/cachethq/cachet/releases/latest', [ + 'headers' => $headers, + ])->getBody(), true); + }); + + return $release['tag_name']; + } +} diff --git a/app/Http/Controllers/Dashboard/ApiController.php b/app/Http/Controllers/Dashboard/ApiController.php index da0faca6..92919a79 100644 --- a/app/Http/Controllers/Dashboard/ApiController.php +++ b/app/Http/Controllers/Dashboard/ApiController.php @@ -11,6 +11,7 @@ namespace CachetHQ\Cachet\Http\Controllers\Dashboard; +use CachetHQ\Cachet\GitHub\Release; use CachetHQ\Cachet\Models\Component; use CachetHQ\Cachet\Models\ComponentGroup; use CachetHQ\Cachet\Models\IncidentTemplate; @@ -18,9 +19,29 @@ use Exception; use GrahamCampbell\Binput\Facades\Binput; use Illuminate\Database\Eloquent\ModelNotFoundException; use Illuminate\Routing\Controller; +use Illuminate\Support\Facades\Response; class ApiController extends Controller { + /** + * The release instance. + * + * @var \CachetHQ\Cachet\GitHub\Release + */ + protected $release; + + /** + * Creates a new api controller instance. + * + * @param \CachetHQ\Cachet\GitHub\Release $release + * + * @return void + */ + public function __construct(Release $release) + { + $this->release = $release; + } + /** * Updates a component with the entered info. * @@ -89,4 +110,18 @@ class ApiController extends Controller throw new ModelNotFoundException("Incident template for $templateSlug could not be found."); } + + /** + * Checks if Cachet is up to date. + * + * @return \Illuminate\Http\JsonResponse + */ + public function checkVersion() + { + return Response::json([ + 'cachet_version' => CACHET_VERSION, + 'latest_version' => $this->release->latest(), + 'is_latest' => version_compare(CACHET_VERSION, $this->release->latest()) === 1, + ]); + } } diff --git a/app/Http/Routes/DashboardRoutes.php b/app/Http/Routes/DashboardRoutes.php index 1aa77721..d5062e7d 100644 --- a/app/Http/Routes/DashboardRoutes.php +++ b/app/Http/Routes/DashboardRoutes.php @@ -265,6 +265,7 @@ class DashboardRoutes $router->post('components/groups/order', 'ApiController@postUpdateComponentGroupOrder'); $router->post('components/order', 'ApiController@postUpdateComponentOrder'); $router->post('components/{component}', 'ApiController@postUpdateComponent'); + $router->get('system/version', 'ApiController@checkVersion'); }); }); } diff --git a/app/Providers/GitHubServiceProvider.php b/app/Providers/GitHubServiceProvider.php new file mode 100644 index 00000000..6ab2e804 --- /dev/null +++ b/app/Providers/GitHubServiceProvider.php @@ -0,0 +1,45 @@ +registerRelease(); + } + + /** + * Register the releases class. + * + * @return void + */ + protected function registerRelease() + { + $this->app->singleton('cachet.release', function ($app) { + $cache = $app['cache']; + $config = $app['config']; + + return new Release($cache, $config); + }); + + $this->app->alias('cachet.release', Release::class); + } +} diff --git a/config/app.php b/config/app.php index f4f438fa..d2432aea 100644 --- a/config/app.php +++ b/config/app.php @@ -171,6 +171,7 @@ return [ 'CachetHQ\Cachet\Providers\ComposerServiceProvider', 'CachetHQ\Cachet\Providers\ConfigServiceProvider', 'CachetHQ\Cachet\Providers\EventServiceProvider', + 'CachetHQ\Cachet\Providers\GitHubServiceProvider', 'CachetHQ\Cachet\Providers\RepositoryServiceProvider', 'CachetHQ\Cachet\Providers\RouteServiceProvider', diff --git a/config/services.php b/config/services.php index 7b249322..911a5f50 100644 --- a/config/services.php +++ b/config/services.php @@ -23,6 +23,10 @@ return [ | */ + 'github' => [ + 'token' => env('GITHUB_TOKEN'), + ], + 'mailgun' => [ 'domain' => env('MAILGUN_DOMAIN'), 'secret' => env('MAILGUN_SECRET'), diff --git a/public/build/dist/js/all-29dc2bf4b8.js b/public/build/dist/js/all-29dc2bf4b8.js deleted file mode 100755 index fdaf283d..00000000 --- a/public/build/dist/js/all-29dc2bf4b8.js +++ /dev/null @@ -1,16 +0,0 @@ -function askConfirmation(t){swal({type:"warning",title:"Confirm your action",text:"Are you sure you want to do this?",confirmButtonText:"Yes",confirmButtonColor:"#FF6F6F",showCancelButton:!0},function(){t()})}if(function(t,e){"object"==typeof module&&"object"==typeof module.exports?module.exports=t.document?e(t,!0):function(t){if(!t.document)throw new Error("jQuery requires a window with a document");return e(t)}:e(t)}("undefined"!=typeof window?window:this,function(t,e){function n(t){var e="length"in t&&t.length,n=Z.type(t);return"function"===n||Z.isWindow(t)?!1:1===t.nodeType&&e?!0:"array"===n||0===e||"number"==typeof e&&e>0&&e-1 in t}function i(t,e,n){if(Z.isFunction(e))return Z.grep(t,function(t,i){return!!e.call(t,i,t)!==n});if(e.nodeType)return Z.grep(t,function(t){return t===e!==n});if("string"==typeof e){if(ot.test(e))return Z.filter(e,t,n);e=Z.filter(e,t)}return Z.grep(t,function(t){return U.call(e,t)>=0!==n})}function s(t,e){for(;(t=t[e])&&1!==t.nodeType;);return t}function r(t){var e=ft[t]={};return Z.each(t.match(pt)||[],function(t,n){e[n]=!0}),e}function a(){Q.removeEventListener("DOMContentLoaded",a,!1),t.removeEventListener("load",a,!1),Z.ready()}function o(){Object.defineProperty(this.cache={},0,{get:function(){return{}}}),this.expando=Z.expando+o.uid++}function l(t,e,n){var i;if(void 0===n&&1===t.nodeType)if(i="data-"+e.replace(Mt,"-$1").toLowerCase(),n=t.getAttribute(i),"string"==typeof n){try{n="true"===n?!0:"false"===n?!1:"null"===n?null:+n+""===n?+n:vt.test(n)?Z.parseJSON(n):n}catch(s){}yt.set(t,e,n)}else n=void 0;return n}function u(){return!0}function d(){return!1}function c(){try{return Q.activeElement}catch(t){}}function h(t,e){return Z.nodeName(t,"table")&&Z.nodeName(11!==e.nodeType?e:e.firstChild,"tr")?t.getElementsByTagName("tbody")[0]||t.appendChild(t.ownerDocument.createElement("tbody")):t}function p(t){return t.type=(null!==t.getAttribute("type"))+"/"+t.type,t}function f(t){var e=Wt.exec(t.type);return e?t.type=e[1]:t.removeAttribute("type"),t}function m(t,e){for(var n=0,i=t.length;i>n;n++)gt.set(t[n],"globalEval",!e||gt.get(e[n],"globalEval"))}function _(t,e){var n,i,s,r,a,o,l,u;if(1===e.nodeType){if(gt.hasData(t)&&(r=gt.access(t),a=gt.set(e,r),u=r.events)){delete a.handle,a.events={};for(s in u)for(n=0,i=u[s].length;i>n;n++)Z.event.add(e,s,u[s][n])}yt.hasData(t)&&(o=yt.access(t),l=Z.extend({},o),yt.set(e,l))}}function g(t,e){var n=t.getElementsByTagName?t.getElementsByTagName(e||"*"):t.querySelectorAll?t.querySelectorAll(e||"*"):[];return void 0===e||e&&Z.nodeName(t,e)?Z.merge([t],n):n}function y(t,e){var n=e.nodeName.toLowerCase();"input"===n&&kt.test(t.type)?e.checked=t.checked:("input"===n||"textarea"===n)&&(e.defaultValue=t.defaultValue)}function v(e,n){var i,s=Z(n.createElement(e)).appendTo(n.body),r=t.getDefaultComputedStyle&&(i=t.getDefaultComputedStyle(s[0]))?i.display:Z.css(s[0],"display");return s.detach(),r}function M(t){var e=Q,n=It[t];return n||(n=v(t,e),"none"!==n&&n||(Rt=(Rt||Z("