Skip to content

Commit

Permalink
Merge pull request #43 from zembrodt/develop
Browse files Browse the repository at this point in the history
Merge 0.4.4-dev into main
  • Loading branch information
zembrodt authored Jun 6, 2022
2 parents 0d647e1 + 9f490a5 commit 9306bf7
Show file tree
Hide file tree
Showing 11 changed files with 387 additions and 146 deletions.
31 changes: 17 additions & 14 deletions gulpfile.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,8 @@ gulp.task('generate-config', () => {

// Get current environment
let env = 'dev'; // default environment
if ('MD_ENV' in process.env) {
env = process.env.MD_ENV;
if ('SHOWTUNES_ENV' in process.env) {
env = process.env.SHOWTUNES_ENV;
}

let configJson = {};
Expand All @@ -27,23 +27,26 @@ gulp.task('generate-config', () => {
}

// Overwrite config with environment variables
if ('MD_DOMAIN' in process.env) {
configJson.env.domain = process.env.MD_DOMAIN;
if ('SHOWTUNES_DOMAIN' in process.env) {
configJson.env.domain = process.env.SHOWTUNES_DOMAIN;
}
if ('MD_ALBUM_COLOR_URL' in process.env) {
configJson.env.albumColorUrl = process.env.MD_ALBUM_COLOR_URL;
if ('SHOWTUNES_SPOTIFY_API_URL' in process.env) {
configJson.env.spotifyApiUrl = process.env.SHOWTUNES_SPOTIFY_API_URL;
}
if ('MD_CLIENT_ID' in process.env) {
configJson.auth.clientId = process.env.MD_CLIENT_ID;
if ('SHOWTUNES_ALBUM_COLOR_URL' in process.env) {
configJson.env.albumColorUrl = process.env.SHOWTUNES_ALBUM_COLOR_URL;
}
if ('MD_CLIENT_SECRET' in process.env) {
configJson.auth.clientSecret = process.env.MD_CLIENT_SECRET;
if ('SHOWTUNES_CLIENT_ID' in process.env) {
configJson.auth.clientId = process.env.SHOWTUNES_CLIENT_ID;
}
if ('MD_TOKEN_URL' in process.env) {
configJson.auth.tokenUrl = process.env.MD_TOKEN_URL;
if ('SHOWTUNES_CLIENT_SECRET' in process.env) {
configJson.auth.clientSecret = process.env.SHOWTUNES_CLIENT_SECRET;
}
if ('MD_DIRECT_REQ' in process.env) {
configJson.auth.isDirectSpotifyRequest = process.env.MD_DIRECT_REQ === 'true';
if ('SHOWTUNES_TOKEN_URL' in process.env) {
configJson.auth.tokenUrl = process.env.SHOWTUNES_TOKEN_URL;
}
if ('SHOWTUNES_DIRECT_REQ' in process.env) {
configJson.auth.isDirectSpotifyRequest = process.env.SHOWTUNES_DIRECT_REQ === 'true';
}
console.log('In gulp :: After OS Env: ' + JSON.stringify(configJson));

Expand Down
4 changes: 2 additions & 2 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "showtunes",
"version": "0.4.3",
"version": "0.4.4",
"scripts": {
"ng": "ng",
"start": "ng serve",
Expand Down
8 changes: 7 additions & 1 deletion src/app/app.module.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { HttpClientModule } from '@angular/common/http';
import { HTTP_INTERCEPTORS, HttpClientModule } from '@angular/common/http';
import { APP_INITIALIZER, NgModule } from '@angular/core';
import { FlexLayoutModule } from '@angular/flex-layout';
import { BrowserModule } from '@angular/platform-browser';
Expand Down Expand Up @@ -32,6 +32,7 @@ import { SettingsState } from './core/settings/settings.state';
import { MaterialModule } from './modules/material.module';
import { InactivityService } from './services/inactivity/inactivity.service';
import { PlaybackService } from './services/playback/playback.service';
import { SpotifyInterceptor } from './services/spotify/spotify.interceptor';
import { SpotifyService } from './services/spotify/spotify.service';
import { StorageService } from './services/storage/storage.service';

Expand Down Expand Up @@ -85,6 +86,11 @@ export function initializeApp(appConfig: AppConfig): () => Promise<void> {
InactivityService,
StorageService,
SpotifyService,
{
provide: HTTP_INTERCEPTORS,
useClass: SpotifyInterceptor,
multi: true
},
PlaybackService,
],
bootstrap: [ AppComponent ]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,7 @@ describe('AlbumDisplayComponent', () => {
AppConfig.settings = {
env: {
albumColorUrl: 'test-album-color-url',
spotifyApiUrl: null,
name: null,
domain: null
},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,7 @@ describe('SettingsMenuComponent', () => {

AppConfig.settings = {
env: {
spotifyApiUrl: null,
albumColorUrl: null,
name: null,
domain: null
Expand Down
1 change: 1 addition & 0 deletions src/app/models/app-config.model.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ export interface IAppConfig {
env: {
name: string;
domain: string;
spotifyApiUrl: string;
albumColorUrl: string;
};
auth: {
Expand Down
143 changes: 143 additions & 0 deletions src/app/services/spotify/spotify.interceptor.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,143 @@
import { HTTP_INTERCEPTORS, HttpClient } from '@angular/common/http';
import { HttpClientTestingModule, HttpTestingController } from '@angular/common/http/testing';
import { TestBed } from '@angular/core/testing';
import { expect } from '@angular/flex-layout/_private-utils/testing';
import { MockProvider } from 'ng-mocks';
import { AppConfig } from '../../app.config';
import { SpotifyInterceptor } from './spotify.interceptor';
import { SpotifyAPIResponse, SpotifyService } from './spotify.service';


describe('SpotifyInterceptor', () => {
let spotify: SpotifyService;
let httpMock: HttpTestingController;
let http: HttpClient;

beforeEach(() => {
AppConfig.settings = {
env: {
name: 'test-name',
domain: 'test-domain',
spotifyApiUrl: 'spotify-url',
albumColorUrl: 'album-url'
},
auth: {
clientId: 'test-client-id',
clientSecret: 'test-client-secret',
tokenUrl: 'token-url',
isDirectSpotifyRequest: false
},
logging: null
};
SpotifyService.initialize();

TestBed.configureTestingModule({
imports: [
HttpClientTestingModule
],
providers: [
{
provide: HTTP_INTERCEPTORS,
useClass: SpotifyInterceptor,
multi: true
},
MockProvider(SpotifyService),
]
});
spotify = TestBed.inject(SpotifyService);
httpMock = TestBed.inject(HttpTestingController);
http = TestBed.inject(HttpClient);
});

it('should catch HTTP response error and retry request on reauthentication', () => {
spotify.checkErrorResponse = jasmine.createSpy().and.returnValue(SpotifyAPIResponse.ReAuthenticated);
http.get('/test').subscribe(
(data) => expect(data).toBeTruthy(),
(err) => {
console.log(err);
fail('Should not have thrown error');
});

let request = httpMock.expectOne('/test');
request.error(new ProgressEvent('401 Invalid token'), {
status: 401,
statusText: 'Invalid token'
});
request = httpMock.expectOne('/test');
request.flush({
status: 200,
statusText: 'Ok'
});
httpMock.verify();
});

it('should catch HTTP response error and fail when cannot reauthenticate', () => {
spotify.checkErrorResponse = jasmine.createSpy().and.returnValue(SpotifyAPIResponse.Error);
http.get('/test').subscribe(
(data) => {
console.log(data);
fail('Should not of had a successful request');
},
(err) => expect(err).toBeTruthy());

const request = httpMock.expectOne('/test');
request.error(new ProgressEvent('429 Exceeded rate limit'), {
status: 429,
statusText: 'Exceeded rate limit'
});
httpMock.verify();
});

it('should add the Authorization header when making a request for the Spotify API URL', () => {
spotify.getAuthorizationHeader = jasmine.createSpy().and.returnValue('test-token');
http.get('spotify-url').subscribe(
(data) => expect(data).toBeTruthy(),
(err) => {
console.log(err);
fail('Should not have thrown error');
});

const request = httpMock.expectOne('spotify-url');
request.flush({
status: 200,
statusText: 'Ok'
});
httpMock.verify();

expect(request.request.headers.get('Authorization')).toEqual('test-token');
});

it('should throw an error when making a request to the Spotify API URL but no authToken', () => {
spotify.getAuthorizationHeader = jasmine.createSpy().and.returnValue(null);
http.get('spotify-url').subscribe(
(data) => {
console.log(data);
fail('Should not have returned successfully');
},
(err) => {
expect(err).toBeTruthy();
});

httpMock.expectNone('spotify-url');
httpMock.verify();
});

it('should not add the Authorization header when request is not to the Spotify API URL', () => {
spotify.getAuthorizationHeader = jasmine.createSpy().and.returnValue('test-token');
http.get('album-url').subscribe(
(data) => expect(data).toBeTruthy(),
(err) => {
console.log(err);
fail('Should not have thrown error');
});

const request = httpMock.expectOne('album-url');
request.flush({
status: 200,
statusText: 'Ok'
});
httpMock.verify();

expect(request.request.headers.get('Authorization')).toBeFalsy();
});
});
35 changes: 35 additions & 0 deletions src/app/services/spotify/spotify.interceptor.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
import { HttpErrorResponse, HttpEvent, HttpHandler, HttpInterceptor, HttpRequest } from '@angular/common/http';
import { Injectable } from '@angular/core';
import { Observable, throwError } from 'rxjs';
import { catchError } from 'rxjs/operators';
import { SpotifyAPIResponse, SpotifyService } from './spotify.service';

@Injectable()
export class SpotifyInterceptor implements HttpInterceptor {
constructor(private spotify: SpotifyService) {}

intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
let authReq = req;
if (req.url.startsWith(SpotifyService.spotifyApiUrl)) {
const authHeader = this.spotify.getAuthorizationHeader();
if (!authHeader) {
return throwError('No auth token present');
}
authReq = req.clone({
headers: req.headers.set('Authorization', authHeader)
});
}

return next.handle(authReq).pipe(
catchError(err => {
if (err instanceof HttpErrorResponse) {
const apiResponse = this.spotify.checkErrorResponse(err);
if (apiResponse === SpotifyAPIResponse.ReAuthenticated) {
return next.handle(authReq);
}
}
return throwError(err);
})
);
}
}
Loading

0 comments on commit 9306bf7

Please sign in to comment.