more !wip stuff

pull/1941/head
Jamie 7 years ago
parent e235475413
commit 59173b8bc4

@ -0,0 +1,17 @@
using System.Collections.Generic;
using Ombi.Settings.Settings.Models.Notifications;
using Ombi.Store.Entities;
namespace Ombi.Core.Models.UI
{
public class MobileNotificationsViewModel : MobileNotificationSettings
{
/// <summary>
/// Gets or sets the notification templates.
/// </summary>
/// <value>
/// The notification templates.
/// </value>
public List<NotificationTemplates> NotificationTemplates { get; set; }
}
}

@ -17,6 +17,7 @@ namespace Ombi.Mapping.Profiles
CreateMap<MattermostNotificationsViewModel, MattermostNotificationSettings>().ReverseMap();
CreateMap<TelegramNotificationsViewModel, TelegramSettings>().ReverseMap();
CreateMap<UpdateSettingsViewModel, UpdateSettings>().ReverseMap();
CreateMap<MobileNotificationsViewModel, MobileNotificationSettings>().ReverseMap();
}
}
}

@ -120,8 +120,10 @@ namespace Ombi.Notifications.Agents
var plaintext = await LoadPlainTextMessage(NotificationType.IssueResolved, model, settings);
message.Other.Add("PlainTextBody", plaintext);
// Issues should be sent to admin
message.To = settings.AdminEmail;
// Issues resolved should be sent to the user
message.To = model.RequestType == RequestType.Movie
? MovieRequest.RequestedUser.Email
: TvRequest.RequestedUser.Email;
await Send(message, settings);
}

