Skip to content

Commit

Permalink
Merge d2e12d7 into 4c5132d
Browse files Browse the repository at this point in the history
  • Loading branch information
zakhenry committed Jan 12, 2016
2 parents 4c5132d + d2e12d7 commit 459e633
Show file tree
Hide file tree
Showing 21 changed files with 567 additions and 14 deletions.
Binary file added .DS_Store
Binary file not shown.
38 changes: 38 additions & 0 deletions api/app/Http/Controllers/UtilityController.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
<?php

/*
* This file is part of the Spira framework.
*
* @link https://github.com/spira/spira
*
* For the full copyright and license information, please view the LICENSE file that was distributed with this source code.
*/

namespace App\Http\Controllers;

use Illuminate\Support\Facades\Storage;
use Spira\Core\Controllers\ApiController;
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;

class UtilityController extends ApiController
{
/**
* Enable permissions checks.
*/
protected $permissionsEnabled = true;

public function getSystemInformation()
{
$file = 'system-information.json';

if (! Storage::disk('local')->has($file)) {
throw new NotFoundHttpException("file $file not found");
}

$file = Storage::disk('local')->get($file);
$data = json_decode($file, true);

return $this->getResponse()
->item($data);
}
}
2 changes: 2 additions & 0 deletions api/app/Http/routes.php
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,8 @@
$app->patch('images/{id}', 'ImageController@patchOne');
$app->delete('images/{id}', 'ImageController@deleteOne');

$app->get('utility/system-information', 'UtilityController@getSystemInformation');

});

