notification improvements

This commit is contained in:
tidusjar 2016-09-25 01:03:23 +01:00
parent 5816ddef98
commit 9c789363f6
17 changed files with 712 additions and 160 deletions

View file

@ -1,147 +1,147 @@
#region Copyright //#region Copyright
// /************************************************************************ //// /************************************************************************
// Copyright (c) 2016 Jamie Rees //// Copyright (c) 2016 Jamie Rees
// File: AuthenticationSettingsTests.cs //// File: AuthenticationSettingsTests.cs
// Created By: Jamie Rees //// Created By: Jamie Rees
// ////
// Permission is hereby granted, free of charge, to any person obtaining //// Permission is hereby granted, free of charge, to any person obtaining
// a copy of this software and associated documentation files (the //// a copy of this software and associated documentation files (the
// "Software"), to deal in the Software without restriction, including //// "Software"), to deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge, publish, //// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Software, and to //// distribute, sublicense, and/or sell copies of the Software, and to
// permit persons to whom the Software is furnished to do so, subject to //// permit persons to whom the Software is furnished to do so, subject to
// the following conditions: //// the following conditions:
// ////
// The above copyright notice and this permission notice shall be //// The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software. //// included in all copies or substantial portions of the Software.
// ////
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, //// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF //// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND //// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE //// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION //// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION //// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. //// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
// ************************************************************************/ //// ************************************************************************/
#endregion //#endregion
using System; //using System;
using System.Collections.Generic; //using System.Collections.Generic;
using NUnit.Framework; //using NUnit.Framework;
using PlexRequests.Core.Models; //using PlexRequests.Core.Models;
using PlexRequests.Core.Notification; //using PlexRequests.Core.Notification;
using PlexRequests.Core.SettingModels; //using PlexRequests.Core.SettingModels;
namespace PlexRequests.Core.Tests //namespace PlexRequests.Core.Tests
{ //{
[TestFixture] // [TestFixture]
public class NotificationMessageResolverTests // public class NotificationMessageResolverTests
{ // {
[TestCaseSource(nameof(MessageBodyResolver))] // [TestCaseSource(nameof(MessageBodyResolver))]
public string ResolveBody(string body, NotificationMessageCurlys param) // public string ResolveBody(string body, NotificationMessageCurlys param)
{ // {
var n = new NotificationMessageResolver(); // var n = new NotificationMessageResolver();
var s = new NotificationSettings // var s = new NotificationSettings
{ // {
Message = new List<Notification.NotificationMessage> { new Notification.NotificationMessage { NotificationType = NotificationType.NewRequest, Body = body } } // Message = new List<Notification.NotificationMessage> { new Notification.NotificationMessage { NotificationType = NotificationType.NewRequest, Body = body } }
}; // };
var result = n.ParseMessage(s, NotificationType.NewRequest, param); // var result = n.ParseMessage(s, NotificationType.NewRequest, param, TransportType.Email);
return result.Body; // return result.Body;
} // }
[TestCaseSource(nameof(MessageSubjectResolver))] // [TestCaseSource(nameof(MessageSubjectResolver))]
public string ResolveSubject(string subject, NotificationMessageCurlys param) // public string ResolveSubject(string subject, NotificationMessageCurlys param)
{ // {
var n = new NotificationMessageResolver(); // var n = new NotificationMessageResolver();
var s = new NotificationSettings // var s = new NotificationSettings
{ // {
Message = new List<Notification.NotificationMessage> { new Notification.NotificationMessage { NotificationType = NotificationType.NewRequest, Subject = subject }} // Message = new List<Notification.NotificationMessage> { new Notification.NotificationMessage { NotificationType = NotificationType.NewRequest, Subject = subject }}
}; // };
var result = n.ParseMessage(s, NotificationType.NewRequest, param); // var result = n.ParseMessage(s, NotificationType.NewRequest, param, TransportType.Email);
return result.Subject; // return result.Subject;
} // }
private static IEnumerable<TestCaseData> MessageSubjectResolver // private static IEnumerable<TestCaseData> MessageSubjectResolver
{ // {
get // get
{ // {
yield return new TestCaseData( // yield return new TestCaseData(
"{Username} has requested a {Type}", // "{Username} has requested a {Type}",
new NotificationMessageCurlys("Jamie", "Finding Dory", DateTime.Now.ToString(), "Movie", string.Empty)) // new NotificationMessageCurlys("Jamie", "Finding Dory", DateTime.Now.ToString(), "Movie", string.Empty))
.Returns("Jamie has requested a Movie").SetName("Subject Curlys"); // .Returns("Jamie has requested a Movie").SetName("Subject Curlys");
yield return new TestCaseData( // yield return new TestCaseData(
null, // null,
new NotificationMessageCurlys("Jamie", "Finding Dory", DateTime.Now.ToString(), "Movie", string.Empty)) // new NotificationMessageCurlys("Jamie", "Finding Dory", DateTime.Now.ToString(), "Movie", string.Empty))
.Returns(string.Empty).SetName("Empty Subject"); // .Returns(string.Empty).SetName("Empty Subject");
yield return new TestCaseData( // yield return new TestCaseData(
"New Request Incoming!", // "New Request Incoming!",
new NotificationMessageCurlys("Jamie", "Finding Dory", DateTime.Now.ToString(), "Movie", string.Empty)) // new NotificationMessageCurlys("Jamie", "Finding Dory", DateTime.Now.ToString(), "Movie", string.Empty))
.Returns("New Request Incoming!").SetName("No curlys"); // .Returns("New Request Incoming!").SetName("No curlys");
yield return new TestCaseData( // yield return new TestCaseData(
"%$R£%$£^%$&{Username}@{}:§", // "%$R£%$£^%$&{Username}@{}:§",
new NotificationMessageCurlys("Jamie", "Finding Dory", DateTime.Now.ToString(), "Movie", string.Empty)) // new NotificationMessageCurlys("Jamie", "Finding Dory", DateTime.Now.ToString(), "Movie", string.Empty))
.Returns("%$R£%$£^%$&Jamie@{}:§").SetName("Special Chars"); // .Returns("%$R£%$£^%$&Jamie@{}:§").SetName("Special Chars");
} // }
} // }
private static IEnumerable<TestCaseData> MessageBodyResolver // private static IEnumerable<TestCaseData> MessageBodyResolver
{ // {
get // get
{ // {
yield return new TestCaseData( // yield return new TestCaseData(
"There has been a new request from {Username}, Title: {Title} for {Type}", // "There has been a new request from {Username}, Title: {Title} for {Type}",
new NotificationMessageCurlys("Jamie", "Finding Dory", DateTime.Now.ToString(), "Movie", string.Empty)) // new NotificationMessageCurlys("Jamie", "Finding Dory", DateTime.Now.ToString(), "Movie", string.Empty))
.Returns("There has been a new request from Jamie, Title: Finding Dory for Movie").SetName("FindingDory"); // .Returns("There has been a new request from Jamie, Title: Finding Dory for Movie").SetName("FindingDory");
yield return new TestCaseData( // yield return new TestCaseData(
null, // null,
new NotificationMessageCurlys(string.Empty, string.Empty, string.Empty, string.Empty, string.Empty)) // new NotificationMessageCurlys(string.Empty, string.Empty, string.Empty, string.Empty, string.Empty))
.Returns(string.Empty) // .Returns(string.Empty)
.SetName("Empty Message"); // .SetName("Empty Message");
yield return new TestCaseData( // yield return new TestCaseData(
"{{Wowwzer}} Damn}{{Username}}}}", // "{{Wowwzer}} Damn}{{Username}}}}",
new NotificationMessageCurlys("HEY!", string.Empty, string.Empty, string.Empty, string.Empty)) // new NotificationMessageCurlys("HEY!", string.Empty, string.Empty, string.Empty, string.Empty))
.Returns("{{Wowwzer}} Damn}{HEY!}}}") // .Returns("{{Wowwzer}} Damn}{HEY!}}}")
.SetName("Multiple Curlys"); // .SetName("Multiple Curlys");
yield return new TestCaseData( // yield return new TestCaseData(
"This is a message with no curlys", // "This is a message with no curlys",
new NotificationMessageCurlys("Jamie", "Finding Dory", DateTime.Now.ToString(), "Movie", string.Empty)) // new NotificationMessageCurlys("Jamie", "Finding Dory", DateTime.Now.ToString(), "Movie", string.Empty))
.Returns("This is a message with no curlys") // .Returns("This is a message with no curlys")
.SetName("No Curlys"); // .SetName("No Curlys");
yield return new TestCaseData( // yield return new TestCaseData(
new string(')', 5000), // new string(')', 5000),
new NotificationMessageCurlys(string.Empty, string.Empty, string.Empty, string.Empty, string.Empty)) // new NotificationMessageCurlys(string.Empty, string.Empty, string.Empty, string.Empty, string.Empty))
.Returns(new string(')', 5000)) // .Returns(new string(')', 5000))
.SetName("Long String"); // .SetName("Long String");
yield return new TestCaseData( // yield return new TestCaseData(
"This is a {Username} and {Username} Because {Issue}{Issue}", // "This is a {Username} and {Username} Because {Issue}{Issue}",
new NotificationMessageCurlys("HEY!", string.Empty, string.Empty, string.Empty, "Bob")) // new NotificationMessageCurlys("HEY!", string.Empty, string.Empty, string.Empty, "Bob"))
.Returns("This is a HEY! and HEY! Because BobBob") // .Returns("This is a HEY! and HEY! Because BobBob")
.SetName("Double Curly"); // .SetName("Double Curly");
yield return new TestCaseData( // yield return new TestCaseData(
"This is a {username} and {username} Because {Issue}{Issue}", // "This is a {username} and {username} Because {Issue}{Issue}",
new NotificationMessageCurlys("HEY!", string.Empty, string.Empty, string.Empty, "Bob")) // new NotificationMessageCurlys("HEY!", string.Empty, string.Empty, string.Empty, "Bob"))
.Returns("This is a {username} and {username} Because BobBob") // .Returns("This is a {username} and {username} Because BobBob")
.SetName("Case sensitive"); // .SetName("Case sensitive");
yield return new TestCaseData( // yield return new TestCaseData(
"{Date}{Date}{Date}{Date}{Date}{Date}{Date}{Date}{Date}{Date}{Date}{Date}{Date}{Date}{Date}{Date}{Date}{Date}{Date}{Date}{Date}{Date}{Date}{Date}{Date}{Date}{Date}{Date}{Date}{Date}{Date}{Date}{Date}{Date}{Date}{Date}{Date}{Date}{Date}{Date}{Date}{Date}{Date}{Date}{Date}{Date}{Date}{Date}{Date}{Date}{Date}{Date}{Date}{Date}{Date}{Date}{Date}{Date}{Date}{Date}{Date}{Date}{Date}{Date}{Date}{Date}{Date}{Date}{Date}{Date}{Date}{Date}{Date}{Date}{Date}{Date}{Date}{Date}{Date}{Date}{Date}{Date}{Date}{Date}{Date}{Date}{Date}{Date}{Date}{Date}{Date}{Date}{Date}{Date}{Date}{Date}{Date}{Date}{Date}{Date}{Date}{Date}{Date}{Date}{Date}{Date}{Date}", // "{Date}{Date}{Date}{Date}{Date}{Date}{Date}{Date}{Date}{Date}{Date}{Date}{Date}{Date}{Date}{Date}{Date}{Date}{Date}{Date}{Date}{Date}{Date}{Date}{Date}{Date}{Date}{Date}{Date}{Date}{Date}{Date}{Date}{Date}{Date}{Date}{Date}{Date}{Date}{Date}{Date}{Date}{Date}{Date}{Date}{Date}{Date}{Date}{Date}{Date}{Date}{Date}{Date}{Date}{Date}{Date}{Date}{Date}{Date}{Date}{Date}{Date}{Date}{Date}{Date}{Date}{Date}{Date}{Date}{Date}{Date}{Date}{Date}{Date}{Date}{Date}{Date}{Date}{Date}{Date}{Date}{Date}{Date}{Date}{Date}{Date}{Date}{Date}{Date}{Date}{Date}{Date}{Date}{Date}{Date}{Date}{Date}{Date}{Date}{Date}{Date}{Date}{Date}{Date}{Date}{Date}{Date}",
new NotificationMessageCurlys("HEY!", string.Empty, "b", string.Empty, "Bob")) // new NotificationMessageCurlys("HEY!", string.Empty, "b", string.Empty, "Bob"))
.Returns("bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb") // .Returns("bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb")
.SetName("Lots of curlys"); // .SetName("Lots of curlys");
} // }
} // }
} // }
} //}