@ -39,7 +39,7 @@ namespace Ombi.Notifications.Agents
protected override bool ValidateConfiguration(MobileNotificationSettings settings)
{
return false;
return true;
}
protected override async Task NewRequest(NotificationOptions model, MobileNotificationSettings settings)
@ -56,9 +56,7 @@ namespace Ombi.Notifications.Agents
};
// Get admin devices
var adminUsers = (await _userManager.GetUsersInRoleAsync(OmbiRoles.Admin)).Select(x => x.Id).ToList();
var notificationUsers = _notifications.GetAll().Include(x => x.User).Where(x => adminUsers.Contains(x.UserId));
var playerIds = await notificationUsers.Select(x => x.PlayerId).ToListAsync();
var playerIds = await GetAdmins(NotificationType.NewRequest);
await Send(playerIds, notification, settings);
}
@ -74,8 +72,10 @@ namespace Ombi.Notifications.Agents
{
Message = parsed.Message,
};
notification.Other.Add("image", parsed.Image);
await Send(notification, settings);
// Get admin devices
var playerIds = await GetAdmins(NotificationType.Issue);
await Send(playerIds, notification, settings);
}
protected override async Task IssueResolved(NotificationOptions model, MobileNotificationSettings settings)
@ -90,34 +90,36 @@ namespace Ombi.Notifications.Agents
{
Message = parsed.Message,
};
notification.Other.Add("image", parsed.Image);
await Send(notification, settings);
// Send to user
var playerIds = GetUsers(model, NotificationType.IssueResolved);
await Send(playerIds, notification, settings);
}
protected override async Task AddedToRequestQueue(NotificationOptions model, MobileNotificationSettings settings)
{
var user = string.Empty;
var title = string.Empty;
var image = string.Empty;
string user;
string title;
if (model.RequestType == RequestType.Movie)
{
user = MovieRequest.RequestedUser.UserAlias;
title = MovieRequest.Title;
image = MovieRequest.PosterPath;
}
else
{
user = TvRequest.RequestedUser.UserAlias;
title = TvRequest.ParentRequest.Title;
image = TvRequest.ParentRequest.PosterPath;
}
var message = $"Hello! The user '{user}' has requested {title} but it could not be added. This has been added into the requests queue and will keep retrying";
var notification = new NotificationMessage
{
Message = message
};
notification.Other.Add("image", image);
await Send(notification, settings);
// Get admin devices
var playerIds = await GetAdmins(NotificationType.Test);
await Send(playerIds, notification, settings);
}
protected override async Task RequestDeclined(NotificationOptions model, MobileNotificationSettings settings)
@ -132,8 +134,10 @@ namespace Ombi.Notifications.Agents
{
Message = parsed.Message,
};
notification.Other.Add("image", parsed.Image);
await Send(notification, settings);
// Send to user
var playerIds = GetUsers(model, NotificationType.RequestDeclined);
await Send(playerIds, notification, settings);
}
protected override async Task RequestApproved(NotificationOptions model, MobileNotificationSettings settings)
@ -149,8 +153,9 @@ namespace Ombi.Notifications.Agents
Message = parsed.Message,
};
notification.Other.Add("image", parsed.Image);
await Send(notification, settings);
// Send to user
var playerIds = GetUsers(model, NotificationType.RequestApproved);
await Send(playerIds, notification, settings);
}
protected override async Task AvailableRequest(NotificationOptions model, MobileNotificationSettings settings)
@ -165,8 +170,9 @@ namespace Ombi.Notifications.Agents
{
Message = parsed.Message,
};
notification.Other.Add("image", parsed.Image);
await Send(notification, settings);
// Send to user
var playerIds = GetUsers(model, NotificationType.RequestAvailable);
await Send(playerIds, notification, settings);
}
protected override Task Send(NotificationMessage model, MobileNotificationSettings settings)
{
@ -175,6 +181,10 @@ namespace Ombi.Notifications.Agents
protected async Task Send(List<string> playerIds, NotificationMessage model, MobileNotificationSettings settings)
{
if (!playerIds.Any())
{
return;
}
var response = await _api.PushNotification(playerIds, model.Message);
_logger.LogDebug("Sent message to {0} recipients with message id {1}", response.recipients, response.id);
}
@ -186,7 +196,39 @@ namespace Ombi.Notifications.Agents
{
Message = message,
};
await Send(notification, settings);
// Send to user
var playerIds = await GetAdmins(NotificationType.RequestAvailable);
await Send(playerIds, notification, settings);
}
private async Task<List<string>> GetAdmins(NotificationType type)
{
var adminUsers = (await _userManager.GetUsersInRoleAsync(OmbiRoles.Admin)).Select(x => x.Id).ToList();
var notificationUsers = _notifications.GetAll().Include(x => x.User).Where(x => adminUsers.Contains(x.UserId));
var playerIds = await notificationUsers.Select(x => x.PlayerId).ToListAsync();
if (!playerIds.Any())
{
_logger.LogInformation(
$"there are no admins to send a notification for {type}, for agent {NotificationAgent.Mobile}");
return null;
}
return playerIds;
}
private List<string> GetUsers(NotificationOptions model, NotificationType type)
{
var notificationIds = model.RequestType == RequestType.Movie
? MovieRequest.RequestedUser.NotificationUserIds
: TvRequest.RequestedUser.NotificationUserIds;
if (!notificationIds.Any())
{
_logger.LogInformation(
$"there are no admins to send a notification for {type}, for agent {NotificationAgent.Mobile}");
return null;
}
var playerIds = notificationIds.Select(x => x.PlayerId).ToList();
return playerIds;
}
}
}

@ -44,6 +44,7 @@ namespace Ombi.Store.Repository.Requests
{
return Db.MovieRequests
.Include(x => x.RequestedUser)
.ThenInclude(x => x.NotificationUserIds)
.AsQueryable();
}

@ -87,3 +87,7 @@ export interface IMattermostNotifcationSettings extends INotificationSettings {
iconUrl: string;
notificationTemplates: INotificationTemplates[];
}
export interface IMobileNotifcationSettings extends INotificationSettings {
notificationTemplates: INotificationTemplates[];
}

@ -44,3 +44,8 @@ export interface IResetPasswordToken {
token: string;
password: string;
}
export interface IMobileUsersViewModel {
username: string;
devices: number;
}

@ -11,3 +11,4 @@ export * from "./settings.service";
export * from "./status.service";
export * from "./job.service";
export * from "./issues.service";
export * from "./mobile.service";

@ -0,0 +1,18 @@
import { PlatformLocation } from "@angular/common";
import { Injectable } from "@angular/core";
import { HttpClient } from "@angular/common/http";
import { Observable } from "rxjs/Rx";
import { IMobileUsersViewModel } from "./../interfaces";
import { ServiceHelpers } from "./service.helpers";
@Injectable()
export class MobileService extends ServiceHelpers {
constructor(http: HttpClient, public platformLocation: PlatformLocation) {
super(http, "/api/v1/mobile/", platformLocation);
}
public getUserDeviceList(): Observable<IMobileUsersViewModel[]> {
return this.http.get<IMobileUsersViewModel[]>(`${this.url}notification/`, {headers: this.headers});
}
}

@ -16,6 +16,7 @@ import {
IJobSettings,
ILandingPageSettings,
IMattermostNotifcationSettings,
IMobileNotifcationSettings,
IOmbiSettings,
IPlexSettings,
IPushbulletNotificationSettings,
@ -139,14 +140,15 @@ export class SettingsService extends ServiceHelpers {
return this.http.get<IMattermostNotifcationSettings>(`${this.url}/notifications/mattermost`, {headers: this.headers});
}
public saveMattermostNotificationSettings(settings: IMattermostNotifcationSettings): Observable<boolean> {
return this.http.post<boolean>(`${this.url}/notifications/mattermost`, JSON.stringify(settings), {headers: this.headers});
}
public saveDiscordNotificationSettings(settings: IDiscordNotifcationSettings): Observable<boolean> {
return this.http
.post<boolean>(`${this.url}/notifications/discord`, JSON.stringify(settings), {headers: this.headers});
}
public saveMattermostNotificationSettings(settings: IMattermostNotifcationSettings): Observable<boolean> {
return this.http.post<boolean>(`${this.url}/notifications/mattermost`, JSON.stringify(settings), {headers: this.headers});
}
public getPushbulletNotificationSettings(): Observable<IPushbulletNotificationSettings> {
return this.http.get<IPushbulletNotificationSettings>(`${this.url}/notifications/pushbullet`, {headers: this.headers});
}
@ -172,6 +174,14 @@ export class SettingsService extends ServiceHelpers {
.post<boolean>(`${this.url}/notifications/slack`, JSON.stringify(settings), {headers: this.headers});
}
public getMobileNotificationSettings(): Observable<IMobileNotifcationSettings> {
return this.http.get<IMobileNotifcationSettings>(`${this.url}/notifications/mobile`, {headers: this.headers});
}
public saveMobileNotificationSettings(settings: IMobileNotifcationSettings): Observable<boolean> {
return this.http.post<boolean>(`${this.url}/notifications/mobile`, JSON.stringify(settings), {headers: this.headers});
}
public getUpdateSettings(): Observable<IUpdateSettings> {
return this.http.get<IUpdateSettings>(`${this.url}/update`, {headers: this.headers});
}

@ -0,0 +1,39 @@

<settings-menu></settings-menu>
<div *ngIf="form">
<fieldset>
<legend>Mobile Notifications</legend>
<div class="col-md-6">
<form novalidate [formGroup]="form" (ngSubmit)="onSubmit(form)">
<div *ngFor="let user of userList">
<span>{{user.username}} - {{user.devices}}</span>
</div>
<div class="form-group">
<div>
<button [disabled]="form.invalid" 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" 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 { FormBuilder, FormGroup } from "@angular/forms";
import { IMobileNotifcationSettings, IMobileUsersViewModel, INotificationTemplates, NotificationType } from "../../interfaces";
import { TesterService } from "../../services";
import { NotificationService } from "../../services";
import { MobileService, SettingsService } from "../../services";
@Component({
templateUrl: "./mobile.component.html",
})
export class MobileComponent implements OnInit {
public NotificationType = NotificationType;
public templates: INotificationTemplates[];
public form: FormGroup;
public userList: IMobileUsersViewModel[];
constructor(private settingsService: SettingsService,
private notificationService: NotificationService,
private fb: FormBuilder,
private testerService: TesterService,
private mobileService: MobileService) { }
public ngOnInit() {
this.settingsService.getMobileNotificationSettings().subscribe(x => {
this.templates = x.notificationTemplates;
this.form = this.fb.group({
});
});
this.mobileService.getUserDeviceList().subscribe(x => this.userList = x);
}
public onSubmit(form: FormGroup) {
if (form.invalid) {
this.notificationService.error("Please check your entered values");
return;
}
const settings = <IMobileNotifcationSettings>form.value;
settings.notificationTemplates = this.templates;
this.settingsService.saveMobileNotificationSettings(settings).subscribe(x => {
if (x) {
this.notificationService.success("Successfully saved the Mobile settings");
} else {
this.notificationService.success("There was an error when saving the Mobile settings");
}
});
}
public test(form: FormGroup) {
if (form.invalid) {
this.notificationService.error("Please check your entered values");
return;
}
this.testerService.discordTest(form.value).subscribe(x => {
if (x) {
this.notificationService.success("Successfully sent a Mobile message, please check the admin mobile device");
} else {
this.notificationService.error("There was an error when sending the Mobile message. Please check your settings");
}
});
}
}

@ -7,7 +7,7 @@ import { ClipboardModule } from "ngx-clipboard/dist";
import { AuthGuard } from "../auth/auth.guard";
import { AuthService } from "../auth/auth.service";
import { CouchPotatoService, EmbyService, IssuesService, JobService, PlexService, RadarrService, SonarrService, TesterService, ValidationService } from "../services";
import { CouchPotatoService, EmbyService, IssuesService, JobService, MobileService, PlexService, RadarrService, SonarrService, TesterService, ValidationService } from "../services";
import { PipeModule } from "../pipes/pipe.module";
import { AboutComponent } from "./about/about.component";
@ -22,6 +22,7 @@ import { LandingPageComponent } from "./landingpage/landingpage.component";
import { DiscordComponent } from "./notifications/discord.component";
import { EmailNotificationComponent } from "./notifications/emailnotification.component";
import { MattermostComponent } from "./notifications/mattermost.component";
import { MobileComponent } from "./notifications/mobile.component";
import { NotificationTemplate } from "./notifications/notificationtemplate.component";
import { PushbulletComponent } from "./notifications/pushbullet.component";
import { PushoverComponent } from "./notifications/pushover.component";
@ -64,6 +65,7 @@ const routes: Routes = [
{ path: "SickRage", component: SickRageComponent, canActivate: [AuthGuard] },
{ path: "Issues", component: IssuesComponent, canActivate: [AuthGuard] },
{ path: "Authentication", component: AuthenticationComponent, canActivate: [AuthGuard] },
{ path: "Mobile", component: MobileComponent, canActivate: [AuthGuard] },
];
@NgModule({
@ -111,6 +113,7 @@ const routes: Routes = [
TelegramComponent,
IssuesComponent,
AuthenticationComponent,
MobileComponent,
],
exports: [
RouterModule,
@ -127,6 +130,7 @@ const routes: Routes = [
IssuesService,
PlexService,
EmbyService,
MobileService,
],
})

@ -1,8 +1,11 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
using Ombi.Attributes;
using Ombi.Core.Authentication;
using Ombi.Helpers;
using Ombi.Models;
@ -26,6 +29,7 @@ namespace Ombi.Controllers
private readonly OmbiUserManager _userManager;
[HttpPost("Notification")]
[ApiExplorerSettings(IgnoreApi = true)]
public async Task<IActionResult> AddNotitficationId([FromBody] NotificationIdBody body)
{
if (body?.PlayerId.HasValue() ?? false)
@ -50,5 +54,25 @@ namespace Ombi.Controllers
}
return BadRequest();
}
[HttpGet("Notification")]
[ApiExplorerSettings(IgnoreApi = true)]
[Admin]
public IEnumerable<MobileUsersViewModel> GetRegisteredMobileUsers()
{
var users = _userManager.Users.Include(x => x.NotificationUserIds).Where(x => x.NotificationUserIds.Any());
var vm = new List<MobileUsersViewModel>();
foreach (var u in users)
{
vm.Add(new MobileUsersViewModel
{
Username = u.UserAlias,
Devices = u.NotificationUserIds.Count
});
}
return vm;
}
}
}

@ -765,6 +765,40 @@ namespace Ombi.Controllers
return model;
}
/// <summary>
/// Saves the Mobile notification settings.
/// </summary>
/// <param name="model">The model.</param>
/// <returns></returns>
[HttpPost("notifications/mobile")]
public async Task<bool> MobileNotificationSettings([FromBody] MobileNotificationsViewModel model)
{
// Save the email settings
var settings = Mapper.Map<MobileNotificationSettings>(model);
var result = await Save(settings);
// Save the templates
await TemplateRepository.UpdateRange(model.NotificationTemplates);
return result;
}
/// <summary>
/// Gets the Mobile Notification Settings.
/// </summary>
/// <returns></returns>
[HttpGet("notifications/mobile")]
public async Task<MobileNotificationsViewModel> MobileNotificationSettings()
{
var settings = await Get<MobileNotificationSettings>();
var model = Mapper.Map<MobileNotificationsViewModel>(settings);
// Lookup to see if we have any templates saved
model.NotificationTemplates = await BuildTemplates(NotificationAgent.Mobile);
return model;
}
private async Task<List<NotificationTemplates>> BuildTemplates(NotificationAgent agent)
{
var templates = await TemplateRepository.GetAllTemplates(agent);

@ -0,0 +1,8 @@
namespace Ombi.Models
{
public class MobileUsersViewModel
{
public string Username { get; set; }
public int Devices { get; set; }
}
}

@ -5,6 +5,7 @@ const run = require('gulp-run');
const runSequence = require('run-sequence');
const del = require('del');
const path = require('path');
const fs = require('fs');
const outputDir = './wwwroot/dist';
@ -23,26 +24,56 @@ function getEnvOptions() {
}
}
gulp.task('vendor', function () {
return run('webpack --config webpack.config.vendor.ts' + getEnvOptions()).exec();
function webpack(vendor) {
return run(`webpack --config webpack.config${vendor ? '.vendor' : ''}.ts${getEnvOptions()}`).exec();
}
gulp.task('vendor', () => {
let build = false;
const vendorPath = path.join(outputDir, "vendor.js");
const vendorExists = fs.existsSync(vendorPath);
if (vendorExists) {
const vendorStat = fs.statSync(vendorPath);
const packageStat = fs.statSync("package.json");
const vendorConfigStat = fs.statSync("webpack.config.vendor.ts");
if (packageStat.mtime > vendorStat.mtime) {
build = true;
}
if (vendorConfigStat.mtime > vendorStat.mtime) {
build = true;
}
} else {
build = true;
}
if (build) {
return webpack(true);
}
});
gulp.task('main', function () {
return run('webpack --config webpack.config.ts' + getEnvOptions()).exec();
gulp.task('vendor_force', () => {
return webpack(true);
})
gulp.task('main', () => {
return webpack()
});
gulp.task('prod_var', function () {
gulp.task('prod_var', () => {
global.prod = true;
})
gulp.task('analyse_var', function () {
gulp.task('analyse_var', () => {
global.analyse = true;
})
gulp.task('clean', function() {
del.sync(outputDir, { force: true });
gulp.task('clean', () => {
del.sync(outputDir, { force: true });
});
gulp.task('lint', () => run("npm run lint").exec());
gulp.task('build', callback => runSequence('vendor', 'main', callback));
gulp.task('analyse', callback => runSequence('analyse_var', 'build'));
gulp.task('full', callback => runSequence('clean', 'build'));

Loading…
Cancel
Save