parent
e159cfec37
commit
63ac5b5d84
16 changed files with 510 additions and 98 deletions
@ -0,0 +1,35 @@ |
||||
const models = require('../models'); |
||||
import * as api from '../../client/src/api'; |
||||
import { EndpointError, EndpointHandler, catchUnhandledErrors } from './types'; |
||||
|
||||
export const ArtistDetailsEndpointHandler: EndpointHandler = async (req: any, res: any) => { |
||||
if (!api.checkArtistDetailsRequest(req)) { |
||||
const e: EndpointError = { |
||||
internalMessage: 'Invalid ArtistDetails request: ' + JSON.stringify(req.body), |
||||
httpStatus: 400 |
||||
}; |
||||
throw e; |
||||
} |
||||
const reqObject: api.ArtistDetailsRequest = req.body; |
||||
|
||||
await models.Artist.findAll({ |
||||
where: { |
||||
id: reqObject.id |
||||
} |
||||
}) |
||||
.then((artists: any[]) => { |
||||
if (artists.length != 1) { |
||||
const e: EndpointError = { |
||||
internalMessage: 'There is no artist with id ' + reqObject.id + '.', |
||||
httpStatus: 400 |
||||
}; |
||||
throw e; |
||||
} |
||||
let artist = artists[0]; |
||||
const response: api.ArtistDetailsResponse = { |
||||
name: artist.name |
||||
}; |
||||
res.send(response); |
||||
}) |
||||
.catch(catchUnhandledErrors); |
||||
} |
@ -1,23 +0,0 @@ |
||||
const models = require('../models'); |
||||
import * as api from '../../client/src/api'; |
||||
import { EndpointError, EndpointHandler } from './types'; |
||||
|
||||
export const ListArtistsEndpointHandler:EndpointHandler = async (req: any, res: any) => { |
||||
if (!api.checkListArtistsRequest(req)) { |
||||
const e:EndpointError = { |
||||
internalMessage: 'Invalid ListArtists request: ' + JSON.stringify(req.body), |
||||
httpStatus: 400 |
||||
}; |
||||
throw e; |
||||
} |
||||
await models.Artist.findAll() |
||||
.then((artists: any[]) => { |
||||
const response: api.ListArtistsResponse = artists.map((artist: any) => { |
||||
return { |
||||
name: artist.name, |
||||
id: artist.id, |
||||
}; |
||||
}); |
||||
res.send(response); |
||||
}); |
||||
} |
@ -1,38 +0,0 @@ |
||||
const models = require('../models'); |
||||
import * as api from '../../client/src/api'; |
||||
import { EndpointError, EndpointHandler } from './types'; |
||||
|
||||
export const ListSongsEndpointHandler:EndpointHandler = async (req: any, res: any) => { |
||||
if (!api.checkListSongsRequest(req)) { |
||||
const e:EndpointError = { |
||||
internalMessage: 'Invalid ListSongs request: ' + JSON.stringify(req.body), |
||||
httpStatus: 400 |
||||
}; |
||||
throw e; |
||||
} |
||||
await models.Song.findAll({ |
||||
include: [models.Artist, models.Album] |
||||
}) |
||||
.then((songs: any[]) => { |
||||
console.log(songs); |
||||
const response: api.ListSongsResponse = songs.map((song: any) => { |
||||
return { |
||||
title: song.title, |
||||
id: song.id, |
||||
artists: song.Artists.map((artist: any) => { |
||||
return { |
||||
name: artist.name, |
||||
id: artist.id, |
||||
}; |
||||
}), |
||||
albums: song.Albums.map((album: any) => { |
||||
return { |
||||
name: album.name, |
||||
id: album.id, |
||||
}; |
||||
}), |
||||
}; |
||||
}); |
||||
res.send(response); |
||||
}); |
||||
} |
@ -0,0 +1,34 @@ |
||||
const models = require('../models'); |
||||
import * as api from '../../client/src/api'; |
||||
import { EndpointError, EndpointHandler, catchUnhandledErrors } from './types'; |
||||
|
||||
export const ModifyArtistEndpointHandler: EndpointHandler = async (req: any, res: any) => { |
||||
if (!api.checkModifyArtistRequest(req)) { |
||||
const e: EndpointError = { |
||||
internalMessage: 'Invalid ModifyArtist request: ' + JSON.stringify(req.body), |
||||
httpStatus: 400 |
||||
}; |
||||
throw e; |
||||
} |
||||
const reqObject: api.ModifyArtistRequest = req.body; |
||||
|
||||
await models.Artist.findAll({ |
||||
where: { id: reqObject.id } |
||||
}) |
||||
.then(async (artists: any[]) => { |
||||
if (artists.length != 1) { |
||||
const e: EndpointError = { |
||||
internalMessage: 'There is no artist with id ' + reqObject.id + '.', |
||||
httpStatus: 400 |
||||
}; |
||||
throw e; |
||||
} |
||||
let artist = artists[0]; |
||||
artist.name = reqObject.name; |
||||
await artist.save(); |
||||
}) |
||||
.then(() => { |
||||
res.status(200); |
||||
}) |
||||
.catch(catchUnhandledErrors); |
||||
} |
@ -0,0 +1,86 @@ |
||||
const models = require('../models'); |
||||
import * as api from '../../client/src/api'; |
||||
import { EndpointError, EndpointHandler, catchUnhandledErrors } from './types'; |
||||
|
||||
export const ModifySongEndpointHandler: EndpointHandler = async (req: any, res: any) => { |
||||
if (!api.checkModifySongRequest(req)) { |
||||
const e: EndpointError = { |
||||
internalMessage: 'Invalid ModifySong request: ' + JSON.stringify(req.body), |
||||
httpStatus: 400 |
||||
}; |
||||
throw e; |
||||
} |
||||
const reqObject: api.ModifySongRequest = req.body; |
||||
|
||||
// Start retrieving the artist instances to link the song to.
|
||||
var artistInstancePromises: Promise<any>[] = []; |
||||
reqObject.artistIds?.forEach((artistId: Number) => { |
||||
artistInstancePromises.push( |
||||
models.Artist.findAll({ |
||||
where: { id: artistId } |
||||
}) |
||||
.then((artist: any[]) => { |
||||
if (artist.length != 1) { |
||||
const e: EndpointError = { |
||||
internalMessage: 'There is no artist with id ' + artistId + '.', |
||||
httpStatus: 400 |
||||
}; |
||||
throw e; |
||||
} |
||||
return artist[0]; |
||||
}) |
||||
); |
||||
}); |
||||
var artistInstancesPromise = Promise.all(artistInstancePromises); |
||||
|
||||
// Start retrieving the album instances to link the song to.
|
||||
var albumInstancePromises: Promise<any>[] = []; |
||||
reqObject.albumIds?.forEach((albumId: Number) => { |
||||
albumInstancePromises.push( |
||||
models.Album.findAll({ |
||||
where: { id: albumId } |
||||
}) |
||||
.then((album: any[]) => { |
||||
if (album.length != 1) { |
||||
const e: EndpointError = { |
||||
internalMessage: 'There is no album with id ' + albumId + '.', |
||||
httpStatus: 400 |
||||
}; |
||||
throw e; |
||||
} |
||||
return album[0]; |
||||
}) |
||||
); |
||||
}); |
||||
var albumInstancesPromise = Promise.all(albumInstancePromises); |
||||
|
||||
// Start retrieving the song to modify.
|
||||
var songInstancePromise: Promise<any> = |
||||
models.Song.findAll({ |
||||
where: { id: reqObject.id } |
||||
}) |
||||
.then((song: any[]) => { |
||||
if (song.length != 1) { |
||||
const e: EndpointError = { |
||||
internalMessage: 'There is no song with id ' + reqObject.id + '.', |
||||
httpStatus: 400 |
||||
}; |
||||
throw e; |
||||
} |
||||
return song[0]; |
||||
}); |
||||
|
||||
// Upon finish retrieving artists and albums, create the song and associate it.
|
||||
await Promise.all([artistInstancesPromise, albumInstancesPromise, songInstancePromise]) |
||||
.then(async (values: any) => { |
||||
var [artists, albums, song] = values; |
||||
song.setArtists(artists); |
||||
song.setAlbums(albums); |
||||
song.setTitle(reqObject.title); |
||||
await song.save(); |
||||
}) |
||||
.then(() => { |
||||
res.status(200).send({}); |
||||
}) |
||||
.catch(catchUnhandledErrors); |
||||
} |
@ -0,0 +1,23 @@ |
||||
const models = require('../models'); |
||||
import * as api from '../../client/src/api'; |
||||
import { EndpointError, EndpointHandler, catchUnhandledErrors } from './types'; |
||||
|
||||
export const QueryArtistsEndpointHandler: EndpointHandler = async (req: any, res: any) => { |
||||
if (!api.checkQueryArtistsRequest(req)) { |
||||
const e: EndpointError = { |
||||
internalMessage: 'Invalid QueryArtists request: ' + JSON.stringify(req.body), |
||||
httpStatus: 400 |
||||
}; |
||||
throw e; |
||||
} |
||||
await models.Artist.findAll() |
||||
.then((artists: any[]) => { |
||||
const response: api.QueryArtistsResponse = { |
||||
ids: artists.map((artist: any) => { |
||||
return artist.id |
||||
}) |
||||
} |
||||
res.send(response); |
||||
}) |
||||
.catch(catchUnhandledErrors); |
||||
} |
@ -0,0 +1,23 @@ |
||||
const models = require('../models'); |
||||
import * as api from '../../client/src/api'; |
||||
import { EndpointError, EndpointHandler, catchUnhandledErrors } from './types'; |
||||
|
||||
export const QuerySongsEndpointHandler: EndpointHandler = async (req: any, res: any) => { |
||||
if (!api.checkQuerySongsRequest(req)) { |
||||
const e: EndpointError = { |
||||
internalMessage: 'Invalid QuerySongs request: ' + JSON.stringify(req.body), |
||||
httpStatus: 400 |
||||
}; |
||||
throw e; |
||||
} |
||||
await models.Song.findAll() |
||||
.then((songs: any[]) => { |
||||
const response: api.QuerySongsResponse = { |
||||
ids: songs.map((song: any) => { |
||||
return song.id; |
||||
}) |
||||
}; |
||||
res.send(response); |
||||
}) |
||||
.catch(catchUnhandledErrors); |
||||
} |
@ -0,0 +1,38 @@ |
||||
const models = require('../models'); |
||||
import * as api from '../../client/src/api'; |
||||
import { EndpointError, EndpointHandler, catchUnhandledErrors } from './types'; |
||||
|
||||
export const SongDetailsEndpointHandler: EndpointHandler = async (req: any, res: any) => { |
||||
if (!api.checkSongDetailsRequest(req)) { |
||||
const e: EndpointError = { |
||||
internalMessage: 'Invalid SongDetails request: ' + JSON.stringify(req.body), |
||||
httpStatus: 400 |
||||
}; |
||||
throw e; |
||||
} |
||||
const reqObject: api.SongDetailsRequest = req.body; |
||||
|
||||
await models.Song.findAll({ |
||||
include: [models.Artist, models.Album], |
||||
where: { |
||||
id: reqObject.id |
||||
} |
||||
}) |
||||
.then((songs: any[]) => { |
||||
if (songs.length != 1) { |
||||
const e: EndpointError = { |
||||
internalMessage: 'There is no song with id ' + reqObject.id + '.', |
||||
httpStatus: 400 |
||||
}; |
||||
throw e; |
||||
} |
||||
let song = songs[0]; |
||||
const response: api.SongDetailsResponse = { |
||||
title: song.title, |
||||
artistIds: song.ArtistIds, |
||||
albumIds: song.AlbumIds |
||||
} |
||||
res.send(response); |
||||
}) |
||||
.catch(catchUnhandledErrors); |
||||
} |
@ -1,6 +1,25 @@ |
||||
export type EndpointHandler = (req: any, res: any) => Promise<void>; |
||||
|
||||
export interface EndpointError { |
||||
internalMessage:String; |
||||
httpStatus:Number; |
||||
internalMessage: String; |
||||
httpStatus: Number; |
||||
} |
||||
|
||||
export function isEndpointError(obj: any): obj is EndpointError { |
||||
return obj.internalMessage !== undefined && |
||||
obj.httpStatus !== undefined; |
||||
} |
||||
|
||||
export const catchUnhandledErrors = (_e: any) => { |
||||
if (isEndpointError(_e)) { |
||||
// Rethrow
|
||||
throw _e; |
||||
} |
||||
|
||||
// This is an unhandled error, make an internal server error out of it.
|
||||
const e: EndpointError = { |
||||
internalMessage: _e, |
||||
httpStatus: 500 |
||||
} |
||||
throw e; |
||||
} |
@ -0,0 +1,51 @@ |
||||
const chai = require('chai'); |
||||
const chaiHttp = require('chai-http'); |
||||
const express = require('express'); |
||||
const models = require('../../../models'); |
||||
import { SetupApp } from '../../../app'; |
||||
import { expect } from 'chai'; |
||||
|
||||
async function init() { |
||||
chai.use(chaiHttp); |
||||
const app = express(); |
||||
SetupApp(app); |
||||
await models.sequelize.sync({ force: true }); |
||||
return app; |
||||
} |
||||
|
||||
describe('POST /artist/create with no name', () => { |
||||
it('should fail', done => { |
||||
init().then((app) => { |
||||
chai |
||||
.request(app) |
||||
.post('/artist/create') |
||||
.send({}) |
||||
.end((err, res) => { |
||||
expect(err).to.be.null; |
||||
expect(res).to.have.status(400); |
||||
done(); |
||||
}); |
||||
}); |
||||
}); |
||||
}); |
||||
|
||||
describe('POST /artist/create with a correct request', () => { |
||||
it('should succeed', done => { |
||||
init().then((app) => { |
||||
chai |
||||
.request(app) |
||||
.post('/artist/create') |
||||
.send({ |
||||
name: "MyArtist" |
||||
}) |
||||
.end((err, res) => { |
||||
expect(err).to.be.null; |
||||
expect(res).to.have.status(200); |
||||
expect(res.body).to.deep.equal({ |
||||
id: 1 |
||||
}); |
||||
done(); |
||||
}); |
||||
}); |
||||
}); |
||||
}); |
@ -0,0 +1,71 @@ |
||||
const chai = require('chai'); |
||||
const chaiHttp = require('chai-http'); |
||||
const express = require('express'); |
||||
const models = require('../../../models'); |
||||
import { SetupApp } from '../../../app'; |
||||
import { expect } from 'chai'; |
||||
|
||||
async function init() { |
||||
chai.use(chaiHttp); |
||||
const app = express(); |
||||
SetupApp(app); |
||||
await models.sequelize.sync({ force: true }); |
||||
return app; |
||||
} |
||||
|
||||
describe('POST /artist/modify on nonexistent artist', () => { |
||||
it('should fail', done => { |
||||
init().then((app) => { |
||||
chai |
||||
.request(app) |
||||
.post('/artist/modify') |
||||
.send({ |
||||
id: 1, |
||||
name: "NewArtistName" |
||||
}) |
||||
.then((res) => { |
||||
expect(res).to.have.status(400); |
||||
}) |
||||
.then(done) |
||||
}); |
||||
}); |
||||
}); |
||||
|
||||
describe('POST /artist/modify with an existing artist', () => { |
||||
it('should succeed', done => { |
||||
init().then((app) => { |
||||
async function createArtist() { |
||||
await chai.request(app) |
||||
.post('/artist/create') |
||||
.send({ |
||||
name: "MyArtist" |
||||
}) |
||||
.then((res) => { |
||||
expect(res).to.have.status(200); |
||||
expect(res.body).to.deep.equal({ |
||||
id: 1 |
||||
}); |
||||
}); |
||||
} |
||||
|
||||
async function modifyArtist() { |
||||
chai.request(app) |
||||
.post('/artist/modify') |
||||
.send({ |
||||
name: "MyNewArtist", |
||||
id: 1 |
||||
}) |
||||
.then((res) => { |
||||
expect(res).to.have.status(200); |
||||
}); |
||||
} |
||||
|
||||
// TODO: Check artist
|
||||
|
||||
init() |
||||
.then(createArtist) |
||||
.then(modifyArtist) |
||||
.then(done); |
||||
}); |
||||
}); |
||||
}); |
Loading…
Reference in new issue