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 type EndpointHandler = (req: any, res: any) => Promise<void>; |
||||||
|
|
||||||
export interface EndpointError { |
export interface EndpointError { |
||||||
internalMessage:String; |
internalMessage: String; |
||||||
httpStatus:Number; |
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