View file

@ -24,6 +24,8 @@
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
// ************************************************************************/ // ************************************************************************/
#endregion #endregion
using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
@ -50,16 +52,37 @@ namespace PlexRequests.Core.Notification
/// <param name="notification">The notification.</param> /// <param name="notification">The notification.</param>
/// <param name="type">The type.</param> /// <param name="type">The type.</param>
/// <param name="c">The c.</param> /// <param name="c">The c.</param>
/// <param name="transportType">Type of the transport.</param>
/// <returns></returns> /// <returns></returns>
public NotificationMessageContent ParseMessage<T>(T notification, NotificationType type, NotificationMessageCurlys c) where T : NotificationSettings public NotificationMessageContent ParseMessage(NotificationSettingsV2 notification, NotificationType type, NotificationMessageCurlys c, TransportType transportType)
{ {
var content = notification.Message.FirstOrDefault(x => x.NotificationType == type); IEnumerable<NotificationMessage> content = null;
switch (transportType)
{
case TransportType.Email:
content = notification.EmailNotification;
break;
case TransportType.Pushbullet:
content = notification.PushbulletNotification;
break;
case TransportType.Pushover:
content = notification.PushoverNotification;
break;
case TransportType.Slack:
content = notification.SlackNotification;
break;
default:
throw new ArgumentOutOfRangeException(nameof(transportType), transportType, null);
}
if (content == null) if (content == null)
{ {
return new NotificationMessageContent(); return new NotificationMessageContent();
} }
return Resolve(content.Body, content.Subject, c.Curlys); var message = content.FirstOrDefault(x => x.NotificationType == type) ?? new NotificationMessage();
return Resolve(message.Body, message.Subject, c.Curlys);
} }
/// <summary> /// <summary>
@ -78,7 +101,7 @@ namespace PlexRequests.Core.Notification
body = ReplaceFields(bodyFields, parameters, body); body = ReplaceFields(bodyFields, parameters, body);
subject = ReplaceFields(subjectFields, parameters, subject); subject = ReplaceFields(subjectFields, parameters, subject);
return new NotificationMessageContent { Body = body ?? string.Empty, Subject = subject ?? string.Empty }; return new NotificationMessageContent {Body = body ?? string.Empty, Subject = subject ?? string.Empty};
} }
/// <summary> /// <summary>
@ -123,7 +146,6 @@ namespace PlexRequests.Core.Notification
{ {
currentWord += c.ToString(); // Add the character onto the word. currentWord += c.ToString(); // Add the character onto the word.
} }
} }
return fields; return fields;

