diff --git a/client/package.json b/client/package.json index a3d0398..be120df 100644 --- a/client/package.json +++ b/client/package.json @@ -24,6 +24,7 @@ "@angular/platform-browser": "6.0.0", "@angular/platform-browser-dynamic": "6.0.0", "@angular/router": "6.0.0", + "@aspnet/signalr": "^1.0.0-rtm-30751", "@ngrx/effects": "^5.1.0", "@ngrx/store": "^5.1.0", "@ngrx/store-devtools": "^5.1.0", diff --git a/client/src/app/actions/chat.actions.ts b/client/src/app/actions/chat.actions.ts index 92b0a3f..a7828bd 100644 --- a/client/src/app/actions/chat.actions.ts +++ b/client/src/app/actions/chat.actions.ts @@ -23,12 +23,29 @@ export const ADD_SUCCESS = '[Chat] Add Chat Success'; export const ADD_FAIL = '[Chat] Add Chat Fail'; export class AddAction implements Action { readonly type = ADD; - constructor(public payload: ChatModel) { - } + constructor(public payload: ChatModel) {} } export class AddSuccessAction implements Action { readonly type = ADD_SUCCESS; + constructor(public payload: ChatModel) {} +} +//#endregion +//#region Add +// the receive action is for messages from signalR +// we don't want to initiate a POST to the server. +export const RECEIVE = '[Chat] Receive Chat'; +export const RECEIVE_SUCCESS = '[Chat] Receive Chat Success'; +export const RECEIVE_FAIL = '[Chat] Receive Chat Fail'; +export class ReceiveAction implements Action { + readonly type = RECEIVE; constructor(public payload: ChatModel) { + console.log('chat.actions', 'RECEIVE', payload); + } +} +export class ReceiveSuccessAction implements Action { + readonly type = RECEIVE_SUCCESS; + constructor(public payload: ChatModel) { + console.log('chat.actions', 'RECEIVE_SUCESS', payload); } } //#endregion @@ -37,5 +54,6 @@ export type Actions = | LoadSuccessAction | LoadFailAction | AddAction - | AddSuccessAction; - + | AddSuccessAction + | ReceiveAction + | ReceiveSuccessAction; diff --git a/client/src/app/app.component.ts b/client/src/app/app.component.ts index 4919310..5f75394 100644 --- a/client/src/app/app.component.ts +++ b/client/src/app/app.component.ts @@ -58,13 +58,11 @@ export class AppComponent implements OnInit { const chatterChannel = `${p.id}`; this._signalrService .init('userupdates') - .then((r) => { - this._signalrService.connection.on( - chatterChannel, - (result) => { - this._toastyService.info(result); - } - ); + .then((listener) => { + listener.on(chatterChannel) + .subscribe(result => { + this._toastyService.info(result); + }); }) .catch((err) => { console.error( diff --git a/client/src/app/app.module.ts b/client/src/app/app.module.ts index 3c9bfce..819c25c 100644 --- a/client/src/app/app.module.ts +++ b/client/src/app/app.module.ts @@ -156,7 +156,7 @@ export function provideConfig() { authDomain: 'podnoms-api.firebaseapp.com', databaseURL: 'https://podnoms-api.firebaseio.com', projectId: 'podnoms-api', - storageBucket: '', + storageBucket: 'podnoms-api.appspot.com', messagingSenderId: '357461672895' }), AngularFireDatabaseModule, diff --git a/client/src/app/components/chat-widget/chat-widget.component.html b/client/src/app/components/chat-widget/chat-widget.component.html index de5ae22..ac217f0 100644 --- a/client/src/app/components/chat-widget/chat-widget.component.html +++ b/client/src/app/components/chat-widget/chat-widget.component.html @@ -25,8 +25,9 @@ -
- +
+
Attach Document diff --git a/client/src/app/components/chat-widget/chat-widget.component.ts b/client/src/app/components/chat-widget/chat-widget.component.ts index ed00045..001996b 100644 --- a/client/src/app/components/chat-widget/chat-widget.component.ts +++ b/client/src/app/components/chat-widget/chat-widget.component.ts @@ -1,4 +1,4 @@ -import { Component, OnInit } from '@angular/core'; +import { Component, ViewChild, ElementRef } from '@angular/core'; import { ProfileService } from '../../services/profile.service'; import { SignalRService } from '../../services/signalr.service'; import { ProfileModel } from 'app/models/profile.model'; @@ -15,11 +15,17 @@ import { Observable } from 'rxjs/Observable'; templateUrl: './chat-widget.component.html', styleUrls: ['./chat-widget.component.css'] }) -export class ChatWidgetComponent implements OnInit { +export class ChatWidgetComponent { chatActive: boolean = false; - loading: boolean = false; - user: ProfileModel; + private user: ProfileModel; messages$: Observable; + private messageEl: ElementRef; + + // have to handle ViewChild like this as it's hidden with ngIf + @ViewChild('message') + set content(content: ElementRef) { + this.messageEl = content; + } constructor( private _profileService: ProfileService, @@ -28,25 +34,17 @@ export class ChatWidgetComponent implements OnInit { ) { this._profileService.getProfile().subscribe((p) => (this.user = p)); this.messages$ = _store.select(fromChat.getChat); + this.messages$.subscribe((r) => { + if (r.length != 0) { + this.chatActive = true; + } + }); } - ngOnInit() {} - togglePopup() { this.chatActive = !this.chatActive; - - if (this.chatActive && this.user) { - this.loading = true; - this._signalRService.init('chat').then(() => { - this.loading = false; - this._signalRService.connection.on('SendMessage', (message) => { - console.log( - 'chat-widget.component', - 'SendMessage', - message - ); - }); - }); + if (this.chatActive) { + setTimeout(() => this.messageEl.nativeElement.focus(), 0); } } diff --git a/client/src/app/components/podcast/entry-list-item/entry-list-item.component.ts b/client/src/app/components/podcast/entry-list-item/entry-list-item.component.ts index b753d52..a057f36 100644 --- a/client/src/app/components/podcast/entry-list-item/entry-list-item.component.ts +++ b/client/src/app/components/podcast/entry-list-item/entry-list-item.component.ts @@ -10,6 +10,7 @@ import * as fromEntriesActions from 'app/actions/entries.actions'; import { PodcastService } from '../../../services/podcast.service'; import { AudioService } from 'app/services/audio.service'; import { Observable } from 'rxjs/Observable'; +import { AudioProcessingMessageModel } from 'app/models/audioprocessingmessage.model'; @Component({ selector: '[app-entry-list-item]', @@ -39,23 +40,22 @@ export class EntryListItemComponent implements OnInit { ) { this._signalRService .init('audioprocessing') - .then(() => { + .then((listener) => { const updateChannel: string = `${ this.entry.uid }__progress_update`; const processedChannel: string = `${ this.entry.uid }__info_processed`; - this._signalRService.connection.on( - updateChannel, - (result) => { + listener + .on(updateChannel) + .subscribe((result) => { this.percentageProcessed = result.percentage; this.currentSpeed = result.currentSpeed; - } - ); - this._signalRService.connection.on( - processedChannel, - (result) => { + }); + listener + .on(processedChannel) + .subscribe((result) => { this.entry = result; if (this.entry.processingStatus === 'Processed') { // only update the store when we're finished. @@ -65,8 +65,7 @@ export class EntryListItemComponent implements OnInit { ) ); } - } - ); + }); }) .catch((err) => console.error( diff --git a/client/src/app/effects/chat.effects.ts b/client/src/app/effects/chat.effects.ts index ceef335..d5075f6 100644 --- a/client/src/app/effects/chat.effects.ts +++ b/client/src/app/effects/chat.effects.ts @@ -1,7 +1,4 @@ -import { - LoadAction, - LOAD_FAIL -} from './../actions/chat.actions'; +import { LoadAction, LOAD_FAIL } from './../actions/chat.actions'; import { Injectable } from '@angular/core'; import { Actions, Effect } from '@ngrx/effects'; import { Observable } from 'rxjs/Observable'; @@ -22,17 +19,26 @@ export class ChatEffects { .switchMap((payload: chat.LoadAction) => this._service .get() - .map(res => ({ type: chat.LOAD_SUCCESS, payload: res })) - .catch(err => { + .map((res) => ({ type: chat.LOAD_SUCCESS, payload: res })) + .catch((err) => { console.error('ChatEffects', 'get$', err); return Observable.of({ type: chat.LOAD_FAIL }); }) ); - @Effect() - put$ = this.actions$ - .ofType(chat.ADD) - .switchMap((action: chat.AddAction) => this._service.send(action.payload)) - .map(res => ({ type: chat.ADD_SUCCESS, payload: res })); + @Effect() + put$ = this.actions$ + .ofType(chat.ADD) + .switchMap((action: chat.AddAction) => + this._service.send(action.payload) + ) + .map((res) => ({ type: chat.ADD_SUCCESS, payload: res })); + @Effect() + receive$ = this.actions$ + .ofType(chat.RECEIVE) + .map((res: chat.ReceiveAction) => ({ type: chat.RECEIVE_SUCCESS, payload: res.payload })); + // receive$ = this.actions$.ofType(chat.RECEIVE).map((res) => { + // return { type: chat.RECEIVE_SUCCESS, payload: res }; + // }); constructor(private _service: ChatService, private actions$: Actions) {} } diff --git a/client/src/app/models/audioprocessingmessage.model.ts b/client/src/app/models/audioprocessingmessage.model.ts new file mode 100644 index 0000000..53626a0 --- /dev/null +++ b/client/src/app/models/audioprocessingmessage.model.ts @@ -0,0 +1,6 @@ +export class AudioProcessingMessageModel { + percentage: number; + totalSize: string; + currentSpeed: string; + eTA: string; +} diff --git a/client/src/app/reducers/chat.reducer.ts b/client/src/app/reducers/chat.reducer.ts index 8e29c5b..8eb0ad3 100644 --- a/client/src/app/reducers/chat.reducer.ts +++ b/client/src/app/reducers/chat.reducer.ts @@ -33,7 +33,8 @@ export function reducer(state = initialState, action: chat.Actions): State { loading: false }; } - case chat.ADD_SUCCESS: { + case chat.ADD_SUCCESS: + case chat.RECEIVE_SUCCESS: { const newResults = _.clone(state.result); newResults.push(action.payload); const newState = { diff --git a/client/src/app/services/chat.service.ts b/client/src/app/services/chat.service.ts index c85cd6e..07165d0 100644 --- a/client/src/app/services/chat.service.ts +++ b/client/src/app/services/chat.service.ts @@ -4,11 +4,35 @@ import { Observable } from 'rxjs/Observable'; import { environment } from 'environments/environment'; import { ChatModel } from 'app/models/chat.model'; import { HttpClient } from '@angular/common/http'; +import { SignalRService } from './signalr.service'; +import { Subject } from 'rxjs'; +import * as fromChat from 'app/reducers'; +import * as fromChatActions from 'app/actions/chat.actions'; +import { ApplicationState } from '../store'; +import { Store } from '@ngrx/store'; @Injectable() export class ChatService extends BaseService { - constructor(private _http: HttpClient) { + constructor( + private _http: HttpClient, + private _signalRService: SignalRService, + private _store: Store + ) { super(); + this._signalRService.init('chat').then((listener) => { + listener + .on('SendMessage') + .subscribe((message: ChatModel) => { + console.log( + 'chat-widget.component', + 'SendMessage', + message + ); + this._store.dispatch( + new fromChatActions.ReceiveAction(message) + ); + }); + }); } get(): Observable { diff --git a/client/src/app/services/messaging.service.ts b/client/src/app/services/messaging.service.ts index cf76aed..18850f2 100644 --- a/client/src/app/services/messaging.service.ts +++ b/client/src/app/services/messaging.service.ts @@ -18,7 +18,7 @@ export class MessagingService { private _pushRegistrationServer: PushRegistrationService ) { this.messaging.usePublicVapidKey( - 'BKyhUqIVZLauKNA-DXPXbIVLj5XiWurHbRV_0Rd3BOjY5cU9GOrd5ptXVJ2CNExxdveKYzZevrep2CflKeqkyqo' + 'BP05eVFzqeEh54DaL3TOe6x_8UFs60nw_gfSrI5tdILjb5VnHwas0n7c_075tsc1w5fm87u9d4Dawj_YN13PSAI' ); } diff --git a/client/src/app/services/signalr.service.ts b/client/src/app/services/signalr.service.ts index 5138d6e..a9452f3 100644 --- a/client/src/app/services/signalr.service.ts +++ b/client/src/app/services/signalr.service.ts @@ -1,31 +1,37 @@ import { PodnomsAuthService } from './podnoms-auth.service'; import { Injectable } from '@angular/core'; -import { - HubConnection, - HubConnectionBuilder, - JsonHubProtocol, - LogLevel -} from '@aspnet/signalr'; +import { HubConnection, HubConnectionBuilder, LogLevel } from '@aspnet/signalr'; import { environment } from 'environments/environment'; +import { Observable, Subscriber } from 'rxjs'; @Injectable() export class SignalRService { - public connection: HubConnection; + private _connected: boolean = false; + private _connection: HubConnection; constructor(private _auth: PodnomsAuthService) {} - public init(hub: string): Promise { - const url = `${environment.SIGNALR_HOST}/hubs/${hub}`; + public init(hub: string): Promise { + return new Promise((resolve) => { + const url = `${environment.SIGNALR_HOST}/hubs/${hub}`; + const token = this._auth.getToken(); + this._connection = new HubConnectionBuilder() + .configureLogging(LogLevel.Debug) + .withUrl(url + '?token=' + token) + .build(); + resolve(this); + }); + } - const token = this._auth.getToken(); - const options: any = { - transport: 0 - }; - - this.connection = new HubConnectionBuilder() - .configureLogging(LogLevel.Error) - .withUrl(url + '?token=' + token, options) - .withHubProtocol(new JsonHubProtocol()) - .build(); - return this.connection.start(); + public on(channel: string): Observable { + const listener = new Observable((subscriber: Subscriber) => { + this._connection.on(channel, (message) => { + const result: T = message as T; + subscriber.next(result); + }); + }); + if (!this._connected) { + this._connection.start().then(() => (this._connected = true)); + } + return listener; } } diff --git a/client/src/index.html b/client/src/index.html index ee63f3e..696d82d 100644 --- a/client/src/index.html +++ b/client/src/index.html @@ -32,9 +32,6 @@ ga('send', 'pageview'); - - - diff --git a/server/Controllers/AudioUploadController.cs b/server/Controllers/AudioUploadController.cs index 1b47d17..c8c88a9 100644 --- a/server/Controllers/AudioUploadController.cs +++ b/server/Controllers/AudioUploadController.cs @@ -15,6 +15,7 @@ using Microsoft.Extensions.Logging; using Microsoft.Extensions.Options; using Microsoft.Net.Http.Headers; using PodNoms.Api.Models; +using PodNoms.Api.Models.Settings; using PodNoms.Api.Models.ViewModels; using PodNoms.Api.Persistence; using PodNoms.Api.Providers; diff --git a/server/Controllers/AuthController.cs b/server/Controllers/AuthController.cs index 437f8c8..f03830b 100644 --- a/server/Controllers/AuthController.cs +++ b/server/Controllers/AuthController.cs @@ -8,6 +8,7 @@ using Microsoft.AspNetCore.Mvc; using Microsoft.Extensions.Options; using Newtonsoft.Json; using PodNoms.Api.Models; +using PodNoms.Api.Models.Settings; using PodNoms.Api.Models.ViewModels; using PodNoms.Api.Services; using PodNoms.Api.Services.Auth; diff --git a/server/Controllers/BaseAuthController.cs b/server/Controllers/BaseAuthController.cs index 5d4ac9d..e0efa0e 100644 --- a/server/Controllers/BaseAuthController.cs +++ b/server/Controllers/BaseAuthController.cs @@ -1,10 +1,12 @@ using System.Linq; using System.Security.Claims; +using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Identity; using Microsoft.AspNetCore.Mvc; using PodNoms.Api.Services.Auth; +[Authorize] public class BaseAuthController : Controller { private readonly ClaimsPrincipal _caller; protected readonly UserManager _userManager; diff --git a/server/Controllers/ChatController.cs b/server/Controllers/ChatController.cs index a9d4cf2..5abba7b 100644 --- a/server/Controllers/ChatController.cs +++ b/server/Controllers/ChatController.cs @@ -1,29 +1,40 @@ using System.Threading.Tasks; +using Lib.Net.Http.WebPush; using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Identity; using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.SignalR; +using Microsoft.Extensions.Options; +using PodNoms.Api.Models.Settings; using PodNoms.Api.Models.ViewModels; +using PodNoms.Api.Services; using PodNoms.Api.Services.Auth; using PodNoms.Api.Services.Hubs; +using PodNoms.Api.Services.Push; +using WebPush = Lib.Net.Http.WebPush; namespace PodNoms.Api.Controllers { [Route("[controller]")] [Authorize] public class ChatController : BaseAuthController { - private readonly HubLifetimeManager _hub; + private readonly ISupportChatService _supportChatService; public ChatController(IHttpContextAccessor contextAccessor, UserManager userManager, - HubLifetimeManager chatHubContext) : + ISupportChatService supportChatService) : base(contextAccessor, userManager) { - this._hub = chatHubContext; + this._supportChatService = supportChatService; } [HttpPost] public async Task> Post([FromBody]ChatViewModel message) { - await this._hub.SendAllAsync("SendMessage", new object[] { message.Message }); - return Ok(message); + //need to lookup the current support host and notify them + message.FromUserName = _applicationUser.FullName; + message.FromUserId = _applicationUser.Id; + if (await _supportChatService.InitiateSupportRequest(_userId, message)) { + return Ok(message); + } + return Accepted(message); } } } diff --git a/server/Controllers/DebugController.cs b/server/Controllers/DebugController.cs index 18e8dc1..be1cfa3 100644 --- a/server/Controllers/DebugController.cs +++ b/server/Controllers/DebugController.cs @@ -10,6 +10,7 @@ using Microsoft.AspNetCore.SignalR; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.Options; using PodNoms.Api.Models; +using PodNoms.Api.Models.Settings; using PodNoms.Api.Persistence; using PodNoms.Api.Services.Auth; using PodNoms.Api.Services.Downloader; @@ -24,7 +25,7 @@ namespace PodNoms.Api.Controllers { public class DebugController : BaseAuthController { private readonly StorageSettings _storageSettings; private readonly AudioFileStorageSettings _audioFileStorageSettings; - private readonly ApplicationsSettings _applicationsSettings; + private readonly HelpersSettings _helpersSettings; private readonly ImageFileStorageSettings _imageFileStorageSettings; private readonly HubLifetimeManager _hubManager; private readonly IPushSubscriptionStore _subscriptionStore; @@ -34,7 +35,7 @@ namespace PodNoms.Api.Controllers { public DebugController(IOptions settings, IOptions appSettings, HubLifetimeManager hubManager, - IOptions applicationsSettings, + IOptions helpersSettings, IOptions audioFileStorageSettings, IOptions imageFileStorageSettings, IPushSubscriptionStore subscriptionStore, @@ -43,7 +44,7 @@ namespace PodNoms.Api.Controllers { IHttpContextAccessor contextAccessor) : base(contextAccessor, userManager) { this._appSettings = appSettings.Value; this._storageSettings = settings.Value; - this._applicationsSettings = applicationsSettings.Value; + this._helpersSettings = helpersSettings.Value; this._audioFileStorageSettings = audioFileStorageSettings.Value; this._imageFileStorageSettings = imageFileStorageSettings.Value; this._hubManager = hubManager; @@ -59,8 +60,8 @@ namespace PodNoms.Api.Controllers { CdnUrl = _storageSettings.CdnUrl, AudioContainer = _audioFileStorageSettings.ContainerName, ImageContainer = _imageFileStorageSettings.ContainerName, - YouTubeDlPath = _applicationsSettings.Downloader, - YouTubeDlVersion = AudioDownloader.GetVersion(_applicationsSettings.Downloader), + YouTubeDlPath = _helpersSettings.Downloader, + YouTubeDlVersion = AudioDownloader.GetVersion(_helpersSettings.Downloader), OSVersion = System.Environment.OSVersion, RssUrl = _appSettings.RssUrl }; diff --git a/server/Controllers/EntryController.cs b/server/Controllers/EntryController.cs index 6d68274..e0b0ddd 100644 --- a/server/Controllers/EntryController.cs +++ b/server/Controllers/EntryController.cs @@ -7,12 +7,14 @@ using AutoMapper; using Hangfire; using Microsoft.AspNetCore.Hosting; using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Identity; using Microsoft.AspNetCore.Mvc; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.Logging; using Microsoft.Extensions.Options; using PodNoms.Api.Models; +using PodNoms.Api.Models.Settings; using PodNoms.Api.Models.ViewModels; using PodNoms.Api.Persistence; using PodNoms.Api.Services; @@ -24,6 +26,7 @@ using PodNoms.Api.Utils.RemoteParsers; namespace PodNoms.Api.Controllers { [Route("[controller]")] + [Authorize] public class EntryController : BaseAuthController { private readonly IPodcastRepository _podcastRepository; private readonly IEntryRepository _repository; diff --git a/server/Controllers/ImageUploadController.cs b/server/Controllers/ImageUploadController.cs index 4863f27..5333365 100644 --- a/server/Controllers/ImageUploadController.cs +++ b/server/Controllers/ImageUploadController.cs @@ -22,6 +22,7 @@ using SixLabors.ImageSharp.PixelFormats; using SixLabors.ImageSharp.Processing; using SixLabors.ImageSharp.Processing.Transforms; using SixLabors.ImageSharp.Processing.Filters; +using PodNoms.Api.Models.Settings; namespace PodNoms.Api.Controllers { [Authorize] @@ -42,6 +43,7 @@ namespace PodNoms.Api.Controllers { this._fileUploader = fileUploader; this._imageFileStorageSettings = imageFileStorageSettings.Value; this._repository = repository; + //this._repository = repository; this._unitOfWork = unitOfWork; this._mapper = mapper; this._logger = loggerFactory.CreateLogger(); diff --git a/server/Controllers/PodcastController.cs b/server/Controllers/PodcastController.cs index 9d5d498..d9a6674 100644 --- a/server/Controllers/PodcastController.cs +++ b/server/Controllers/PodcastController.cs @@ -23,17 +23,14 @@ namespace PodNoms.Api.Controllers { [Route("[controller]")] public class PodcastController : BaseAuthController { private readonly IPodcastRepository _repository; - private readonly IOptions _settings; private readonly IMapper _mapper; private readonly IUnitOfWork _uow; - public PodcastController(IPodcastRepository repository, IOptions options, - IMapper mapper, IUnitOfWork unitOfWork, + public PodcastController(IPodcastRepository repository, IMapper mapper, IUnitOfWork unitOfWork, UserManager userManager, IHttpContextAccessor contextAccessor) : base(contextAccessor, userManager) { this._uow = unitOfWork; this._repository = repository; - this._settings = options; this._mapper = mapper; } diff --git a/server/Controllers/RssController.cs b/server/Controllers/RssController.cs index d0d420a..71d895b 100644 --- a/server/Controllers/RssController.cs +++ b/server/Controllers/RssController.cs @@ -10,6 +10,7 @@ using Microsoft.AspNetCore.Mvc; using Microsoft.Extensions.Logging; using Microsoft.Extensions.Options; using PodNoms.Api.Models; +using PodNoms.Api.Models.Settings; using PodNoms.Api.Models.ViewModels.RssViewModels; using PodNoms.Api.Persistence; using PodNoms.Api.Services.Auth; diff --git a/server/Models/ImageSettings.cs b/server/Models/ImageSettings.cs deleted file mode 100644 index 6c65543..0000000 --- a/server/Models/ImageSettings.cs +++ /dev/null @@ -1,29 +0,0 @@ -using System.IO; -using System.Linq; - -namespace PodNoms.Api.Models -{ - public class ImageFileStorageSettings : FileStorageSettings - { - } - - public class AudioFileStorageSettings : FileStorageSettings - { - } - - public class FileStorageSettings - { - public string ContainerName { get; set; } - public long MaxUploadFileSize { get; set; } - public string[] AllowedFileTypes { get; set; } - - public bool IsSupported(string fileName) - { - return AllowedFileTypes.Any(s => s == Path.GetExtension(fileName).ToLower()); - } - } - public class ApplicationsSettings - { - public string Downloader { get; set; } - } -} \ No newline at end of file diff --git a/server/Models/AppSettings.cs b/server/Models/Settings/AppSettings.cs similarity index 71% rename from server/Models/AppSettings.cs rename to server/Models/Settings/AppSettings.cs index 32d062a..de3331f 100644 --- a/server/Models/AppSettings.cs +++ b/server/Models/Settings/AppSettings.cs @@ -1,8 +1,9 @@ -namespace PodNoms.Api.Models { +namespace PodNoms.Api.Models.Settings { public class AppSettings { public string Version { get; set; } public string SiteUrl { get; set; } public string RssUrl { get; set; } public string GoogleApiKey { get; set; } + public string Downloader { get; set; } } } \ No newline at end of file diff --git a/server/Models/Settings/ApplicationsSettings.cs b/server/Models/Settings/ApplicationsSettings.cs new file mode 100644 index 0000000..ae48e44 --- /dev/null +++ b/server/Models/Settings/ApplicationsSettings.cs @@ -0,0 +1,5 @@ +namespace PodNoms.Api.Models.Settings { + public class HelpersSettings { + public string Downloader { get; set; } + } +} \ No newline at end of file diff --git a/server/Models/Settings/AudioFileStorageSettings.cs b/server/Models/Settings/AudioFileStorageSettings.cs new file mode 100644 index 0000000..7f2fd01 --- /dev/null +++ b/server/Models/Settings/AudioFileStorageSettings.cs @@ -0,0 +1,4 @@ +namespace PodNoms.Api.Models.Settings { + public class AudioFileStorageSettings : FileStorageSettings { + } +} \ No newline at end of file diff --git a/server/Models/Settings/ChatSettings.cs b/server/Models/Settings/ChatSettings.cs new file mode 100644 index 0000000..65298de --- /dev/null +++ b/server/Models/Settings/ChatSettings.cs @@ -0,0 +1,5 @@ +namespace PodNoms.Api.Models.Settings { + public class ChatSettings { + public string CurrentChatUser { get; set; } + } +} \ No newline at end of file diff --git a/server/Models/EmailSettings.cs b/server/Models/Settings/EmailSettings.cs similarity index 84% rename from server/Models/EmailSettings.cs rename to server/Models/Settings/EmailSettings.cs index ac7f011..941d6fe 100644 --- a/server/Models/EmailSettings.cs +++ b/server/Models/Settings/EmailSettings.cs @@ -1,4 +1,4 @@ -namespace PodNoms.Api.Models { +namespace PodNoms.Api.Models.Settings { public class EmailSettings { public string ApiKey { get; set; } diff --git a/server/Models/Settings/FileStorageSettings.cs b/server/Models/Settings/FileStorageSettings.cs new file mode 100644 index 0000000..9fe4d27 --- /dev/null +++ b/server/Models/Settings/FileStorageSettings.cs @@ -0,0 +1,15 @@ +using System.IO; +using System.Linq; + +namespace PodNoms.Api.Models.Settings { + + public class FileStorageSettings { + public string ContainerName { get; set; } + public long MaxUploadFileSize { get; set; } + public string[] AllowedFileTypes { get; set; } + + public bool IsSupported(string fileName) { + return AllowedFileTypes.Any(s => s == Path.GetExtension(fileName).ToLower()); + } + } +} \ No newline at end of file diff --git a/server/Models/Settings/ImageFileStorageSettings.cs b/server/Models/Settings/ImageFileStorageSettings.cs new file mode 100644 index 0000000..280ec57 --- /dev/null +++ b/server/Models/Settings/ImageFileStorageSettings.cs @@ -0,0 +1,4 @@ +namespace PodNoms.Api.Models.Settings { + public class ImageFileStorageSettings : FileStorageSettings { + } +} \ No newline at end of file diff --git a/server/Models/StorageSettings.cs b/server/Models/Settings/StorageSettings.cs similarity index 77% rename from server/Models/StorageSettings.cs rename to server/Models/Settings/StorageSettings.cs index 44cc0f4..83cb446 100644 --- a/server/Models/StorageSettings.cs +++ b/server/Models/Settings/StorageSettings.cs @@ -1,7 +1,6 @@ -namespace PodNoms.Api.Models { +namespace PodNoms.Api.Models.Settings { public class StorageSettings { public string ConnectionString { get; set; } public string CdnUrl { get; set; } - } } \ No newline at end of file diff --git a/server/Models/ViewModels/ChatViewModel.cs b/server/Models/ViewModels/ChatViewModel.cs index 35722d1..0a3c61e 100644 --- a/server/Models/ViewModels/ChatViewModel.cs +++ b/server/Models/ViewModels/ChatViewModel.cs @@ -1,5 +1,9 @@ namespace PodNoms.Api.Models.ViewModels { public class ChatViewModel { public string Message { get; set; } + public string FromUserId { get; set; } + public string FromUserName { get; set; } + public string ToUserId { get; set; } + public string ToUserName { get; set; } } } \ No newline at end of file diff --git a/server/Models/ViewModels/DownloadProgress.cs b/server/Models/ViewModels/DownloadProgress.cs index 80812c3..0e170fa 100644 --- a/server/Models/ViewModels/DownloadProgress.cs +++ b/server/Models/ViewModels/DownloadProgress.cs @@ -1,5 +1,4 @@ -namespace PodNoms.Api.Models.ViewModels -{ +namespace PodNoms.Api.Models.ViewModels { public class ProcessProgressEvent { public double Percentage { get; set; } public string TotalSize; diff --git a/server/Persistence/PodcastRepository.cs b/server/Persistence/PodcastRepository.cs index bda10de..79d1069 100644 --- a/server/Persistence/PodcastRepository.cs +++ b/server/Persistence/PodcastRepository.cs @@ -5,6 +5,7 @@ using System.Threading.Tasks; using Microsoft.EntityFrameworkCore; using Microsoft.Extensions.Options; using PodNoms.Api.Models; +using PodNoms.Api.Models.Settings; using PodNoms.Api.Persistence; using PodNoms.Api.Services.Storage; using PodNoms.Api.Utils; diff --git a/server/PodNoms.Api.csproj b/server/PodNoms.Api.csproj index 5e23e71..52b95ee 100644 --- a/server/PodNoms.Api.csproj +++ b/server/PodNoms.Api.csproj @@ -19,7 +19,7 @@ - + @@ -31,7 +31,7 @@ - + diff --git a/server/Services/Auth/ApplicationUser.cs b/server/Services/Auth/ApplicationUser.cs index 63cf101..0c75fd8 100644 --- a/server/Services/Auth/ApplicationUser.cs +++ b/server/Services/Auth/ApplicationUser.cs @@ -8,5 +8,6 @@ namespace PodNoms.Api.Services.Auth { public long? FacebookId { get; set; } public string PictureUrl { get; set; } public string Slug { get; set; } + public string FullName { get => $"{FirstName} {LastName}"; } } } \ No newline at end of file diff --git a/server/Services/Auth/ClaimsPrincipalExtensions.cs b/server/Services/Auth/ClaimsPrincipalExtensions.cs index 89a38e6..493bef2 100644 --- a/server/Services/Auth/ClaimsPrincipalExtensions.cs +++ b/server/Services/Auth/ClaimsPrincipalExtensions.cs @@ -1,12 +1,9 @@ using System; using System.Security.Claims; -namespace PodNoms.Api.Services.Auth -{ - public static class ClaimsPrincipalExtensions - { - public static string GetUserId(this ClaimsPrincipal principal) - { +namespace PodNoms.Api.Services.Auth { + public static class ClaimsPrincipalExtensions { + public static string GetUserId(this ClaimsPrincipal principal) { if (principal == null) throw new ArgumentNullException(nameof(principal)); diff --git a/server/Services/Auth/PodNomsUserManager.cs b/server/Services/Auth/PodNomsUserManager.cs index b70301e..dba75f0 100644 --- a/server/Services/Auth/PodNomsUserManager.cs +++ b/server/Services/Auth/PodNomsUserManager.cs @@ -12,6 +12,7 @@ using Microsoft.AspNetCore.Mvc; using PodNoms.Api.Services.Gravatar; using PodNoms.Api.Models; using PodNoms.Api.Utils; +using PodNoms.Api.Models.Settings; namespace PodNoms.Api.Services.Auth { public class PodNomsUserManager : UserManager { diff --git a/server/Services/Hubs/ChatHub.cs b/server/Services/Hubs/ChatHub.cs index 089a2eb..1be46a5 100644 --- a/server/Services/Hubs/ChatHub.cs +++ b/server/Services/Hubs/ChatHub.cs @@ -1,4 +1,5 @@ using System; +using System.Linq; using System.Threading.Tasks; using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.SignalR; @@ -7,15 +8,12 @@ namespace PodNoms.Api.Services.Hubs { [Authorize] public class ChatHub : Hub { public override async Task OnConnectedAsync() { - await Clients.All.SendAsync("SendAction", Context.User.Identity.Name, "joined"); + // await Clients.All.SendAsync("SendAction", Context.User.Identity.Name, "joined"); } public override async Task OnDisconnectedAsync(Exception ex) { - await Clients.All.SendAsync("SendAction", Context.User.Identity.Name, "left"); - } - - public async Task Send(string message) { - await Clients.All.SendAsync("SendMessage", Context.User.Identity.Name, message); + // await Clients.All.SendAsync("SendAction", Context.User.Identity.Name, "left"); } + } } \ No newline at end of file diff --git a/server/Services/ISupportChatService.cs b/server/Services/ISupportChatService.cs new file mode 100644 index 0000000..3c76fcd --- /dev/null +++ b/server/Services/ISupportChatService.cs @@ -0,0 +1,8 @@ +using System.Threading.Tasks; +using PodNoms.Api.Models.ViewModels; + +namespace PodNoms.Api.Services { + public interface ISupportChatService { + Task InitiateSupportRequest(string fromUser, ChatViewModel message); + } +} diff --git a/server/Services/Jobs/ClearOrphanAudioJob.cs b/server/Services/Jobs/ClearOrphanAudioJob.cs index ab0b496..7b309d3 100644 --- a/server/Services/Jobs/ClearOrphanAudioJob.cs +++ b/server/Services/Jobs/ClearOrphanAudioJob.cs @@ -5,6 +5,7 @@ using Microsoft.Extensions.Options; using Microsoft.WindowsAzure.Storage; using Microsoft.WindowsAzure.Storage.Blob; using PodNoms.Api.Models; +using PodNoms.Api.Models.Settings; using PodNoms.Api.Persistence; namespace PodNoms.Api.Services.Jobs { diff --git a/server/Services/Jobs/NotifyJobCompleteService.cs b/server/Services/Jobs/NotifyJobCompleteService.cs index fae8ae4..8536aff 100644 --- a/server/Services/Jobs/NotifyJobCompleteService.cs +++ b/server/Services/Jobs/NotifyJobCompleteService.cs @@ -12,7 +12,6 @@ namespace PodNoms.Api.Services.Jobs { IPushNotificationService notificationService) { this._notificationService = notificationService; this._subscriptionStore = subscriptionStore; - } public async Task NotifyUser(string userId, string title, string body, string image) { WebPush.PushMessage pushMessage = new WebPush.PushMessage(body) { diff --git a/server/Services/Jobs/ProcessPlaylistItemJob.cs b/server/Services/Jobs/ProcessPlaylistItemJob.cs index b211af1..58de727 100644 --- a/server/Services/Jobs/ProcessPlaylistItemJob.cs +++ b/server/Services/Jobs/ProcessPlaylistItemJob.cs @@ -4,6 +4,7 @@ using Microsoft.Extensions.Configuration; using Microsoft.Extensions.Logging; using Microsoft.Extensions.Options; using PodNoms.Api.Models; +using PodNoms.Api.Models.Settings; using PodNoms.Api.Persistence; using PodNoms.Api.Services.Downloader; using PodNoms.Api.Services.Processor; @@ -16,12 +17,12 @@ namespace PodNoms.Api.Services.Jobs { private readonly IAudioUploadProcessService _uploadService; private readonly IConfiguration _options; private readonly IPodcastRepository _podcastRepository; - private readonly ApplicationsSettings _applicationsSettings; + private readonly HelpersSettings _helpersSettings; private readonly ILogger _logger; private readonly IUnitOfWork _unitOfWork; public ProcessPlaylistItemJob(IPlaylistRepository playlistRepository, IEntryRepository entryRepository, IAudioUploadProcessService uploadService, IConfiguration options, - IPodcastRepository podcastRepository, IOptions applicationsSettings, + IPodcastRepository podcastRepository, IOptions _helpersSettings, IUnitOfWork unitOfWork, ILogger logger) { this._unitOfWork = unitOfWork; this._playlistRepository = playlistRepository; @@ -29,7 +30,7 @@ namespace PodNoms.Api.Services.Jobs { this._uploadService = uploadService; this._options = options; this._podcastRepository = podcastRepository; - this._applicationsSettings = applicationsSettings.Value; + this._helpersSettings = _helpersSettings.Value; this._logger = logger; } public async Task Execute() { @@ -42,7 +43,7 @@ namespace PodNoms.Api.Services.Jobs { var item = await _playlistRepository.GetParsedItem(itemId, playlistId); if (item != null && !string.IsNullOrEmpty(item.VideoType) && item.VideoType.Equals("youtube")) { var url = $"https://www.youtube.com/watch?v={item.VideoId}"; - var downloader = new AudioDownloader(url, _applicationsSettings.Downloader); + var downloader = new AudioDownloader(url, _helpersSettings.Downloader); var info = downloader.GetInfo(); if (info == AudioType.Valid) { var podcast = await _podcastRepository.GetAsync(item.Playlist.PodcastId); diff --git a/server/Services/Jobs/ProcessPlaylistsJob.cs b/server/Services/Jobs/ProcessPlaylistsJob.cs index 38994c2..825c1f5 100644 --- a/server/Services/Jobs/ProcessPlaylistsJob.cs +++ b/server/Services/Jobs/ProcessPlaylistsJob.cs @@ -8,6 +8,7 @@ using Microsoft.Extensions.Logging; using Microsoft.Extensions.Options; using NYoutubeDL.Models; using PodNoms.Api.Models; +using PodNoms.Api.Models.Settings; using PodNoms.Api.Persistence; using PodNoms.Api.Services.Downloader; using PodNoms.Api.Utils.RemoteParsers; @@ -17,21 +18,21 @@ namespace PodNoms.Api.Services.Jobs { public class ProcessPlaylistsJob : IJob { public readonly IPlaylistRepository _playlistRepository; public readonly IEntryRepository _entryRepository; - private readonly ApplicationsSettings _applicationsSettings; + private readonly HelpersSettings _helpersSettings; private readonly ILogger _logger; private readonly YouTubeParser _youTubeParser; private readonly MixcloudParser _mixcloudParser; private readonly IUnitOfWork _unitOfWork; public ProcessPlaylistsJob(IPlaylistRepository playlistRepository, IEntryRepository entryRepository, - IUnitOfWork unitOfWork, IOptions applicationsSettings, + IUnitOfWork unitOfWork, IOptions helpersSettings, ILoggerFactory logger, YouTubeParser youTubeParser, MixcloudParser mixcloudParser) { this._unitOfWork = unitOfWork; this._youTubeParser = youTubeParser; this._mixcloudParser = mixcloudParser; this._playlistRepository = playlistRepository; this._entryRepository = entryRepository; - this._applicationsSettings = applicationsSettings.Value; + this._helpersSettings = helpersSettings.Value; this._logger = logger.CreateLogger(); } @@ -40,7 +41,7 @@ namespace PodNoms.Api.Services.Jobs { var resultList = new List(); foreach (var playlist in playlists) { - var downloader = new AudioDownloader(playlist.SourceUrl, _applicationsSettings.Downloader); + var downloader = new AudioDownloader(playlist.SourceUrl, _helpersSettings.Downloader); var info = downloader.GetInfo(); var id = ((PlaylistDownloadInfo)downloader.RawProperties).Id; if (info == AudioType.Playlist && downloader.RawProperties is PlaylistDownloadInfo) { diff --git a/server/Services/MailgunSender.cs b/server/Services/MailgunSender.cs index b60d104..be6fcfe 100644 --- a/server/Services/MailgunSender.cs +++ b/server/Services/MailgunSender.cs @@ -10,6 +10,7 @@ using PodNoms.Api.Models; using System.Net; using PodNoms.Api.Utils; using HandlebarsDotNet; +using PodNoms.Api.Models.Settings; namespace PodNoms.Api.Services { public class MailgunSender : IMailSender { diff --git a/server/Services/Processor/AudioUploadProcessService.cs b/server/Services/Processor/AudioUploadProcessService.cs index 3e045fb..f117b27 100644 --- a/server/Services/Processor/AudioUploadProcessService.cs +++ b/server/Services/Processor/AudioUploadProcessService.cs @@ -6,6 +6,7 @@ using Microsoft.Extensions.Logging; using Microsoft.Extensions.Options; using Newtonsoft.Json.Linq; using PodNoms.Api.Models; +using PodNoms.Api.Models.Settings; using PodNoms.Api.Models.ViewModels; using PodNoms.Api.Persistence; using PodNoms.Api.Services.Realtime; diff --git a/server/Services/Processor/UrlProcessService.cs b/server/Services/Processor/UrlProcessService.cs index cbfc48c..952faa6 100644 --- a/server/Services/Processor/UrlProcessService.cs +++ b/server/Services/Processor/UrlProcessService.cs @@ -11,6 +11,7 @@ using Newtonsoft.Json; using Newtonsoft.Json.Linq; using Newtonsoft.Json.Serialization; using PodNoms.Api.Models; +using PodNoms.Api.Models.Settings; using PodNoms.Api.Models.ViewModels; using PodNoms.Api.Persistence; using PodNoms.Api.Services.Downloader; @@ -23,14 +24,14 @@ namespace PodNoms.Api.Services.Processor { private readonly IUnitOfWork _unitOfWork; private readonly IEntryRepository _repository; - public ApplicationsSettings _applicationsSettings { get; } + public HelpersSettings _helpersSettings { get; } private readonly HubLifetimeManager _userUpdateHub; public UrlProcessService(IEntryRepository repository, IUnitOfWork unitOfWork, - IFileUploader fileUploader, IOptions applicationsSettings, + IFileUploader fileUploader, IOptions helpersSettings, HubLifetimeManager userUpdateHub, ILoggerFactory logger, IMapper mapper, IRealTimeUpdater pusher) : base(logger, mapper, pusher) { - this._applicationsSettings = applicationsSettings.Value; + this._helpersSettings = helpersSettings.Value; this._repository = repository; this._unitOfWork = unitOfWork; this._userUpdateHub = userUpdateHub; @@ -56,7 +57,7 @@ namespace PodNoms.Api.Services.Processor { public async Task GetInformation(PodcastEntry entry) { - var downloader = new AudioDownloader(entry.SourceUrl, _applicationsSettings.Downloader); + var downloader = new AudioDownloader(entry.SourceUrl, _helpersSettings.Downloader); var ret = downloader.GetInfo(); if (ret == AudioType.Valid) { entry.Title = downloader.Properties?.Title; @@ -81,7 +82,7 @@ namespace PodNoms.Api.Services.Processor { if (entry == null) return false; try { - var downloader = new AudioDownloader(entry.SourceUrl, _applicationsSettings.Downloader); + var downloader = new AudioDownloader(entry.SourceUrl, _helpersSettings.Downloader); var outputFile = Path.Combine(System.IO.Path.GetTempPath(), $"{System.Guid.NewGuid().ToString()}.mp3"); diff --git a/server/Services/Push/FirebasePushNotificationService.cs b/server/Services/Push/FirebasePushNotificationService.cs index b61fab2..304c683 100644 --- a/server/Services/Push/FirebasePushNotificationService.cs +++ b/server/Services/Push/FirebasePushNotificationService.cs @@ -13,10 +13,10 @@ namespace PodNoms.Api.Services.Push { private readonly ILogger _logger; private readonly IHttpClientFactory _httpClientFactory; public string PublicKey => _options.PublicKey; - public FirebasePushNotificationService(IOptions optionsAccessor, + public FirebasePushNotificationService(IOptions pushOptions, IHttpClientFactory httpClientFactory, ILogger logger) { - _options = optionsAccessor.Value; + _options = pushOptions.Value; _logger = logger; _httpClientFactory = httpClientFactory; } diff --git a/server/Services/Storage/AzureFileUploader.cs b/server/Services/Storage/AzureFileUploader.cs index f360b31..3e7ddeb 100644 --- a/server/Services/Storage/AzureFileUploader.cs +++ b/server/Services/Storage/AzureFileUploader.cs @@ -9,6 +9,7 @@ using Microsoft.Extensions.Options; using Microsoft.WindowsAzure.Storage; using Microsoft.WindowsAzure.Storage.Blob; using PodNoms.Api.Models; +using PodNoms.Api.Models.Settings; using PodNoms.Api.Services.Processor; using PodNoms.Api.Services.Realtime; using PodNoms.Api.Utils.Extensions; @@ -28,7 +29,7 @@ namespace PodNoms.Api.Services.Storage { CloudBlockBlob blockBlob = container.GetBlockBlobReference(destinationFile); blockBlob.Properties.ContentType = contentType; - + var blockSize = 256 * 1024; blockBlob.StreamWriteSizeInBytes = blockSize; long bytesToUpload = (new FileInfo(sourceFile)).Length; diff --git a/server/Services/SupportChatService.cs b/server/Services/SupportChatService.cs new file mode 100644 index 0000000..9b9adb6 --- /dev/null +++ b/server/Services/SupportChatService.cs @@ -0,0 +1,55 @@ +using System.Threading.Tasks; +using Lib.Net.Http.WebPush; +using Microsoft.AspNetCore.Identity; +using Microsoft.AspNetCore.SignalR; +using Microsoft.Extensions.Options; +using Newtonsoft.Json; +using PodNoms.Api.Models.Settings; +using PodNoms.Api.Models.ViewModels; +using PodNoms.Api.Services.Auth; +using PodNoms.Api.Services.Hubs; +using PodNoms.Api.Services.Push; +using WebPush = Lib.Net.Http.WebPush; + +namespace PodNoms.Api.Services { + public class SupportChatService : ISupportChatService { + private readonly ChatSettings _chatSettings; + private readonly IPushNotificationService _notificationService; + private readonly HubLifetimeManager _chatHub; + private readonly UserManager _userManager; + private readonly IPushSubscriptionStore _subscriptionStore; + private readonly HubLifetimeManager _hub; + public SupportChatService(UserManager userManager, IOptions chatSettings, + IPushSubscriptionStore subscriptionStore, IPushNotificationService notificationService, + HubLifetimeManager chatHub) { + this._chatSettings = chatSettings.Value; + this._notificationService = notificationService; + this._chatHub = chatHub; + this._userManager = userManager; + this._subscriptionStore = subscriptionStore; + + } + public async Task InitiateSupportRequest(string fromUser, ChatViewModel message) { + if (!string.IsNullOrEmpty(_chatSettings.CurrentChatUser)) { + var user = await _userManager.FindByEmailAsync(_chatSettings.CurrentChatUser); + if (!string.IsNullOrEmpty(user?.Id)) { + message.ToUserId = user.Id; + message.ToUserName = user.FullName; + //send firebase message to notify via web worker + WebPush.PushMessage pushMessage = new WebPush.PushMessage(message.Message) { + Topic = "New support chat message", + Urgency = PushMessageUrgency.Normal + }; + await _subscriptionStore.ForEachSubscriptionAsync(user.Id, (WebPush.PushSubscription subscription) => { + _notificationService.SendNotificationAsync(subscription, pushMessage); + }); + + //send SignalR message to notify in chat.component + await _chatHub.SendUserAsync(user.Email, "SendMessage", new object[] { message }); + return true; + } + } + return false; + } + } +} \ No newline at end of file diff --git a/server/Startup.cs b/server/Startup.cs index c3f2b77..289afc3 100644 --- a/server/Startup.cs +++ b/server/Startup.cs @@ -26,6 +26,7 @@ using Newtonsoft.Json; using Newtonsoft.Json.Converters; using Newtonsoft.Json.Serialization; using PodNoms.Api.Models; +using PodNoms.Api.Models.Settings; using PodNoms.Api.Models.ViewModels; using PodNoms.Api.Persistence; using PodNoms.Api.Providers; @@ -97,9 +98,10 @@ namespace PodNoms.Api { services.AddOptions(); services.Configure(Configuration.GetSection("App")); services.Configure(Configuration.GetSection("Storage")); - services.Configure(Configuration.GetSection("ApplicationsSettings")); + services.Configure(Configuration.GetSection("HelpersSettings")); services.Configure(Configuration.GetSection("EmailSettings")); services.Configure(Configuration.GetSection("FacebookAuthSettings")); + services.Configure(Configuration.GetSection("ChatSettings")); services.Configure(Configuration.GetSection("ImageFileStorageSettings")); services.Configure(Configuration.GetSection("AudioFileStorageSettings")); services.Configure(options => { @@ -188,7 +190,7 @@ namespace PodNoms.Api { .AddJsonOptions(options => { options.SerializerSettings.ContractResolver = new CamelCasePropertyNamesContractResolver(); options.SerializerSettings.ReferenceLoopHandling = ReferenceLoopHandling.Serialize; - }) + }) .AddXmlSerializerFormatters() .AddFluentValidation(fv => fv.RegisterValidatorsFromAssemblyContaining()); @@ -201,10 +203,24 @@ namespace PodNoms.Api { x.ValueLengthLimit = int.MaxValue; x.MultipartBodyLengthLimit = int.MaxValue; // In case of multipart }); - services.AddSignalR(config => { }); + + services.AddSignalR() + .AddJsonProtocol(options => options.PayloadSerializerSettings.ContractResolver = new DefaultContractResolver() { + NamingStrategy = new CamelCaseNamingStrategy() { + ProcessDictionaryKeys = true + } + }); services.AddCors(options => { - options.AddPolicy("AllowAllOrigins", + options.AddPolicy("PodNomsClientPolicy", + builder => builder + .AllowAnyMethod() + .AllowAnyHeader() + .WithOrigins("http://localhost:4200", "https://*.podnoms.com") + .AllowCredentials()); + }); + services.AddCors(options => { + options.AddPolicy("AllowAllPolicy", builder => builder .AllowAnyOrigin() .AllowAnyMethod() @@ -224,6 +240,7 @@ namespace PodNoms.Api { services.AddScoped(); services.AddScoped(); services.AddScoped(); + services.AddScoped(); services.AddScoped(); services.AddScoped(); services.AddScoped(); @@ -271,7 +288,7 @@ namespace PodNoms.Api { }); app.UseAuthentication(); - app.UseCors("AllowAllOrigins"); + app.UseCors("AllowAllPolicy"); app.UseSignalR(routes => { routes.MapHub("/hubs/audioprocessing"); diff --git a/server/Utils/RemoteParsers/YouTubeParser.cs b/server/Utils/RemoteParsers/YouTubeParser.cs index 635f954..0fdfd2c 100644 --- a/server/Utils/RemoteParsers/YouTubeParser.cs +++ b/server/Utils/RemoteParsers/YouTubeParser.cs @@ -6,6 +6,7 @@ using Google.Apis.Services; using Google.Apis.YouTube.v3; using Microsoft.Extensions.Options; using PodNoms.Api.Models; +using PodNoms.Api.Models.Settings; namespace PodNoms.Api.Utils.RemoteParsers { public partial class YouTubeParser { diff --git a/server/appsettings.json b/server/appsettings.json index 5e24936..54dab60 100644 --- a/server/appsettings.json +++ b/server/appsettings.json @@ -23,7 +23,7 @@ "Key": "9f59ab0666214980ef76", "Cluster": "eu" }, - "ApplicationsSettings": { + "HelpersSettings": { "Downloader": "/usr/local/bin/youtube-dl" }, "ImageFileStorageSettings": {