mirror of
https://github.com/Ombi-app/Ombi.git
synced 2025-07-10 15:32:37 -07:00
most of #273 done
This commit is contained in:
parent
66bede34f4
commit
4808fffcef
15 changed files with 453 additions and 103 deletions
|
@ -43,6 +43,7 @@ namespace PlexRequests.Core.Models
|
||||||
public bool Deleted { get; set; }
|
public bool Deleted { get; set; }
|
||||||
public RequestType Type { get; set; }
|
public RequestType Type { get; set; }
|
||||||
public IssueStatus IssueStatus { get; set; }
|
public IssueStatus IssueStatus { get; set; }
|
||||||
|
public int ProviderId { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
public class IssueModel
|
public class IssueModel
|
||||||
|
@ -56,7 +57,6 @@ namespace PlexRequests.Core.Models
|
||||||
public enum IssueStatus
|
public enum IssueStatus
|
||||||
{
|
{
|
||||||
PendingIssue,
|
PendingIssue,
|
||||||
InProgressIssue,
|
|
||||||
ResolvedIssue
|
ResolvedIssue
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -102,6 +102,7 @@
|
||||||
<Compile Include="ApiModuleTests.cs" />
|
<Compile Include="ApiModuleTests.cs" />
|
||||||
<Compile Include="BootstrapperExtensions.cs" />
|
<Compile Include="BootstrapperExtensions.cs" />
|
||||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||||
|
<Compile Include="StringHelperTests.cs" />
|
||||||
<Compile Include="TestRootPathProvider.cs" />
|
<Compile Include="TestRootPathProvider.cs" />
|
||||||
<Compile Include="UserLoginModuleTests.cs" />
|
<Compile Include="UserLoginModuleTests.cs" />
|
||||||
<Compile Include="AdminModuleTests.cs" />
|
<Compile Include="AdminModuleTests.cs" />
|
||||||
|
|
76
PlexRequests.UI.Tests/StringHelperTests.cs
Normal file
76
PlexRequests.UI.Tests/StringHelperTests.cs
Normal file
|
@ -0,0 +1,76 @@
|
||||||
|
#region Copyright
|
||||||
|
// /************************************************************************
|
||||||
|
// Copyright (c) 2016 Jamie Rees
|
||||||
|
// File: StringHelperTests.cs
|
||||||
|
// Created By: Jamie Rees
|
||||||
|
//
|
||||||
|
// Permission is hereby granted, free of charge, to any person obtaining
|
||||||
|
// a copy of this software and associated documentation files (the
|
||||||
|
// "Software"), to deal in the Software without restriction, including
|
||||||
|
// without limitation the rights to use, copy, modify, merge, publish,
|
||||||
|
// distribute, sublicense, and/or sell copies of the Software, and to
|
||||||
|
// permit persons to whom the Software is furnished to do so, subject to
|
||||||
|
// the following conditions:
|
||||||
|
//
|
||||||
|
// The above copyright notice and this permission notice shall be
|
||||||
|
// included in all copies or substantial portions of the Software.
|
||||||
|
//
|
||||||
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||||
|
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||||
|
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||||
|
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||||
|
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||||
|
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||||
|
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
|
// ************************************************************************/
|
||||||
|
#endregion
|
||||||
|
using System.Collections.Generic;
|
||||||
|
|
||||||
|
using NUnit.Framework;
|
||||||
|
|
||||||
|
using PlexRequests.Core.Models;
|
||||||
|
using PlexRequests.UI.Helpers;
|
||||||
|
|
||||||
|
namespace PlexRequests.UI.Tests
|
||||||
|
{
|
||||||
|
[TestFixture]
|
||||||
|
public class StringHelperTests
|
||||||
|
{
|
||||||
|
[TestCaseSource(nameof(StringData))]
|
||||||
|
public string FirstCharToUpperTest(string input)
|
||||||
|
{
|
||||||
|
return input.FirstCharToUpper();
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestCaseSource(nameof(StringCaseData))]
|
||||||
|
public string ToCamelCaseWordsTest(string input)
|
||||||
|
{
|
||||||
|
return input.ToCamelCaseWords();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static IEnumerable<TestCaseData> StringData
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
yield return new TestCaseData("abcCba").Returns("AbcCba");
|
||||||
|
yield return new TestCaseData("").Returns("");
|
||||||
|
yield return new TestCaseData("12DSAda").Returns("12DSAda");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static IEnumerable<TestCaseData> StringCaseData
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
yield return new TestCaseData("abcCba").Returns("Abc Cba");
|
||||||
|
yield return new TestCaseData("").Returns("");
|
||||||
|
yield return new TestCaseData("JamieRees").Returns("Jamie Rees");
|
||||||
|
yield return new TestCaseData("Jamierees").Returns("Jamierees");
|
||||||
|
yield return new TestCaseData("ThisIsANewString").Returns("This Is A New String");
|
||||||
|
yield return new TestCaseData("").Returns("");
|
||||||
|
yield return new TestCaseData(IssueStatus.PendingIssue.ToString()).Returns("Pending Issue");
|
||||||
|
yield return new TestCaseData(IssueStatus.ResolvedIssue.ToString()).Returns("Resolved Issue");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -111,11 +111,12 @@ namespace PlexRequests.UI
|
||||||
container.Register<IHeadphonesApi, HeadphonesApi>();
|
container.Register<IHeadphonesApi, HeadphonesApi>();
|
||||||
container.Register<ISlackApi, SlackApi>();
|
container.Register<ISlackApi, SlackApi>();
|
||||||
|
|
||||||
|
|
||||||
|
container.AutoRegister();
|
||||||
|
|
||||||
// Notification Service
|
// Notification Service
|
||||||
container.Register<INotificationService, NotificationService>().AsSingleton();
|
container.Register<INotificationService, NotificationService>().AsSingleton();
|
||||||
|
|
||||||
JsonSettings.MaxJsonLength = int.MaxValue;
|
|
||||||
|
|
||||||
SubscribeAllObservers(container);
|
SubscribeAllObservers(container);
|
||||||
base.ConfigureRequestContainer(container, context);
|
base.ConfigureRequestContainer(container, context);
|
||||||
var loc = ServiceLocator.Instance;
|
var loc = ServiceLocator.Instance;
|
||||||
|
@ -131,6 +132,7 @@ namespace PlexRequests.UI
|
||||||
container.Register<IUserMapper, UserMapper>();
|
container.Register<IUserMapper, UserMapper>();
|
||||||
container.Register<ICustomUserMapper, UserMapper>();
|
container.Register<ICustomUserMapper, UserMapper>();
|
||||||
|
|
||||||
|
JsonSettings.MaxJsonLength = int.MaxValue;
|
||||||
|
|
||||||
CookieBasedSessions.Enable(pipelines, CryptographyConfiguration.Default);
|
CookieBasedSessions.Enable(pipelines, CryptographyConfiguration.Default);
|
||||||
StaticConfiguration.DisableErrorTraces = false;
|
StaticConfiguration.DisableErrorTraces = false;
|
||||||
|
|
|
@ -17,9 +17,6 @@ initLoad();
|
||||||
$('a[data-toggle="tab"]').on('shown.bs.tab', function (e) {
|
$('a[data-toggle="tab"]').on('shown.bs.tab', function (e) {
|
||||||
var target = $(e.target).attr('href');
|
var target = $(e.target).attr('href');
|
||||||
|
|
||||||
if (target === "#inProgressTab") {
|
|
||||||
loadInProgressIssues();
|
|
||||||
}
|
|
||||||
if (target === "#resolvedTab") {
|
if (target === "#resolvedTab") {
|
||||||
loadResolvedIssues();
|
loadResolvedIssues();
|
||||||
}
|
}
|
||||||
|
@ -117,10 +114,12 @@ $('#myModal').on('show.bs.modal', function (event) {
|
||||||
var button = $(event.relatedTarget); // Button that triggered the modal
|
var button = $(event.relatedTarget); // Button that triggered the modal
|
||||||
var id = button.data('identifier'); // Extract info from data-* attributes
|
var id = button.data('identifier'); // Extract info from data-* attributes
|
||||||
|
|
||||||
|
|
||||||
var modal = $(this);
|
var modal = $(this);
|
||||||
modal.find('.theSaveButton').val(id); // Add ID to the button
|
modal.find('.theSaveButton').val(id); // Add ID to the button
|
||||||
var requestField = modal.find('input');
|
var requestField = modal.find('input');
|
||||||
requestField.val(id); // Add ID to the hidden field
|
requestField.val(id); // Add ID to the hidden field
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
// Update the note modal
|
// Update the note modal
|
||||||
|
@ -194,7 +193,7 @@ function initLoad() {
|
||||||
}
|
}
|
||||||
|
|
||||||
function loadCounts() {
|
function loadCounts() {
|
||||||
var url = createBaseUrl(base, "issues/tabCount");
|
var url = createBaseUrl(base, "/issues/tabCount");
|
||||||
$.ajax({
|
$.ajax({
|
||||||
type: "get",
|
type: "get",
|
||||||
url: url,
|
url: url,
|
||||||
|
@ -226,13 +225,6 @@ function loadPendingIssues() {
|
||||||
loadIssues("pending", $('#pendingIssues'));
|
loadIssues("pending", $('#pendingIssues'));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
function loadInProgressIssues() {
|
|
||||||
var $element = $('#inprogressIssues');
|
|
||||||
$element.html("");
|
|
||||||
loadIssues("inprogress", $element);
|
|
||||||
}
|
|
||||||
|
|
||||||
function loadResolvedIssues() {
|
function loadResolvedIssues() {
|
||||||
var $element = $('#resolvedIssues');
|
var $element = $('#resolvedIssues');
|
||||||
$element.html("");
|
$element.html("");
|
||||||
|
@ -240,8 +232,8 @@ function loadResolvedIssues() {
|
||||||
}
|
}
|
||||||
|
|
||||||
function loadIssues(type, element) {
|
function loadIssues(type, element) {
|
||||||
var url = createBaseUrl(base, "issues/" + type);
|
var url = createBaseUrl(base, "/issues/" + type);
|
||||||
var linkUrl = createBaseUrl(base, "issues/");
|
var linkUrl = createBaseUrl(base, "/issues/");
|
||||||
$.ajax({
|
$.ajax({
|
||||||
type: "get",
|
type: "get",
|
||||||
url: url,
|
url: url,
|
||||||
|
@ -272,7 +264,7 @@ function buildIssueContext(result) {
|
||||||
requestId: result.requestId,
|
requestId: result.requestId,
|
||||||
type: result.type,
|
type: result.type,
|
||||||
title: result.title,
|
title: result.title,
|
||||||
count: result.count
|
issues: result.issues
|
||||||
};
|
};
|
||||||
|
|
||||||
return context;
|
return context;
|
||||||
|
|
|
@ -184,6 +184,78 @@ $(function () {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Report Issue
|
||||||
|
$(document).on("click", ".dropdownIssue", function (e) {
|
||||||
|
var issue = $(this).attr("issue-select");
|
||||||
|
var id = e.target.id;
|
||||||
|
// Other issue so the modal is opening
|
||||||
|
if (issue == 4) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
e.preventDefault();
|
||||||
|
|
||||||
|
var $form = $('#report' + id);
|
||||||
|
var data = $form.serialize();
|
||||||
|
data = data + "&issue=" + issue;
|
||||||
|
|
||||||
|
$.ajax({
|
||||||
|
type: $form.prop('method'),
|
||||||
|
url: $form.prop('action'),
|
||||||
|
data: data,
|
||||||
|
dataType: "json",
|
||||||
|
success: function (response) {
|
||||||
|
if (checkJsonResponse(response)) {
|
||||||
|
generateNotify("Successfully Reported Issue.", "success");
|
||||||
|
}
|
||||||
|
},
|
||||||
|
error: function (e) {
|
||||||
|
console.log(e);
|
||||||
|
generateNotify("Something went wrong!", "danger");
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
// Save Modal click
|
||||||
|
$(".theSaveButton").click(function (e) {
|
||||||
|
var comment = $("#commentArea").val();
|
||||||
|
e.preventDefault();
|
||||||
|
|
||||||
|
var $form = $("#commentForm");
|
||||||
|
var data = $form.serialize();
|
||||||
|
data = data + "&comment=" + comment;
|
||||||
|
|
||||||
|
$.ajax({
|
||||||
|
type: $form.prop("method"),
|
||||||
|
url: $form.prop("action"),
|
||||||
|
data: data,
|
||||||
|
dataType: "json",
|
||||||
|
success: function (response) {
|
||||||
|
if (checkJsonResponse(response)) {
|
||||||
|
generateNotify("Success! Added Issue.", "success");
|
||||||
|
$("#myModal").modal("hide");
|
||||||
|
}
|
||||||
|
},
|
||||||
|
error: function (e) {
|
||||||
|
console.log(e);
|
||||||
|
generateNotify("Something went wrong!", "danger");
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
// Update the modal
|
||||||
|
$('#issuesModal').on('show.bs.modal', function (event) {
|
||||||
|
var button = $(event.relatedTarget); // Button that triggered the modal
|
||||||
|
var id = button.data('identifier'); // Extract info from data-* attributes
|
||||||
|
var type = button.data('type'); // Extract info from data-* attributes
|
||||||
|
|
||||||
|
var modal = $(this);
|
||||||
|
modal.find('.theSaveButton').val(id); // Add ID to the button
|
||||||
|
|
||||||
|
|
||||||
|
$('#providerIdModal').val(id);
|
||||||
|
$('#typeModal').val(type);
|
||||||
|
});
|
||||||
|
|
||||||
function focusSearch($content) {
|
function focusSearch($content) {
|
||||||
if ($content.length > 0) {
|
if ($content.length > 0) {
|
||||||
$('input[type=text].form-control', $content).first().focus();
|
$('input[type=text].form-control', $content).first().focus();
|
||||||
|
|
|
@ -1,4 +1,29 @@
|
||||||
using System;
|
#region Copyright
|
||||||
|
// /************************************************************************
|
||||||
|
// Copyright (c) 2016 Jamie Rees
|
||||||
|
// File: StringHelper.cs
|
||||||
|
// Created By: Jamie Rees
|
||||||
|
//
|
||||||
|
// Permission is hereby granted, free of charge, to any person obtaining
|
||||||
|
// a copy of this software and associated documentation files (the
|
||||||
|
// "Software"), to deal in the Software without restriction, including
|
||||||
|
// without limitation the rights to use, copy, modify, merge, publish,
|
||||||
|
// distribute, sublicense, and/or sell copies of the Software, and to
|
||||||
|
// permit persons to whom the Software is furnished to do so, subject to
|
||||||
|
// the following conditions:
|
||||||
|
//
|
||||||
|
// The above copyright notice and this permission notice shall be
|
||||||
|
// included in all copies or substantial portions of the Software.
|
||||||
|
//
|
||||||
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||||
|
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||||
|
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||||
|
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||||
|
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||||
|
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||||
|
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
|
// ************************************************************************/
|
||||||
|
#endregion
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Text.RegularExpressions;
|
using System.Text.RegularExpressions;
|
||||||
|
|
||||||
|
@ -8,15 +33,18 @@ namespace PlexRequests.UI.Helpers
|
||||||
{
|
{
|
||||||
public static string FirstCharToUpper(this string input)
|
public static string FirstCharToUpper(this string input)
|
||||||
{
|
{
|
||||||
if (String.IsNullOrEmpty(input))
|
if (string.IsNullOrEmpty(input))
|
||||||
return input;
|
return input;
|
||||||
|
|
||||||
return input.First().ToString().ToUpper() + String.Join("", input.Skip(1));
|
var firstUpper = char.ToUpper(input[0]);
|
||||||
|
return firstUpper + string.Join("", input.Skip(1));
|
||||||
}
|
}
|
||||||
|
|
||||||
public static string CamelCaseToWords(this string input)
|
public static string ToCamelCaseWords(this string input)
|
||||||
{
|
{
|
||||||
|
if (string.IsNullOrEmpty(input))
|
||||||
|
return input;
|
||||||
return Regex.Replace(input.FirstCharToUpper(), "([a-z](?=[A-Z])|[A-Z](?=[A-Z][a-z]))", "$1 ");
|
return Regex.Replace(input.FirstCharToUpper(), "([a-z](?=[A-Z])|[A-Z](?=[A-Z][a-z]))", "$1 ");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -34,7 +34,7 @@ namespace PlexRequests.UI.Models
|
||||||
public int Id { get; set; }
|
public int Id { get; set; }
|
||||||
public int RequestId { get; set; }
|
public int RequestId { get; set; }
|
||||||
public string Title { get; set; }
|
public string Title { get; set; }
|
||||||
public int Count { get; set; }
|
public string Issues { get; set; }
|
||||||
public string Type { get; set; }
|
public string Type { get; set; }
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,10 +10,13 @@ using Nancy.Security;
|
||||||
|
|
||||||
using NLog;
|
using NLog;
|
||||||
|
|
||||||
|
using PlexRequests.Api;
|
||||||
using PlexRequests.Core;
|
using PlexRequests.Core;
|
||||||
using PlexRequests.Core.Models;
|
using PlexRequests.Core.Models;
|
||||||
using PlexRequests.Core.SettingModels;
|
using PlexRequests.Core.SettingModels;
|
||||||
using PlexRequests.Helpers;
|
using PlexRequests.Helpers;
|
||||||
|
using PlexRequests.Services.Interfaces;
|
||||||
|
using PlexRequests.Services.Notification;
|
||||||
using PlexRequests.Store;
|
using PlexRequests.Store;
|
||||||
using PlexRequests.UI.Helpers;
|
using PlexRequests.UI.Helpers;
|
||||||
using PlexRequests.UI.Models;
|
using PlexRequests.UI.Models;
|
||||||
|
@ -22,31 +25,34 @@ namespace PlexRequests.UI.Modules
|
||||||
{
|
{
|
||||||
public class IssuesModule : BaseAuthModule
|
public class IssuesModule : BaseAuthModule
|
||||||
{
|
{
|
||||||
public IssuesModule(ISettingsService<PlexRequestSettings> pr, IIssueService issueService, IRequestService request) : base("issues", pr)
|
public IssuesModule(ISettingsService<PlexRequestSettings> pr, IIssueService issueService, IRequestService request, INotificationService n) : base("issues", pr)
|
||||||
{
|
{
|
||||||
IssuesService = issueService;
|
IssuesService = issueService;
|
||||||
RequestService = request;
|
RequestService = request;
|
||||||
|
NotificationService = n;
|
||||||
|
|
||||||
Get["/"] = x => Index();
|
Get["/"] = x => Index();
|
||||||
|
|
||||||
Get["/{id}", true] = async (x, ct) => await Details(x.id);
|
Get["/{id}", true] = async (x, ct) => await Details(x.id);
|
||||||
|
|
||||||
Post["/issue", true] = async (x, ct) => await ReportIssue((int)Request.Form.requestId, (IssueState)(int)Request.Form.issue, null);
|
Post["/issue", true] = async (x, ct) => await ReportRequestIssue((int)Request.Form.requestId, (IssueState)(int)Request.Form.issue, null);
|
||||||
|
|
||||||
Get["/inprogress", true] = async (x, ct) => await GetIssues(IssueStatus.InProgressIssue);
|
|
||||||
Get["/pending", true] = async (x, ct) => await GetIssues(IssueStatus.PendingIssue);
|
Get["/pending", true] = async (x, ct) => await GetIssues(IssueStatus.PendingIssue);
|
||||||
Get["/resolved", true] = async (x, ct) => await GetIssues(IssueStatus.ResolvedIssue);
|
Get["/resolved", true] = async (x, ct) => await GetIssues(IssueStatus.ResolvedIssue);
|
||||||
|
|
||||||
Post["/remove", true] = async (x, ct) => await RemoveIssue((int)Request.Form.issueId);
|
Post["/remove", true] = async (x, ct) => await RemoveIssue((int)Request.Form.issueId);
|
||||||
Post["/inprogressUpdate", true] = async (x, ct) => await ChangeStatus((int)Request.Form.issueId, IssueStatus.InProgressIssue);
|
|
||||||
Post["/resolvedUpdate", true] = async (x, ct) => await ChangeStatus((int)Request.Form.issueId, IssueStatus.ResolvedIssue);
|
Post["/resolvedUpdate", true] = async (x, ct) => await ChangeStatus((int)Request.Form.issueId, IssueStatus.ResolvedIssue);
|
||||||
|
|
||||||
Post["/clear", true] = async (x, ct) => await ClearIssue((int) Request.Form.issueId, (IssueState) (int) Request.Form.issue);
|
Post["/clear", true] = async (x, ct) => await ClearIssue((int)Request.Form.issueId, (IssueState)(int)Request.Form.issue);
|
||||||
|
|
||||||
Get["/issuecount", true] = async (x, ct) => await IssueCount();
|
Get["/issuecount", true] = async (x, ct) => await IssueCount();
|
||||||
Get["/tabCount", true] = async (x, ct) => await TabCount();
|
Get["/tabCount", true] = async (x, ct) => await TabCount();
|
||||||
|
|
||||||
Post["/issuecomment", true] = async (x, ct) => await ReportIssue((int)Request.Form.requestId, IssueState.Other, (string)Request.Form.commentArea);
|
Post["/issuecomment", true] = async (x, ct) => await ReportRequestIssue((int)Request.Form.provierId, IssueState.Other, (string)Request.Form.commentArea);
|
||||||
|
|
||||||
|
Post["/nonrequestissue", true] = async (x, ct) => await ReportNonRequestIssue((int)Request.Form.providerId, (string)Request.Form.type, (IssueState)(int)Request.Form.issue, null);
|
||||||
|
|
||||||
|
Post["/nonrequestissuecomment", true] = async (x, ct) => await ReportNonRequestIssue((int)Request.Form.providerId, (string)Request.Form.type, IssueState.Other, (string)Request.Form.commentArea);
|
||||||
|
|
||||||
|
|
||||||
Post["/addnote", true] = async (x, ct) => await AddNote((int)Request.Form.requestId, (string)Request.Form.noteArea, (IssueState)(int)Request.Form.issue);
|
Post["/addnote", true] = async (x, ct) => await AddNote((int)Request.Form.requestId, (string)Request.Form.noteArea, (IssueState)(int)Request.Form.issue);
|
||||||
|
@ -54,6 +60,7 @@ namespace PlexRequests.UI.Modules
|
||||||
|
|
||||||
private IIssueService IssuesService { get; }
|
private IIssueService IssuesService { get; }
|
||||||
private IRequestService RequestService { get; }
|
private IRequestService RequestService { get; }
|
||||||
|
private INotificationService NotificationService { get; }
|
||||||
private static Logger Log = LogManager.GetCurrentClassLogger();
|
private static Logger Log = LogManager.GetCurrentClassLogger();
|
||||||
|
|
||||||
public Negotiator Index()
|
public Negotiator Index()
|
||||||
|
@ -64,22 +71,43 @@ namespace PlexRequests.UI.Modules
|
||||||
private async Task<Response> GetIssues(IssueStatus status)
|
private async Task<Response> GetIssues(IssueStatus status)
|
||||||
{
|
{
|
||||||
var issues = await IssuesService.GetAllAsync();
|
var issues = await IssuesService.GetAllAsync();
|
||||||
issues = await FilterIssues(issues);
|
issues = await FilterIssuesAsync(issues, status == IssueStatus.ResolvedIssue);
|
||||||
|
|
||||||
var issuesModels = issues as IssuesModel[] ?? issues.Where(x => x.IssueStatus == status).ToArray();
|
var issuesModels = issues as IssuesModel[] ?? issues.Where(x => x.IssueStatus == status).ToArray();
|
||||||
var model = issuesModels.Select(i => new IssuesViewModel
|
var viewModel = new List<IssuesViewModel>();
|
||||||
{
|
|
||||||
Title = i.Title, Type = i.Type.ToString().CamelCaseToWords(), Count = i.Issues.Count, Id = i.Id, RequestId = i.RequestId
|
|
||||||
}).ToList();
|
|
||||||
|
|
||||||
return Response.AsJson(model);
|
foreach (var i in issuesModels)
|
||||||
|
{
|
||||||
|
var model = new IssuesViewModel { Id = i.Id, RequestId = i.RequestId, Title = i.Title, Type = i.Type.ToString().ToCamelCaseWords(), };
|
||||||
|
|
||||||
|
// Create a string with all of the current issue states with a "," delimiter in e.g. Wrong Content, Playback Issues
|
||||||
|
var state = i.Issues.Select(x => x.Issue).ToArray();
|
||||||
|
var issueState = string.Empty;
|
||||||
|
for (var j = 0; j < state.Length; j++)
|
||||||
|
{
|
||||||
|
var word = state[j].ToString().ToCamelCaseWords();
|
||||||
|
if (j != state.Length - 1)
|
||||||
|
{
|
||||||
|
issueState += $"{word}, ";
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
issueState += word;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
model.Issues = issueState;
|
||||||
|
|
||||||
|
viewModel.Add(model);
|
||||||
|
}
|
||||||
|
|
||||||
|
return Response.AsJson(viewModel);
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<Response> IssueCount()
|
public async Task<Response> IssueCount()
|
||||||
{
|
{
|
||||||
var issues = await IssuesService.GetAllAsync();
|
var issues = await IssuesService.GetAllAsync();
|
||||||
|
|
||||||
var myIssues = await FilterIssues(issues);
|
var myIssues = await FilterIssuesAsync(issues);
|
||||||
|
|
||||||
var count = myIssues.Count();
|
var count = myIssues.Count();
|
||||||
|
|
||||||
|
@ -90,19 +118,17 @@ namespace PlexRequests.UI.Modules
|
||||||
{
|
{
|
||||||
var issues = await IssuesService.GetAllAsync();
|
var issues = await IssuesService.GetAllAsync();
|
||||||
|
|
||||||
var myIssues = await FilterIssues(issues);
|
var myIssues = await FilterIssuesAsync(issues);
|
||||||
|
|
||||||
var count = new List<object>();
|
var count = new List<object>();
|
||||||
|
|
||||||
var issuesModels = myIssues as IssuesModel[] ?? myIssues.ToArray();
|
var issuesModels = myIssues as IssuesModel[] ?? myIssues.ToArray();
|
||||||
var pending = issuesModels.Where(x => x.IssueStatus == IssueStatus.PendingIssue);
|
var pending = issuesModels.Where(x => x.IssueStatus == IssueStatus.PendingIssue);
|
||||||
var progress = issuesModels.Where(x => x.IssueStatus == IssueStatus.InProgressIssue);
|
|
||||||
var resolved = issuesModels.Where(x => x.IssueStatus == IssueStatus.ResolvedIssue);
|
var resolved = issuesModels.Where(x => x.IssueStatus == IssueStatus.ResolvedIssue);
|
||||||
|
|
||||||
count.Add(new { Name = IssueStatus.PendingIssue, Count = pending.Count()});
|
count.Add(new { Name = IssueStatus.PendingIssue, Count = pending.Count() });
|
||||||
count.Add(new { Name = IssueStatus.InProgressIssue, Count = progress.Count()});
|
count.Add(new { Name = IssueStatus.ResolvedIssue, Count = resolved.Count() });
|
||||||
count.Add(new { Name = IssueStatus.ResolvedIssue, Count = resolved.Count()});
|
|
||||||
|
|
||||||
return Response.AsJson(count);
|
return Response.AsJson(count);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -115,7 +141,7 @@ namespace PlexRequests.UI.Modules
|
||||||
: View["Details", issue];
|
: View["Details", issue];
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task<Response> ReportIssue(int requestId, IssueState issue, string comment)
|
private async Task<Response> ReportRequestIssue(int requestId, IssueState issue, string comment)
|
||||||
{
|
{
|
||||||
|
|
||||||
var model = new IssueModel
|
var model = new IssueModel
|
||||||
|
@ -132,13 +158,22 @@ namespace PlexRequests.UI.Modules
|
||||||
var issueEntity = await IssuesService.GetAllAsync();
|
var issueEntity = await IssuesService.GetAllAsync();
|
||||||
var existingIssue = issueEntity.FirstOrDefault(x => x.RequestId == requestId);
|
var existingIssue = issueEntity.FirstOrDefault(x => x.RequestId == requestId);
|
||||||
|
|
||||||
|
var notifyModel = new NotificationModel
|
||||||
|
{
|
||||||
|
User = Username,
|
||||||
|
NotificationType = NotificationType.Issue,
|
||||||
|
Title = request.Title,
|
||||||
|
DateTime = DateTime.Now,
|
||||||
|
Body = issue == IssueState.Other ? comment : issue.ToString().ToCamelCaseWords()
|
||||||
|
};
|
||||||
|
|
||||||
// An issue already exists
|
// An issue already exists
|
||||||
if (existingIssue != null)
|
if (existingIssue != null)
|
||||||
{
|
{
|
||||||
if (existingIssue.Issues.Any(x => x.Issue == issue))
|
if (existingIssue.Issues.Any(x => x.Issue == issue))
|
||||||
{
|
{
|
||||||
return
|
return
|
||||||
Response.AsJson(new JsonResponseModel()
|
Response.AsJson(new JsonResponseModel
|
||||||
{
|
{
|
||||||
Result = false,
|
Result = false,
|
||||||
Message = "This issue has already been reported!"
|
Message = "This issue has already been reported!"
|
||||||
|
@ -148,6 +183,9 @@ namespace PlexRequests.UI.Modules
|
||||||
existingIssue.Issues.Add(model);
|
existingIssue.Issues.Add(model);
|
||||||
var result = await IssuesService.UpdateIssueAsync(existingIssue);
|
var result = await IssuesService.UpdateIssueAsync(existingIssue);
|
||||||
|
|
||||||
|
|
||||||
|
await NotificationService.Publish(notifyModel);
|
||||||
|
|
||||||
return Response.AsJson(result
|
return Response.AsJson(result
|
||||||
? new JsonResponseModel { Result = true }
|
? new JsonResponseModel { Result = true }
|
||||||
: new JsonResponseModel { Result = false });
|
: new JsonResponseModel { Result = false });
|
||||||
|
@ -169,28 +207,144 @@ namespace PlexRequests.UI.Modules
|
||||||
request.IssueId = issueId;
|
request.IssueId = issueId;
|
||||||
await RequestService.UpdateRequestAsync(request);
|
await RequestService.UpdateRequestAsync(request);
|
||||||
|
|
||||||
|
await NotificationService.Publish(notifyModel);
|
||||||
|
return Response.AsJson(new JsonResponseModel { Result = true });
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task<Response> ReportNonRequestIssue(int providerId, string type, IssueState issue, string comment)
|
||||||
|
{
|
||||||
|
var currentIssues = await IssuesService.GetAllAsync();
|
||||||
|
var notifyModel = new NotificationModel
|
||||||
|
{
|
||||||
|
User = Username,
|
||||||
|
NotificationType = NotificationType.Issue,
|
||||||
|
DateTime = DateTime.Now,
|
||||||
|
Body = issue == IssueState.Other ? comment : issue.ToString().ToCamelCaseWords()
|
||||||
|
};
|
||||||
|
var model = new IssueModel
|
||||||
|
{
|
||||||
|
Issue = issue,
|
||||||
|
UserReported = Username,
|
||||||
|
UserNote = !string.IsNullOrEmpty(comment)
|
||||||
|
? $"{Username} - {comment}"
|
||||||
|
: string.Empty,
|
||||||
|
};
|
||||||
|
|
||||||
|
var existing = currentIssues.FirstOrDefault(x => x.ProviderId == providerId && !x.Deleted && x.IssueStatus == IssueStatus.PendingIssue);
|
||||||
|
if (existing != null)
|
||||||
|
{
|
||||||
|
existing.Issues.Add(model);
|
||||||
|
await IssuesService.UpdateIssueAsync(existing);
|
||||||
|
return Response.AsJson(new JsonResponseModel { Result = true });
|
||||||
|
}
|
||||||
|
|
||||||
|
if (type == "movie")
|
||||||
|
{
|
||||||
|
var movieApi = new TheMovieDbApi();
|
||||||
|
|
||||||
|
var result = await movieApi.GetMovieInformation(providerId);
|
||||||
|
if (result != null)
|
||||||
|
{
|
||||||
|
notifyModel.Title = result.Title;
|
||||||
|
// New issue
|
||||||
|
var issues = new IssuesModel
|
||||||
|
{
|
||||||
|
Title = result.Title,
|
||||||
|
PosterUrl = "https://image.tmdb.org/t/p/w150/" + result.PosterPath,
|
||||||
|
ProviderId = providerId,
|
||||||
|
Type = RequestType.Movie,
|
||||||
|
IssueStatus = IssueStatus.PendingIssue
|
||||||
|
};
|
||||||
|
issues.Issues.Add(model);
|
||||||
|
|
||||||
|
var issueId = await IssuesService.AddIssueAsync(issues);
|
||||||
|
|
||||||
|
await NotificationService.Publish(notifyModel);
|
||||||
|
return Response.AsJson(new JsonResponseModel { Result = true });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (type == "tv")
|
||||||
|
{
|
||||||
|
var tv = new TvMazeApi();
|
||||||
|
var result = tv.ShowLookupByTheTvDbId(providerId);
|
||||||
|
if (result != null)
|
||||||
|
{
|
||||||
|
var banner = result.image?.medium;
|
||||||
|
if (!string.IsNullOrEmpty(banner))
|
||||||
|
{
|
||||||
|
banner = banner.Replace("http", "https");
|
||||||
|
}
|
||||||
|
|
||||||
|
notifyModel.Title = result.name;
|
||||||
|
// New issue
|
||||||
|
var issues = new IssuesModel
|
||||||
|
{
|
||||||
|
Title = result.name,
|
||||||
|
PosterUrl = banner,
|
||||||
|
ProviderId = providerId,
|
||||||
|
Type = RequestType.TvShow,
|
||||||
|
IssueStatus = IssueStatus.PendingIssue
|
||||||
|
};
|
||||||
|
issues.Issues.Add(model);
|
||||||
|
|
||||||
|
var issueId = await IssuesService.AddIssueAsync(issues);
|
||||||
|
|
||||||
|
await NotificationService.Publish(notifyModel);
|
||||||
|
return Response.AsJson(new JsonResponseModel { Result = true });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
return Response.AsJson(new JsonResponseModel { Result = true });
|
return Response.AsJson(new JsonResponseModel { Result = true });
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task<IEnumerable<IssuesModel>> FilterIssues(IEnumerable<IssuesModel> issues)
|
/// <summary>
|
||||||
|
/// Filters the issues. Checks to see if we have set <c>UsersCanViewOnlyOwnIssues</c> in the database and filters upon the user logged in and that setting.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="issues">The issues.</param>
|
||||||
|
private async Task<IEnumerable<IssuesModel>> FilterIssuesAsync(IEnumerable<IssuesModel> issues, bool showResolved = false)
|
||||||
{
|
{
|
||||||
var settings = await PlexRequestSettings.GetSettingsAsync();
|
var settings = await PlexRequestSettings.GetSettingsAsync();
|
||||||
IEnumerable<IssuesModel> myIssues;
|
IEnumerable<IssuesModel> myIssues;
|
||||||
|
|
||||||
|
// Is the user an Admin? If so show everything
|
||||||
if (IsAdmin)
|
if (IsAdmin)
|
||||||
{
|
{
|
||||||
myIssues = issues.Where(x => x.Deleted == false);
|
var issuesModels = issues as IssuesModel[] ?? issues.ToArray();
|
||||||
|
myIssues = issuesModels.Where(x => x.Deleted == false);
|
||||||
|
if (!showResolved)
|
||||||
|
{
|
||||||
|
myIssues = issuesModels.Where(x => x.IssueStatus != IssueStatus.ResolvedIssue);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else if (settings.UsersCanViewOnlyOwnIssues)
|
else if (settings.UsersCanViewOnlyOwnIssues) // The user is not an Admin, do we have the settings to hide them?
|
||||||
{
|
{
|
||||||
myIssues =
|
if (!showResolved)
|
||||||
issues.Where(
|
{
|
||||||
x =>
|
myIssues =
|
||||||
x.Issues.Any(i => i.UserReported.Equals(Username, StringComparison.CurrentCultureIgnoreCase)) && x.Deleted == false);
|
issues.Where(
|
||||||
|
x =>
|
||||||
|
x.Issues.Any(i => i.UserReported.Equals(Username, StringComparison.CurrentCultureIgnoreCase)) && x.Deleted == false
|
||||||
|
&& x.IssueStatus != IssueStatus.ResolvedIssue);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
myIssues =
|
||||||
|
issues.Where(
|
||||||
|
x =>
|
||||||
|
x.Issues.Any(i => i.UserReported.Equals(Username, StringComparison.CurrentCultureIgnoreCase)) && x.Deleted == false);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else
|
else // Looks like the user is not an admin and there is no settings set.
|
||||||
{
|
{
|
||||||
myIssues = issues.Where(x => x.Deleted == false);
|
var issuesModels = issues as IssuesModel[] ?? issues.ToArray();
|
||||||
|
myIssues = issuesModels.Where(x => x.Deleted == false);
|
||||||
|
if (!showResolved)
|
||||||
|
{
|
||||||
|
myIssues = issuesModels.Where(x => x.IssueStatus != IssueStatus.ResolvedIssue);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return myIssues;
|
return myIssues;
|
||||||
|
@ -200,10 +354,19 @@ namespace PlexRequests.UI.Modules
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
this.RequiresClaims(UserClaims.Admin);
|
this.RequiresClaims(UserClaims.Admin);
|
||||||
|
var issue = await IssuesService.GetAsync(issueId);
|
||||||
|
var request = await RequestService.GetAsync(issue.RequestId);
|
||||||
|
|
||||||
await IssuesService.DeleteIssueAsync(issueId);
|
request.IssueId = 0; // No issue;
|
||||||
|
|
||||||
|
var result = await RequestService.UpdateRequestAsync(request);
|
||||||
|
if (result)
|
||||||
|
{
|
||||||
|
await IssuesService.DeleteIssueAsync(issueId);
|
||||||
|
}
|
||||||
|
|
||||||
return View["Index"];
|
return View["Index"];
|
||||||
|
|
||||||
}
|
}
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
{
|
{
|
||||||
|
@ -256,10 +419,12 @@ namespace PlexRequests.UI.Modules
|
||||||
}
|
}
|
||||||
var toAddNote = issue.Issues.FirstOrDefault(x => x.Issue == state);
|
var toAddNote = issue.Issues.FirstOrDefault(x => x.Issue == state);
|
||||||
|
|
||||||
issue.Issues.Remove(toAddNote);
|
if (toAddNote != null)
|
||||||
toAddNote.AdminNote = noteArea;
|
{
|
||||||
issue.Issues.Add(toAddNote);
|
issue.Issues.Remove(toAddNote);
|
||||||
|
toAddNote.AdminNote = noteArea;
|
||||||
|
issue.Issues.Add(toAddNote);
|
||||||
|
}
|
||||||
|
|
||||||
var result = await IssuesService.UpdateIssueAsync(issue);
|
var result = await IssuesService.UpdateIssueAsync(issue);
|
||||||
return Response.AsJson(result
|
return Response.AsJson(result
|
||||||
|
@ -267,6 +432,11 @@ namespace PlexRequests.UI.Modules
|
||||||
: new JsonResponseModel { Result = false, Message = "Could not update the notes, please try again or check the logs" });
|
: new JsonResponseModel { Result = false, Message = "Could not update the notes, please try again or check the logs" });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Orders the issues descending by the <see cref="IssueState"/>.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="issues">The issues.</param>
|
||||||
|
/// <returns></returns>
|
||||||
private IssuesModel Order(IssuesModel issues)
|
private IssuesModel Order(IssuesModel issues)
|
||||||
{
|
{
|
||||||
issues.Issues = issues.Issues.OrderByDescending(x => x.Issue).ToList();
|
issues.Issues = issues.Issues.OrderByDescending(x => x.Issue).ToList();
|
||||||
|
|
|
@ -328,7 +328,7 @@ namespace PlexRequests.UI.Modules
|
||||||
NotificationType = NotificationType.Issue,
|
NotificationType = NotificationType.Issue,
|
||||||
Title = originalRequest.Title,
|
Title = originalRequest.Title,
|
||||||
DateTime = DateTime.Now,
|
DateTime = DateTime.Now,
|
||||||
Body = issue == IssueState.Other ? comment : issue.ToString().CamelCaseToWords()
|
Body = issue == IssueState.Other ? comment : issue.ToString().ToCamelCaseWords()
|
||||||
};
|
};
|
||||||
await NotificationService.Publish(model);
|
await NotificationService.Publish(model);
|
||||||
|
|
||||||
|
|
|
@ -408,11 +408,9 @@ namespace PlexRequests.UI.Modules
|
||||||
|
|
||||||
private async Task<Response> RequestMovie(int movieId)
|
private async Task<Response> RequestMovie(int movieId)
|
||||||
{
|
{
|
||||||
var movieApi = new TheMovieDbApi();
|
var movieInfo = MovieApi.GetMovieInformation(movieId).Result;
|
||||||
var movieInfo = movieApi.GetMovieInformation(movieId).Result;
|
|
||||||
var fullMovieName = $"{movieInfo.Title}{(movieInfo.ReleaseDate.HasValue ? $" ({movieInfo.ReleaseDate.Value.Year})" : string.Empty)}";
|
var fullMovieName = $"{movieInfo.Title}{(movieInfo.ReleaseDate.HasValue ? $" ({movieInfo.ReleaseDate.Value.Year})" : string.Empty)}";
|
||||||
Log.Trace("Getting movie info from TheMovieDb");
|
Log.Trace("Getting movie info from TheMovieDb");
|
||||||
//#if !DEBUG
|
|
||||||
|
|
||||||
var settings = await PrService.GetSettingsAsync();
|
var settings = await PrService.GetSettingsAsync();
|
||||||
|
|
||||||
|
|
|
@ -34,13 +34,6 @@
|
||||||
<div class="col-md-2">
|
<div class="col-md-2">
|
||||||
|
|
||||||
@if (Model.IssueStatus == IssueStatus.PendingIssue)
|
@if (Model.IssueStatus == IssueStatus.PendingIssue)
|
||||||
{
|
|
||||||
<form action="@formAction/issues/inprogressUpdate" method="post">
|
|
||||||
<input id="issueId" name="issueId" value="@Model.Id" hidden="hidden" />
|
|
||||||
<button id="@Model.Id" class="btn btn-sm btn-primary-outline dropdown-toggle inProgress">In-Progress</button>
|
|
||||||
</form>
|
|
||||||
}
|
|
||||||
@if (Model.IssueStatus == IssueStatus.InProgressIssue)
|
|
||||||
{
|
{
|
||||||
<form action="@formAction/issues/resolvedUpdate" method="post">
|
<form action="@formAction/issues/resolvedUpdate" method="post">
|
||||||
<input id="issueId" name="issueId" value="@Model.Id" hidden="hidden" />
|
<input id="issueId" name="issueId" value="@Model.Id" hidden="hidden" />
|
||||||
|
@ -67,7 +60,7 @@
|
||||||
{
|
{
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col-sm-11">
|
<div class="col-sm-11">
|
||||||
<div><strong>Type:</strong> @StringHelper.CamelCaseToWords(issue.Issue.ToString())</div>
|
<div><strong>Type:</strong> @StringHelper.ToCamelCaseWords(issue.Issue.ToString())</div>
|
||||||
<div><strong>User Reported:</strong> @issue.UserReported</div>
|
<div><strong>User Reported:</strong> @issue.UserReported</div>
|
||||||
<div><strong>User Note:</strong> @issue.UserNote</div>
|
<div><strong>User Note:</strong> @issue.UserNote</div>
|
||||||
<div><strong>Admin Note:</strong>@issue.AdminNote</div>
|
<div><strong>Admin Note:</strong>@issue.AdminNote</div>
|
||||||
|
|
|
@ -6,11 +6,10 @@
|
||||||
|
|
||||||
<ul id="nav-tabs" class="nav nav-tabs" role="tablist">
|
<ul id="nav-tabs" class="nav nav-tabs" role="tablist">
|
||||||
<li role="presentation" class="active"><a href="#pendingTab" aria-controls="home" role="tab" data-toggle="tab">Pending <span id="pendingCount"></span></a></li>
|
<li role="presentation" class="active"><a href="#pendingTab" aria-controls="home" role="tab" data-toggle="tab">Pending <span id="pendingCount"></span></a></li>
|
||||||
<li role="presentation"><a href="#inProgressTab" aria-controls="profile" role="tab" data-toggle="tab">In-Progress <span id="inProgressCount"></span></a></li>
|
|
||||||
<li role="presentation"><a href="#resolvedTab" aria-controls="profile" role="tab" data-toggle="tab">Resolved <span id="resolvedCount"></span></a></li>
|
<li role="presentation"><a href="#resolvedTab" aria-controls="profile" role="tab" data-toggle="tab">Resolved <span id="resolvedCount"></span></a></li>
|
||||||
</ul>
|
</ul>
|
||||||
<br/>
|
<br/>
|
||||||
<hr/>
|
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col-md-3">
|
<div class="col-md-3">
|
||||||
<h4>Title</h4>
|
<h4>Title</h4>
|
||||||
|
@ -18,18 +17,18 @@
|
||||||
<div class="col-md-2">
|
<div class="col-md-2">
|
||||||
<h4>Type</h4>
|
<h4>Type</h4>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-md-1">
|
<div class="col-md-4">
|
||||||
<h4>Issue's</h4>
|
<h4>Issue's</h4>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="col-md-2">
|
<div class="col-md-2">
|
||||||
<h4>Requested</h4>
|
<h4>Requested</h4>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-sm-3 col-sm-push-3">
|
<div class="col-sm-1">
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<hr />
|
||||||
<div id="myTabContent" class="tab-content">
|
<div id="myTabContent" class="tab-content">
|
||||||
<!-- Pending tab -->
|
<!-- Pending tab -->
|
||||||
<div role="tabpanel" class="tab-pane active" id="pendingTab">
|
<div role="tabpanel" class="tab-pane active" id="pendingTab">
|
||||||
|
@ -41,17 +40,6 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!--In Progress-->
|
|
||||||
<div role="tabpanel" class="tab-pane" id="inProgressTab">
|
|
||||||
|
|
||||||
<br />
|
|
||||||
<br />
|
|
||||||
<!-- In progress content -->
|
|
||||||
<div id="inprogressIssues">
|
|
||||||
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- Resolved -->
|
<!-- Resolved -->
|
||||||
<div role="tabpanel" class="tab-pane" id="resolvedTab">
|
<div role="tabpanel" class="tab-pane" id="resolvedTab">
|
||||||
|
|
||||||
|
@ -73,8 +61,8 @@
|
||||||
<div class="col-md-2">
|
<div class="col-md-2">
|
||||||
<div id="type">{{type}}</div>
|
<div id="type">{{type}}</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-md-1">
|
<div class="col-md-4">
|
||||||
Issues: {{count}}
|
<small>{{issues}}</small>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="col-md-2">
|
<div class="col-md-2">
|
||||||
|
@ -84,7 +72,7 @@
|
||||||
<div><i class="fa fa-times"></i></div>
|
<div><i class="fa fa-times"></i></div>
|
||||||
{{/if}}
|
{{/if}}
|
||||||
</div>
|
</div>
|
||||||
<div class="col-sm-3 col-sm-push-3">
|
<div class="col-sm-1">
|
||||||
<a href="" id="{{id}}link" class="btn btn-sm btn-info-outline approve"><i class="fa fa-info"></i> Details</a>
|
<a href="" id="{{id}}link" class="btn btn-sm btn-info-outline approve"><i class="fa fa-info"></i> Details</a>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -215,11 +215,6 @@
|
||||||
<button id="{{requestId}}" style="text-align: right" class="btn btn-sm btn-danger-outline delete" type="submit"><i class="fa fa-minus"></i> Remove</button>
|
<button id="{{requestId}}" style="text-align: right" class="btn btn-sm btn-danger-outline delete" type="submit"><i class="fa fa-minus"></i> Remove</button>
|
||||||
</form>
|
</form>
|
||||||
|
|
||||||
<form method="POST" action="@formAction/requests/clearissues" id="clear{{requestId}}">
|
|
||||||
<input name="Id" type="text" value="{{requestId}}" hidden="hidden" />
|
|
||||||
<button id="{{requestId}}" style="text-align: right" class="btn btn-sm btn-info-outline clear" type="submit"><i class="fa fa-check"></i> Clear Issues</button>
|
|
||||||
</form>
|
|
||||||
|
|
||||||
<form method="POST" action="@formAction/requests/changeavailability" id="change{{requestId}}">
|
<form method="POST" action="@formAction/requests/changeavailability" id="change{{requestId}}">
|
||||||
<input name="Id" type="text" value="{{requestId}}" hidden="hidden" />
|
<input name="Id" type="text" value="{{requestId}}" hidden="hidden" />
|
||||||
{{#if_eq available true}}
|
{{#if_eq available true}}
|
||||||
|
|
|
@ -196,14 +196,25 @@
|
||||||
{{/if_eq}}
|
{{/if_eq}}
|
||||||
{{/if_eq}}
|
{{/if_eq}}
|
||||||
{{/if_eq}}
|
{{/if_eq}}
|
||||||
<br />
|
|
||||||
<br />
|
|
||||||
<br />
|
|
||||||
{{#if voteAverage}}
|
|
||||||
|
|
||||||
<small class="row">Vote Average: {{voteAverage}}</small>
|
<br />
|
||||||
<small class="row">Vote Count: {{voteCount}}</small>
|
</form>
|
||||||
{{/if}}
|
<form method="POST" action="@url/issues/nonrequestissue/" id="report{{id}}">
|
||||||
|
<input name="providerId" type="text" value="{{id}}" hidden="hidden" />
|
||||||
|
<input name="type" type="text" value="{{type}}" hidden="hidden" />
|
||||||
|
<div class="dropdown">
|
||||||
|
<button id="{{id}}" class="btn btn-sm btn-danger-outline dropdown-toggle" type="button" data-toggle="dropdown" aria-haspopup="true" aria-expanded="true">
|
||||||
|
<i class="fa fa-exclamation"></i> Report Issue
|
||||||
|
<span class="caret"></span>
|
||||||
|
</button>
|
||||||
|
<ul class="dropdown-menu" aria-labelledby="dropdownMenu1">
|
||||||
|
<li><a id="{{id}}" issue-select="0" class="dropdownIssue" href="#">Wrong Audio</a></li>
|
||||||
|
<li><a id="{{id}}" issue-select="1" class="dropdownIssue" href="#">No Subtitles</a></li>
|
||||||
|
<li><a id="{{id}}" issue-select="2" class="dropdownIssue" href="#">Wrong Content</a></li>
|
||||||
|
<li><a id="{{id}}" issue-select="3" class="dropdownIssue" href="#">Playback Issues</a></li>
|
||||||
|
<li><a id="{{id}}" issue-select="4" class="dropdownIssue" data-identifier="{{id}}" data-type="{{type}}" href="#" data-toggle="modal" data-target="#issuesModal">Other</a></li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
@ -277,6 +288,30 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
<div class="modal fade" id="issuesModal">
|
||||||
|
<div class="modal-dialog">
|
||||||
|
<div class="modal-content">
|
||||||
|
<div class="modal-header">
|
||||||
|
<button type="button" class="close" data-dismiss="modal" aria-hidden="true"><i class="fa fa-times"></i></button>
|
||||||
|
<h4 class="modal-title">Add an issue</h4>
|
||||||
|
</div>
|
||||||
|
<form method="POST" action="@url/issues/nonrequestissuecomment" id="commentForm">
|
||||||
|
<div class="modal-body">
|
||||||
|
<input id="providerIdModal" name="providerId" class="providerId" type="text" hidden="hidden" value="" />
|
||||||
|
<input name="issue" class="issue" type="text" hidden="hidden" value="" />
|
||||||
|
<input id="typeModal" name="type" class="type" type="text" hidden="hidden" value="" />
|
||||||
|
<textarea class="form-control form-control-custom" rows="3" id="commentArea" name="commentArea"></textarea>
|
||||||
|
</div>
|
||||||
|
<div class="modal-footer">
|
||||||
|
<button type="button" class="btn btn-danger-outline" data-dismiss="modal">Close</button>
|
||||||
|
<button type="button" class="btn btn-primary-outline theSaveButton" data-dismiss="modal">Save changes</button>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<script id="seasons-template" type="text/x-handlebars-template">
|
<script id="seasons-template" type="text/x-handlebars-template">
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<div class="checkbox">
|
<div class="checkbox">
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue