added /logs

This commit is contained in:
Keivan Beigi 2013-06-04 17:49:53 -07:00
parent fc7d4536ac
commit 9160343a51
16 changed files with 231 additions and 16 deletions

View File

@ -8,6 +8,7 @@ using NzbDrone.Api.Config;
using NzbDrone.Api.Episodes; using NzbDrone.Api.Episodes;
using NzbDrone.Api.History; using NzbDrone.Api.History;
using NzbDrone.Api.Indexers; using NzbDrone.Api.Indexers;
using NzbDrone.Api.Logs;
using NzbDrone.Api.Mapping; using NzbDrone.Api.Mapping;
using NzbDrone.Api.Qualities; using NzbDrone.Api.Qualities;
using NzbDrone.Api.RootFolders; using NzbDrone.Api.RootFolders;
@ -15,6 +16,7 @@ using NzbDrone.Api.Series;
using NzbDrone.Api.Update; using NzbDrone.Api.Update;
using NzbDrone.Core.DecisionEngine; using NzbDrone.Core.DecisionEngine;
using NzbDrone.Core.Indexers; using NzbDrone.Core.Indexers;
using NzbDrone.Core.Instrumentation;
using NzbDrone.Core.Organizer; using NzbDrone.Core.Organizer;
using NzbDrone.Core.Parser.Model; using NzbDrone.Core.Parser.Model;
using NzbDrone.Core.Qualities; using NzbDrone.Core.Qualities;
@ -40,6 +42,7 @@ namespace NzbDrone.Api.Test.MappingTests
[TestCase(typeof(UpdatePackage), typeof(UpdateResource))] [TestCase(typeof(UpdatePackage), typeof(UpdateResource))]
[TestCase(typeof(QualityProfile), typeof(QualityProfileResource))] [TestCase(typeof(QualityProfile), typeof(QualityProfileResource))]
[TestCase(typeof(Quality), typeof(QualityResource))] [TestCase(typeof(Quality), typeof(QualityResource))]
[TestCase(typeof(Log), typeof(LogResource))]
public void matching_fields(Type modelType, Type resourceType) public void matching_fields(Type modelType, Type resourceType)
{ {
MappingValidation.ValidateMapping(modelType, resourceType); MappingValidation.ValidateMapping(modelType, resourceType);

View File

@ -0,0 +1,25 @@
using NzbDrone.Core.Datastore;
using NzbDrone.Core.History;
using NzbDrone.Core.Instrumentation;
using NzbDrone.Api.Mapping;
namespace NzbDrone.Api.Logs
{
public class LogModule : NzbDroneRestModule<LogResource>
{
private readonly ILogService _logService;
private readonly IHistoryService _historyService;
public LogModule(ILogService logService)
{
_logService = logService;
GetResourcePaged = GetLogs;
}
private PagingResource<LogResource> GetLogs(PagingResource<LogResource> pagingResource)
{
var pageSpec = pagingResource.InjectTo<PagingSpec<Log>>();
return ApplyToPage(_logService.Paged, pageSpec);
}
}
}

View File

@ -0,0 +1,16 @@
using System;
using NzbDrone.Api.REST;
namespace NzbDrone.Api.Logs
{
public class LogResource : RestResource
{
public DateTime Time { get; set; }
public String Exception { get; set; }
public String ExceptionType { get; set; }
public String Level { get; set; }
public String Logger { get; set; }
public String Message { get; set; }
public String Method { get; set; }
}
}

View File

@ -115,6 +115,8 @@
<Compile Include="Indexers\IndexerResource.cs" /> <Compile Include="Indexers\IndexerResource.cs" />
<Compile Include="Indexers\ReleaseModule.cs" /> <Compile Include="Indexers\ReleaseModule.cs" />
<Compile Include="Extensions\LazyExtensions.cs" /> <Compile Include="Extensions\LazyExtensions.cs" />
<Compile Include="Logs\LogModule.cs" />
<Compile Include="Logs\LogResource.cs" />
<Compile Include="Mapping\CloneInjection.cs" /> <Compile Include="Mapping\CloneInjection.cs" />
<Compile Include="Mapping\MappingValidation.cs" /> <Compile Include="Mapping\MappingValidation.cs" />
<Compile Include="Mapping\ResourceMappingException.cs" /> <Compile Include="Mapping\ResourceMappingException.cs" />

View File

@ -195,22 +195,26 @@ namespace NzbDrone.Api.REST
Int32.TryParse(Request.Query.Page.ToString(), out page); Int32.TryParse(Request.Query.Page.ToString(), out page);
if (page == 0) page = 1; if (page == 0) page = 1;
var sortKey = Request.Query.SortKey.ToString();
if (String.IsNullOrEmpty(sortKey)) sortKey = "AirDate";
var sortDirection = Request.Query.SortDir.ToString()
.Equals("Asc", StringComparison.InvariantCultureIgnoreCase)
? SortDirection.Ascending
: SortDirection.Descending;
var pagingResource = new PagingResource<TResource> var pagingResource = new PagingResource<TResource>
{ {
PageSize = pageSize, PageSize = pageSize,
Page = page, Page = page,
SortKey = sortKey,
SortDirection = sortDirection
}; };
if (Request.Query.SortKey != null)
{
pagingResource.SortKey = Request.Query.SortKey.ToString();
if (Request.Query.SortDir != null)
{
pagingResource.SortDirection = Request.Query.SortDir.ToString()
.Equals("Asc", StringComparison.InvariantCultureIgnoreCase)
? SortDirection.Ascending
: SortDirection.Descending;
}
}
return pagingResource; return pagingResource;
} }
} }

View File

@ -31,6 +31,7 @@ namespace NzbDrone.Core.Datastore
void DeleteMany(IEnumerable<int> ids); void DeleteMany(IEnumerable<int> ids);
void SetFields(TModel model, params Expression<Func<TModel, object>>[] properties); void SetFields(TModel model, params Expression<Func<TModel, object>>[] properties);
TModel Single(); TModel Single();
PagingSpec<TModel> GetPaged(PagingSpec<TModel> pagingSpec);
} }
@ -198,6 +199,21 @@ namespace NzbDrone.Core.Datastore
} }
public virtual PagingSpec<TModel> GetPaged(PagingSpec<TModel> pagingSpec)
{
var pagingQuery = Query.OrderBy(pagingSpec.OrderByClause(), pagingSpec.ToSortDirection())
.Skip(pagingSpec.PagingOffset())
.Take(pagingSpec.PageSize);
pagingSpec.Records = pagingQuery.ToList();
//TODO: Use the same query for count and records
pagingSpec.TotalRecords = Count();
return pagingSpec;
}
private void PublishModelEvent(TModel model, RepositoryAction action) private void PublishModelEvent(TModel model, RepositoryAction action)
{ {
if (PublishModelEvents) if (PublishModelEvents)

View File

@ -13,7 +13,6 @@ namespace NzbDrone.Core.History
{ {
void Trim(); void Trim();
List<QualityModel> GetEpisodeHistory(int episodeId); List<QualityModel> GetEpisodeHistory(int episodeId);
PagingSpec<History> Paged(PagingSpec<History> pagingSpec);
} }
public class HistoryRepository : BasicRepository<History>, IHistoryRepository public class HistoryRepository : BasicRepository<History>, IHistoryRepository
@ -36,7 +35,7 @@ namespace NzbDrone.Core.History
return history.Select(h => h.Quality).ToList(); return history.Select(h => h.Quality).ToList();
} }
public PagingSpec<History> Paged(PagingSpec<History> pagingSpec) public override PagingSpec<History> GetPaged(PagingSpec<History> pagingSpec)
{ {
var pagingQuery = Query.Join<History, Series>(JoinType.Inner, h => h.Series, (h, s) => h.SeriesId == s.Id) var pagingQuery = Query.Join<History, Series>(JoinType.Inner, h => h.Series, (h, s) => h.SeriesId == s.Id)
.Join<History, Episode>(JoinType.Inner, h => h.Episode, (h, e) => h.EpisodeId == e.Id) .Join<History, Episode>(JoinType.Inner, h => h.Episode, (h, e) => h.EpisodeId == e.Id)

View File

@ -36,7 +36,7 @@ namespace NzbDrone.Core.History
public PagingSpec<History> Paged(PagingSpec<History> pagingSpec) public PagingSpec<History> Paged(PagingSpec<History> pagingSpec)
{ {
return _historyRepository.Paged(pagingSpec); return _historyRepository.GetPaged(pagingSpec);
} }
public void Purge() public void Purge()

View File

@ -1,4 +1,5 @@
using System.Linq; using System.Linq;
using NzbDrone.Core.Datastore;
namespace NzbDrone.Core.Instrumentation namespace NzbDrone.Core.Instrumentation
{ {
@ -6,6 +7,7 @@ namespace NzbDrone.Core.Instrumentation
{ {
void DeleteAll(); void DeleteAll();
void Trim(); void Trim();
PagingSpec<Log> Paged(PagingSpec<Log> pagingSpec);
} }
public class LogService : ILogService public class LogService : ILogService
@ -26,5 +28,10 @@ namespace NzbDrone.Core.Instrumentation
{ {
_logRepository.Trim(); _logRepository.Trim();
} }
public PagingSpec<Log> Paged(PagingSpec<Log> pagingSpec)
{
return _logRepository.GetPaged(pagingSpec);
}
} }
} }

View File