View file

@ -0,0 +1,189 @@
<!doctype html>
<html>
<head>
<meta name="viewport" content="width=device-width" />
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<title>Plex Requests .Net</title>
<style media="all" type="text/css">
@media all {
.btn-primary table td:hover {
background-color: #34495e !important;
}
.btn-primary a:hover {
background-color: #34495e !important;
border-color: #34495e !important;
}
}
@media all {
.btn-secondary a:hover {
border-color: #34495e !important;
color: #34495e !important;
}
}
@media only screen and (max-width: 620px) {
table[class=body] h1 {
font-size: 28px !important;
margin-bottom: 10px !important;
}
table[class=body] h2 {
font-size: 22px !important;
margin-bottom: 10px !important;
}
table[class=body] h3 {
font-size: 16px !important;
margin-bottom: 10px !important;
}
table[class=body] p,
table[class=body] ul,
table[class=body] ol,
table[class=body] td,
table[class=body] span,
table[class=body] a {
font-size: 16px !important;
}
table[class=body] .wrapper,
table[class=body] .article {
padding: 10px !important;
}
table[class=body] .content {
padding: 0 !important;
}
table[class=body] .container {
padding: 0 !important;
width: 100% !important;
}
table[class=body] .header {
margin-bottom: 10px !important;
}
table[class=body] .main {
border-left-width: 0 !important;
border-radius: 0 !important;
border-right-width: 0 !important;
}
table[class=body] .btn table {
width: 100% !important;
}
table[class=body] .btn a {
width: 100% !important;
}
table[class=body] .img-responsive {
height: auto !important;
max-width: 100% !important;
width: auto !important;
}
table[class=body] .alert td {
border-radius: 0 !important;
padding: 10px !important;
}
table[class=body] .span-2,
table[class=body] .span-3 {
max-width: none !important;
width: 100% !important;
}
table[class=body] .receipt {
width: 100% !important;
}
}
@media all {
.ExternalClass {
width: 100%;
}
.ExternalClass,
.ExternalClass p,
.ExternalClass span,
.ExternalClass font,
.ExternalClass td,
.ExternalClass div {
line-height: 100%;
}
.apple-link a {
color: inherit !important;
font-family: inherit !important;
font-size: inherit !important;
font-weight: inherit !important;
line-height: inherit !important;
text-decoration: none !important;
}
}
</style>
</head>
<body class="" style="font-family: sans-serif; -webkit-font-smoothing: antialiased; font-size: 14px; line-height: 1.4; -ms-text-size-adjust: 100%; -webkit-text-size-adjust: 100%; background-color: #f6f6f6; margin: 0; padding: 0;">
<table border="0" cellpadding="0" cellspacing="0" class="body" style="border-collapse: separate; mso-table-lspace: 0pt; mso-table-rspace: 0pt; width: 100%; background-color: #f6f6f6;" width="100%" bgcolor="#f6f6f6">
<tr>
<td style="font-family: sans-serif; font-size: 14px; vertical-align: top;" valign="top">&nbsp;</td>
<td class="container" style="font-family: sans-serif; font-size: 14px; vertical-align: top; display: block; Margin: 0 auto !important; max-width: 580px; padding: 10px; width: 580px;" width="580" valign="top">
<div class="content" style="box-sizing: border-box; display: block; Margin: 0 auto; max-width: 580px; padding: 10px;">
<!-- START CENTERED WHITE CONTAINER -->
<span class="preheader" style="color: transparent; display: none; height: 0; max-height: 0; max-width: 0; opacity: 0; overflow: hidden; mso-hide: all; visibility: hidden; width: 0;">This is preheader text. Some clients will show this text as a preview.</span>
<table class="main" style="border-collapse: separate; mso-table-lspace: 0pt; mso-table-rspace: 0pt; width: 100%; background: #fff; border-radius: 3px;" width="100%">
<!-- START MAIN CONTENT AREA -->
<tr>
<td class="wrapper" style="font-family: sans-serif; font-size: 14px; vertical-align: top; box-sizing: border-box; padding: 20px;" valign="top">
<table border="0" cellpadding="0" cellspacing="0" style="border-collapse: separate; mso-table-lspace: 0pt; mso-table-rspace: 0pt; width: 100%;" width="100%">
<tr>
<td align="center">
<img src="http://i.imgur.com/s4nswSA.png?" width="400px" text-align="center" />
</td>
</tr>
<tr>
<td style="font-family: sans-serif; font-size: 14px; vertical-align: top;" valign="top">
<p style="font-family: sans-serif; font-size: 14px; font-weight: normal; margin: 0; Margin-bottom: 15px;">Hi there!</p>
<p style="font-family: sans-serif; font-size: 14px; font-weight: normal; margin: 0; Margin-bottom: 15px;">{@SUBJECT}</p>
<p style="font-family: sans-serif; font-size: 14px; font-weight: normal; margin: 0; Margin-bottom: 15px;">{@BODY}</p>
</td>
</tr>
<tr>
<td align="center">
<img src="{@IMGSRC}" width="400px" text-align="center" />
</td>
</tr>
</table>
</td>
</tr>
<!-- END MAIN CONTENT AREA -->
</table>
<!-- START FOOTER -->
<div class="footer" style="clear: both; padding-top: 10px; text-align: center; width: 100%;">
<table border="0" cellpadding="0" cellspacing="0" style="border-collapse: separate; mso-table-lspace: 0pt; mso-table-rspace: 0pt; width: 100%;" width="100%">
<tr>
<td class="content-block powered-by" style="font-family: sans-serif; vertical-align: top; padding-top: 10px; padding-bottom: 10px; font-size: 12px; color: #999999; text-align: center;" valign="top" align="center">
Powered by <a href="https://github.com/tidusjar/PlexRequests.Net" style="color: #999999; font-size: 12px; text-align: center; text-decoration: underline;">Plex Requests .Net</a>
</td>
</tr>
</table>
</div>
<!-- END FOOTER -->
<!-- END CENTERED WHITE CONTAINER -->
</div>
</td>
<td style="font-family: sans-serif; font-size: 14px; vertical-align: top;" valign="top">&nbsp;</td>
</tr>
</table>
</body>
</html>

View file

@ -0,0 +1,70 @@
#region Copyright
// /************************************************************************
// Copyright (c) 2016 Jamie Rees
// File: EmailBasicTemplate.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;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using NLog;
using PlexRequests.Core.Models;
using PlexRequests.Core.SettingModels;
namespace PlexRequests.Core.Notification.Templates
{
public class EmailBasicTemplate : IEmailBasicTemplate
{
public string TemplateLocation => Path.Combine(Path.GetDirectoryName(Application.ExecutablePath) ?? string.Empty, "Notification", "Templates", "BasicRequestTemplate.html");
private static readonly Logger Log = LogManager.GetCurrentClassLogger();
private const string SubjectKey = "{@SUBJECT}";
private const string BodyKey = "{@BODY}";
private const string ImgSrc = "{@IMGSRC}";
private const string DateKey = "{@DATENOW}";
public string LoadTemplate(string subject, string body, string imgSrc)
{
try
{
var sb = new StringBuilder(File.ReadAllText(TemplateLocation));
sb.Replace(SubjectKey, subject);
sb.Replace(BodyKey, body);
sb.Replace(ImgSrc, imgSrc);
sb.Replace(DateKey, DateTime.Now.ToString("f"));
return sb.ToString();
}
catch (Exception e)
{
Log.Error(e);
return string.Empty;
}
}
}
}

View file

@ -0,0 +1,37 @@
#region Copyright
// /************************************************************************
// Copyright (c) 2016 Jamie Rees
// File: IEmailBasicTemplate.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.Threading.Tasks;
namespace PlexRequests.Core.Notification.Templates
{
public interface IEmailBasicTemplate
{
string LoadTemplate(string subject, string body, string imgSrc);
string TemplateLocation { get; }
}
}

View file

@ -0,0 +1,36 @@
#region Copyright
// /************************************************************************
// Copyright (c) 2016 Jamie Rees
// File: TransportType.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
namespace PlexRequests.Core.Notification
{
public enum TransportType
{
Email,
Pushbullet,
Pushover,
Slack
}
}

View file

