added controllers and services

parent 9c5d2760
This diff is collapsed.
...@@ -12,15 +12,18 @@ ...@@ -12,15 +12,18 @@
"dependencies": { "dependencies": {
"@types/node": "^18.15.3", "@types/node": "^18.15.3",
"body-parser": "^1.20.2", "body-parser": "^1.20.2",
"class-validator": "^0.14.0",
"cors": "^2.8.5", "cors": "^2.8.5",
"dotenv": "^16.0.3", "dotenv": "^16.0.3",
"express": "^4.18.2", "express": "^4.18.2",
"express-validator": "^6.15.0",
"http-status-codes": "^2.2.0",
"joi": "^17.9.1",
"mongoose": "^7.0.1", "mongoose": "^7.0.1",
"multer": "^1.4.5-lts.1", "multer": "^1.4.5-lts.1",
"ts-node-dev": "^2.0.0" "ts-node-dev": "^2.0.0"
}, },
"devDependencies": { "devDependencies": {
"@types/body-parser": "^1.19.2",
"@types/cors": "^2.8.13", "@types/cors": "^2.8.13",
"@types/express": "^4.17.17", "@types/express": "^4.17.17",
"@types/mongoose": "^5.11.97", "@types/mongoose": "^5.11.97",
......
import express from 'express';
import {ArtistService} from '../services/artist';
import {unlink} from 'fs';
export const ArtistController = {
createArtist: async (req: express.Request, res: express.Response) => {
try {
const {name, info} = req.body;
await ArtistService.generate({
name,
info,
photo: req.file?.filename || '',
})
.then((result) => {
return res.send(result);
})
.catch((err) => {
unlink(`uploads/${req.file?.filename}`, (err) => {
if (err) throw err;
});
return res.send({error: err.message});
});
} catch (err: unknown) {
res.json({err});
}
},
getArtists: async (req: express.Request, res: express.Response) => {
try {
ArtistService.get()
.then((result) => {
res.send(result);
})
.catch((err) => {
res.json({err});
});
} catch (err: unknown) {
res.json({err});
}
},
};
import express, {Express, json} from 'express'; import express, {Express, json, urlencoded} from 'express';
import 'dotenv/config'; import 'dotenv/config';
import {artistRouter} from './routes/artist';
import cors from 'cors'; import cors from 'cors';
import {albumRouter} from './routes/albums'; import {mongoose} from './repository/mongoose';
import {connect} from 'mongoose'; import {ArtistRouter} from './routes/artist';
import {trackRouter} from './routes/track';
mongoose.run();
const app: Express = express(); const app: Express = express();
app.use(json()); app.use(json());
app.use(cors()); app.use(cors());
app.use(urlencoded({extended: true}));
app.use('/artists', artistRouter); app.use(express.static('images'));
app.use('/albums', albumRouter); app.use('/artists', ArtistRouter);
app.use('/tracks', trackRouter);
const run = async () => {
await connect(`${process.env.MONGO_URL}/musicApp`);
};
run().catch((err) => console.log(err));
app.listen(process.env.PORT, () => { app.listen(process.env.PORT, () => {
console.log('Server started on port ' + process.env.PORT); console.log(`App started on port ${process.env.PORT}`);
}); });
export default interface IArtist {
name: string;
photo: string;
info: string;
}
import {model, Schema} from 'mongoose';
import IArtist from '../interfaces/IArtist';
const ArtistSchema = new Schema<IArtist>(
{
name: {
type: String,
required: [true, 'Name is required'],
trim: true,
},
photo: {
type: String,
required: [true, 'Photo is required'],
},
info: {
type: String,
required: [true, 'Info is required'],
trim: true,
},
},
{versionKey: false}
);
const ArtistModel = model<IArtist>('artist', ArtistSchema);
export default ArtistModel;
import {connect, connection} from 'mongoose';
export const mongoose = {
run: async () => {
try {
return await connect(`${process.env.MONGO_URL}/MyPlayer`);
} catch (error) {
console.log(error);
}
},
stop: async () => {
try {
return await connection.destroy();
} catch (error) {
console.log(error);
}
},
};
import express, {Request, Response} from 'express';
import {model, Schema, HydratedDocument, Types} from 'mongoose';
import multer from 'multer';
import fs from 'fs';
import path from 'path';
import {IArtist} from './artist';
const upload = multer({dest: 'uploads/albums'});
const router = express.Router();
export interface IAlbum {
name: string;
albumImage: File;
year: number;
artist: Types.ObjectId;
}
const Album = model<IAlbum>(
'Album',
new Schema({
artist: {
type: Schema.Types.ObjectId,
ref: 'Artist',
},
name: String,
year: Number,
albumImage: {
data: Buffer,
contentType: String,
},
})
);
router.get('/', async (req: Request, res: Response) => {
if (!req.query.artist) {
try {
const albums = await Album.find().populate<{artist: IArtist}>('artist');
res.send(albums);
return;
} catch (err: unknown) {
res.send('Could not get albums');
}
}
try {
const artistsAlbums = await Album.find({artist: req.query.artist});
res.send(artistsAlbums);
} catch (err: unknown) {
res.send(`Could not find albums of ${req.query.artist} `);
}
});
router.get('/:id', async (req: Request, res: Response) => {
try {
const album = await Album.findById(req.params.id).populate<{
artist: IArtist;
}>('artist');
if (album === null) {
res.send('Nothing such album found');
}
res.send(album);
} catch (err: unknown) {
res.send('No such artist exists');
}
});
router.post(
'/',
upload.single('albumImage'),
async (req: Request, res: Response) => {
if (!req.body.name || !req.file || !req.body.year || !req.body.artist) {
res.send('Name, year, artist or albumimage is required');
return;
}
try {
const album: HydratedDocument<IAlbum> = new Album({
name: req.body.name,
albumImage: {
data: fs.readFileSync(
path.join('uploads/albums/' + req.file?.filename)
),
contentType: 'image',
},
year: req.body.year,
artist: req.body.artist,
});
await album.save();
res.send('Sucessfully saved');
} catch (err: unknown) {
res.send('Could not post album');
}
}
);
export {router as albumRouter};
import express, {Request, Response} from 'express'; import expres, {Router} from 'express';
import {model, Schema, HydratedDocument} from 'mongoose';
import multer from 'multer'; import multer from 'multer';
import fs from 'fs'; import {ArtistController} from '../controllers/artist';
import path from 'path';
const upload = multer({dest: 'uploads/artists'}); const upload = multer({dest: 'uploads'});
const router = express.Router(); const router: Router = expres.Router();
export interface IArtist { router.get('/', ArtistController.getArtists);
name: string; router.post('/', upload.single('photo'), ArtistController.createArtist);
image: File;
description: string;
}
const artistSchema = new Schema<IArtist>({ export {router as ArtistRouter};
name: {
type: String,
required: true,
},
image: {
data: Buffer,
contentType: String,
},
description: {
type: String,
required: true,
},
});
const Artist = model<IArtist>('Artist', artistSchema);
router.get('/', async (req: Request, res: Response) => {
try {
const artists = await Artist.find();
res.send(artists);
} catch (err: unknown) {
res.send('could not get artists');
}
});
router.post(
'/',
upload.single('image'),
async (req: Request, res: Response) => {
if (!req.body.name || !req.body.description || !req.file) {
res.send('Name, description or image cannot be emtpty');
return;
}
try {
const artist: HydratedDocument<IArtist> = new Artist({
name: req.body.name,
description: req.body.description,
image: {
data: fs.readFileSync(
path.join('uploads/artists/' + req.file?.filename)
),
contentType: 'image',
},
});
await artist.save();
res.send('Sucessfully saved');
} catch (err: unknown) {
res.send('Could not post');
}
}
);
export {router as artistRouter};
import express, {Request, Response} from 'express';
import {model, Schema, HydratedDocument, Types} from 'mongoose';
import {IAlbum} from './albums';
const router = express.Router();
interface ITrack {
name: string;
album: Types.ObjectId;
duration: string;
}
const Track = model<ITrack>(
'Track',
new Schema({
name: String,
duration: String,
album: {
type: Schema.Types.ObjectId,
ref: 'Album',
},
})
);
router.get('/', async (req: Request, res: Response) => {
if (!req.query.album) {
try {
const tracks = await Track.find().populate<{album: IAlbum}>('album');
res.send(tracks);
return;
} catch (err: unknown) {
res.send('Could not get tracks');
}
}
try {
const albumTracks = await Track.find({album: req.query.album});
res.send(albumTracks);
} catch (err: unknown) {
res.send(`Could not find album tracks of ${req.query.album} `);
}
});
router.post('/', async (req: Request, res: Response) => {
if (!req.body.name || !req.body.album || !req.body.duration) {
res.send('Name, album or duration cannot be emtpty');
return;
}
try {
const track: HydratedDocument<ITrack> = new Track({
name: req.body.name,
album: req.body.album,
duration: req.body.duration,
});
await track.save();
res.send(`Saved track: ${track}`);
} catch (err: unknown) {
res.send('Could not create track');
}
});
export {router as trackRouter};
import IArtist from '../interfaces/IArtist';
import ArtistModel from '../models/artist';
export const ArtistService = {
generate: async ({name, info, photo}: IArtist) => {
return await new ArtistModel({
name,
info,
photo,
}).save();
},
get: async () => {
return await ArtistModel.find();
},
};
...@@ -11,7 +11,7 @@ ...@@ -11,7 +11,7 @@
// "disableReferencedProjectLoad": true, /* Reduce the number of projects loaded automatically by TypeScript. */ // "disableReferencedProjectLoad": true, /* Reduce the number of projects loaded automatically by TypeScript. */
/* Language and Environment */ /* Language and Environment */
"target": "ES2022", /* Set the JavaScript language version for emitted JavaScript and include compatible library declarations. */ "target": "ES2022" /* Set the JavaScript language version for emitted JavaScript and include compatible library declarations. */,
// "lib": [], /* Specify a set of bundled library declaration files that describe the target runtime environment. */ // "lib": [], /* Specify a set of bundled library declaration files that describe the target runtime environment. */
// "jsx": "preserve", /* Specify what JSX code is generated. */ // "jsx": "preserve", /* Specify what JSX code is generated. */
// "experimentalDecorators": true, /* Enable experimental support for TC39 stage 2 draft decorators. */ // "experimentalDecorators": true, /* Enable experimental support for TC39 stage 2 draft decorators. */
...@@ -25,9 +25,9 @@ ...@@ -25,9 +25,9 @@
// "moduleDetection": "auto", /* Control what method is used to detect module-format JS files. */ // "moduleDetection": "auto", /* Control what method is used to detect module-format JS files. */
/* Modules */ /* Modules */
"module": "NodeNext", /* Specify what module code is generated. */ "module": "NodeNext" /* Specify what module code is generated. */,
// "rootDir": "./", /* Specify the root folder within your source files. */ // "rootDir": "./", /* Specify the root folder within your source files. */
"moduleResolution": "nodenext", /* Specify how TypeScript looks up a file from a given module specifier. */ "moduleResolution": "nodenext" /* Specify how TypeScript looks up a file from a given module specifier. */,
// "baseUrl": "./", /* Specify the base directory to resolve non-relative module names. */ // "baseUrl": "./", /* Specify the base directory to resolve non-relative module names. */
// "paths": {}, /* Specify a set of entries that re-map imports to additional lookup locations. */ // "paths": {}, /* Specify a set of entries that re-map imports to additional lookup locations. */
// "rootDirs": [], /* Allow multiple folders to be treated as one when resolving modules. */ // "rootDirs": [], /* Allow multiple folders to be treated as one when resolving modules. */
...@@ -49,7 +49,7 @@ ...@@ -49,7 +49,7 @@
// "emitDeclarationOnly": true, /* Only output d.ts files and not JavaScript files. */ // "emitDeclarationOnly": true, /* Only output d.ts files and not JavaScript files. */
// "sourceMap": true, /* Create source map files for emitted JavaScript files. */ // "sourceMap": true, /* Create source map files for emitted JavaScript files. */
// "outFile": "./", /* Specify a file that bundles all outputs into one JavaScript file. If 'declaration' is true, also designates a file that bundles all .d.ts output. */ // "outFile": "./", /* Specify a file that bundles all outputs into one JavaScript file. If 'declaration' is true, also designates a file that bundles all .d.ts output. */
"outDir": "dist", /* Specify an output folder for all emitted files. */ "outDir": "dist" /* Specify an output folder for all emitted files. */,
// "removeComments": true, /* Disable emitting comments. */ // "removeComments": true, /* Disable emitting comments. */
// "noEmit": true, /* Disable emitting files from a compilation. */ // "noEmit": true, /* Disable emitting files from a compilation. */
// "importHelpers": true, /* Allow importing helper functions from tslib once per project, instead of including them per-file. */ // "importHelpers": true, /* Allow importing helper functions from tslib once per project, instead of including them per-file. */
...@@ -71,13 +71,13 @@ ...@@ -71,13 +71,13 @@
/* Interop Constraints */ /* Interop Constraints */
// "isolatedModules": true, /* Ensure that each file can be safely transpiled without relying on other imports. */ // "isolatedModules": true, /* Ensure that each file can be safely transpiled without relying on other imports. */
// "allowSyntheticDefaultImports": true, /* Allow 'import x from y' when a module doesn't have a default export. */ // "allowSyntheticDefaultImports": true, /* Allow 'import x from y' when a module doesn't have a default export. */
"esModuleInterop": true, /* Emit additional JavaScript to ease support for importing CommonJS modules. This enables 'allowSyntheticDefaultImports' for type compatibility. */ "esModuleInterop": true /* Emit additional JavaScript to ease support for importing CommonJS modules. This enables 'allowSyntheticDefaultImports' for type compatibility. */,
// "preserveSymlinks": true, /* Disable resolving symlinks to their realpath. This correlates to the same flag in node. */ // "preserveSymlinks": true, /* Disable resolving symlinks to their realpath. This correlates to the same flag in node. */
"forceConsistentCasingInFileNames": true, /* Ensure that casing is correct in imports. */ "forceConsistentCasingInFileNames": true /* Ensure that casing is correct in imports. */,
/* Type Checking */ /* Type Checking */
"strict": true, /* Enable all strict type-checking options. */ "strict": true /* Enable all strict type-checking options. */,
// "noImplicitAny": true, /* Enable error reporting for expressions and declarations with an implied 'any' type. */ "noImplicitAny": true /* Enable error reporting for expressions and declarations with an implied 'any' type. */,
// "strictNullChecks": true, /* When type checking, take into account 'null' and 'undefined'. */ // "strictNullChecks": true, /* When type checking, take into account 'null' and 'undefined'. */
// "strictFunctionTypes": true, /* When assigning functions, check to ensure parameters and the return values are subtype-compatible. */ // "strictFunctionTypes": true, /* When assigning functions, check to ensure parameters and the return values are subtype-compatible. */
// "strictBindCallApply": true, /* Check that the arguments for 'bind', 'call', and 'apply' methods match the original function. */ // "strictBindCallApply": true, /* Check that the arguments for 'bind', 'call', and 'apply' methods match the original function. */
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment