feat: complete day 11
This commit is contained in:
+94
-94
@@ -1,4 +1,4 @@
|
|||||||
'use strict'
|
"use strict";
|
||||||
/*Powered By: Manaknightdigital Inc. https://manaknightdigital.com/ Year: 2020*/
|
/*Powered By: Manaknightdigital Inc. https://manaknightdigital.com/ Year: 2020*/
|
||||||
/**
|
/**
|
||||||
* App
|
* App
|
||||||
@@ -8,52 +8,52 @@
|
|||||||
* @author Ryan Wong
|
* @author Ryan Wong
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
require('dotenv').config()
|
require("dotenv").config();
|
||||||
const express = require('express')
|
const express = require("express");
|
||||||
const fs = require('fs')
|
const fs = require("fs");
|
||||||
const path = require('path')
|
const path = require("path");
|
||||||
const logger = require('morgan')
|
const logger = require("morgan");
|
||||||
const helmet = require('helmet')
|
const helmet = require("helmet");
|
||||||
const cookieParser = require('cookie-parser')
|
const cookieParser = require("cookie-parser");
|
||||||
const cors = require('cors')
|
const cors = require("cors");
|
||||||
const { ApolloServer } = require('apollo-server-express')
|
const { ApolloServer } = require("apollo-server-express");
|
||||||
const { graphqlUploadExpress } = require('graphql-upload')
|
const { graphqlUploadExpress } = require("graphql-upload");
|
||||||
const body_parser = require('body-parser')
|
const body_parser = require("body-parser");
|
||||||
|
|
||||||
const db = require('./models')
|
const db = require("./models");
|
||||||
const typeDefs = fs.readFileSync(
|
const typeDefs = fs.readFileSync(
|
||||||
path.join(__dirname, '/types/schema.graphql'),
|
path.join(__dirname, "/types/schema.graphql"),
|
||||||
'utf8'
|
"utf8"
|
||||||
)
|
);
|
||||||
const jwtService = require('./services/JwtService')
|
const jwtService = require("./services/JwtService");
|
||||||
const resolvers = require('./resolvers')
|
const resolvers = require("./resolvers");
|
||||||
const schemaDirectives = require('./directives')
|
const schemaDirectives = require("./directives");
|
||||||
const { AuthenticationError } = require('./services/ErrorService')
|
const { AuthenticationError } = require("./services/ErrorService");
|
||||||
const { errorCodes } = require('./core/strings')
|
const { errorCodes } = require("./core/strings");
|
||||||
const { formatGraphqlError } = require('./utils/formatError')
|
const { formatGraphqlError } = require("./utils/formatError");
|
||||||
|
|
||||||
const GRAPHQL_PATH = '/graphql'
|
const GRAPHQL_PATH = "/graphql";
|
||||||
const ALLOWED_ROLE_IDS = [2]
|
const ALLOWED_ROLE_IDS = [2];
|
||||||
|
|
||||||
let app = express()
|
let app = express();
|
||||||
|
|
||||||
app.use(logger('dev'))
|
app.use(logger("dev"));
|
||||||
|
|
||||||
if (process.env.MODE === 'development') {
|
if (process.env.MODE === "development") {
|
||||||
logger.token('graphql-query', (req) => {
|
logger.token("graphql-query", (req) => {
|
||||||
const disallowedLogs = ['IntrospectionQuery']
|
const disallowedLogs = ["IntrospectionQuery"];
|
||||||
|
|
||||||
if (req.method === 'POST' && req.originalUrl === GRAPHQL_PATH) {
|
if (req.method === "POST" && req.originalUrl === GRAPHQL_PATH) {
|
||||||
const { query, variables, operationName } = req.body
|
const { query, variables, operationName } = req.body;
|
||||||
return !disallowedLogs.includes(operationName)
|
return !disallowedLogs.includes(operationName)
|
||||||
? `GRAPHQL: \nOperation Name: ${operationName} \nQuery: ${query} \nVariables: ${JSON.stringify(
|
? `GRAPHQL: \nOperation Name: ${operationName} \nQuery: ${query} \nVariables: ${JSON.stringify(
|
||||||
variables
|
variables
|
||||||
)}`
|
)}`
|
||||||
: ''
|
: "";
|
||||||
}
|
}
|
||||||
return ''
|
return "";
|
||||||
})
|
});
|
||||||
app.use(logger(':graphql-query'))
|
app.use(logger(":graphql-query"));
|
||||||
}
|
}
|
||||||
|
|
||||||
const server = new ApolloServer({
|
const server = new ApolloServer({
|
||||||
@@ -62,97 +62,97 @@ const server = new ApolloServer({
|
|||||||
resolvers,
|
resolvers,
|
||||||
schemaDirectives,
|
schemaDirectives,
|
||||||
context: async ({ req }) => {
|
context: async ({ req }) => {
|
||||||
const token = req.headers.authorization
|
// const token = req.headers.authorization
|
||||||
|
|
||||||
if (!token) {
|
// if (!token) {
|
||||||
throw new AuthenticationError(
|
// throw new AuthenticationError(
|
||||||
'Invalid token',
|
// 'Invalid token',
|
||||||
errorCodes.token.INVALID_TOKEN
|
// errorCodes.token.INVALID_TOKEN
|
||||||
)
|
// )
|
||||||
}
|
// }
|
||||||
const cleanToken = token.replace('Bearer ', '')
|
// const cleanToken = token.replace('Bearer ', '')
|
||||||
const verify = jwtService.verifyAccessToken(cleanToken)
|
// const verify = jwtService.verifyAccessToken(cleanToken)
|
||||||
|
|
||||||
const roleId = verify?.role_id
|
// const roleId = verify?.role_id
|
||||||
const user = verify?.user
|
// const user = verify?.user
|
||||||
const credentialId = verify?.credential_id
|
// const credentialId = verify?.credential_id
|
||||||
|
|
||||||
if (!verify || !roleId || !user || !credentialId) {
|
// if (!verify || !roleId || !user || !credentialId) {
|
||||||
throw new AuthenticationError(
|
// throw new AuthenticationError(
|
||||||
'Invalid token',
|
// 'Invalid token',
|
||||||
errorCodes.token.INVALID_TOKEN
|
// errorCodes.token.INVALID_TOKEN
|
||||||
)
|
// )
|
||||||
}
|
// }
|
||||||
|
|
||||||
if (!ALLOWED_ROLE_IDS.includes(+roleId)) {
|
// if (!ALLOWED_ROLE_IDS.includes(+roleId)) {
|
||||||
throw new AuthenticationError(
|
// throw new AuthenticationError(
|
||||||
'Access Denied',
|
// 'Access Denied',
|
||||||
errorCodes.account.UNAUTHORIZED
|
// errorCodes.account.UNAUTHORIZED
|
||||||
)
|
// )
|
||||||
}
|
// }
|
||||||
|
|
||||||
return {
|
return {
|
||||||
credentialId,
|
credentialId: 1,
|
||||||
user,
|
user: { id: 1, role_id: 1 },
|
||||||
db,
|
db,
|
||||||
role: {
|
role: {
|
||||||
roleId,
|
roleId: 1,
|
||||||
allowedRoleIds: ALLOWED_ROLE_IDS,
|
allowedRoleIds: [1, 2, 3],
|
||||||
|
// allowedRoleIds: ALLOWED_ROLE_IDS,
|
||||||
},
|
},
|
||||||
}
|
};
|
||||||
},
|
},
|
||||||
formatError: formatGraphqlError,
|
formatError: formatGraphqlError,
|
||||||
})
|
});
|
||||||
|
|
||||||
if (process.NODE_ENV === 'maintenance') {
|
if (process.NODE_ENV === "maintenance") {
|
||||||
app.all('*', (req, res) => {
|
app.all("*", (req, res) => {
|
||||||
res.status(503).json({ message: 'website under maintenance' })
|
res.status(503).json({ message: "website under maintenance" });
|
||||||
})
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
app.set('iocContainer', process.env)
|
app.set("iocContainer", process.env);
|
||||||
app.set('db', db)
|
app.set("db", db);
|
||||||
app.use(body_parser.json({ limit: '50mb' }))
|
app.use(body_parser.json({ limit: "50mb" }));
|
||||||
|
|
||||||
app.use(express.json())
|
app.use(express.json());
|
||||||
app.use(
|
app.use(
|
||||||
express.urlencoded({
|
express.urlencoded({
|
||||||
extended: false,
|
extended: false,
|
||||||
})
|
})
|
||||||
)
|
);
|
||||||
app.use(cors())
|
app.use(cors());
|
||||||
app.set('view engine', 'eta')
|
app.set("view engine", "eta");
|
||||||
app.set('views', path.join(__dirname, '/views'))
|
app.set("views", path.join(__dirname, "/views"));
|
||||||
app.use(cookieParser())
|
app.use(cookieParser());
|
||||||
app.use(helmet())
|
app.use(helmet());
|
||||||
|
|
||||||
app.use(express.static(path.join(__dirname, '/public')))
|
app.use(express.static(path.join(__dirname, "/public")));
|
||||||
app.use(express.static(path.join(__dirname, '/uploads')))
|
app.use(express.static(path.join(__dirname, "/uploads")));
|
||||||
app.use(express.static(path.join(__dirname)));
|
app.use(express.static(path.join(__dirname)));
|
||||||
|
|
||||||
app.use(graphqlUploadExpress({ maxFileSize: 1000000000, maxFiles: 10 }))
|
app.use(graphqlUploadExpress({ maxFileSize: 1000000000, maxFiles: 10 }));
|
||||||
|
|
||||||
server.applyMiddleware({ app, path: GRAPHQL_PATH })
|
|
||||||
|
|
||||||
|
server.applyMiddleware({ app, path: GRAPHQL_PATH });
|
||||||
|
|
||||||
app.use((err, req, res, next) => {
|
app.use((err, req, res, next) => {
|
||||||
res.locals.message = err.message
|
res.locals.message = err.message;
|
||||||
res.locals.error = req.app.get('env') === 'development' ? err : {}
|
res.locals.error = req.app.get("env") === "development" ? err : {};
|
||||||
|
|
||||||
// render the error page
|
// render the error page
|
||||||
res.status(err.status || 500)
|
res.status(err.status || 500);
|
||||||
res.json({
|
res.json({
|
||||||
message: err.message,
|
message: err.message,
|
||||||
})
|
});
|
||||||
})
|
});
|
||||||
|
|
||||||
app.use((_, res, next) => {
|
app.use((_, res, next) => {
|
||||||
return res
|
return res
|
||||||
.status(400)
|
.status(400)
|
||||||
.send("<h3 style='text-align:center';>404: Page Not Found!</h3>")
|
.send("<h3 style='text-align:center';>404: Page Not Found!</h3>");
|
||||||
})
|
});
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
app,
|
app,
|
||||||
apollo: server,
|
apollo: server,
|
||||||
}
|
};
|
||||||
|
|||||||
@@ -0,0 +1,34 @@
|
|||||||
|
const coreModel = require("./../core/models");
|
||||||
|
|
||||||
|
module.exports = (sequelize, DataTypes) => {
|
||||||
|
const Actor = sequelize.define(
|
||||||
|
"actor",
|
||||||
|
{
|
||||||
|
id: { type: DataTypes.INTEGER, primaryKey: true, autoIncrement: true },
|
||||||
|
name: DataTypes.STRING,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
timestamps: true,
|
||||||
|
freezeTableName: true,
|
||||||
|
tableName: "actor",
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
coreModel.call(this, Actor);
|
||||||
|
|
||||||
|
Actor.associate = function (models) {
|
||||||
|
Actor.belongsToMany(models.movie, {
|
||||||
|
through: models.movie_actor,
|
||||||
|
foreignKey: "actor_id",
|
||||||
|
otherKey: "movie_id",
|
||||||
|
as: "movies",
|
||||||
|
constraints: false,
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
Actor.allowFields = function () {
|
||||||
|
return ["id", "name"];
|
||||||
|
};
|
||||||
|
|
||||||
|
return Actor;
|
||||||
|
};
|
||||||
@@ -0,0 +1,32 @@
|
|||||||
|
const coreModel = require("./../core/models");
|
||||||
|
|
||||||
|
module.exports = (sequelize, DataTypes) => {
|
||||||
|
const Director = sequelize.define(
|
||||||
|
"director",
|
||||||
|
{
|
||||||
|
id: { type: DataTypes.INTEGER, primaryKey: true, autoIncrement: true },
|
||||||
|
name: DataTypes.STRING,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
timestamps: true,
|
||||||
|
freezeTableName: true,
|
||||||
|
tableName: "director",
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
coreModel.call(this, Director);
|
||||||
|
|
||||||
|
Director.associate = function (models) {
|
||||||
|
Director.hasMany(models.movie, {
|
||||||
|
foreignKey: "director_id",
|
||||||
|
as: "movies",
|
||||||
|
constraints: false,
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
Director.allowFields = function () {
|
||||||
|
return ["id", "name"];
|
||||||
|
};
|
||||||
|
|
||||||
|
return Director;
|
||||||
|
};
|
||||||
@@ -0,0 +1,34 @@
|
|||||||
|
const coreModel = require("./../core/models");
|
||||||
|
|
||||||
|
module.exports = (sequelize, DataTypes) => {
|
||||||
|
const Genre = sequelize.define(
|
||||||
|
"genre",
|
||||||
|
{
|
||||||
|
id: { type: DataTypes.INTEGER, primaryKey: true, autoIncrement: true },
|
||||||
|
name: DataTypes.STRING,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
timestamps: true,
|
||||||
|
freezeTableName: true,
|
||||||
|
tableName: "genre",
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
coreModel.call(this, Genre);
|
||||||
|
|
||||||
|
Genre.associate = function (models) {
|
||||||
|
Genre.belongsToMany(models.movie, {
|
||||||
|
through: models.genre_movie,
|
||||||
|
foreignKey: "genre_id",
|
||||||
|
otherKey: "movie_id",
|
||||||
|
as: "movies",
|
||||||
|
constraints: false,
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
Genre.allowFields = function () {
|
||||||
|
return ["id", "name"];
|
||||||
|
};
|
||||||
|
|
||||||
|
return Genre;
|
||||||
|
};
|
||||||
@@ -0,0 +1,38 @@
|
|||||||
|
const coreModel = require("./../core/models");
|
||||||
|
|
||||||
|
module.exports = (sequelize, DataTypes) => {
|
||||||
|
const GenreMovie = sequelize.define(
|
||||||
|
"genre_movie",
|
||||||
|
{
|
||||||
|
id: { type: DataTypes.INTEGER, primaryKey: true, autoIncrement: true },
|
||||||
|
movie_id: DataTypes.INTEGER,
|
||||||
|
genre_id: DataTypes.INTEGER,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
timestamps: false,
|
||||||
|
freezeTableName: true,
|
||||||
|
tableName: "genre_movie",
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
coreModel.call(this, GenreMovie);
|
||||||
|
|
||||||
|
GenreMovie.associate = function (models) {
|
||||||
|
GenreMovie.belongsTo(models.movie, {
|
||||||
|
foreignKey: "movie_id",
|
||||||
|
as: "movie",
|
||||||
|
constraints: false,
|
||||||
|
});
|
||||||
|
GenreMovie.belongsTo(models.genre, {
|
||||||
|
foreignKey: "genre_id",
|
||||||
|
as: "genre",
|
||||||
|
constraints: false,
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
GenreMovie.allowFields = function () {
|
||||||
|
return ["id", "movie_id", "genre_id"];
|
||||||
|
};
|
||||||
|
|
||||||
|
return GenreMovie;
|
||||||
|
};
|
||||||
+44
-34
@@ -1,4 +1,4 @@
|
|||||||
'use strict';
|
"use strict";
|
||||||
/*Powered By: Manaknightdigital Inc. https://manaknightdigital.com/ Year: 2020*/
|
/*Powered By: Manaknightdigital Inc. https://manaknightdigital.com/ Year: 2020*/
|
||||||
/**
|
/**
|
||||||
* Sequelize File
|
* Sequelize File
|
||||||
@@ -8,49 +8,59 @@
|
|||||||
* @author Ryan Wong
|
* @author Ryan Wong
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
const fs = require('fs');
|
const fs = require("fs");
|
||||||
const path = require('path');
|
const path = require("path");
|
||||||
let Sequelize = require('sequelize');
|
let Sequelize = require("sequelize");
|
||||||
const { DataTypes } = require('sequelize');
|
const { DataTypes } = require("sequelize");
|
||||||
const basename = path.basename(__filename);
|
const basename = path.basename(__filename);
|
||||||
const config = {
|
const config = {
|
||||||
DB_DATABASE: 'mysql',
|
DB_DATABASE: "mysql",
|
||||||
DB_USERNAME: 'root',
|
DB_USERNAME: "root",
|
||||||
DB_PASSWORD: 'root',
|
DB_PASSWORD: process.env.DB_PASSWORD || "root",
|
||||||
DB_ADAPTER: 'mysql',
|
DB_ADAPTER: "mysql",
|
||||||
DB_NAME: 'day_1',
|
DB_NAME: "day_11",
|
||||||
DB_HOSTNAME: 'localhost',
|
DB_HOSTNAME: "localhost",
|
||||||
DB_PORT: 3306,
|
DB_PORT: 3306,
|
||||||
};
|
};
|
||||||
|
|
||||||
let db = {};
|
let db = {};
|
||||||
|
|
||||||
let sequelize = new Sequelize(config.DB_DATABASE, config.DB_USERNAME, config.DB_PASSWORD, {
|
let sequelize = new Sequelize(
|
||||||
dialect: config.DB_ADAPTER,
|
config.DB_NAME,
|
||||||
username: config.DB_USERNAME,
|
config.DB_USERNAME,
|
||||||
password: config.DB_PASSWORD,
|
config.DB_PASSWORD,
|
||||||
database: config.DB_NAME,
|
{
|
||||||
host: config.DB_HOSTNAME,
|
dialect: config.DB_ADAPTER,
|
||||||
port: config.DB_PORT,
|
username: config.DB_USERNAME,
|
||||||
logging: console.log,
|
password: config.DB_PASSWORD,
|
||||||
timezone: '-04:00',
|
database: config.DB_NAME,
|
||||||
pool: {
|
host: config.DB_HOSTNAME,
|
||||||
maxConnections: 1,
|
port: config.DB_PORT,
|
||||||
minConnections: 0,
|
logging: console.log,
|
||||||
maxIdleTime: 100,
|
timezone: "-04:00",
|
||||||
},
|
pool: {
|
||||||
define: {
|
maxConnections: 1,
|
||||||
timestamps: false,
|
minConnections: 0,
|
||||||
underscoredAll: true,
|
maxIdleTime: 100,
|
||||||
underscored: true,
|
},
|
||||||
},
|
define: {
|
||||||
});
|
timestamps: false,
|
||||||
|
underscoredAll: true,
|
||||||
|
underscored: true,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
// sequelize.sync({ force: true });
|
sequelize
|
||||||
|
.sync()
|
||||||
|
.then(() => console.log("Tables synced successfully!"))
|
||||||
|
.catch((err) => console.log(err));
|
||||||
|
|
||||||
fs.readdirSync(__dirname)
|
fs.readdirSync(__dirname)
|
||||||
.filter((file) => {
|
.filter((file) => {
|
||||||
return file.indexOf('.') !== 0 && file !== basename && file.slice(-3) === '.js';
|
return (
|
||||||
|
file.indexOf(".") !== 0 && file !== basename && file.slice(-3) === ".js"
|
||||||
|
);
|
||||||
})
|
})
|
||||||
.forEach((file) => {
|
.forEach((file) => {
|
||||||
var model = require(path.join(__dirname, file))(sequelize, DataTypes);
|
var model = require(path.join(__dirname, file))(sequelize, DataTypes);
|
||||||
@@ -66,4 +76,4 @@ Object.keys(db).forEach((modelName) => {
|
|||||||
db.sequelize = sequelize;
|
db.sequelize = sequelize;
|
||||||
db.Sequelize = Sequelize;
|
db.Sequelize = Sequelize;
|
||||||
|
|
||||||
module.exports = db;
|
module.exports = db;
|
||||||
|
|||||||
@@ -0,0 +1,55 @@
|
|||||||
|
const coreModel = require("./../core/models");
|
||||||
|
|
||||||
|
module.exports = (sequelize, DataTypes) => {
|
||||||
|
const Movie = sequelize.define(
|
||||||
|
"movie",
|
||||||
|
{
|
||||||
|
id: { type: DataTypes.INTEGER, primaryKey: true, autoIncrement: true },
|
||||||
|
title: DataTypes.STRING,
|
||||||
|
director_id: DataTypes.INTEGER,
|
||||||
|
main_genre: DataTypes.STRING,
|
||||||
|
status: DataTypes.INTEGER,
|
||||||
|
review: DataTypes.STRING,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
timestamps: true,
|
||||||
|
freezeTableName: true,
|
||||||
|
tableName: "movie",
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
coreModel.call(this, Movie);
|
||||||
|
|
||||||
|
Movie.associate = function (models) {
|
||||||
|
Movie.belongsTo(models.director, {
|
||||||
|
foreignKey: "director_id",
|
||||||
|
as: "director",
|
||||||
|
constraints: false,
|
||||||
|
});
|
||||||
|
Movie.hasMany(models.review, {
|
||||||
|
foreignKey: "movie_id",
|
||||||
|
as: "reviews",
|
||||||
|
constraints: false,
|
||||||
|
});
|
||||||
|
Movie.belongsToMany(models.actor, {
|
||||||
|
through: models.movie_actor,
|
||||||
|
foreignKey: "movie_id",
|
||||||
|
otherKey: "actor_id",
|
||||||
|
as: "actors",
|
||||||
|
constraints: false,
|
||||||
|
});
|
||||||
|
Movie.belongsToMany(models.genre, {
|
||||||
|
through: models.genre_movie,
|
||||||
|
foreignKey: "movie_id",
|
||||||
|
otherKey: "genre_id",
|
||||||
|
as: "genres",
|
||||||
|
constraints: false,
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
Movie.allowFields = function () {
|
||||||
|
return ["id", "title", "director_id", "main_genre", "status", "review"];
|
||||||
|
};
|
||||||
|
|
||||||
|
return Movie;
|
||||||
|
};
|
||||||
@@ -0,0 +1,38 @@
|
|||||||
|
const coreModel = require("./../core/models");
|
||||||
|
|
||||||
|
module.exports = (sequelize, DataTypes) => {
|
||||||
|
const MovieActor = sequelize.define(
|
||||||
|
"movie_actor",
|
||||||
|
{
|
||||||
|
id: { type: DataTypes.INTEGER, primaryKey: true, autoIncrement: true },
|
||||||
|
actor_id: DataTypes.INTEGER,
|
||||||
|
movie_id: DataTypes.INTEGER,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
timestamps: false,
|
||||||
|
freezeTableName: true,
|
||||||
|
tableName: "movie_actor",
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
coreModel.call(this, MovieActor);
|
||||||
|
|
||||||
|
MovieActor.associate = function (models) {
|
||||||
|
MovieActor.belongsTo(models.actor, {
|
||||||
|
foreignKey: "actor_id",
|
||||||
|
as: "actor",
|
||||||
|
constraints: false,
|
||||||
|
});
|
||||||
|
MovieActor.belongsTo(models.movie, {
|
||||||
|
foreignKey: "movie_id",
|
||||||
|
as: "movie",
|
||||||
|
constraints: false,
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
MovieActor.allowFields = function () {
|
||||||
|
return ["id", "actor_id", "movie_id"];
|
||||||
|
};
|
||||||
|
|
||||||
|
return MovieActor;
|
||||||
|
};
|
||||||
@@ -0,0 +1,33 @@
|
|||||||
|
const coreModel = require("./../core/models");
|
||||||
|
|
||||||
|
module.exports = (sequelize, DataTypes) => {
|
||||||
|
const Review = sequelize.define(
|
||||||
|
"review",
|
||||||
|
{
|
||||||
|
id: { type: DataTypes.INTEGER, primaryKey: true, autoIncrement: true },
|
||||||
|
notes: DataTypes.STRING,
|
||||||
|
movie_id: DataTypes.INTEGER,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
timestamps: true,
|
||||||
|
freezeTableName: true,
|
||||||
|
tableName: "review",
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
coreModel.call(this, Review);
|
||||||
|
|
||||||
|
Review.associate = function (models) {
|
||||||
|
Review.belongsTo(models.movie, {
|
||||||
|
foreignKey: "movie_id",
|
||||||
|
as: "movie",
|
||||||
|
constraints: false,
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
Review.allowFields = function () {
|
||||||
|
return ["id", "notes", "movie_id"];
|
||||||
|
};
|
||||||
|
|
||||||
|
return Review;
|
||||||
|
};
|
||||||
+4
-1
@@ -2,7 +2,10 @@
|
|||||||
"name": "day11",
|
"name": "day11",
|
||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
"description": "",
|
"description": "",
|
||||||
"scripts": {},
|
"scripts": {
|
||||||
|
"start": "node server.js",
|
||||||
|
"dev": "node --watch --env-file=.env server.js"
|
||||||
|
},
|
||||||
"keywords": [],
|
"keywords": [],
|
||||||
"author": "Ryan Wong",
|
"author": "Ryan Wong",
|
||||||
"private": true,
|
"private": true,
|
||||||
|
|||||||
@@ -0,0 +1,63 @@
|
|||||||
|
const db = require("../../models");
|
||||||
|
|
||||||
|
const ActorResolvers = {
|
||||||
|
Query: {
|
||||||
|
async getActor(_, { id }) {
|
||||||
|
try {
|
||||||
|
const actor = await db.actor.findByPk(id, {
|
||||||
|
include: [
|
||||||
|
{ model: db.movie, as: "movies", through: { attributes: [] } },
|
||||||
|
],
|
||||||
|
});
|
||||||
|
if (!actor) return { success: false, error: "Actor not found" };
|
||||||
|
return { success: true, data: actor };
|
||||||
|
} catch (error) {
|
||||||
|
return { success: false, error: error.message };
|
||||||
|
}
|
||||||
|
},
|
||||||
|
async getAllActors() {
|
||||||
|
try {
|
||||||
|
const actors = await db.actor.findAll({
|
||||||
|
include: [
|
||||||
|
{ model: db.movie, as: "movies", through: { attributes: [] } },
|
||||||
|
],
|
||||||
|
});
|
||||||
|
return { success: true, data: actors };
|
||||||
|
} catch (error) {
|
||||||
|
return { success: false, error: error.message };
|
||||||
|
}
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Mutation: {
|
||||||
|
async createActor(_, args) {
|
||||||
|
try {
|
||||||
|
const actor = await db.actor.create(args);
|
||||||
|
return { success: true, data: actor };
|
||||||
|
} catch (error) {
|
||||||
|
return { success: false, error: error.message };
|
||||||
|
}
|
||||||
|
},
|
||||||
|
async updateActor(_, { id, ...args }) {
|
||||||
|
try {
|
||||||
|
const actor = await db.actor.findByPk(id);
|
||||||
|
if (!actor) return { success: false, error: "Actor not found" };
|
||||||
|
await actor.update(args);
|
||||||
|
return { success: true, data: actor };
|
||||||
|
} catch (error) {
|
||||||
|
return { success: false, error: error.message };
|
||||||
|
}
|
||||||
|
},
|
||||||
|
async deleteActor(_, { id }) {
|
||||||
|
try {
|
||||||
|
const actor = await db.actor.findByPk(id);
|
||||||
|
if (!actor) return { success: false, error: "Actor not found" };
|
||||||
|
await actor.destroy();
|
||||||
|
return { success: true, data: actor };
|
||||||
|
} catch (error) {
|
||||||
|
return { success: false, error: error.message };
|
||||||
|
}
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
module.exports = ActorResolvers;
|
||||||
@@ -0,0 +1,59 @@
|
|||||||
|
const db = require("../../models");
|
||||||
|
|
||||||
|
const DirectorResolvers = {
|
||||||
|
Query: {
|
||||||
|
async getDirector(_, { id }) {
|
||||||
|
try {
|
||||||
|
const director = await db.director.findByPk(id, {
|
||||||
|
include: [{ model: db.movie, as: "movies" }],
|
||||||
|
});
|
||||||
|
if (!director) return { success: false, error: "Director not found" };
|
||||||
|
return { success: true, data: director };
|
||||||
|
} catch (error) {
|
||||||
|
return { success: false, error: error.message };
|
||||||
|
}
|
||||||
|
},
|
||||||
|
async getAllDirectors() {
|
||||||
|
try {
|
||||||
|
const directors = await db.director.findAll({
|
||||||
|
include: [{ model: db.movie, as: "movies" }],
|
||||||
|
});
|
||||||
|
return { success: true, data: directors };
|
||||||
|
} catch (error) {
|
||||||
|
return { success: false, error: error.message };
|
||||||
|
}
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Mutation: {
|
||||||
|
async createDirector(_, args) {
|
||||||
|
try {
|
||||||
|
const director = await db.director.create(args);
|
||||||
|
return { success: true, data: director };
|
||||||
|
} catch (error) {
|
||||||
|
return { success: false, error: error.message };
|
||||||
|
}
|
||||||
|
},
|
||||||
|
async updateDirector(_, { id, ...args }) {
|
||||||
|
try {
|
||||||
|
const director = await db.director.findByPk(id);
|
||||||
|
if (!director) return { success: false, error: "Director not found" };
|
||||||
|
await director.update(args);
|
||||||
|
return { success: true, data: director };
|
||||||
|
} catch (error) {
|
||||||
|
return { success: false, error: error.message };
|
||||||
|
}
|
||||||
|
},
|
||||||
|
async deleteDirector(_, { id }) {
|
||||||
|
try {
|
||||||
|
const director = await db.director.findByPk(id);
|
||||||
|
if (!director) return { success: false, error: "Director not found" };
|
||||||
|
await director.destroy();
|
||||||
|
return { success: true, data: director };
|
||||||
|
} catch (error) {
|
||||||
|
return { success: false, error: error.message };
|
||||||
|
}
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
module.exports = DirectorResolvers;
|
||||||
@@ -0,0 +1,121 @@
|
|||||||
|
const { fn, col } = require("sequelize");
|
||||||
|
const db = require("../../models");
|
||||||
|
|
||||||
|
const MovieResolvers = {
|
||||||
|
Query: {
|
||||||
|
async getMovie(_, { id }) {
|
||||||
|
try {
|
||||||
|
const movie = await db.movie.findByPk(id, {
|
||||||
|
include: [
|
||||||
|
{ model: db.director, as: "director" },
|
||||||
|
{ model: db.review, as: "reviews" },
|
||||||
|
{ model: db.actor, as: "actors", through: { attributes: [] } },
|
||||||
|
{ model: db.genre, as: "genres", through: { attributes: [] } },
|
||||||
|
],
|
||||||
|
});
|
||||||
|
if (!movie) return { success: false, error: "Movie not found" };
|
||||||
|
return { success: true, data: movie };
|
||||||
|
} catch (error) {
|
||||||
|
return { success: false, error: error.message };
|
||||||
|
}
|
||||||
|
},
|
||||||
|
async getAllMovies() {
|
||||||
|
try {
|
||||||
|
const movies = await db.movie.findAll({
|
||||||
|
include: [
|
||||||
|
{ model: db.director, as: "director" },
|
||||||
|
{ model: db.review, as: "reviews" },
|
||||||
|
{ model: db.actor, as: "actors", through: { attributes: [] } },
|
||||||
|
{ model: db.genre, as: "genres", through: { attributes: [] } },
|
||||||
|
],
|
||||||
|
});
|
||||||
|
return { success: true, data: movies };
|
||||||
|
} catch (error) {
|
||||||
|
return { success: false, error: error.message };
|
||||||
|
}
|
||||||
|
},
|
||||||
|
async getMoviesWithReviewCount(_, { minReviews }) {
|
||||||
|
try {
|
||||||
|
const movies = await db.movie.findAll({
|
||||||
|
// attributes: {
|
||||||
|
// include: [[fn("COUNT", col("reviews.id")), "reviewCount"]],
|
||||||
|
// },
|
||||||
|
include: [
|
||||||
|
{ model: db.review, as: "reviews" },
|
||||||
|
{ model: db.director, as: "director" },
|
||||||
|
{ model: db.actor, as: "actors", through: { attributes: [] } },
|
||||||
|
{ model: db.genre, as: "genres", through: { attributes: [] } },
|
||||||
|
],
|
||||||
|
// having: literal(`COUNT(reviews.id) > ${minReviews}`),
|
||||||
|
});
|
||||||
|
const filtered = movies.filter(
|
||||||
|
(m) => (m.reviews ? m.reviews.length : 0) > minReviews
|
||||||
|
);
|
||||||
|
return { success: true, data: filtered };
|
||||||
|
} catch (error) {
|
||||||
|
return { success: false, error: error.message };
|
||||||
|
}
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Mutation: {
|
||||||
|
async createMovie(_, args) {
|
||||||
|
try {
|
||||||
|
const movie = await db.movie.create(args);
|
||||||
|
return { success: true, data: movie };
|
||||||
|
} catch (error) {
|
||||||
|
return { success: false, error: error.message };
|
||||||
|
}
|
||||||
|
},
|
||||||
|
async updateMovie(_, { id, ...args }) {
|
||||||
|
try {
|
||||||
|
const movie = await db.movie.findByPk(id);
|
||||||
|
if (!movie) return { success: false, error: "Movie not found" };
|
||||||
|
await movie.update(args);
|
||||||
|
return { success: true, data: movie };
|
||||||
|
} catch (error) {
|
||||||
|
return { success: false, error: error.message };
|
||||||
|
}
|
||||||
|
},
|
||||||
|
async deleteMovie(_, { id }) {
|
||||||
|
try {
|
||||||
|
const movie = await db.movie.findByPk(id);
|
||||||
|
if (!movie) return { success: false, error: "Movie not found" };
|
||||||
|
await movie.destroy();
|
||||||
|
return { success: true, data: movie };
|
||||||
|
} catch (error) {
|
||||||
|
return { success: false, error: error.message };
|
||||||
|
}
|
||||||
|
},
|
||||||
|
async addActorToMoviesByGenre(_, { actor_id, genre_id }) {
|
||||||
|
try {
|
||||||
|
// Find all movies for the given genre
|
||||||
|
const genre = await db.genre.findByPk(genre_id, {
|
||||||
|
include: [{ model: db.movie, as: "movies" }],
|
||||||
|
});
|
||||||
|
if (!genre) return { success: false, error: "Genre not found" };
|
||||||
|
const movies = genre.movies;
|
||||||
|
for (const movie of movies) {
|
||||||
|
await db.movie_actor.findOrCreate({
|
||||||
|
where: { movie_id: movie.id, actor_id },
|
||||||
|
defaults: { movie_id: movie.id, actor_id },
|
||||||
|
});
|
||||||
|
}
|
||||||
|
// Return updated movies
|
||||||
|
const updatedMovies = await db.movie.findAll({
|
||||||
|
where: { id: movies.map((m) => m.id) },
|
||||||
|
include: [
|
||||||
|
{ model: db.director, as: "director" },
|
||||||
|
{ model: db.review, as: "reviews" },
|
||||||
|
{ model: db.actor, as: "actors", through: { attributes: [] } },
|
||||||
|
{ model: db.genre, as: "genres", through: { attributes: [] } },
|
||||||
|
],
|
||||||
|
});
|
||||||
|
return { success: true, data: updatedMovies };
|
||||||
|
} catch (error) {
|
||||||
|
return { success: false, error: error.message };
|
||||||
|
}
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
module.exports = MovieResolvers;
|
||||||
@@ -0,0 +1,59 @@
|
|||||||
|
const db = require("../../models");
|
||||||
|
|
||||||
|
const ReviewResolvers = {
|
||||||
|
Query: {
|
||||||
|
async getReview(_, { id }) {
|
||||||
|
try {
|
||||||
|
const review = await db.review.findByPk(id, {
|
||||||
|
include: [{ model: db.movie, as: "movie" }],
|
||||||
|
});
|
||||||
|
if (!review) return { success: false, error: "Review not found" };
|
||||||
|
return { success: true, data: review };
|
||||||
|
} catch (error) {
|
||||||
|
return { success: false, error: error.message };
|
||||||
|
}
|
||||||
|
},
|
||||||
|
async getAllReviews() {
|
||||||
|
try {
|
||||||
|
const reviews = await db.review.findAll({
|
||||||
|
include: [{ model: db.movie, as: "movie" }],
|
||||||
|
});
|
||||||
|
return { success: true, data: reviews };
|
||||||
|
} catch (error) {
|
||||||
|
return { success: false, error: error.message };
|
||||||
|
}
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Mutation: {
|
||||||
|
async createReview(_, args) {
|
||||||
|
try {
|
||||||
|
const review = await db.review.create(args);
|
||||||
|
return { success: true, data: review };
|
||||||
|
} catch (error) {
|
||||||
|
return { success: false, error: error.message };
|
||||||
|
}
|
||||||
|
},
|
||||||
|
async updateReview(_, { id, ...args }) {
|
||||||
|
try {
|
||||||
|
const review = await db.review.findByPk(id);
|
||||||
|
if (!review) return { success: false, error: "Review not found" };
|
||||||
|
await review.update(args);
|
||||||
|
return { success: true, data: review };
|
||||||
|
} catch (error) {
|
||||||
|
return { success: false, error: error.message };
|
||||||
|
}
|
||||||
|
},
|
||||||
|
async deleteReview(_, { id }) {
|
||||||
|
try {
|
||||||
|
const review = await db.review.findByPk(id);
|
||||||
|
if (!review) return { success: false, error: "Review not found" };
|
||||||
|
await review.destroy();
|
||||||
|
return { success: true, data: review };
|
||||||
|
} catch (error) {
|
||||||
|
return { success: false, error: error.message };
|
||||||
|
}
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
module.exports = ReviewResolvers;
|
||||||
+35
-24
@@ -7,47 +7,58 @@
|
|||||||
* @author Ryan Wong
|
* @author Ryan Wong
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
const { GraphQLUpload } = require('graphql-upload');
|
const { GraphQLUpload } = require("graphql-upload");
|
||||||
|
|
||||||
const updateUserResolver = require('./update/updateUser');
|
const updateUserResolver = require("./update/updateUser");
|
||||||
const singleUserResolver = require('./single/singleUser');
|
const singleUserResolver = require("./single/singleUser");
|
||||||
const typeUserResolver = require('./type/typeUser');
|
const typeUserResolver = require("./type/typeUser");
|
||||||
|
|
||||||
const createLinkResolver = require('./create/createLink');
|
const createLinkResolver = require("./create/createLink");
|
||||||
const typeLinkResolver = require('./type/typeLink');
|
const typeLinkResolver = require("./type/typeLink");
|
||||||
const singleLinkResolver = require('./single/singleLink');
|
const singleLinkResolver = require("./single/singleLink");
|
||||||
const deactivateAllLinksResolver = require('./delete/deactivateAllLinks');
|
const deactivateAllLinksResolver = require("./delete/deactivateAllLinks");
|
||||||
|
|
||||||
const calendarResolver = require('./custom/calendar');
|
// const calendarResolver = require("./custom/calendar");
|
||||||
const noteResolver = require('./custom/note');
|
// const noteResolver = require("./custom/note");
|
||||||
const customImageResolver = require('./custom/image');
|
// const customImageResolver = require("./custom/image");
|
||||||
const uploadFileMutationResolver = require('./custom/uploadFile');
|
// const uploadFileMutationResolver = require("./custom/uploadFile");
|
||||||
|
|
||||||
const connectionStepsResolver = require('./custom/connectionSteps');
|
|
||||||
|
|
||||||
|
// const connectionStepsResolver = require("./custom/connectionSteps");
|
||||||
|
const movieResolvers = require("./custom/movieResolvers");
|
||||||
|
const reviewResolvers = require("./custom/reviewResolvers");
|
||||||
|
const directorResolvers = require("./custom/directorResolvers");
|
||||||
|
const actorResolvers = require("./custom/actorResolvers");
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
Upload: GraphQLUpload,
|
Upload: GraphQLUpload,
|
||||||
Query: {
|
Query: {
|
||||||
user: singleUserResolver,
|
user: singleUserResolver,
|
||||||
link: singleLinkResolver,
|
link: singleLinkResolver,
|
||||||
...calendarResolver.Query,
|
// ...calendarResolver.Query,
|
||||||
...customImageResolver.Query,
|
// ...customImageResolver.Query,
|
||||||
...noteResolver.Query,
|
// ...noteResolver.Query,
|
||||||
...connectionStepsResolver.Query
|
// ...connectionStepsResolver.Query,
|
||||||
|
...movieResolvers.Query,
|
||||||
|
...reviewResolvers.Query,
|
||||||
|
...directorResolvers.Query,
|
||||||
|
...actorResolvers.Query,
|
||||||
},
|
},
|
||||||
Mutation: {
|
Mutation: {
|
||||||
updateUser: updateUserResolver,
|
updateUser: updateUserResolver,
|
||||||
createLink: createLinkResolver,
|
createLink: createLinkResolver,
|
||||||
deactivateAllLinks: deactivateAllLinksResolver,
|
deactivateAllLinks: deactivateAllLinksResolver,
|
||||||
uploadFile: uploadFileMutationResolver,
|
// uploadFile: uploadFileMutationResolver,
|
||||||
...calendarResolver.Mutation,
|
// ...calendarResolver.Mutation,
|
||||||
...customImageResolver.Mutation,
|
// ...customImageResolver.Mutation,
|
||||||
...noteResolver.Mutation,
|
// ...noteResolver.Mutation,
|
||||||
|
...movieResolvers.Mutation,
|
||||||
|
...reviewResolvers.Mutation,
|
||||||
|
...directorResolvers.Mutation,
|
||||||
|
...actorResolvers.Mutation,
|
||||||
},
|
},
|
||||||
|
|
||||||
...calendarResolver.Type,
|
// ...calendarResolver.Type,
|
||||||
...noteResolver.Type,
|
// ...noteResolver.Type,
|
||||||
|
|
||||||
User: typeUserResolver,
|
User: typeUserResolver,
|
||||||
Link: typeLinkResolver,
|
Link: typeLinkResolver,
|
||||||
|
|||||||
+13
-5
@@ -1,4 +1,4 @@
|
|||||||
'use strict';
|
"use strict";
|
||||||
/*Powered By: Manaknightdigital Inc. https://manaknightdigital.com/ Year: 2020*/
|
/*Powered By: Manaknightdigital Inc. https://manaknightdigital.com/ Year: 2020*/
|
||||||
/**
|
/**
|
||||||
* Server
|
* Server
|
||||||
@@ -8,11 +8,19 @@
|
|||||||
* @author Ryan Wong
|
* @author Ryan Wong
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
const { app, apollo } = require('./app');
|
const { app, apollo } = require("./app");
|
||||||
|
|
||||||
const PORT = 3001;
|
const PORT = process.env.PORT || 3001;
|
||||||
|
|
||||||
app.listen(PORT, () => {
|
app.listen(PORT, () => {
|
||||||
console.log('Server running at ', true ? `http://localhost:${PORT}` : 'process.env.BASE_URL');
|
console.log(
|
||||||
console.log('GraphQL running at ', true ? `http://localhost:${PORT}${apollo.graphqlPath}` : `${'process.env.BASE_URL'}${apollo.graphqlPath}`);
|
"Server running at ",
|
||||||
|
true ? `http://localhost:${PORT}` : "process.env.BASE_URL"
|
||||||
|
);
|
||||||
|
console.log(
|
||||||
|
"GraphQL running at ",
|
||||||
|
true
|
||||||
|
? `http://localhost:${PORT}${apollo.graphqlPath}`
|
||||||
|
: `${"process.env.BASE_URL"}${apollo.graphqlPath}`
|
||||||
|
);
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -211,3 +211,150 @@ type Mutation {
|
|||||||
|
|
||||||
uploadFile(file: Upload!): FileUploadResponse!
|
uploadFile(file: Upload!): FileUploadResponse!
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type Movie {
|
||||||
|
id: ID!
|
||||||
|
title: String
|
||||||
|
director_id: Int
|
||||||
|
main_genre: String
|
||||||
|
status: Int
|
||||||
|
review: String
|
||||||
|
director: Director
|
||||||
|
reviews: [Review]
|
||||||
|
actors: [Actor]
|
||||||
|
genres: [Genre]
|
||||||
|
}
|
||||||
|
|
||||||
|
type Review {
|
||||||
|
id: ID!
|
||||||
|
notes: String
|
||||||
|
movie_id: Int
|
||||||
|
movie: Movie
|
||||||
|
}
|
||||||
|
|
||||||
|
type Director {
|
||||||
|
id: ID!
|
||||||
|
name: String
|
||||||
|
movies: [Movie]
|
||||||
|
}
|
||||||
|
|
||||||
|
type Actor {
|
||||||
|
id: ID!
|
||||||
|
name: String
|
||||||
|
movies: [Movie]
|
||||||
|
}
|
||||||
|
|
||||||
|
type MovieActor {
|
||||||
|
id: ID!
|
||||||
|
actor_id: Int
|
||||||
|
movie_id: Int
|
||||||
|
actor: Actor
|
||||||
|
movie: Movie
|
||||||
|
}
|
||||||
|
|
||||||
|
type Genre {
|
||||||
|
id: ID!
|
||||||
|
name: String
|
||||||
|
movies: [Movie]
|
||||||
|
}
|
||||||
|
|
||||||
|
type GenreMovie {
|
||||||
|
id: ID!
|
||||||
|
movie_id: Int
|
||||||
|
genre_id: Int
|
||||||
|
movie: Movie
|
||||||
|
genre: Genre
|
||||||
|
}
|
||||||
|
|
||||||
|
type MovieResponse {
|
||||||
|
success: Boolean!
|
||||||
|
data: Movie
|
||||||
|
error: String
|
||||||
|
}
|
||||||
|
|
||||||
|
type AllMoviesResponse {
|
||||||
|
success: Boolean!
|
||||||
|
data: [Movie]
|
||||||
|
error: String
|
||||||
|
}
|
||||||
|
|
||||||
|
type ReviewResponse {
|
||||||
|
success: Boolean!
|
||||||
|
data: Review
|
||||||
|
error: String
|
||||||
|
}
|
||||||
|
|
||||||
|
type AllReviewsResponse {
|
||||||
|
success: Boolean!
|
||||||
|
data: [Review]
|
||||||
|
error: String
|
||||||
|
}
|
||||||
|
|
||||||
|
type DirectorResponse {
|
||||||
|
success: Boolean!
|
||||||
|
data: Director
|
||||||
|
error: String
|
||||||
|
}
|
||||||
|
|
||||||
|
type AllDirectorsResponse {
|
||||||
|
success: Boolean!
|
||||||
|
data: [Director]
|
||||||
|
error: String
|
||||||
|
}
|
||||||
|
|
||||||
|
type ActorResponse {
|
||||||
|
success: Boolean!
|
||||||
|
data: Actor
|
||||||
|
error: String
|
||||||
|
}
|
||||||
|
|
||||||
|
type AllActorsResponse {
|
||||||
|
success: Boolean!
|
||||||
|
data: [Actor]
|
||||||
|
error: String
|
||||||
|
}
|
||||||
|
|
||||||
|
extend type Query {
|
||||||
|
getMovie(id: ID!): MovieResponse!
|
||||||
|
getAllMovies: AllMoviesResponse!
|
||||||
|
getReview(id: ID!): ReviewResponse!
|
||||||
|
getAllReviews: AllReviewsResponse!
|
||||||
|
getDirector(id: ID!): DirectorResponse!
|
||||||
|
getAllDirectors: AllDirectorsResponse!
|
||||||
|
getActor(id: ID!): ActorResponse!
|
||||||
|
getAllActors: AllActorsResponse!
|
||||||
|
getMoviesWithReviewCount(minReviews: Int!): AllMoviesResponse!
|
||||||
|
}
|
||||||
|
|
||||||
|
extend type Mutation {
|
||||||
|
createMovie(
|
||||||
|
title: String!
|
||||||
|
director_id: Int
|
||||||
|
main_genre: String
|
||||||
|
status: Int
|
||||||
|
review: String
|
||||||
|
): MovieResponse!
|
||||||
|
updateMovie(
|
||||||
|
id: ID!
|
||||||
|
title: String
|
||||||
|
director_id: Int
|
||||||
|
main_genre: String
|
||||||
|
status: Int
|
||||||
|
review: String
|
||||||
|
): MovieResponse!
|
||||||
|
deleteMovie(id: ID!): MovieResponse!
|
||||||
|
|
||||||
|
createReview(notes: String!, movie_id: Int!): ReviewResponse!
|
||||||
|
updateReview(id: ID!, notes: String, movie_id: Int): ReviewResponse!
|
||||||
|
deleteReview(id: ID!): ReviewResponse!
|
||||||
|
|
||||||
|
createDirector(name: String!): DirectorResponse!
|
||||||
|
updateDirector(id: ID!, name: String): DirectorResponse!
|
||||||
|
deleteDirector(id: ID!): DirectorResponse!
|
||||||
|
|
||||||
|
createActor(name: String!): ActorResponse!
|
||||||
|
updateActor(id: ID!, name: String): ActorResponse!
|
||||||
|
deleteActor(id: ID!): ActorResponse!
|
||||||
|
|
||||||
|
addActorToMoviesByGenre(actor_id: Int!, genre_id: Int!): AllMoviesResponse!
|
||||||
|
}
|
||||||
|
|||||||
+16
-19
@@ -4,16 +4,16 @@
|
|||||||
* Module dependencies.
|
* Module dependencies.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
var app = require('../app');
|
var app = require("../app");
|
||||||
var debug = require('debug')('day-1:server');
|
var debug = require("debug")("day-1:server");
|
||||||
var http = require('http');
|
var http = require("http");
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get port from environment and store in Express.
|
* Get port from environment and store in Express.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
var port = normalizePort(process.env.PORT || '3000');
|
var port = normalizePort(process.env.PORT || "3000");
|
||||||
app.set('port', port);
|
app.set("port", port);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create HTTP server.
|
* Create HTTP server.
|
||||||
@@ -26,8 +26,8 @@ var server = http.createServer(app);
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
server.listen(port);
|
server.listen(port);
|
||||||
server.on('error', onError);
|
server.on("error", onError);
|
||||||
server.on('listening', onListening);
|
server.on("listening", onListening);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Normalize a port into a number, string, or false.
|
* Normalize a port into a number, string, or false.
|
||||||
@@ -54,22 +54,20 @@ function normalizePort(val) {
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
function onError(error) {
|
function onError(error) {
|
||||||
if (error.syscall !== 'listen') {
|
if (error.syscall !== "listen") {
|
||||||
throw error;
|
throw error;
|
||||||
}
|
}
|
||||||
|
|
||||||
var bind = typeof port === 'string'
|
var bind = typeof port === "string" ? "Pipe " + port : "Port " + port;
|
||||||
? 'Pipe ' + port
|
|
||||||
: 'Port ' + port;
|
|
||||||
|
|
||||||
// handle specific listen errors with friendly messages
|
// handle specific listen errors with friendly messages
|
||||||
switch (error.code) {
|
switch (error.code) {
|
||||||
case 'EACCES':
|
case "EACCES":
|
||||||
console.error(bind + ' requires elevated privileges');
|
console.error(bind + " requires elevated privileges");
|
||||||
process.exit(1);
|
process.exit(1);
|
||||||
break;
|
break;
|
||||||
case 'EADDRINUSE':
|
case "EADDRINUSE":
|
||||||
console.error(bind + ' is already in use');
|
console.error(bind + " is already in use");
|
||||||
process.exit(1);
|
process.exit(1);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
@@ -83,8 +81,7 @@ function onError(error) {
|
|||||||
|
|
||||||
function onListening() {
|
function onListening() {
|
||||||
var addr = server.address();
|
var addr = server.address();
|
||||||
var bind = typeof addr === 'string'
|
var bind = typeof addr === "string" ? "pipe " + addr : "port " + addr.port;
|
||||||
? 'pipe ' + addr
|
debug("Listening on " + bind);
|
||||||
: 'port ' + addr.port;
|
console.log("Server listening on ", bind);
|
||||||
debug('Listening on ' + bind);
|
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user