@ -44,6 +44,7 @@
</Reference> </Reference>
<Reference Include="System" /> <Reference Include="System" />
<Reference Include="System.Core" /> <Reference Include="System.Core" />
<Reference Include="System.Windows.Forms" />
<Reference Include="System.Xml.Linq" /> <Reference Include="System.Xml.Linq" />
<Reference Include="System.Data.DataSetExtensions" /> <Reference Include="System.Data.DataSetExtensions" />
<Reference Include="Microsoft.CSharp" /> <Reference Include="Microsoft.CSharp" />
@ -81,11 +82,15 @@
<Compile Include="Models\NotificationType.cs" /> <Compile Include="Models\NotificationType.cs" />
<Compile Include="Models\StatusModel.cs" /> <Compile Include="Models\StatusModel.cs" />
<Compile Include="Models\UserProperties.cs" /> <Compile Include="Models\UserProperties.cs" />
<Compile Include="Notification\Templates\EmailBasicTemplate.cs" />
<Compile Include="Notification\Templates\IEmailBasicTemplate.cs" />
<Compile Include="Notification\TransportType.cs" />
<Compile Include="SettingModels\AuthenticationSettings.cs" /> <Compile Include="SettingModels\AuthenticationSettings.cs" />
<Compile Include="SettingModels\ExternalSettings.cs" /> <Compile Include="SettingModels\ExternalSettings.cs" />
<Compile Include="SettingModels\HeadphonesSettings.cs" /> <Compile Include="SettingModels\HeadphonesSettings.cs" />
<Compile Include="SettingModels\LandingPageSettings.cs" /> <Compile Include="SettingModels\LandingPageSettings.cs" />
<Compile Include="SettingModels\NotificationSettings.cs" /> <Compile Include="SettingModels\NotificationSettings.cs" />
<Compile Include="SettingModels\NotificationSettingsV2.cs" />
<Compile Include="SettingModels\RequestSettings.cs" /> <Compile Include="SettingModels\RequestSettings.cs" />
<Compile Include="SettingModels\ScheduledJobsSettings.cs" /> <Compile Include="SettingModels\ScheduledJobsSettings.cs" />
<Compile Include="SettingModels\SlackNotificationSettings.cs" /> <Compile Include="SettingModels\SlackNotificationSettings.cs" />
@ -134,7 +139,11 @@
<Name>PlexRequests.Store</Name> <Name>PlexRequests.Store</Name>
</ProjectReference> </ProjectReference>
</ItemGroup> </ItemGroup>
<ItemGroup /> <ItemGroup>
<Content Include="Notification\Templates\BasicRequestTemplate.html">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" /> <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<!-- To modify your build process, add your task inside one of the targets below and uncomment it. <!-- To modify your build process, add your task inside one of the targets below and uncomment it.
Other similar extension points exist, see Microsoft.Common.targets. Other similar extension points exist, see Microsoft.Common.targets.

View file

@ -34,7 +34,7 @@ namespace PlexRequests.Core.SettingModels
public string EmailSender { get; set; } public string EmailSender { get; set; }
public string EmailUsername { get; set; } public string EmailUsername { get; set; }
public bool Enabled { get; set; } public bool Enabled { get; set; }
public bool Authentication { get; set; } public bool Authentication { get; set; }
public bool EnableUserEmailNotifications { get; set; } public bool EnableUserEmailNotifications { get; set; }
public string RecipientEmail { get; set; } public string RecipientEmail { get; set; }
} }

View file

@ -0,0 +1,62 @@
#region Copyright
// /************************************************************************
// Copyright (c) 2016 Jamie Rees
// File: NotificationSettingsV2.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 PlexRequests.Core.Models;
using PlexRequests.Core.Notification;
namespace PlexRequests.Core.SettingModels
{
public class NotificationSettingsV2 : Settings
{
public NotificationSettingsV2()
{
EmailNotification = new List<NotificationMessage>
{
new NotificationMessage
{
Body = "BODY",
NotificationType = NotificationType.NewRequest,
Subject = "SUB"
},
new NotificationMessage
{
NotificationType = NotificationType.Issue,
Body = "issue",
Subject = "issuesub"
}
};
SlackNotification = new List<NotificationMessage>();
PushoverNotification = new List<NotificationMessage>();
PushbulletNotification = new List<NotificationMessage>();
}
public List<NotificationMessage> EmailNotification { get; set; }
public List<NotificationMessage> SlackNotification { get; set; }
public List<NotificationMessage> PushbulletNotification { get; set; }
public List<NotificationMessage> PushoverNotification { get; set; }
}
}

View file

