mirror of https://github.com/Ombi-app/Ombi
Merge 43a1b24599
into 7e3ef3c76b
commit
adf7b2f148
@ -0,0 +1,8 @@
|
||||
using Ombi.Api.Ntfy.Models;
|
||||
|
||||
namespace Ombi.Api.Ntfy;
|
||||
|
||||
public interface INtfyApi
|
||||
{
|
||||
Task PushAsync(string endpoint, string authorizationHeader, NtfyNotificationBody body);
|
||||
}
|
@ -0,0 +1,21 @@
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace Ombi.Api.Ntfy.Models;
|
||||
|
||||
public class NtfyNotificationBody
|
||||
{
|
||||
[JsonConstructor]
|
||||
public NtfyNotificationBody()
|
||||
{
|
||||
}
|
||||
|
||||
public string topic { get; set; }
|
||||
public string message { get; set; }
|
||||
public string title { get; set; }
|
||||
public List<string> tags { get; set; }
|
||||
public sbyte priority { get; set; }
|
||||
public string click { get; set; }
|
||||
public string attach { get; set; }
|
||||
public string filename { get; set; }
|
||||
public string delay { get; set; }
|
||||
}
|
@ -0,0 +1,26 @@
|
||||
using Ombi.Api.Ntfy.Models;
|
||||
|
||||
namespace Ombi.Api.Ntfy;
|
||||
|
||||
public class NtfyApi: INtfyApi
|
||||
{
|
||||
public NtfyApi(IApi api)
|
||||
{
|
||||
_api = api;
|
||||
}
|
||||
|
||||
private readonly IApi _api;
|
||||
|
||||
public async Task PushAsync(string endpoint, string authorizationHeader, NtfyNotificationBody body)
|
||||
{
|
||||
var request = new Request("/", endpoint, HttpMethod.Post);
|
||||
if(!String.IsNullOrEmpty(authorizationHeader)) request.AddHeader("Authorization", authorizationHeader);
|
||||
request.ApplicationJsonContentType();
|
||||
request.AddJsonBody(body);
|
||||
|
||||
Console.WriteLine(endpoint);
|
||||
Console.WriteLine(request.JsonBody);
|
||||
|
||||
await _api.Request(request);
|
||||
}
|
||||
}
|
@ -0,0 +1,13 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net6.0</TargetFramework>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\Ombi.Api\Ombi.Api.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
@ -0,0 +1,23 @@
|
||||
|
||||
using System.Collections.Generic;
|
||||
using Ombi.Settings.Settings.Models.Notifications;
|
||||
using Ombi.Store.Entities;
|
||||
|
||||
namespace Ombi.Core.Models.UI
|
||||
{
|
||||
/// <summary>
|
||||
/// The view model for the notification settings page
|
||||
/// </summary>
|
||||
/// <seealso cref="NtfyNotificationViewModel" />
|
||||
public class NtfyNotificationViewModel : NtfySettings
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets or sets the notification templates.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// The notification templates.
|
||||
/// </value>
|
||||
public List<NotificationTemplates> NotificationTemplates { get; set; }
|
||||
|
||||
}
|
||||
}
|
@ -0,0 +1,6 @@
|
||||
namespace Ombi.Notifications.Agents
|
||||
{
|
||||
public interface INtfyNotification : INotification
|
||||
{
|
||||
}
|
||||
}
|
@ -0,0 +1,130 @@
|
||||
using System;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNetCore.Identity;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Ombi.Api.Ntfy;
|
||||
using Ombi.Api.Ntfy;
|
||||
using Ombi.Api.Ntfy.Models;
|
||||
using Ombi.Core.Settings;
|
||||
using Ombi.Helpers;
|
||||
using Ombi.Notifications.Models;
|
||||
using Ombi.Settings.Settings.Models;
|
||||
using Ombi.Settings.Settings.Models.Notifications;
|
||||
using Ombi.Store.Entities;
|
||||
using Ombi.Store.Repository;
|
||||
using Ombi.Store.Repository.Requests;
|
||||
|
||||
namespace Ombi.Notifications.Agents
|
||||
{
|
||||
public class NtfyNotification : BaseNotification<NtfySettings>, INtfyNotification
|
||||
{
|
||||
public NtfyNotification(INtfyApi api, ISettingsService<NtfySettings> sn, ILogger<NtfyNotification> log, INotificationTemplatesRepository r, IMovieRequestRepository m, ITvRequestRepository t,
|
||||
ISettingsService<CustomizationSettings> s, IRepository<RequestSubscription> sub, IMusicRequestRepository music,
|
||||
IRepository<UserNotificationPreferences> userPref, UserManager<OmbiUser> um) : base(sn, r, m, t, s, log, sub, music, userPref, um)
|
||||
{
|
||||
Api = api;
|
||||
Logger = log;
|
||||
}
|
||||
|
||||
public override string NotificationName => "NtfyNotification";
|
||||
|
||||
private INtfyApi Api { get; }
|
||||
private ILogger<NtfyNotification> Logger { get; }
|
||||
|
||||
protected override bool ValidateConfiguration(NtfySettings settings)
|
||||
{
|
||||
return settings.Enabled && !string.IsNullOrEmpty(settings.BaseUrl);
|
||||
}
|
||||
|
||||
protected override async Task NewRequest(NotificationOptions model, NtfySettings settings)
|
||||
{
|
||||
await Run(model, settings, NotificationType.NewRequest);
|
||||
}
|
||||
|
||||
|
||||
protected override async Task NewIssue(NotificationOptions model, NtfySettings settings)
|
||||
{
|
||||
await Run(model, settings, NotificationType.Issue);
|
||||
}
|
||||
|
||||
protected override async Task IssueComment(NotificationOptions model, NtfySettings settings)
|
||||
{
|
||||
await Run(model, settings, NotificationType.IssueComment);
|
||||
}
|
||||
|
||||
protected override async Task IssueResolved(NotificationOptions model, NtfySettings settings)
|
||||
{
|
||||
await Run(model, settings, NotificationType.IssueResolved);
|
||||
}
|
||||
|
||||
protected override async Task AddedToRequestQueue(NotificationOptions model, NtfySettings settings)
|
||||
{
|
||||
await Run(model, settings, NotificationType.ItemAddedToFaultQueue);
|
||||
}
|
||||
|
||||
protected override async Task RequestDeclined(NotificationOptions model, NtfySettings settings)
|
||||
{
|
||||
await Run(model, settings, NotificationType.RequestDeclined);
|
||||
}
|
||||
|
||||
protected override async Task RequestApproved(NotificationOptions model, NtfySettings settings)
|
||||
{
|
||||
await Run(model, settings, NotificationType.RequestApproved);
|
||||
}
|
||||
|
||||
protected override async Task AvailableRequest(NotificationOptions model, NtfySettings settings)
|
||||
{
|
||||
await Run(model, settings, NotificationType.RequestAvailable);
|
||||
}
|
||||
|
||||
protected override async Task Send(NotificationMessage model, NtfySettings settings)
|
||||
{
|
||||
try
|
||||
{
|
||||
await Api.PushAsync(settings.BaseUrl, settings.AuthorizationHeader, new NtfyNotificationBody()
|
||||
{
|
||||
topic = settings.Topic, // To change
|
||||
title = model.Subject,
|
||||
message = model.Message,
|
||||
priority = settings.Priority
|
||||
});
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Logger.LogError(LoggingEvents.NtfyNotification, e, "Failed to send Ntfy notification");
|
||||
}
|
||||
}
|
||||
|
||||
protected override async Task Test(NotificationOptions model, NtfySettings settings)
|
||||
{
|
||||
var message = $"This is a test from Ombi, if you can see this then we have successfully pushed a notification!";
|
||||
var notification = new NotificationMessage
|
||||
{
|
||||
Message = message,
|
||||
};
|
||||
await Send(notification, settings);
|
||||
}
|
||||
|
||||
private async Task Run(NotificationOptions model, NtfySettings settings, NotificationType type)
|
||||
{
|
||||
var parsed = await LoadTemplate(NotificationAgent.Ntfy, type, model);
|
||||
if (parsed.Disabled)
|
||||
{
|
||||
Logger.LogInformation($"Template {type} is disabled for {NotificationAgent.Ntfy}");
|
||||
return;
|
||||
}
|
||||
|
||||
var notification = new NotificationMessage
|
||||
{
|
||||
Message = parsed.Message,
|
||||
};
|
||||
|
||||
await Send(notification, settings);
|
||||
}
|
||||
|
||||
protected override async Task PartiallyAvailable(NotificationOptions model, NtfySettings settings)
|
||||
{
|
||||
await Run(model, settings, NotificationType.PartiallyAvailable);
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,11 @@
|
||||
namespace Ombi.Settings.Settings.Models.Notifications
|
||||
{
|
||||
public class NtfySettings : Settings
|
||||
{
|
||||
public bool Enabled { get; set; }
|
||||
public string BaseUrl { get; set; }
|
||||
public string AuthorizationHeader { get; set; }
|
||||
public string Topic { get; set; }
|
||||
public sbyte Priority { get; set; } = 4;
|
||||
}
|
||||
}
|
@ -0,0 +1,74 @@
|
||||
|
||||
<settings-menu></settings-menu>
|
||||
<div *ngIf="form" class="small-middle-container">
|
||||
<fieldset>
|
||||
<legend>Ntfy Notifications</legend>
|
||||
<div class="col-md-6">
|
||||
<form novalidate [formGroup]="form" (ngSubmit)="onSubmit(form)">
|
||||
|
||||
<div class="form-group">
|
||||
<div class="checkbox">
|
||||
<input type="checkbox" id="enable" formControlName="enabled">
|
||||
<label for="enable">Enabled</label>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="baseUrl" class="control-label">Base URL</label>
|
||||
|
||||
<input type="text" class="form-control form-control-custom " id="baseUrl" name="baseUrl" [ngClass]="{'form-error': form.get('baseUrl').hasError('required')}" formControlName="baseUrl" pTooltip="Enter the URL of your ntfy server.">
|
||||
<small *ngIf="form.get('baseUrl').hasError('required')" class="error-text">The Base URL is required</small>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="authorizationHeader" class="control-label">Authorization Header</label>
|
||||
|
||||
<input type="text" class="form-control form-control-custom " id="authorizationHeader" name="authorizationHeader" [ngClass]="{'form-error': form.get('authorizationHeader').hasError('required')}" formControlName="authorizationHeader" pTooltip="Enter your Authorization header from Ntfy.">
|
||||
<small *ngIf="form.get('authorizationHeader').hasError('required')" class="error-text">The Authorization Header is required</small>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="topic" class="control-label">Topic</label>
|
||||
|
||||
<input type="text" class="form-control form-control-custom " id="topic" name="topic" [ngClass]="{'form-error': form.get('topic').hasError('required')}" formControlName="topic" pTooltip="Enter your topic from Ntfy.">
|
||||
<small *ngIf="form.get('topic').hasError('required')" class="error-text">The Topic is required</small>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="priority" class="control-label">Priority</label>
|
||||
<div>
|
||||
<select class="form-control form-control-custom " id="priority" name="priority" formControlName="priority" pTooltip="The priority you want your ntfy notifications sent as.">
|
||||
<option value="4">Normal</option>
|
||||
<option value="8">High</option>
|
||||
<option value="2">Low</option>
|
||||
<option value="0">Lowest</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<div class="form-group">
|
||||
<div>
|
||||
<button [disabled]="form.invalid" mat-raised-button type="button" (click)="test(form)" class="btn btn-primary-outline">
|
||||
Test
|
||||
<div id="spinner"></div>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
<div class="form-group">
|
||||
<div>
|
||||
<button [disabled]="form.invalid" mat-raised-button type="submit" id="save" class="btn btn-primary-outline">Submit</button>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
|
||||
<div class="col-md-6">
|
||||
<notification-templates [templates]="templates" [showSubject]="false"></notification-templates>
|
||||
</div>
|
||||
</fieldset>
|
||||
</div>
|
@ -0,0 +1,70 @@
|
||||
import { Component, OnInit } from "@angular/core";
|
||||
import { UntypedFormBuilder, UntypedFormGroup, Validators } from "@angular/forms";
|
||||
|
||||
import { INtfyNotificationSettings, INotificationTemplates, NotificationType } from "../../interfaces";
|
||||
import { TesterService } from "../../services";
|
||||
import { NotificationService } from "../../services";
|
||||
import { SettingsService } from "../../services";
|
||||
|
||||
@Component({
|
||||
templateUrl: "./ntfy.component.html",
|
||||
styleUrls: ["./notificationtemplate.component.scss"]
|
||||
})
|
||||
export class NtfyComponent implements OnInit {
|
||||
public NotificationType = NotificationType;
|
||||
public templates: INotificationTemplates[];
|
||||
public form: UntypedFormGroup;
|
||||
|
||||
constructor(private settingsService: SettingsService,
|
||||
private notificationService: NotificationService,
|
||||
private fb: UntypedFormBuilder,
|
||||
private testerService: TesterService) { }
|
||||
|
||||
public ngOnInit() {
|
||||
this.settingsService.getNtfyNotificationSettings().subscribe(x => {
|
||||
this.templates = x.notificationTemplates;
|
||||
|
||||
this.form = this.fb.group({
|
||||
enabled: [x.enabled],
|
||||
baseUrl: [x.baseUrl, [Validators.required]],
|
||||
authorizationHeader: [x.authorizationHeader, []],
|
||||
topic: [x.topic, [Validators.required]],
|
||||
priority: [x.priority],
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
public onSubmit(form: UntypedFormGroup) {
|
||||
if (form.invalid) {
|
||||
this.notificationService.error("Please check your entered values");
|
||||
return;
|
||||
}
|
||||
|
||||
const settings = <INtfyNotificationSettings> form.value;
|
||||
settings.notificationTemplates = this.templates;
|
||||
|
||||
this.settingsService.saveNtfyNotificationSettings(settings).subscribe(x => {
|
||||
if (x) {
|
||||
this.notificationService.success("Successfully saved the Ntfy settings");
|
||||
} else {
|
||||
this.notificationService.success("There was an error when saving the Ntfy settings");
|
||||
}
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
public test(form: UntypedFormGroup) {
|
||||
if (form.invalid) {
|
||||
this.notificationService.error("Please check your entered values");
|
||||
return;
|
||||
}
|
||||
|
||||
this.testerService.ntfyTest(form.value).subscribe(x => {
|
||||
if (x) {
|
||||
this.notificationService.success("Successfully sent a Ntfy message");
|
||||
} else {
|
||||
this.notificationService.error("There was an error when sending the Ntfy message. Please check your settings");
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
Loading…
Reference in new issue