$app->group(['namespace' => 'App\Http\Controllers'], function (Application $app) {
Expand Down
1 change: 1 addition & 0 deletions app/src/app/admin/admin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ namespace app.admin {
namespace + '.media',
namespace + '.users',
namespace + '.articles',
namespace + '.utilities',
namespace + '.dashboard',
namespace + '.navigation',
])
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
<section layout="row" id="shopping-list-builder" layout-align="space-around start">

<md-card flex novalidate class="md-whiteframe-z2" layout-padding>

<md-toolbar>
<div class="md-toolbar-tools">
<h2>System Information</h2>
</div>
</md-toolbar>


<div ng-repeat="(source, commitDetails) in SystemInformationController.systemInformation" ng-if="!SystemInformationController.appMatchesApi || source == 'app'">


<h2>
<span ng-if="SystemInformationController.appMatchesApi">Commit Details (APP and API match)</span>
<span ng-if="!SystemInformationController.appMatchesApi">{{source | uppercase}} Commit Details</span>
</h2>

<div ng-if="source == 'app'">
<h3>Last App Build</h3>
<h4>{{commitDetails.appBuildDate}} ({{commitDetails.appBuildDate | fromNow}})</h4>
</div>

<h3>Latest Commit</h3>
<div layout="row">
<strong flex>Commit Hash</strong>
<span flex>{{commitDetails.latestCommit.commit}}</span>
</div>
<div layout="row">
<strong flex>Author</strong>
<span flex>{{commitDetails.latestCommit.author}}</span>
</div>
<div layout="row">
<strong flex>Message</strong>
<span flex>{{commitDetails.latestCommit.message}}</span>
</div>
<div layout="row">
<strong flex>Date</strong>
<span flex>{{commitDetails.latestCommit.date}} ({{commitDetails.latestCommit.date | fromNow}})</span>
</div>
<div layout="row">
<strong flex>Refs</strong>
<span flex>{{commitDetails.latestCommit.refs}}</span>
</div>

<div ng-if="commitDetails.latestCommit.commit !== commitDetails.tagCommit.commit">
<h3>Latest Tag (not the head commit)</h3>
<div layout="row">
<strong flex>Commit Hash</strong>
<span flex>{{commitDetails.tagCommit.commit}}</span>
</div>
<div layout="row">
<strong flex>Author</strong>
<span flex>{{commitDetails.tagCommit.author}}</span>
</div>
<div layout="row">
<strong flex>Message</strong>
<span flex>{{commitDetails.tagCommit.message}}</span>
</div>
<div layout="row">
<strong flex>Date</strong>
<span flex>{{commitDetails.tagCommit.date}} ({{commitDetails.tagCommit.date | fromNow}})</span>
</div>
<div layout="row">
<strong flex>Refs</strong>
<span flex>{{commitDetails.tagCommit.refs}}</span>
</div>

</div>

<h3>Continuous Integration</h3>
<div layout="row">
<strong flex>Build ID</strong>
<span flex><a target="_blank" href="{{commitDetails.ciBuild.url}}">{{commitDetails.ciBuild.id}}</a></span>
</div>
<div layout="row">
<strong flex>Build Date</strong>
<span flex>{{commitDetails.ciBuild.date}} ({{commitDetails.ciBuild.date | fromNow}})</span>
</div>
<div layout="row">
<strong flex>Deployment ID</strong>
<span flex><a target="_blank" href="{{commitDetails.ciDeployment.url}}">{{commitDetails.ciDeployment.id}}</a></span>
</div>
<div layout="row">
<strong flex>Build Date</strong>
<span flex>{{commitDetails.ciDeployment.date}} ({{commitDetails.ciDeployment.date | fromNow}})</span>
</div>

</div>

</md-card>
</section>
61 changes: 61 additions & 0 deletions app/src/app/admin/utilities/systemInformation/systemInformation.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
namespace app.admin.utilities.systemInformation {

export const namespace = 'app.admin.utilities.systemInformation';

export class SystemInformationConfig {

static $inject = ['stateHelperServiceProvider'];
constructor(private stateHelperServiceProvider){

let state:global.IState = {
url: '/system-information',
views: {
"main@app.admin": {
controller: namespace+'.controller',
controllerAs: 'SystemInformationController',
templateUrl: 'templates/app/admin/utilities/systemInformation/systemInformation.tpl.html',
}
},
resolve: /*@ngInject*/{
systemInformation: (systemInformationService:common.services.systemInformation.SystemInformationService):ng.IPromise<common.services.systemInformation.ISystemInformationSources> => {
return systemInformationService.getSystemInformation();
},
},
data: {
title: "System Information",
icon: 'developer_mode',
navigation: true,
}
};

stateHelperServiceProvider.addState(namespace, state);

}

}


export class SystemInformationController {

public appMatchesApi:boolean;

static $inject = [
'systemInformation',
];
constructor(
public systemInformation:common.services.systemInformation.ISystemInformationSources
) {

this.appMatchesApi = systemInformation.app.latestCommit.commit === systemInformation.api.latestCommit.commit;
}

}

angular.module(namespace, [])
.config(SystemInformationConfig)
.controller(namespace+'.controller', SystemInformationController);
}




32 changes: 32 additions & 0 deletions app/src/app/admin/utilities/utilities.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
namespace app.admin.utilities {

export const namespace = 'app.admin.utilities';

export class UtilitiesConfig {

static $inject = ['stateHelperServiceProvider'];
constructor(private stateHelperServiceProvider){

let state:global.IState = {
url: '/utilities',
abstract: true,
data: {
title: "Utilities",
icon: 'settings_applications',
navigation: true,
navigationGroup: 'admin',
sortAfter: app.admin.users.namespace,
}
};

stateHelperServiceProvider.addState(namespace, state);
}

}

angular.module(namespace, [
namespace + '.systemInformation',
])
.config(UtilitiesConfig);

}
1 change: 1 addition & 0 deletions app/src/common/filters/filters.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ namespace common.filters {

angular.module(namespace, [
namespace + '.trust',
namespace + '.momentFilters',
]);


Expand Down
24 changes: 24 additions & 0 deletions app/src/common/filters/moment/moment.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
namespace common.filters.momentFilters {

describe('Moment filter', function () {
let $filter:ng.IFilterService;

beforeEach(function () {
module('app');

inject(function (_$filter_) {
$filter = _$filter_;
});
});

it('should filter a moment object to a friendly date', function () {

let dt = moment().subtract(10, 'minutes');

let result = $filter('fromNow')(dt);

expect(result).to.equal('10 minutes ago');
});
});

}
20 changes: 20 additions & 0 deletions app/src/common/filters/moment/moment.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
namespace common.filters.momentFilters {

export const namespace = 'common.filters.momentFilters';

export function FromNowFilter() {

return function fromNow(date:moment.Moment):string|any{
if(!moment.isMoment(date)){
return date;
}
return date.fromNow();
}
}

angular.module(namespace, [])
.filter('fromNow', FromNowFilter)
;


}
23 changes: 22 additions & 1 deletion app/src/common/models/abstractModel.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,12 +12,14 @@ namespace common.models {
};

protected __attributeCastMap:IAttributeCastMap = {
bar: sinon.stub().returns('bar')
bar: sinon.stub().returns('bar'),
'deep.casting': sinon.stub().returns('deep-casting')
};

public foo:string;
public bar:string;
public foobar:string;
public deep:{casting:string};
public _hasOne:TestChildModel;
public _hasMany:TestChildModel[] = [];
public _hydrate:TestChildModel[] = [];
Expand Down Expand Up @@ -156,6 +158,25 @@ namespace common.models {

});

it('should run deep functions in the attribute cast map', () => {

let model = new TestModel({
deep: {
casting: 'foo',
}
});

expect(model.deep.casting).to.equal('deep-casting');

});

it('should not create a value for an undefined value', () => {

let model = new TestModel({});

expect(model.bar).to.be.undefined;
});

});

}
12 changes: 4 additions & 8 deletions app/src/common/models/abstractModel.ts
Original file line number Diff line number Diff line change
Expand Up @@ -77,15 +77,11 @@ namespace common.models {

if (_.isObject(data)) {

_.transform(data, (model, value, key) => {
_.assign(this, data);

if(_.has(this.__attributeCastMap, key)) {
model[key] = this.__attributeCastMap[key](value);
} else {
model[key] = value;
}

}, this);
_.forIn(this.__attributeCastMap, (caster:IAttributeCastFunction, accessor:string) => {
_.has(this, accessor) && (<any>_).set(this, accessor, caster.call(this, _.get(data, accessor)));
});

if (!_.isEmpty(this.__nestedEntityMap)) {
this.hydrateNested(data, exists);
Expand Down
Loading

0 comments on commit 459e633

Please sign in to comment.