@ -25,18 +25,13 @@
// ************************************************************************/ // ************************************************************************/
#endregion #endregion
using System; using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Threading.Tasks; using System.Threading.Tasks;
using MailKit.Security;
using MimeKit; using MimeKit;
using NLog; using NLog;
using PlexRequests.Core; using PlexRequests.Core;
using PlexRequests.Core.Models; using PlexRequests.Core.Models;
using PlexRequests.Core.Notification.Templates;
using PlexRequests.Core.SettingModels; using PlexRequests.Core.SettingModels;
using PlexRequests.Services.Interfaces; using PlexRequests.Services.Interfaces;
using SmtpClient = MailKit.Net.Smtp.SmtpClient; using SmtpClient = MailKit.Net.Smtp.SmtpClient;
@ -109,7 +104,7 @@ namespace PlexRequests.Services.Notification
if (string.IsNullOrEmpty(settings.EmailUsername) || string.IsNullOrEmpty(settings.EmailPassword)) if (string.IsNullOrEmpty(settings.EmailUsername) || string.IsNullOrEmpty(settings.EmailPassword))
{ {
return false; return false;
} }
} }
if (string.IsNullOrEmpty(settings.EmailHost) || string.IsNullOrEmpty(settings.RecipientEmail) || string.IsNullOrEmpty(settings.EmailPort.ToString())) if (string.IsNullOrEmpty(settings.EmailHost) || string.IsNullOrEmpty(settings.RecipientEmail) || string.IsNullOrEmpty(settings.EmailPort.ToString()))
{ {
@ -129,13 +124,16 @@ namespace PlexRequests.Services.Notification
private async Task EmailNewRequest(NotificationModel model, EmailNotificationSettings settings) private async Task EmailNewRequest(NotificationModel model, EmailNotificationSettings settings)
{ {
//var r = new NotificationMessageCurlys(model.User, model.Title, DateTime.Now.ToString(), model.RequestType.ToString(), string.Empty); var email = new EmailBasicTemplate();
//var resolver = new NotificationMessageResolver(); var html = email.LoadTemplate(
//var bodyResult = resolver.ParseMessage(settings, NotificationType.NewRequest, r); $"Plex Requests: New {model.RequestType.GetString()?.ToLower()} request for {model.Title}!",
$"Hello! The user '{model.User}' has requested the {model.RequestType.GetString()?.ToLower()} '{model.Title}'! Please log in to approve this request. Request Date: {model.DateTime.ToString("f")}",
model.ImgSrc);
var body = new BodyBuilder { HtmlBody = html, };
var message = new MimeMessage var message = new MimeMessage
{ {
Body = new TextPart("plain") { Text = $"Hello! The user '{model.User}' has requested the {model.RequestType.GetString()?.ToLower()} '{model.Title}'! Please log in to approve this request. Request Date: {model.DateTime.ToString("f")}" }, Body = body.ToMessageBody(),
Subject = $"Plex Requests: New {model.RequestType.GetString()?.ToLower()} request for {model.Title}!" Subject = $"Plex Requests: New {model.RequestType.GetString()?.ToLower()} request for {model.Title}!"
}; };
message.From.Add(new MailboxAddress(settings.EmailSender, settings.EmailSender)); message.From.Add(new MailboxAddress(settings.EmailSender, settings.EmailSender));
@ -147,9 +145,16 @@ namespace PlexRequests.Services.Notification
private async Task EmailIssue(NotificationModel model, EmailNotificationSettings settings) private async Task EmailIssue(NotificationModel model, EmailNotificationSettings settings)
{ {
var email = new EmailBasicTemplate();
var html = email.LoadTemplate(
$"Plex Requests: New issue for {model.Title}!",
$"Hello! The user '{model.User}' has reported a new issue {model.Body} for the title {model.Title}!",
model.ImgSrc);
var body = new BodyBuilder { HtmlBody = html, };
var message = new MimeMessage var message = new MimeMessage
{ {
Body = new TextPart("plain") { Text = $"Hello! The user '{model.User}' has reported a new issue {model.Body} for the title {model.Title}!" }, Body = body.ToMessageBody(),
Subject = $"Plex Requests: New issue for {model.Title}!" Subject = $"Plex Requests: New issue for {model.Title}!"
}; };
message.From.Add(new MailboxAddress(settings.EmailSender, settings.EmailSender)); message.From.Add(new MailboxAddress(settings.EmailSender, settings.EmailSender));
@ -165,10 +170,16 @@ namespace PlexRequests.Services.Notification
{ {
await Task.FromResult(false); await Task.FromResult(false);
} }
var email = new EmailBasicTemplate();
var html = email.LoadTemplate(
$"Plex Requests: {model.Title} is now available!",
$"Hello! You requested {model.Title} on PlexRequests! This is now available on Plex! :)",
model.ImgSrc);
var body = new BodyBuilder { HtmlBody = html, };
var message = new MimeMessage var message = new MimeMessage
{ {
Body = new TextPart("plain") { Text = $"Hello! You requested {model.Title} on PlexRequests! This is now available on Plex! :)" }, Body = body.ToMessageBody(),
Subject = $"Plex Requests: {model.Title} is now available!" Subject = $"Plex Requests: {model.Title} is now available!"
}; };
message.From.Add(new MailboxAddress(settings.EmailSender, settings.EmailSender)); message.From.Add(new MailboxAddress(settings.EmailSender, settings.EmailSender));
@ -206,10 +217,15 @@ namespace PlexRequests.Services.Notification
private async Task EmailTest(NotificationModel model, EmailNotificationSettings settings) private async Task EmailTest(NotificationModel model, EmailNotificationSettings settings)
{ {
var email = new EmailBasicTemplate();
var html = email.LoadTemplate(
"Test Message",
"This is just a test! Success!",
model.ImgSrc);
var body = new BodyBuilder { HtmlBody = html, };
var message = new MimeMessage var message = new MimeMessage
{ {
Body = new TextPart("plain") { Text = "This is just a test! Success!" }, Body = body.ToMessageBody()
Subject = "Plex Requests: Test Message!",
}; };
message.From.Add(new MailboxAddress(settings.EmailSender, settings.EmailSender)); message.From.Add(new MailboxAddress(settings.EmailSender, settings.EmailSender));
message.To.Add(new MailboxAddress(settings.RecipientEmail, settings.RecipientEmail)); message.To.Add(new MailboxAddress(settings.RecipientEmail, settings.RecipientEmail));

View file

@ -75,7 +75,7 @@ namespace PlexRequests.Services.Notification
if (user.Equals(adminUsername, StringComparison.CurrentCultureIgnoreCase)) if (user.Equals(adminUsername, StringComparison.CurrentCultureIgnoreCase))
{ {
Log.Info("This user is the Plex server owner"); Log.Info("This user is the Plex server owner");
await PublishUserNotification(userAccount.Username, userAccount.Email, model.Title); await PublishUserNotification(userAccount.Username, userAccount.Email, model.Title, model.PosterPath);
return; return;
} }
@ -88,7 +88,7 @@ namespace PlexRequests.Services.Notification
} }
Log.Info("Sending notification to: {0} at: {1}, for title: {2}", email.Username, email.Email, model.Title); Log.Info("Sending notification to: {0} at: {1}, for title: {2}", email.Username, email.Email, model.Title);
await PublishUserNotification(email.Username, email.Email, model.Title); await PublishUserNotification(email.Username, email.Email, model.Title, model.PosterPath);
} }
} }
} }
@ -117,7 +117,7 @@ namespace PlexRequests.Services.Notification
if (user.Equals(adminUsername, StringComparison.CurrentCultureIgnoreCase)) if (user.Equals(adminUsername, StringComparison.CurrentCultureIgnoreCase))
{ {
Log.Info("This user is the Plex server owner"); Log.Info("This user is the Plex server owner");
await PublishUserNotification(userAccount.Username, userAccount.Email, model.Title); await PublishUserNotification(userAccount.Username, userAccount.Email, model.Title, model.PosterPath);
return; return;
} }
@ -130,7 +130,7 @@ namespace PlexRequests.Services.Notification
} }
Log.Info("Sending notification to: {0} at: {1}, for title: {2}", email.Username, email.Email, model.Title); Log.Info("Sending notification to: {0} at: {1}, for title: {2}", email.Username, email.Email, model.Title);
await PublishUserNotification(email.Username, email.Email, model.Title); await PublishUserNotification(email.Username, email.Email, model.Title, model.PosterPath);
} }
} }
catch (Exception e) catch (Exception e)
@ -139,14 +139,15 @@ namespace PlexRequests.Services.Notification
} }
} }
private async Task PublishUserNotification(string username, string email, string title) private async Task PublishUserNotification(string username, string email, string title, string img)
{ {
var notificationModel = new NotificationModel var notificationModel = new NotificationModel
{ {
User = username, User = username,
UserEmail = email, UserEmail = email,
NotificationType = NotificationType.RequestAvailable, NotificationType = NotificationType.RequestAvailable,
Title = title Title = title,
ImgSrc = img
}; };
// Send the notification to the user. // Send the notification to the user.

View file

@ -40,5 +40,6 @@ namespace PlexRequests.Services.Notification
public string User { get; set; } public string User { get; set; }
public string UserEmail { get; set; } public string UserEmail { get; set; }
public RequestType RequestType { get; set; } public RequestType RequestType { get; set; }
public string ImgSrc { get; set; }
} }
} }

