Added MassEdit for series editing.
This commit is contained in:
parent
906b5d12cd
commit
e885fadc59
NzbDrone.Core.Test/ProviderTests
NzbDrone.Core/Providers
NzbDrone.Web
|
@ -706,5 +706,80 @@ namespace NzbDrone.Core.Test.ProviderTests
|
|||
//Assert
|
||||
series.Should().HaveCount(1);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void UpdateFromMassEdit_should_only_update_certain_values()
|
||||
{
|
||||
WithRealDb();
|
||||
var newQualityProfileId = 10;
|
||||
var newMonitored = false;
|
||||
var newSeasonFolder = false;
|
||||
|
||||
var fakeQuality = Builder<QualityProfile>.CreateNew().Build();
|
||||
var fakeSeries = Builder<Series>.CreateListOfSize(1)
|
||||
.All()
|
||||
.With(e => e.QualityProfileId = fakeQuality.QualityProfileId)
|
||||
.With(e => e.Monitored = true)
|
||||
.With(e => e.SeasonFolder = true)
|
||||
.With(s => s.Title = "It's Always Sunny")
|
||||
.Build();
|
||||
|
||||
Db.InsertMany(fakeSeries);
|
||||
Db.Insert(fakeQuality);
|
||||
|
||||
fakeSeries[0].QualityProfileId = newQualityProfileId;
|
||||
fakeSeries[0].Monitored = newMonitored;
|
||||
fakeSeries[0].SeasonFolder = newSeasonFolder;
|
||||
|
||||
//Act
|
||||
Mocker.Resolve<SeriesProvider>().UpdateFromMassEdit(fakeSeries);
|
||||
|
||||
//Assert
|
||||
var result = Db.Fetch<Series>();
|
||||
result.Count.Should().Be(1);
|
||||
result.First().QualityProfileId.Should().Be(newQualityProfileId);
|
||||
result.First().Monitored.Should().Be(newMonitored);
|
||||
result.First().SeasonFolder.Should().Be(newSeasonFolder);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void UpdateFromMassEdit_should_only_update_changed_values()
|
||||
{
|
||||
WithRealDb();
|
||||
var newQualityProfileId = 10;
|
||||
var newMonitored = false;
|
||||
var newSeasonFolder = false;
|
||||
var monitored = true;
|
||||
var seasonFolder = true;
|
||||
|
||||
var fakeQuality = Builder<QualityProfile>.CreateNew().Build();
|
||||
var fakeSeries = Builder<Series>.CreateListOfSize(2)
|
||||
.All()
|
||||
.With(e => e.QualityProfileId = fakeQuality.QualityProfileId)
|
||||
.With(e => e.Monitored = monitored)
|
||||
.With(e => e.SeasonFolder = seasonFolder)
|
||||
.With(s => s.Title = "It's Always Sunny")
|
||||
.Build();
|
||||
|
||||
Db.InsertMany(fakeSeries);
|
||||
Db.Insert(fakeQuality);
|
||||
|
||||
fakeSeries[0].QualityProfileId = newQualityProfileId;
|
||||
fakeSeries[0].Monitored = newMonitored;
|
||||
fakeSeries[0].SeasonFolder = newSeasonFolder;
|
||||
|
||||
//Act
|
||||
Mocker.Resolve<SeriesProvider>().UpdateFromMassEdit(fakeSeries);
|
||||
|
||||
//Assert
|
||||
var result = Db.Fetch<Series>();
|
||||
result.Count.Should().Be(2);
|
||||
result.First().QualityProfileId.Should().Be(newQualityProfileId);
|
||||
result.First().Monitored.Should().Be(newMonitored);
|
||||
result.First().SeasonFolder.Should().Be(newSeasonFolder);
|
||||
result.Last().QualityProfileId.Should().Be(fakeQuality.QualityProfileId);
|
||||
result.Last().Monitored.Should().Be(monitored);
|
||||
result.Last().SeasonFolder.Should().Be(seasonFolder);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -198,6 +198,23 @@ namespace NzbDrone.Core.Providers
|
|||
return series;
|
||||
}
|
||||
|
||||
public virtual void UpdateFromMassEdit(IList<Series> editedSeries)
|
||||
{
|
||||
var allSeries = GetAllSeries();
|
||||
|
||||
foreach(var series in allSeries)
|
||||
{
|
||||
//Only update parameters that can be changed in MassEdit
|
||||
var edited = editedSeries.Single(s => s.SeriesId == series.SeriesId);
|
||||
series.QualityProfileId = edited.QualityProfileId;
|
||||
series.Monitored = edited.Monitored;
|
||||
series.SeasonFolder = edited.SeasonFolder;
|
||||
series.Path = edited.Path;
|
||||
}
|
||||
|
||||
_database.UpdateMany(allSeries);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Cleans up the AirsTime Component from TheTVDB since it can be garbage that comes in.
|
||||
/// </summary>
|
||||
|
|
|
@ -9,6 +9,7 @@ using NzbDrone.Core.Helpers;
|
|||
using NzbDrone.Core.Jobs;
|
||||
using NzbDrone.Core.Providers;
|
||||
using NzbDrone.Core.Repository;
|
||||
using NzbDrone.Core.Repository.Quality;
|
||||
using NzbDrone.Web.Models;
|
||||
using Telerik.Web.Mvc;
|
||||
|
||||
|
@ -148,6 +149,40 @@ namespace NzbDrone.Web.Controllers
|
|||
return View(model);
|
||||
}
|
||||
|
||||
public ActionResult MassEdit()
|
||||
{
|
||||
var profiles = _qualityProvider.All();
|
||||
ViewData["QualityProfiles"] = profiles;
|
||||
|
||||
//Create the select lists
|
||||
var masterProfiles = profiles.ToList();
|
||||
masterProfiles.Insert(0, new QualityProfile {QualityProfileId = -10, Name = "Unchanged"});
|
||||
ViewData["MasterProfileSelectList"] = new SelectList(masterProfiles, "QualityProfileId", "Name");
|
||||
|
||||
ViewData["BoolSelectList"] = new SelectList(new List<KeyValuePair<int, string>>
|
||||
{
|
||||
new KeyValuePair<int, string>(-10, "Unchanged"),
|
||||
new KeyValuePair<int, string>(1, "True"),
|
||||
new KeyValuePair<int, string>(0, "False")
|
||||
}, "Key", "Value"
|
||||
);
|
||||
|
||||
var series = _seriesProvider.GetAllSeries().OrderBy(o => SortHelper.SkipArticles(o.Title));
|
||||
|
||||
return View(series);
|
||||
}
|
||||
|
||||
[HttpPost]
|
||||
public JsonResult SaveMassEdit(List<Series> series)
|
||||
{
|
||||
//Save edits
|
||||
if (series == null || series.Count == 0)
|
||||
return JsonNotificationResult.Opps("Invalid post data");
|
||||
|
||||
_seriesProvider.UpdateFromMassEdit(series);
|
||||
return JsonNotificationResult.Info("Series Mass Edit Saved");
|
||||
}
|
||||
|
||||
private List<SeriesModel> GetSeriesModels(IList<Series> seriesInDb)
|
||||
{
|
||||
var series = seriesInDb.Select(s => new SeriesModel
|
||||
|
|
|
@ -523,6 +523,12 @@
|
|||
<ItemGroup>
|
||||
<Content Include="Views\Settings\Misc.cshtml" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Content Include="Views\Series\MassEdit.cshtml" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Content Include="Views\Series\SeriesItem.cshtml" />
|
||||
</ItemGroup>
|
||||
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
|
||||
<Import Project="$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v10.0\WebApplications\Microsoft.WebApplication.targets" />
|
||||
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
|
||||
|
|
|
@ -0,0 +1,147 @@
|
|||
@using NzbDrone.Web.Helpers
|
||||
@model IEnumerable<NzbDrone.Core.Repository.Series>
|
||||
@{ViewBag.Title = "NzbDrone";}
|
||||
|
||||
@section HeaderContent
|
||||
{
|
||||
@Html.IncludeCss("Settings.css")
|
||||
|
||||
<style>
|
||||
.checkboxColumn {
|
||||
width: 95px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.masterControls {
|
||||
margin-top: 10px;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.buttons {
|
||||
width: 600px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
table input[type="text"], table select {
|
||||
margin: 2px 5px 2px 5px;
|
||||
}
|
||||
|
||||
table {
|
||||
width: 100%;
|
||||
border-width: 1px;
|
||||
border-spacing: 2px;
|
||||
border-style: none;
|
||||
border-color: white;
|
||||
border-collapse: collapse;
|
||||
background-color: white;
|
||||
}
|
||||
table th {
|
||||
border-width: 1px;
|
||||
padding: 2px;
|
||||
border-style: inset;
|
||||
border-color: #EEEEEE;
|
||||
background-color: white;
|
||||
-moz-border-radius: ;
|
||||
}
|
||||
table td {
|
||||
border-width: 1px;
|
||||
padding: 2px;
|
||||
border-style: inset;
|
||||
border-color: #EEEEEE;
|
||||
background-color: white;
|
||||
-moz-border-radius: ;
|
||||
}
|
||||
</style>
|
||||
}
|
||||
|
||||
@using (Html.BeginForm("SaveMassEdit", "Series", FormMethod.Post, new { id = "MassEdit", name = "MassEdit" }))
|
||||
{
|
||||
<table>
|
||||
<tr>
|
||||
<th>@Html.CheckBox("editToggleMaster", false, new { @class = "editToggleMaster" })</th>
|
||||
<th>Title</th>
|
||||
<th>Quality</th>
|
||||
<th class="checkboxColumn">Monitored</th>
|
||||
<th class="checkboxColumn">Season Folder</th>
|
||||
<th>Path</th>
|
||||
</tr>
|
||||
|
||||
@foreach (var series in Model)
|
||||
{
|
||||
Html.RenderPartial("SeriesItem", series);
|
||||
}
|
||||
</table>
|
||||
|
||||
<div class="masterControls">
|
||||
<div id="stylized" style="border-color: transparent;">
|
||||
<div class="settingsForm">
|
||||
<label class="labelClass">Quality Profile
|
||||
<span class="small">Which Quality Profile should NzbDrone use to download episodes?</span>
|
||||
</label>
|
||||
@Html.DropDownList("masterQualitySelector", (SelectList)ViewData["MasterProfileSelectList"], new { @class = "inputClass" })
|
||||
<label class="labelClass">Monitored
|
||||
<span class="small">Should NzbDrone download episodes for this series?</span>
|
||||
</label>
|
||||
@Html.DropDownList("masterMonitored", (SelectList)ViewData["BoolSelectList"], new { @class = "inputClass" })
|
||||
<label class="labelClass">Use Season Folder
|
||||
<span class="small">Should downloaded episodes be stored in season folders?</span>
|
||||
</label>
|
||||
@Html.DropDownList("masterSeasonFolder", (SelectList)ViewData["BoolSelectList"], new { @class = "inputClass" })
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="buttons">
|
||||
<button id="updateSelected" title="Update the selected series with the settings above">Update Selected</button>
|
||||
|
||||
<button type="submit" class="save_button" disabled="disabled" title="Commit the settings from your series above to the database">
|
||||
Save Changes</button>
|
||||
</div>
|
||||
}
|
||||
|
||||
@section Scripts
|
||||
{
|
||||
<script>
|
||||
$('.editToggleMaster').live('change', function () {
|
||||
var toggle = $(this).prop('checked');
|
||||
$('.editToggle').each(function () {
|
||||
$(this).prop('checked', toggle);
|
||||
});
|
||||
});
|
||||
|
||||
$('#updateSelected').live('click', function () {
|
||||
//Find selected values
|
||||
var profileId = $('#masterQualitySelector').val();
|
||||
var monitored = $('#masterMonitored').val();
|
||||
var seasonFolder = $('#masterSeasonFolder').val();
|
||||
|
||||
var selected = $('.editToggle:checked');
|
||||
|
||||
selected.each(function() {
|
||||
if (profileId != -10) {
|
||||
$(this).parent('td').parent('.seriesEditRow').find('.quality').val(profileId);
|
||||
}
|
||||
|
||||
if (monitored != -10) {
|
||||
var monitoredBool = true;
|
||||
if (monitored != 1)
|
||||
monitoredBool = false;
|
||||
|
||||
$(this).parent('td').parent('.seriesEditRow').find('.monitored').prop('checked', monitoredBool);
|
||||
}
|
||||
|
||||
if (seasonFolder != -10) {
|
||||
var seasonFolderBool = true;
|
||||
if (seasonFolder != 1)
|
||||
seasonFolderBool = false;
|
||||
|
||||
$(this).parent('td').parent('.seriesEditRow').find('.seasonFolder').prop('checked', seasonFolderBool);
|
||||
}
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
|
||||
//Update all checked rows
|
||||
</script>
|
||||
}
|
|
@ -0,0 +1,23 @@
|
|||
@model NzbDrone.Core.Repository.Series
|
||||
@using NzbDrone.Core.Repository.Quality
|
||||
@using NzbDrone.Web.Helpers
|
||||
|
||||
@{
|
||||
Layout = null;
|
||||
}
|
||||
|
||||
@*SeriesId, Title, Quality, Monitored, Use Season Folder, Root Directory/Path*, Backlog Toggle*@
|
||||
|
||||
@using (Html.BeginCollectionItem("series"))
|
||||
{
|
||||
var idClean = ViewData.TemplateInfo.HtmlFieldPrefix.Replace('[', '_').Replace(']', '_');
|
||||
<tr class="seriesEditRow">
|
||||
@Html.HiddenFor(m => m.SeriesId)
|
||||
<td>@Html.CheckBox("editToggle", false, new {@class = "editToggle"})</td>
|
||||
<td>@Model.Title</td>
|
||||
<td>@Html.DropDownListFor(m => m.QualityProfileId, new SelectList((List<QualityProfile>)ViewData["QualityProfiles"], "QualityProfileId", "Name", Model.QualityProfileId), new { @class = "quality" })</td>
|
||||
<td class="checkboxColumn">@Html.CheckBoxFor(m => m.Monitored, new {@class = "seriesCheckbox monitored"})</td>
|
||||
<td class="checkboxColumn">@Html.CheckBoxFor(m => m.SeasonFolder, new {@class = "seriesCheckbox seasonFolder"})</td>
|
||||
<td>@Html.TextBoxFor(m => m.Path)</td>
|
||||
</tr>
|
||||
}
|
Loading…
Reference in New Issue