@ -10,6 +10,7 @@ define(['app',
'Series/Details/SeriesDetailsLayout', 'Series/Details/SeriesDetailsLayout',
'Series/EpisodeCollection', 'Series/EpisodeCollection',
'Settings/SettingsLayout', 'Settings/SettingsLayout',
'Logs/Layout',
'Missing/MissingLayout', 'Missing/MissingLayout',
'History/HistoryLayout'], 'History/HistoryLayout'],
function () { function () {
@ -62,11 +63,17 @@ define(['app',
NzbDrone.mainRegion.show(new NzbDrone.History.HistoryLayout()); NzbDrone.mainRegion.show(new NzbDrone.History.HistoryLayout());
}, },
logs: function () {
this._setTitle('logs');
NzbDrone.mainRegion.show(new NzbDrone.Logs.Layout());
},
notFound: function () { notFound: function () {
this._setTitle('Not Found'); this._setTitle('Not Found');
NzbDrone.mainRegion.show(new NzbDrone.Shared.NotFoundView(this)); NzbDrone.mainRegion.show(new NzbDrone.Shared.NotFoundView(this));
}, },
_setTitle: function (title) { _setTitle: function (title) {
//$('#title-region').html(title); //$('#title-region').html(title);

37
UI/Logs/Collection.js Normal file
View File

@ -0,0 +1,37 @@
"use strict";
define(['app', 'Logs/Model'], function () {
NzbDrone.Logs.Collection = Backbone.PageableCollection.extend({
url : NzbDrone.Constants.ApiRoot + '/log',
model : NzbDrone.Logs.Model,
state: {
pageSize: 50,
sortKey: "time",
order: 1
},
queryParams: {
totalPages: null,
totalRecords: null,
pageSize: 'pageSize',
sortKey: "sortKey",
order: "sortDir",
directions: {
"-1": "asc",
"1": "desc"
}
},
parseState: function (resp, queryParams, state) {
return {totalRecords: resp.totalRecords};
},
parseRecords: function (resp) {
if (resp) {
return resp.records;
}
return resp;
}
});
});

72
UI/Logs/Layout.js Normal file
View File

@ -0,0 +1,72 @@
"use strict";
define([
'app',
'Logs/Collection',
'Shared/Toolbar/ToolbarLayout'
],
function () {
NzbDrone.Logs.Layout = Backbone.Marionette.Layout.extend({
template: 'Logs/LayoutTemplate',
regions: {
grid : '#x-grid',
toolbar: '#x-toolbar',
pager : '#x-pager'
},
columns: [
{
name : 'level',
label : 'Level',
sortable: true,
cell : Backgrid.StringCell
},
{
name : 'logger',
label : 'Component',
sortable: true,
cell : Backgrid.StringCell
},
{
name : 'message',
label : 'Message',
sortable: false,
cell : Backgrid.StringCell
},
{
name : 'time',
label: 'Time',
cell : Backgrid.DatetimeCell
}
],
showTable: function () {
this.grid.show(new Backgrid.Grid(
{
row : Backgrid.Row,
columns : this.columns,
collection: this.collection,
className : 'table table-hover'
}));
this.pager.show(new Backgrid.NzbDronePaginator({
columns : this.columns,
collection: this.collection
}));
},
initialize: function () {
this.collection = new NzbDrone.Logs.Collection();
this.collection.fetch();
},
onShow: function () {
this.showTable();
//this.toolbar.show(new NzbDrone.Shared.Toolbar.ToolbarLayout({right: [ viewButtons], context: this}));
}
})
;
})
;

View File

@ -0,0 +1,11 @@
<div id="x-toolbar"></div>
<div class="row">
<div class="span12">
<div id="x-grid"></div>
</div>
</div>
<div class="row">
<div class="span12">
<div id="x-pager"></div>
</div>
</div>

14
UI/Logs/Model.js Normal file
View File

@ -0,0 +1,14 @@
"use strict";
define(['app'], function (app) {
NzbDrone.Logs.Model = Backbone.Model.extend({
/* mutators: {
seasonNumber: function () {
return this.get('episode').seasonNumber;
},
paddedEpisodeNumber: function () {
return this.get('episode').episodeNumber.pad(2);
}
}*/
});
});

View File

@ -16,6 +16,7 @@ require(['app', 'Controller'], function (app, controller) {
'settings/:action(/:query)' : 'settings', 'settings/:action(/:query)' : 'settings',
'missing' : 'missing', 'missing' : 'missing',
'history' : 'history', 'history' : 'history',
'logs' : 'logs',
':whatever' : 'notFound' ':whatever' : 'notFound'
} }
}); });

View File

@ -82,6 +82,7 @@ define('app', ['shared/modal/region'], function (ModalRegion) {
window.NzbDrone.Missing = {}; window.NzbDrone.Missing = {};
window.NzbDrone.History = {}; window.NzbDrone.History = {};
window.NzbDrone.Logs = {};
window.NzbDrone.Mixins = {}; window.NzbDrone.Mixins = {};
window.NzbDrone.Events = { window.NzbDrone.Events = {