View file

@ -80,6 +80,7 @@ namespace PlexRequests.UI.Tests
private Mock<ISettingsService<LandingPageSettings>> LandingPageSettings { get; set; } private Mock<ISettingsService<LandingPageSettings>> LandingPageSettings { get; set; }
private Mock<ISlackApi> SlackApi { get; set; } private Mock<ISlackApi> SlackApi { get; set; }
private Mock<IAnalytics> Analytics { get; set; } private Mock<IAnalytics> Analytics { get; set; }
private Mock<ISettingsService<NotificationSettingsV2>> NotifyV2 { get; set; }
private ConfigurableBootstrapper Bootstrapper { get; set; } private ConfigurableBootstrapper Bootstrapper { get; set; }
@ -120,6 +121,7 @@ namespace PlexRequests.UI.Tests
ScheduledJobsSettingsMock = new Mock<ISettingsService<ScheduledJobsSettings>>(); ScheduledJobsSettingsMock = new Mock<ISettingsService<ScheduledJobsSettings>>();
RecorderMock = new Mock<IJobRecord>(); RecorderMock = new Mock<IJobRecord>();
Analytics = new Mock<IAnalytics>(); Analytics = new Mock<IAnalytics>();
NotifyV2= new Mock<ISettingsService<NotificationSettingsV2>>();
Bootstrapper = new ConfigurableBootstrapper(with => Bootstrapper = new ConfigurableBootstrapper(with =>
@ -140,6 +142,7 @@ namespace PlexRequests.UI.Tests
with.Dependency(LogRepo.Object); with.Dependency(LogRepo.Object);
with.Dependency(PushoverSettings.Object); with.Dependency(PushoverSettings.Object);
with.Dependency(PushoverApi.Object); with.Dependency(PushoverApi.Object);
with.Dependency(NotifyV2.Object);
with.Dependency(NotificationService.Object); with.Dependency(NotificationService.Object);
with.Dependency(Analytics.Object); with.Dependency(Analytics.Object);
with.Dependency(HeadphonesSettings.Object); with.Dependency(HeadphonesSettings.Object);

View file

@ -94,6 +94,7 @@ namespace PlexRequests.UI.Modules
private ISlackApi SlackApi { get; } private ISlackApi SlackApi { get; }
private IJobRecord JobRecorder { get; } private IJobRecord JobRecorder { get; }
private IAnalytics Analytics { get; } private IAnalytics Analytics { get; }
private ISettingsService<NotificationSettingsV2> NotifySettings { get; }
private static Logger Log = LogManager.GetCurrentClassLogger(); private static Logger Log = LogManager.GetCurrentClassLogger();
public AdminModule(ISettingsService<PlexRequestSettings> prService, public AdminModule(ISettingsService<PlexRequestSettings> prService,
@ -116,7 +117,8 @@ namespace PlexRequests.UI.Modules
ISettingsService<LogSettings> logs, ISettingsService<LogSettings> logs,
ICacheProvider cache, ISettingsService<SlackNotificationSettings> slackSettings, ICacheProvider cache, ISettingsService<SlackNotificationSettings> slackSettings,
ISlackApi slackApi, ISettingsService<LandingPageSettings> lp, ISlackApi slackApi, ISettingsService<LandingPageSettings> lp,
ISettingsService<ScheduledJobsSettings> scheduler, IJobRecord rec, IAnalytics analytics) : base("admin", prService) ISettingsService<ScheduledJobsSettings> scheduler, IJobRecord rec, IAnalytics analytics,
ISettingsService<NotificationSettingsV2> notifyService) : base("admin", prService)
{ {
PrService = prService; PrService = prService;
CpService = cpService; CpService = cpService;
@ -143,6 +145,7 @@ namespace PlexRequests.UI.Modules
ScheduledJobSettings = scheduler; ScheduledJobSettings = scheduler;
JobRecorder = rec; JobRecorder = rec;
Analytics = analytics; Analytics = analytics;
NotifySettings = notifyService;
this.RequiresClaims(UserClaims.Admin); this.RequiresClaims(UserClaims.Admin);
@ -210,6 +213,9 @@ namespace PlexRequests.UI.Modules
Post["/scheduledjobs", true] = async (x, ct) => await SaveScheduledJobs(); Post["/scheduledjobs", true] = async (x, ct) => await SaveScheduledJobs();
Post["/clearlogs", true] = async (x, ct) => await ClearLogs(); Post["/clearlogs", true] = async (x, ct) => await ClearLogs();
Get["/notificationsettings", true] = async (x, ct) => await NotificationSettings();
Post["/notificationsettings", true] = async (x, ct) => await SaveNotificationSettings();
} }
private async Task<Negotiator> Authentication() private async Task<Negotiator> Authentication()
@ -489,7 +495,8 @@ namespace PlexRequests.UI.Modules
var notificationModel = new NotificationModel var notificationModel = new NotificationModel
{ {
NotificationType = NotificationType.Test, NotificationType = NotificationType.Test,
DateTime = DateTime.Now DateTime = DateTime.Now,
ImgSrc = "http://3.bp.blogspot.com/-EFM-XoKoZ0o/UznF567wCRI/AAAAAAAAALM/6ut7MCF2LrU/s1600/xkcd.png"
}; };
try try
{ {
@ -966,5 +973,17 @@ namespace PlexRequests.UI.Modules
return Response.AsJson(new JsonResponseModel { Result = false, Message = e.Message }); return Response.AsJson(new JsonResponseModel { Result = false, Message = e.Message });
} }
} }
private async Task<Negotiator> NotificationSettings()
{
var s = await NotifySettings.GetSettingsAsync();
return View["NotificationSettings", s];
}
private async Task<Negotiator> SaveNotificationSettings()
{
var model = this.Bind<NotificationSettingsV2>();
return View["NotificationSettings", model];
}
} }
} }

View file

@ -707,6 +707,9 @@
<Content Include="Views\UserWizard\Index.cshtml"> <Content Include="Views\UserWizard\Index.cshtml">
<CopyToOutputDirectory>Always</CopyToOutputDirectory> <CopyToOutputDirectory>Always</CopyToOutputDirectory>
</Content> </Content>
<Content Include="Views\Admin\NotificationSettings.cshtml">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</Content>
<None Include="Web.Debug.config"> <None Include="Web.Debug.config">
<DependentUpon>web.config</DependentUpon> <DependentUpon>web.config</DependentUpon>
</None> </None>

View file

@ -0,0 +1,84 @@
@using System.Linq
@using PlexRequests.Core.Models
@using PlexRequests.UI.Helpers
@inherits Nancy.ViewEngines.Razor.NancyRazorViewBase<PlexRequests.Core.SettingModels.NotificationSettingsV2>
@Html.Partial("_Sidebar")
<div class="col-sm-8 col-sm-push-1">
<form class="form-horizontal" method="POST" id="mainForm">
<fieldset>
<legend>Notification Settings</legend>
<!--Accordion Item-->
<div class="panel-group" id="accordion" role="tablist" aria-multiselectable="true">
<div class="panel panel-default">
<div class="panel-heading" role="tab" id="0headingOne">
<h4 class="panel-title">
<a role="button" data-toggle="collapse" data-parent="#accordion" href="#0collapseOne" aria-controls="0collapseOne">
New Request
</a>
</h4>
</div>
<div id="0collapseOne" class="panel-collapse collapse in" role="tabpanel" aria-labelledby="0headingOne">
<div class="panel-body">
<div class="form-group">
<label for="EmailNotification[0].Subject" class="control-label">Subject</label>
<div>
<input type="text" class="form-control form-control-custom " id="EmailNotification[0].Subject" name="EmailNotification0.Subject" value="@(Model.EmailNotification[0].Subject)">
</div>
</div>
<div class="form-group">
<label for="EmailNotification[0].Body" class="control-label">Body</label>
<div>
<input type="text" class="form-control form-control-custom " id="EmailNotification[0].Body" name="EmailNotification0.Body" value="@(Model.EmailNotification[0].Body)">
</div>
</div>
</div>
</div>
</div>
}
</div>
<div class="form-group">
<div>
<button id="save" type="submit" class="btn btn-primary-outline">Submit</button>
</div>
</div>
</fieldset>
</form>
</div>
<script>
$(function () {
var base = '@Html.GetBaseUrl()';
$('#save').click(function (e) {
e.preventDefault();
var $form = $("#mainForm");
var data = $form.serialize();
$.ajax({
type: $form.prop("method"),
data: data,
url: $form.prop("action"),
dataType: "json",
success: function (response) {
if (response.result === true) {
generateNotify(response.message, "success");
} else {
generateNotify(response.message, "warning");
}
},
error: function (e) {
console.log(e);
generateNotify("Something went wrong!", "danger");
}
});
});
});
</script>

View file

@ -1,7 +1,7 @@
 
Microsoft Visual Studio Solution File, Format Version 12.00 Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio 14 # Visual Studio 14
VisualStudioVersion = 14.0.25420.1 VisualStudioVersion = 14.0.25123.0
MinimumVisualStudioVersion = 10.0.40219.1 MinimumVisualStudioVersion = 10.0.40219.1
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "PlexRequests.UI", "PlexRequests.UI\PlexRequests.UI.csproj", "{68F5F5F3-B8BB-4911-875F-6F00AAE04EA6}" Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "PlexRequests.UI", "PlexRequests.UI\PlexRequests.UI.csproj", "{68F5F5F3-B8BB-4911-875F-6F00AAE04EA6}"
EndProject EndProject