diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index cd37e6efb69cf9c8a0b4e813b2cc1e0c8a641f01..971e4e5e7a68d4608bd97943c3e9a2c269fb53ea 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -4,7 +4,6 @@ stages: # - test - build - deploy - - run cache: paths: @@ -60,20 +59,3 @@ pages: paths: - public - - -run_server: - only: - - master - stage: run - dependencies: - - build-client-pages - script: - - mv server public/server - - cd public/server - - ls - - npm install - - npm start - artifacts: - paths: - - public/server diff --git a/client/package-lock.json b/client/package-lock.json index dbab90095cdca69e639e5b8585005bd1b0c4d634..e34bfb0f2e6b1ee1f238ad31f2420d5b8c341f86 100644 --- a/client/package-lock.json +++ b/client/package-lock.json @@ -2229,6 +2229,12 @@ "@babel/types": "^7.3.0" } }, + "@types/cors": { + "version": "2.8.12", + "resolved": "https://registry.npmjs.org/@types/cors/-/cors-2.8.12.tgz", + "integrity": "sha512-vt+kDhq/M2ayberEtJcIN/hxXy1Pk+59g2FV/ZQceeaTyCtCucjL2Q7FXlFjtWn4n15KCr1NE2lNNFhp0lEThw==", + "dev": true + }, "@types/eslint": { "version": "7.28.1", "resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-7.28.1.tgz", diff --git a/client/package.json b/client/package.json index a9f7ff0a240bdc7fa241869ab1f9de0748a00bd8..792c678e7d3149578fd7bbe5ecc2d604d7971718 100644 --- a/client/package.json +++ b/client/package.json @@ -1,5 +1,5 @@ { - "homepage": "https://it2810-h21.pages.stud.idi.ntnu.no/team-54/project-3", + "homepage": "http://it2810-54.idi.ntnu.no", "name": "project-3", "version": "0.1.0", "private": true, @@ -47,6 +47,7 @@ ] }, "devDependencies": { - "@types/react-infinite-scroller": "^1.2.2" + "@types/react-infinite-scroller": "^1.2.2", + "@types/cors": "^2.8.12" } } diff --git a/server/package-lock.json b/server/package-lock.json index 117da5cc1974bd565e245c896f396088eb479d47..b53a57b0a877a2cadfd9ad385aa54c9826b8e06b 100644 --- a/server/package-lock.json +++ b/server/package-lock.json @@ -2292,6 +2292,12 @@ "@types/node": "*" } }, + "@types/cors": { + "version": "2.8.12", + "resolved": "https://registry.npmjs.org/@types/cors/-/cors-2.8.12.tgz", + "integrity": "sha512-vt+kDhq/M2ayberEtJcIN/hxXy1Pk+59g2FV/ZQceeaTyCtCucjL2Q7FXlFjtWn4n15KCr1NE2lNNFhp0lEThw==", + "dev": true + }, "@types/eslint": { "version": "7.28.1", "resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-7.28.1.tgz", @@ -4669,6 +4675,15 @@ "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz", "integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==" }, + "cors": { + "version": "2.8.5", + "resolved": "https://registry.npmjs.org/cors/-/cors-2.8.5.tgz", + "integrity": "sha512-KIHbLJqu73RGr/hnbrO9uBeixNGuvSQjul/jdFvS/KFSIH1hWVd1ng7zOHx+YrEfInLG7q4n6GHQ9cDtxv/P6g==", + "requires": { + "object-assign": "^4", + "vary": "^1" + } + }, "cosmiconfig": { "version": "7.0.1", "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-7.0.1.tgz", @@ -5513,11 +5528,6 @@ "is-obj": "^2.0.0" } }, - "dotenv": { - "version": "10.0.0", - "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-10.0.0.tgz", - "integrity": "sha512-rlBi9d8jpv9Sf1klPjNfFAuWDjKLwTIJJ/VxtoTwIR6hnZxcEOQCZg2oIL3MWBYw5GpUDKOEnND7LXTbIpQ03Q==" - }, "dotenv-expand": { "version": "5.1.0", "resolved": "https://registry.npmjs.org/dotenv-expand/-/dotenv-expand-5.1.0.tgz", diff --git a/server/package.json b/server/package.json index 363c2dfb84c2745ffee9b4bd352f9e93bb38f18d..0d98b02f3e549be5d8d9026691da6b910ea89148 100644 --- a/server/package.json +++ b/server/package.json @@ -12,7 +12,7 @@ "@types/node": "^12.20.33", "@types/react": "^17.0.28", "@types/react-dom": "^17.0.9", - "dotenv": "^10.0.0", + "cors": "^2.8.5", "express": "^4.17.1", "express-graphql": "^0.12.0", "graphql": "^15.6.1", @@ -28,7 +28,7 @@ }, "scripts": { "start": "nodemon src/server.ts --exec ts-node", - "build": "tsc --build", + "build": "tsc src/server.ts", "test": "react-scripts test", "eject": "react-scripts eject" }, @@ -49,5 +49,8 @@ "last 1 firefox version", "last 1 safari version" ] + }, + "devDependencies": { + "@types/cors": "^2.8.12" } -} +} \ No newline at end of file diff --git a/server/src/database.ts b/server/src/database.ts index 392f5432313fff688f1b20c1c1761531db1e4491..b34bf45a8edf087016e326da43b95e452589d1ba 100644 --- a/server/src/database.ts +++ b/server/src/database.ts @@ -1,6 +1,4 @@ import { createPool , Pool} from "mysql2/promise"; -import dotenv from 'dotenv' -dotenv.config({ path: ('../.env') }); export async function connect(): Promise<Pool>{ const connection = createPool({ diff --git a/server/src/server.ts b/server/src/server.ts index cee17fe8fc776c5bdfb637fa181bf09c5aed2562..319f68e4574ef356938ddc62a1c6b5ff5f4c6ec2 100644 --- a/server/src/server.ts +++ b/server/src/server.ts @@ -106,7 +106,7 @@ function getSearchQuery(title: string, genre: string, order: boolean): string { query = query + ' genre LIKE "%' + genre + '%"' } if (order) { - query = query + ' ORDER BY "year" DESC' + query = query + ' ORDER BY year DESC' } console.log(query) return query @@ -188,4 +188,4 @@ app.use('/graphql', graphqlHTTP({ graphiql: true, })); -app.listen(4000, () => console.log('Now browse to localhost:4000/graphql on local')); +app.listen(4000, () => console.log('Now browse to localhost:4000/graphql on local')); \ No newline at end of file diff --git a/server/src/server_build.ts b/server/src/server_build.ts new file mode 100644 index 0000000000000000000000000000000000000000..6b2072d83d1cbb93acc3f9f9695922d2f8347417 --- /dev/null +++ b/server/src/server_build.ts @@ -0,0 +1,217 @@ +declare var require: any +var express = require('express'); +var { graphqlHTTP } = require('express-graphql'); +var { GraphQLObjectType, GraphQLSchema, GraphQLInt, GraphQLString, GraphQLList, GraphQLBoolean } = require('graphql'); + +import {connect} from "./database" +import * as cors from 'cors'; + +const MovieType = new GraphQLObjectType({ + name: "Movie", + fields: () => ({ + id: { type: GraphQLString }, + title: { type: GraphQLString }, + genre: { type: GraphQLString }, + rating_dice_throw: { type: GraphQLInt }, + year: { type: GraphQLString }, + director_first_name: { type: GraphQLString }, + director_last_name: { type: GraphQLString }, + description: { type: GraphQLString }, + cover_image: { type: GraphQLString } + }) +}) + +const RootQuery = new GraphQLObjectType({ + name: "RootQueryType", + description: 'Root query', + fields: { + getAllMovies: { + type: new GraphQLList(MovieType), + args: { + lim: {type: GraphQLInt} + }, + async resolve(parent: any, args: any) { + const connection = await connect(); + const response = await connection.query('SELECT * FROM movie LIMIT '+args.lim); + return response[0]; + } + }, + getMovieByColumnType: { + type: new GraphQLList(MovieType), + args: { + id: { type: GraphQLInt }, + title: { type: GraphQLString }, + genre: { type: GraphQLString }, + rating_dice_throw: { type: GraphQLInt }, + year: { type: GraphQLString }, + director_first_name: { type: GraphQLString }, + director_last_name: { type: GraphQLString }, + description: { type: GraphQLString }, + }, + async resolve(parent: any, args: any) { + const connection = await connect(); + let query = ''; + if(typeof args.id!='undefined' && args.id){query = getQuery('id' , args.id)} + else if(typeof args.title!='undefined' && args.title){query = getQuery('title' , args.title)} + else if(typeof args.genre!='undefined' && args.genre){query = getQuery('genre' , args.genre)} + else if(typeof args.rating_dice_throw!='undefined' && args.rating_dice_throw){query = getQuery('rating_dice_throw' , args.rating_dice_throw)} + else if(typeof args.year!='undefined' && args.year){query = getQuery('year' , args.year)} + else if(typeof args.director_first_name!='undefined' && args.director_first_name){query = getQuery('director_first_name' , args.director_first_name)} + else if(typeof args.director_last_name!='undefined' && args.director_last_name){query = getQuery('director_last_name' , args.director_last_name)} + else if(typeof args.description!='undefined' && args.description){query = getQuery('description' , args.description)} + + const response = await connection.query(query); + return response[0]; + } + }, + getMoviesBySearch: { + type: new GraphQLList(MovieType), + args: { + id: {type: GraphQLInt}, + title: { type: GraphQLString }, + genre: { type: GraphQLString }, + rating_dice_throw: { type: GraphQLInt }, + year: { type: GraphQLInt }, + description: { type: GraphQLString }, + order: {type: GraphQLBoolean} + }, + async resolve(parent: any, args: any) { + const connection = await connect(); + let query = ''; + if(typeof args.title!='undefined' && typeof args.genre!='undefined'){ + console.log("resolve") + query = getSearchQuery(args.title, args.genre, args.order)} + const response = await connection.query(query); + return response[0]; + } + } + } +}) + +function getQuery(key: string, value: string){ + return 'SELECT * FROM movie WHERE ' + key + ' = "' + value + '"' +} + +function getSearchQuery(title: string, genre: string, order: boolean): string { + let query = 'SELECT * FROM movie' + if (title != '') { + query = query + ' WHERE title LIKE "%' + title + '%"' + } + if (title != '' && genre != '') { + query = query + ' AND' + } + if (title == '' && genre != '') { + query = query + ' WHERE' + } + if (genre != '') { + query = query + ' genre LIKE "%' + genre + '%"' + } + if (order) { + query = query + ' ORDER BY "year" DESC' + } + console.log(query) + return query +} + +const Mutation = new GraphQLObjectType({ + name: "Mutation", + description: 'This is for creating a movie', + fields: { + createMovie: { + type: MovieType, + args: { + id: {type: GraphQLInt}, + title: { type: GraphQLString }, + genre: { type: GraphQLString }, + rating_dice_throw: { type: GraphQLInt }, + year: { type: GraphQLInt }, + director_first_name: { type: GraphQLString }, + director_last_name: { type: GraphQLString }, + description: { type: GraphQLString }, + cover_image: { type: GraphQLString } + }, + async resolve(parent: any, args: any) { + const connection = await connect(); + const response = await connection.query('INSERT INTO movie VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)', [args.id, args.title, args.genre, args.rating_dice_throw, args.year, args.director_first_name, args.director_last_name, args.description, args.cover_image]); + return response[0]; + } + }, + deleteMovie: { + type: MovieType, + args: { + id: {type: GraphQLInt} + }, + async resolve(parent: any, args: any) { + const connection = await connect(); + const response = await connection.query('DELETE FROM movie WHERE id = ?', [args.id]); + return response[0]; + } + }, + updateMovie: { + type: MovieType, + args: { + id: {type: GraphQLInt}, + title: { type: GraphQLString }, + genre: { type: GraphQLString }, + rating_dice_throw: { type: GraphQLInt }, + year: { type: GraphQLInt }, + director_first_name: { type: GraphQLString }, + director_last_name: { type: GraphQLString }, + description: { type: GraphQLString }, + cover_image: { type: GraphQLString } + }, + async resolve(parent: any, args: any) { + const connection = await connect(); + const response = await connection.query('UPDATE movie SET title = ?, genre = ?, rating_dice_throw = ?, year = ?, director_first_name = ?, director_last_name = ? , description = ?, cover_image = ? WHERE id = ?', [args.title, args.genre, args.rating_dice_throw, args.year, args.director_first_name, args.director_last_name, args.description, args.cover_image, args.id]); + return response[0]; + } + }, + updateRating: { + type: MovieType, + args: { + id: {type: GraphQLInt}, + rating_dice_throw: { type: GraphQLInt } + }, + async resolve(parent: any, args: any) { + const connection = await connect(); + const response = await connection.query('UPDATE movie SET rating_dice_throw = ? WHERE id = ?', [args.genre, args.id]); + return response[0]; + } + } + } +}) + +const schema = new GraphQLSchema({query: RootQuery, mutation: Mutation}) + + +var app = express(); + +// Add headers +app.use(function (req, res, next) { + + // Website you wish to allow to connect + res.setHeader('Access-Control-Allow-Origin', '*'); + + // Request methods you wish to allow + res.setHeader('Access-Control-Allow-Methods', 'GET, POST, OPTIONS, PUT, PATCH, DELETE'); + + // Request headers you wish to allow + res.setHeader('Access-Control-Allow-Headers', 'X-Requested-With,content-type'); + + // Set to true if you need the website to include cookies in the requests sent + // to the API (e.g. in case you use sessions) + res.setHeader('Access-Control-Allow-Credentials', true); + + // Pass to next layer of middleware + next(); +}); + + +app.use(cors()); + +app.use('/graphql', graphqlHTTP({ + schema: schema, + graphiql: true, +})); + +app.listen(4000, () => console.log('Server running on port 4000'));