Compare commits
1 commit
main
...
will-come-
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
f347cf3ada |
135 changed files with 21136 additions and 27 deletions
17
.browserslistrc
Normal file
17
.browserslistrc
Normal file
|
|
@ -0,0 +1,17 @@
|
||||||
|
# This file is used by the build system to adjust CSS and JS output to support the specified browsers below.
|
||||||
|
# For additional information regarding the format and rule options, please see:
|
||||||
|
# https://github.com/browserslist/browserslist#queries
|
||||||
|
|
||||||
|
# For the full list of supported browsers by the Angular framework, please see:
|
||||||
|
# https://angular.io/guide/browser-support
|
||||||
|
|
||||||
|
# You can see what browsers were selected by your queries by running:
|
||||||
|
# npx browserslist
|
||||||
|
|
||||||
|
last 1 Chrome version
|
||||||
|
last 1 Firefox version
|
||||||
|
last 2 Edge major versions
|
||||||
|
last 2 Safari major versions
|
||||||
|
last 2 iOS major versions
|
||||||
|
Firefox ESR
|
||||||
|
not IE 11 # Angular supports IE 11 only as an opt-in. To opt-in, remove the 'not' prefix on this line.
|
||||||
16
.editorconfig
Normal file
16
.editorconfig
Normal file
|
|
@ -0,0 +1,16 @@
|
||||||
|
# Editor configuration, see https://editorconfig.org
|
||||||
|
root = true
|
||||||
|
|
||||||
|
[*]
|
||||||
|
charset = utf-8
|
||||||
|
indent_style = space
|
||||||
|
indent_size = 2
|
||||||
|
insert_final_newline = true
|
||||||
|
trim_trailing_whitespace = true
|
||||||
|
|
||||||
|
[*.ts]
|
||||||
|
quote_type = single
|
||||||
|
|
||||||
|
[*.md]
|
||||||
|
max_line_length = off
|
||||||
|
trim_trailing_whitespace = false
|
||||||
52
.gitignore
vendored
Normal file
52
.gitignore
vendored
Normal file
|
|
@ -0,0 +1,52 @@
|
||||||
|
# See http://help.github.com/ignore-files/ for more about ignoring files.
|
||||||
|
|
||||||
|
# compiled output
|
||||||
|
/dist
|
||||||
|
/tmp
|
||||||
|
/out-tsc
|
||||||
|
# Only exists if Bazel was run
|
||||||
|
/bazel-out
|
||||||
|
|
||||||
|
# dependencies
|
||||||
|
/node_modules
|
||||||
|
|
||||||
|
# profiling files
|
||||||
|
chrome-profiler-events*.json
|
||||||
|
speed-measure-plugin*.json
|
||||||
|
|
||||||
|
# IDEs and editors
|
||||||
|
/.idea
|
||||||
|
.project
|
||||||
|
.classpath
|
||||||
|
.c9/
|
||||||
|
*.launch
|
||||||
|
.settings/
|
||||||
|
*.sublime-workspace
|
||||||
|
|
||||||
|
# IDE - VSCode
|
||||||
|
.vscode/*
|
||||||
|
!.vscode/settings.json
|
||||||
|
!.vscode/tasks.json
|
||||||
|
!.vscode/launch.json
|
||||||
|
!.vscode/extensions.json
|
||||||
|
.history/*
|
||||||
|
|
||||||
|
# misc
|
||||||
|
/.sass-cache
|
||||||
|
/connect.lock
|
||||||
|
/coverage
|
||||||
|
/libpeerconnection.log
|
||||||
|
npm-debug.log
|
||||||
|
yarn-error.log
|
||||||
|
testem.log
|
||||||
|
/typings
|
||||||
|
*.env
|
||||||
|
|
||||||
|
# System Files
|
||||||
|
.DS_Store
|
||||||
|
Thumbs.db
|
||||||
|
|
||||||
|
/backend/database/
|
||||||
|
/backend/node_modules/
|
||||||
|
|
||||||
|
package-lock.json
|
||||||
6
Dockerfile
Normal file
6
Dockerfile
Normal file
|
|
@ -0,0 +1,6 @@
|
||||||
|
FROM node:current-slim
|
||||||
|
WORKDIR /app-frontend
|
||||||
|
COPY ["package.json", "package-lock.json*", "./"]
|
||||||
|
RUN npm install --NODE_ENV
|
||||||
|
RUN npm install -g @angular/cli
|
||||||
|
COPY . .
|
||||||
41
README.md
41
README.md
|
|
@ -1,40 +1,27 @@
|
||||||
# PolyNotFound
|
# Frontend
|
||||||
|
|
||||||
Le projet est séparé en 3 parties :
|
This project was generated with [Angular CLI](https://github.com/angular/angular-cli) version 11.2.7.
|
||||||
|
|
||||||
- 2 Frontend :
|
## Development server
|
||||||
- 1 partie Administrateur
|
|
||||||
- 1 partie pour les utilisateurs et les publicitaires
|
|
||||||
- 1 Backend
|
|
||||||
|
|
||||||
Nous avons décidé que chaque partie du projet a sa propre branche git et non leur propre répertoire git.
|
Run `ng serve` for a dev server. Navigate to `http://localhost:4200/`. The app will automatically reload if you change any of the source files.
|
||||||
|
|
||||||
En effet, les branches concernées par le projet est :
|
## Code scaffolding
|
||||||
- Frontend partie Administrateur : `front-admin`
|
|
||||||
- Frontend partie pour les utilisateurs et les publicitaires : `front-user-advertiser`
|
|
||||||
- Backend : `backend`
|
|
||||||
|
|
||||||
Nous pouvons récupérer une branche git avec `git checkout <nom_branche>`.
|
Run `ng generate component component-name` to generate a new component. You can also use `ng generate directive|pipe|service|class|guard|interface|enum|module`.
|
||||||
|
|
||||||
# Lancer le projet en Local
|
## Build
|
||||||
|
|
||||||
Dans un premier temps, il est obligatoire d'avoir NodeJS (version >12 au minimum), [téléchargeable sur cette page](https://nodejs.org/en/download/).
|
Run `ng build` to build the project. The build artifacts will be stored in the `dist/` directory. Use the `--prod` flag for a production build.
|
||||||
|
|
||||||
Pour lancer le projet en local dans son ensemble, il faut impérativement avoir les branches concernées dans leur propre dossier.
|
## Running unit tests
|
||||||
Il faudra donc __clone__ le projet 3 fois.
|
|
||||||
|
|
||||||
Dans un dossier nommé par exemple `Polynotfound`:
|
Run `ng test` to execute the unit tests via [Karma](https://karma-runner.github.io).
|
||||||
- frontend-admin : `git clone --branch frontend-admin https://github.com/NyxiumYuuki/PolyNotFound.git polynotfound-frontend-admin`
|
|
||||||
- front-user-advertiser : `git clone --branch front-user-advertiser https://github.com/NyxiumYuuki/PolyNotFound.git polynotfound-front-user-advertiser`
|
|
||||||
- backend : `git clone --branch backend https://github.com/NyxiumYuuki/PolyNotFound.git polynotfound-backend`
|
|
||||||
|
|
||||||
Un README est disponible pour chaque branche pour lancer le projet en local soit en mode **production** soit en mode **développement**.
|
## Running end-to-end tests
|
||||||
|
|
||||||
# Lancer le projet en ligne avec Heroku
|
Run `ng e2e` to execute the end-to-end tests via [Protractor](http://www.protractortest.org/).
|
||||||
|
|
||||||
Nous avons déployé le projet en ligne avec Heroku.
|
## Further help
|
||||||
|
|
||||||
Le projet est disponible sur ces URL :
|
To get more help on the Angular CLI use `ng help` or go check out the [Angular CLI Overview and Command Reference](https://angular.io/cli) page.
|
||||||
- Partie Utilisateurs et Publicitaires : https://polynotfound.herokuapp.com/
|
|
||||||
- Partie Administrateur : https://admin-polynotfound.herokuapp.com/
|
|
||||||
- API : https://api-polynotfound.herokuapp.com/
|
|
||||||
|
|
|
||||||
134
angular.json
Normal file
134
angular.json
Normal file
|
|
@ -0,0 +1,134 @@
|
||||||
|
{
|
||||||
|
"$schema": "./node_modules/@angular/cli/lib/config/schema.json",
|
||||||
|
"cli": {
|
||||||
|
"analytics": "90bb0e32-0eff-4d99-b0f4-059efdd1bfd9"
|
||||||
|
},
|
||||||
|
"version": 1,
|
||||||
|
"newProjectRoot": "projects",
|
||||||
|
"projects": {
|
||||||
|
"frontend": {
|
||||||
|
"projectType": "application",
|
||||||
|
"schematics": {
|
||||||
|
"@schematics/angular:component": {
|
||||||
|
"style": "scss"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"root": "",
|
||||||
|
"sourceRoot": "src",
|
||||||
|
"prefix": "app",
|
||||||
|
"architect": {
|
||||||
|
"build": {
|
||||||
|
"builder": "@angular-devkit/build-angular:browser",
|
||||||
|
"options": {
|
||||||
|
"outputPath": "dist/frontend",
|
||||||
|
"index": "src/index.html",
|
||||||
|
"main": "src/main.ts",
|
||||||
|
"polyfills": "src/polyfills.ts",
|
||||||
|
"tsConfig": "tsconfig.app.json",
|
||||||
|
"aot": true,
|
||||||
|
"assets": [
|
||||||
|
"src/favicon.ico",
|
||||||
|
"src/assets"
|
||||||
|
],
|
||||||
|
"styles": [
|
||||||
|
"./node_modules/@angular/material/prebuilt-themes/indigo-pink.css",
|
||||||
|
"src/styles.scss",
|
||||||
|
"node_modules/bootstrap/scss/bootstrap.scss"
|
||||||
|
],
|
||||||
|
"scripts": []
|
||||||
|
},
|
||||||
|
"configurations": {
|
||||||
|
"production": {
|
||||||
|
"fileReplacements": [
|
||||||
|
{
|
||||||
|
"replace": "src/environments/environment.ts",
|
||||||
|
"with": "src/environments/environment.prod.ts"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"optimization": true,
|
||||||
|
"outputHashing": "all",
|
||||||
|
"sourceMap": false,
|
||||||
|
"namedChunks": false,
|
||||||
|
"extractLicenses": true,
|
||||||
|
"vendorChunk": false,
|
||||||
|
"buildOptimizer": true,
|
||||||
|
"budgets": [
|
||||||
|
{
|
||||||
|
"type": "initial",
|
||||||
|
"maximumWarning": "2mb",
|
||||||
|
"maximumError": "5mb"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "anyComponentStyle",
|
||||||
|
"maximumWarning": "6kb",
|
||||||
|
"maximumError": "10kb"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"serve": {
|
||||||
|
"builder": "@angular-devkit/build-angular:dev-server",
|
||||||
|
"options": {
|
||||||
|
"browserTarget": "frontend:build"
|
||||||
|
},
|
||||||
|
"configurations": {
|
||||||
|
"production": {
|
||||||
|
"browserTarget": "frontend:build:production"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"extract-i18n": {
|
||||||
|
"builder": "@angular-devkit/build-angular:extract-i18n",
|
||||||
|
"options": {
|
||||||
|
"browserTarget": "frontend:build"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"test": {
|
||||||
|
"builder": "@angular-devkit/build-angular:karma",
|
||||||
|
"options": {
|
||||||
|
"main": "src/test.ts",
|
||||||
|
"polyfills": "src/polyfills.ts",
|
||||||
|
"tsConfig": "tsconfig.spec.json",
|
||||||
|
"karmaConfig": "karma.conf.js",
|
||||||
|
"assets": [
|
||||||
|
"src/favicon.ico",
|
||||||
|
"src/assets"
|
||||||
|
],
|
||||||
|
"styles": [
|
||||||
|
"./node_modules/@angular/material/prebuilt-themes/indigo-pink.css",
|
||||||
|
"src/styles.scss"
|
||||||
|
],
|
||||||
|
"scripts": []
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"lint": {
|
||||||
|
"builder": "@angular-devkit/build-angular:tslint",
|
||||||
|
"options": {
|
||||||
|
"tsConfig": [
|
||||||
|
"tsconfig.app.json",
|
||||||
|
"tsconfig.spec.json",
|
||||||
|
"e2e/tsconfig.json"
|
||||||
|
],
|
||||||
|
"exclude": [
|
||||||
|
"**/node_modules/**"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"e2e": {
|
||||||
|
"builder": "@angular-devkit/build-angular:protractor",
|
||||||
|
"options": {
|
||||||
|
"protractorConfig": "e2e/protractor.conf.js",
|
||||||
|
"devServerTarget": "frontend:serve"
|
||||||
|
},
|
||||||
|
"configurations": {
|
||||||
|
"production": {
|
||||||
|
"devServerTarget": "frontend:serve:production"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"defaultProject": "frontend"
|
||||||
|
}
|
||||||
7
backend/Dockerfile
Normal file
7
backend/Dockerfile
Normal file
|
|
@ -0,0 +1,7 @@
|
||||||
|
FROM node:current-slim
|
||||||
|
WORKDIR /app-backend
|
||||||
|
COPY ["package.json", "package-lock.json*", "./"]
|
||||||
|
RUN npm install
|
||||||
|
COPY . .
|
||||||
|
CMD ./app/jwtRS256.sh
|
||||||
|
CMD node server.js
|
||||||
8
backend/app/config/host.config.js
Normal file
8
backend/app/config/host.config.js
Normal file
|
|
@ -0,0 +1,8 @@
|
||||||
|
module.exports = {
|
||||||
|
youtube: {
|
||||||
|
baseAPIUrl: 'https://www.youtube.com/'
|
||||||
|
},
|
||||||
|
dailymotion: {
|
||||||
|
baseAPIUrl: 'https://api.dailymotion.com/'
|
||||||
|
}
|
||||||
|
};
|
||||||
3
backend/app/config/mongodb.config.js
Normal file
3
backend/app/config/mongodb.config.js
Normal file
|
|
@ -0,0 +1,3 @@
|
||||||
|
module.exports = {
|
||||||
|
url: "mongodb://127.0.0.1:27017/polynotfound"
|
||||||
|
};
|
||||||
9
backend/app/config/response.config.js
Normal file
9
backend/app/config/response.config.js
Normal file
|
|
@ -0,0 +1,9 @@
|
||||||
|
function sendMessage (res, successCode, data, token=null) {
|
||||||
|
res.status(200).json({ status: 'success', successCode: successCode, token: token, data: data });
|
||||||
|
}
|
||||||
|
|
||||||
|
function sendError (res, statusCode, errorCode, reason, token=null) {
|
||||||
|
res.status(statusCode).json({ status: 'error', errorCode: errorCode, data: { token: token, reason: reason }});
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = { sendMessage, sendError };
|
||||||
5
backend/app/config/role.config.js
Normal file
5
backend/app/config/role.config.js
Normal file
|
|
@ -0,0 +1,5 @@
|
||||||
|
module.exports = {
|
||||||
|
User: 0,
|
||||||
|
Advertiser: 5,
|
||||||
|
Admin: 10
|
||||||
|
};
|
||||||
99
backend/app/config/sessionJWT.config.js
Normal file
99
backend/app/config/sessionJWT.config.js
Normal file
|
|
@ -0,0 +1,99 @@
|
||||||
|
const sessionJWTConfig = require ('jsonwebtoken');
|
||||||
|
require('dotenv').config({ path: './app/.env' });
|
||||||
|
const {sendError} = require ("./response.config");
|
||||||
|
|
||||||
|
if(process.env.JWTRS256_PRIVATE_KEY === undefined || process.env.JWTRS256_PUBLIC_KEY === undefined){
|
||||||
|
console.log('Error Env Variables');
|
||||||
|
process.exit();
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log('Env variables received');
|
||||||
|
const JWTRS256_PRIVATE_KEY = Buffer.from(process.env.JWTRS256_PRIVATE_KEY, 'base64').toString('utf-8');
|
||||||
|
const JWTRS256_PUBLIC_KEY = Buffer.from(process.env.JWTRS256_PUBLIC_KEY, 'base64').toString('utf-8');
|
||||||
|
|
||||||
|
|
||||||
|
function createSessionJWT (id, login, role) {
|
||||||
|
return sessionJWTConfig.sign(
|
||||||
|
{
|
||||||
|
id: id,
|
||||||
|
login: login,
|
||||||
|
role: role,
|
||||||
|
midExp: Math.floor(Date.now() / 1000) + 1800
|
||||||
|
},
|
||||||
|
JWTRS256_PRIVATE_KEY,
|
||||||
|
{
|
||||||
|
algorithm: 'RS256',
|
||||||
|
expiresIn: '1h'
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function createSessionCookie(req, res, payload) {
|
||||||
|
let jwtToken;
|
||||||
|
if (typeof payload.id !== 'undefined' &&
|
||||||
|
typeof payload.login !== 'undefined' &&
|
||||||
|
typeof payload.role !== 'undefined' &&
|
||||||
|
typeof payload.midExp !== 'undefined' &&
|
||||||
|
(Math.floor(Date.now() / 1000) <= payload.midExp)) {
|
||||||
|
jwtToken = req.headers.cookie;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
jwtToken = createSessionJWT(payload.id, payload.login, payload.role);
|
||||||
|
}
|
||||||
|
res.cookie('SESSIONID', jwtToken, {httpOnly:true, secure:false});
|
||||||
|
}
|
||||||
|
|
||||||
|
function decodeSessionCookie(sessionid) {
|
||||||
|
if (typeof sessionid === 'undefined') {
|
||||||
|
return {id: -1, login: -1, role: -1};
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
const token = sessionJWTConfig.verify(
|
||||||
|
sessionid,
|
||||||
|
JWTRS256_PUBLIC_KEY,
|
||||||
|
{algorithms: ['RS256']});
|
||||||
|
return {token: token};
|
||||||
|
}
|
||||||
|
catch (err) {
|
||||||
|
return {id: -1, login: -1, role: -1};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function getSession(sessionid) {
|
||||||
|
return decodeSessionCookie(sessionid);
|
||||||
|
}
|
||||||
|
module.exports.getSession = getSession
|
||||||
|
|
||||||
|
function setSessionCookie (req, res, session) {
|
||||||
|
createSessionCookie(req, res, session);
|
||||||
|
}
|
||||||
|
module.exports.setSessionCookie = setSessionCookie;
|
||||||
|
|
||||||
|
function getToken(session) {
|
||||||
|
if (typeof session === 'undefined' || typeof session.token === 'undefined') return -1;
|
||||||
|
return session.token;
|
||||||
|
}
|
||||||
|
module.exports.getToken = getToken;
|
||||||
|
|
||||||
|
function checkLogin(req, res, role=null){
|
||||||
|
if(typeof req.cookies !== 'undefined'){
|
||||||
|
const session = getSession(req.cookies.SESSIONID);
|
||||||
|
const token = getToken(session);
|
||||||
|
if(token.login === 'undefined' || token.login === -1){
|
||||||
|
return sendError(res, 500, -1, "User not authenticated.");
|
||||||
|
} else{
|
||||||
|
if(role === null){
|
||||||
|
return token;
|
||||||
|
} else{
|
||||||
|
if(token.role !== 'undefined' && role.includes(token.role)){
|
||||||
|
return token;
|
||||||
|
} else{
|
||||||
|
return sendError(res, 500, -1, "User doesn't have permission.", token);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return sendError(res, 500, -1, "Cookies don't exist.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
module.exports.checkLogin = checkLogin;
|
||||||
53
backend/app/controllers/ad.controller.js
Normal file
53
backend/app/controllers/ad.controller.js
Normal file
|
|
@ -0,0 +1,53 @@
|
||||||
|
const db = require("../models/mongodb.model");
|
||||||
|
const {sendError, sendMessage} = require ("../config/response.config");
|
||||||
|
const {checkLogin} = require("../config/sessionJWT.config");
|
||||||
|
const roles = require("../config/role.config");
|
||||||
|
const Ads = db.ads;
|
||||||
|
|
||||||
|
// Create a new Ad
|
||||||
|
exports.create = (req, res) => {
|
||||||
|
const token = checkLogin(req, res, [roles.Admin, roles.Advertiser]);
|
||||||
|
if(token){
|
||||||
|
return sendError(res, 501, -1, "Ads.create not Implemented", token);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Retrieve all Ads
|
||||||
|
exports.findAll = (req, res) => {
|
||||||
|
const token = checkLogin(req, res);
|
||||||
|
if(token){
|
||||||
|
return sendError(res, 501, -1, "Ads.findAll not Implemented", token);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Retrieve a single Ad with id
|
||||||
|
exports.findOne = (req, res) => {
|
||||||
|
const token = checkLogin(req, res);
|
||||||
|
if(token){
|
||||||
|
return sendError(res, 501, -1, "Ads.findOne not Implemented", token);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Update a Ad with id
|
||||||
|
exports.update = (req, res) => {
|
||||||
|
const token = checkLogin(req, res, [roles.Admin, roles.Advertiser]);
|
||||||
|
if(token){
|
||||||
|
return sendError(res, 501, -1, "Ads.update not Implemented", token);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Delete a Ad with id
|
||||||
|
exports.delete = (req, res) => {
|
||||||
|
const token = checkLogin(req, res, [roles.Admin, roles.Advertiser]);
|
||||||
|
if(token){
|
||||||
|
return sendError(res, 501, -1, "Ads.delete not Implemented", token);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Delete all Ads
|
||||||
|
exports.deleteAll = (req, res) => {
|
||||||
|
const token = checkLogin(req, res, [roles.Admin, roles.Advertiser]);
|
||||||
|
if(token){
|
||||||
|
return sendError(res, 501, -1, "Ads.deleteAll not Implemented", token);
|
||||||
|
}
|
||||||
|
};
|
||||||
52
backend/app/controllers/playlist.controller.js
Normal file
52
backend/app/controllers/playlist.controller.js
Normal file
|
|
@ -0,0 +1,52 @@
|
||||||
|
const db = require("../models/mongodb.model");
|
||||||
|
const {sendError, sendMessage} = require ("../config/response.config");
|
||||||
|
const {checkLogin} = require("../config/sessionJWT.config");
|
||||||
|
const Playlist = db.playlists;
|
||||||
|
|
||||||
|
// Create a new Playlist
|
||||||
|
exports.create = (req, res) => {
|
||||||
|
const token = checkLogin(req, res);
|
||||||
|
if(token){
|
||||||
|
return sendError(res, 501, -1, "Playlist.create not Implemented", token);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Retrieve all Playlists
|
||||||
|
exports.findAll = (req, res) => {
|
||||||
|
const token = checkLogin(req, res);
|
||||||
|
if(token){
|
||||||
|
return sendError(res, 501, -1, "Playlist.findAll not Implemented", token);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Retrieve a single Playlist with id
|
||||||
|
exports.findOne = (req, res) => {
|
||||||
|
const token = checkLogin(req, res);
|
||||||
|
if(token){
|
||||||
|
return sendError(res, 501, -1, "Playlist.findOne not Implemented", token);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Update a Playlist with id
|
||||||
|
exports.update = (req, res) => {
|
||||||
|
const token = checkLogin(req, res);
|
||||||
|
if(token){
|
||||||
|
return sendError(res, 501, -1, "Playlist.update not Implemented", token);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Delete a Playlist with id
|
||||||
|
exports.delete = (req, res) => {
|
||||||
|
const token = checkLogin(req, res);
|
||||||
|
if(token){
|
||||||
|
return sendError(res, 501, -1, "Playlist.delete not Implemented", token);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Delete all Playlists
|
||||||
|
exports.deleteAll = (req, res) => {
|
||||||
|
const token = checkLogin(req, res);
|
||||||
|
if(token){
|
||||||
|
return sendError(res, 501, -1, "Playlist.deleteAll not Implemented", token);
|
||||||
|
}
|
||||||
|
};
|
||||||
175
backend/app/controllers/user.controller.js
Normal file
175
backend/app/controllers/user.controller.js
Normal file
|
|
@ -0,0 +1,175 @@
|
||||||
|
const db = require("../models/mongodb.model");
|
||||||
|
const {sendError, sendMessage} = require ("../config/response.config");
|
||||||
|
const {checkLogin, setSessionCookie} = require("../config/sessionJWT.config");
|
||||||
|
const roles = require("../config/role.config");
|
||||||
|
const User = db.users;
|
||||||
|
|
||||||
|
// Authenticate a User
|
||||||
|
exports.auth = (req, res) => {
|
||||||
|
// Validate request
|
||||||
|
if (!req.body.login || !req.body.hashPass) {
|
||||||
|
sendError(res, 400,-1,"Content can not be empty ! (login and hashPass needed)");
|
||||||
|
} else{
|
||||||
|
// Check User in the database
|
||||||
|
User
|
||||||
|
.findOne({login: req.body.login, hashPass: req.body.hashPass}, {role: true})
|
||||||
|
.then(data => {
|
||||||
|
if (data !== null){
|
||||||
|
setSessionCookie(req, res, {id: data._id, login: req.body.login, role: data.role});
|
||||||
|
return sendMessage(res, 1, true);
|
||||||
|
} else {
|
||||||
|
setSessionCookie(req, res, {id: -1, login: -1, role: -1 });
|
||||||
|
return sendError(res, 500, -1, "Invalid login or password.");
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.catch(err => {
|
||||||
|
sendError(res, 500,-1,err.message || "Some error occurred while authenticating the User.");
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Logout a User
|
||||||
|
exports.disconnect = (req, res) => {
|
||||||
|
const token = checkLogin(req, res);
|
||||||
|
if(token){
|
||||||
|
console.log(token);
|
||||||
|
setSessionCookie(req, res, {id: -1, login: -1, role: -1});
|
||||||
|
return sendMessage(res, 1, {message: "User disconnected"}, token);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Create and Save a new User
|
||||||
|
exports.create = (req, res) => {
|
||||||
|
// Validate request
|
||||||
|
if (!req.body.login || !req.body.hashPass || !req.body.mail) {
|
||||||
|
sendError(res, 400,-1,"Content can not be empty ! (login, hashPass and mail needed");
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
User.exists({login: req.body.login}, function (err, docs){
|
||||||
|
if(err){
|
||||||
|
sendError(res, 500,-1,err.message || "Some error occurred while checking if the User already exists.");
|
||||||
|
} else{
|
||||||
|
if(docs === null) {
|
||||||
|
const user = new User({
|
||||||
|
login: req.body.login,
|
||||||
|
hashPass: req.body.hashPass,
|
||||||
|
mail: req.body.mail,
|
||||||
|
role: req.body.role
|
||||||
|
});
|
||||||
|
|
||||||
|
// Save User in the database
|
||||||
|
user
|
||||||
|
.save(user)
|
||||||
|
.then(data => {
|
||||||
|
data.hashPass = undefined; // Hiding hashPass on return
|
||||||
|
sendMessage(res, 1, data)
|
||||||
|
})
|
||||||
|
.catch(err => {
|
||||||
|
sendError(res, 500,-1,err.message || "Some error occurred while creating the User.");
|
||||||
|
});
|
||||||
|
} else{
|
||||||
|
sendError(res, 500, -1, err || "User already exists.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Retrieve all Users from the database if admin.
|
||||||
|
exports.findAll = (req, res) => {
|
||||||
|
const token = checkLogin(req, res, [roles.Admin]);
|
||||||
|
if(token){
|
||||||
|
console.log(token);
|
||||||
|
const login = req.query.login;
|
||||||
|
let condition = login ? { login: { $regex: new RegExp(login), $options: "i" } } : {};
|
||||||
|
|
||||||
|
User.find(condition, {hashPass: false})
|
||||||
|
.then(data => {
|
||||||
|
sendMessage(res, 1, data, token)
|
||||||
|
})
|
||||||
|
.catch(err => {
|
||||||
|
sendError(res,500,-1,err.message || "Some error occurred while retrieving users.", token);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Find a single User with login if admin or login from cookie session
|
||||||
|
exports.findOne = (req, res) => {
|
||||||
|
const token = checkLogin(req, res);
|
||||||
|
if(token){
|
||||||
|
let login;
|
||||||
|
if(token.role === [roles.Admin]){
|
||||||
|
login = req.params.login;
|
||||||
|
|
||||||
|
} else{
|
||||||
|
login = token.login;
|
||||||
|
}
|
||||||
|
console.log(token.role, login);
|
||||||
|
User.find({login: login}, {hashPass: false})
|
||||||
|
.then(data => {
|
||||||
|
if (data){
|
||||||
|
sendMessage(res, 1, data);
|
||||||
|
} else {
|
||||||
|
sendError(res,404,-1,"Not found User with login " + login );
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.catch(err => {
|
||||||
|
sendError(res,500,-1,err.message || "Error retrieving User with login=" + login );
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Update a User by the id in the request
|
||||||
|
exports.update = (req, res) => {
|
||||||
|
if (!req.body) {
|
||||||
|
sendError(res,400,-1,"Data to update can not be empty!");
|
||||||
|
} else{
|
||||||
|
const id = req.params.id;
|
||||||
|
|
||||||
|
User.findByIdAndUpdate(id, req.body, { useFindAndModify: false })
|
||||||
|
.then(data => {
|
||||||
|
if (data) {
|
||||||
|
sendMessage(res, 1, { message: "User was updated successfully." });
|
||||||
|
} else {
|
||||||
|
sendError(res,404,-1,`Cannot update User with id=${id}. Maybe User was not found!`);
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.catch(err => {
|
||||||
|
sendError(res,500,-1,err.message || "Error updating User with id=" + id);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Delete a User with the specified id in the request
|
||||||
|
exports.delete = (req, res) => {
|
||||||
|
const id = req.params.id;
|
||||||
|
|
||||||
|
User.findByIdAndRemove(id)
|
||||||
|
.then(data => {
|
||||||
|
if (data) {
|
||||||
|
sendMessage(res, 1, { message: "User was deleted successfully!" });
|
||||||
|
} else {
|
||||||
|
sendError(res,404,-1,`Cannot delete User with id=${id}. Maybe User was not found!`);
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.catch(err => {
|
||||||
|
sendError(res,500,-1,err.message || "Could not delete User with id=" + id);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
// Delete all Users from the database.
|
||||||
|
exports.deleteAll = (req, res) => {
|
||||||
|
const token = checkLogin(req, res, [roles.Admin]);
|
||||||
|
if(token) {
|
||||||
|
console.log(token);
|
||||||
|
User.deleteMany({})
|
||||||
|
.then(data => {
|
||||||
|
sendMessage(res, 1, {
|
||||||
|
message: `${data.deletedCount} Users were deleted successfully!`
|
||||||
|
});
|
||||||
|
})
|
||||||
|
.catch(err => {
|
||||||
|
sendError(res, 500, -1, err.message || "Some error occurred while removing all Users.");
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
60
backend/app/controllers/video.controller.js
Normal file
60
backend/app/controllers/video.controller.js
Normal file
|
|
@ -0,0 +1,60 @@
|
||||||
|
const db = require("../models/mongodb.model");
|
||||||
|
const {sendError, sendMessage} = require ("../config/response.config");
|
||||||
|
const {checkLogin} = require("../config/sessionJWT.config");
|
||||||
|
const Video = db.video;
|
||||||
|
|
||||||
|
// Search Video
|
||||||
|
exports.search = (req, res) => {
|
||||||
|
const token = checkLogin(req, res);
|
||||||
|
if(token){
|
||||||
|
return sendError(res, 501, -1, "Video.search not Implemented", token);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Create a new Video
|
||||||
|
exports.create = (req, res) => {
|
||||||
|
const token = checkLogin(req, res);
|
||||||
|
if(token){
|
||||||
|
return sendError(res, 501, -1, "Video.create not Implemented", token);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Retrieve all Videos
|
||||||
|
exports.findAll = (req, res) => {
|
||||||
|
const token = checkLogin(req, res);
|
||||||
|
if(token){
|
||||||
|
return sendError(res, 501, -1, "Video.findAll not Implemented", token);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Retrieve a single Video with id
|
||||||
|
exports.findOne = (req, res) => {
|
||||||
|
const token = checkLogin(req, res);
|
||||||
|
if(token){
|
||||||
|
return sendError(res, 501, -1, "Video.findOne not Implemented", token);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Update a Video with id
|
||||||
|
exports.update = (req, res) => {
|
||||||
|
const token = checkLogin(req, res);
|
||||||
|
if(token){
|
||||||
|
return sendError(res, 501, -1, "Video.update not Implemented", token);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Delete a Video with id
|
||||||
|
exports.delete = (req, res) => {
|
||||||
|
const token = checkLogin(req, res);
|
||||||
|
if(token){
|
||||||
|
return sendError(res, 501, -1, "Video.delete not Implemented", token);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Delete all Videos
|
||||||
|
exports.deleteAll = (req, res) => {
|
||||||
|
const token = checkLogin(req, res);
|
||||||
|
if(token){
|
||||||
|
return sendError(res, 501, -1, "Video.deleteAll not Implemented", token);
|
||||||
|
}
|
||||||
|
};
|
||||||
14
backend/app/jwtRS256.key.pub
Normal file
14
backend/app/jwtRS256.key.pub
Normal file
|
|
@ -0,0 +1,14 @@
|
||||||
|
-----BEGIN PUBLIC KEY-----
|
||||||
|
MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAyTaN1skc89wdcz8SLY9c
|
||||||
|
lkcARENbO40DncmcUZwQEq+EYR9BzUhjIzKJ6JetU+qGt4SJQkPAczQbw8+LaF6P
|
||||||
|
NT0QTF6E6BUgTZg1p98E/208AiFDnoqEjmlLdQN7ekttJXGDrVOTds9WMbn8lVpa
|
||||||
|
4EpVc+8CPDmrSTIC2YVSZmmektmFTSUA6411+5FGlq5oUdyKkToWYdn/ViJbYst8
|
||||||
|
N48E2Vuh1ghY5t7oPWGzPibMc/6A+uDAF7+VVD8x5UydMZ9id+RxC7lhtDDvZeRM
|
||||||
|
BllHcnWfw0UMhVk8PC6/BenJ4I8HiOgyl4cypTvlevfbZjSoNJ4g/u/lDKpdqbBg
|
||||||
|
T76OksaYqvwvTrcvPdgF1f8l/7M9ESYZTMpxvqK6YvYC/MG2355fmZ1SeuqKfDt8
|
||||||
|
rQXfXzesGSNmFNkm8mORHYiXBqyuNAwnSqRtP8qfoB4yXZ2W1HjUf24TvkvMrqwT
|
||||||
|
7PFg55c/f4LVdPjx52z30QzBJmcyVZgzXNOCG1KafwBibhriQmhdfiWogs824mwI
|
||||||
|
9w0vG2pPqSHRAa6N1y9JHSP1rIfu1jzRNFWTUuqyKgLYBE47HqxxJ21BwBryTVUz
|
||||||
|
8Ei+o05lJFkQX2/ISFYP2RunfUBccqmv0nEcGr+RSLTeqz5+WUTWs8tQxUItf2p6
|
||||||
|
9Y30htlmCJlSnHn2JlaJWQUCAwEAAQ==
|
||||||
|
-----END PUBLIC KEY-----
|
||||||
8
backend/app/jwtRS256.sh
Normal file
8
backend/app/jwtRS256.sh
Normal file
|
|
@ -0,0 +1,8 @@
|
||||||
|
#!/usr/bin/env bash
|
||||||
|
ssh-keygen -t rsa -b 4096 -m PEM -f jwtRS256.key -q -N ""
|
||||||
|
openssl rsa -in jwtRS256.key -pubout -outform PEM -out jwtRS256.key.pub
|
||||||
|
rm .env
|
||||||
|
echo "JWTRS256_PRIVATE_KEY='`cat ./jwtRS256.key | base64 -w 0`'" >> .env
|
||||||
|
echo "JWTRS256_PUBLIC_KEY='`cat ./jwtRS256.key.pub | base64 -w 0`'" >> .env
|
||||||
|
source .env
|
||||||
|
rm jwtRS256.key
|
||||||
18
backend/app/models/ad.model.js
Normal file
18
backend/app/models/ad.model.js
Normal file
|
|
@ -0,0 +1,18 @@
|
||||||
|
module.exports = mongoose => {
|
||||||
|
let schema = mongoose.Schema({
|
||||||
|
images: [],
|
||||||
|
text: String,
|
||||||
|
subjectTarget: [],
|
||||||
|
seen: Number
|
||||||
|
},
|
||||||
|
{ timestamps: true }
|
||||||
|
);
|
||||||
|
|
||||||
|
schema.method("toJSON", function() {
|
||||||
|
const { __v, _id, ...object } = this.toObject();
|
||||||
|
object.id = _id;
|
||||||
|
return object;
|
||||||
|
});
|
||||||
|
|
||||||
|
return mongoose.model("ad", schema);
|
||||||
|
};
|
||||||
18
backend/app/models/image.model.js
Normal file
18
backend/app/models/image.model.js
Normal file
|
|
@ -0,0 +1,18 @@
|
||||||
|
module.exports = mongoose => {
|
||||||
|
let schema = mongoose.Schema({
|
||||||
|
base64: String,
|
||||||
|
fromUrl: String,
|
||||||
|
description: String,
|
||||||
|
type: Number
|
||||||
|
},
|
||||||
|
{ timestamps: true }
|
||||||
|
);
|
||||||
|
|
||||||
|
schema.method("toJSON", function() {
|
||||||
|
const { __v, _id, ...object } = this.toObject();
|
||||||
|
object.id = _id;
|
||||||
|
return object;
|
||||||
|
});
|
||||||
|
|
||||||
|
return mongoose.model("image", schema);
|
||||||
|
};
|
||||||
15
backend/app/models/mongodb.model.js
Normal file
15
backend/app/models/mongodb.model.js
Normal file
|
|
@ -0,0 +1,15 @@
|
||||||
|
const dbConfig = require("../config/mongodb.config");
|
||||||
|
|
||||||
|
const mongoose = require("mongoose");
|
||||||
|
mongoose.Promise = global.Promise;
|
||||||
|
|
||||||
|
const db = {};
|
||||||
|
db.mongoose = mongoose;
|
||||||
|
db.url = dbConfig.url;
|
||||||
|
db.users = require("./user.model")(mongoose);
|
||||||
|
db.playlists = require("./playlist.model")(mongoose);
|
||||||
|
db.videos = require("./video.model")(mongoose);
|
||||||
|
db.ads = require("./ad.model")(mongoose);
|
||||||
|
db.images = require("./image.model")(mongoose);
|
||||||
|
|
||||||
|
module.exports = db;
|
||||||
16
backend/app/models/playlist.model.js
Normal file
16
backend/app/models/playlist.model.js
Normal file
|
|
@ -0,0 +1,16 @@
|
||||||
|
module.exports = mongoose => {
|
||||||
|
let schema = mongoose.Schema({
|
||||||
|
name: String,
|
||||||
|
videos: []
|
||||||
|
},
|
||||||
|
{ timestamps: true }
|
||||||
|
);
|
||||||
|
|
||||||
|
schema.method("toJSON", function() {
|
||||||
|
const { __v, _id, ...object } = this.toObject();
|
||||||
|
object.id = _id;
|
||||||
|
return object;
|
||||||
|
});
|
||||||
|
|
||||||
|
return mongoose.model("playlist", schema);
|
||||||
|
};
|
||||||
16
backend/app/models/subjectTarget.model.js
Normal file
16
backend/app/models/subjectTarget.model.js
Normal file
|
|
@ -0,0 +1,16 @@
|
||||||
|
module.exports = mongoose => {
|
||||||
|
let schema = mongoose.Schema({
|
||||||
|
name: String,
|
||||||
|
keywords: []
|
||||||
|
},
|
||||||
|
{ timestamps: true }
|
||||||
|
);
|
||||||
|
|
||||||
|
schema.method("toJSON", function() {
|
||||||
|
const { __v, _id, ...object } = this.toObject();
|
||||||
|
object.id = _id;
|
||||||
|
return object;
|
||||||
|
});
|
||||||
|
|
||||||
|
return mongoose.model("subjectTarget", schema);
|
||||||
|
};
|
||||||
24
backend/app/models/user.model.js
Normal file
24
backend/app/models/user.model.js
Normal file
|
|
@ -0,0 +1,24 @@
|
||||||
|
const roles = require("../config/role.config");
|
||||||
|
|
||||||
|
module.exports = mongoose => {
|
||||||
|
let schema = mongoose.Schema({
|
||||||
|
login: String,
|
||||||
|
hashPass: String, // WARNING: We don't want to send back the hashPass
|
||||||
|
mail: String,
|
||||||
|
role: {
|
||||||
|
type: Number,
|
||||||
|
default: roles.User
|
||||||
|
},
|
||||||
|
playlists: []
|
||||||
|
},
|
||||||
|
{ timestamps: true }
|
||||||
|
);
|
||||||
|
|
||||||
|
schema.method("toJSON", function() {
|
||||||
|
const { __v, _id, ...object } = this.toObject();
|
||||||
|
object.id = _id;
|
||||||
|
return object;
|
||||||
|
});
|
||||||
|
|
||||||
|
return mongoose.model("user", schema);
|
||||||
|
};
|
||||||
18
backend/app/models/video.model.js
Normal file
18
backend/app/models/video.model.js
Normal file
|
|
@ -0,0 +1,18 @@
|
||||||
|
module.exports = mongoose => {
|
||||||
|
let schema = mongoose.Schema({
|
||||||
|
url: String,
|
||||||
|
title: String,
|
||||||
|
description: String,
|
||||||
|
views: Number
|
||||||
|
},
|
||||||
|
{ timestamps: true }
|
||||||
|
);
|
||||||
|
|
||||||
|
schema.method("toJSON", function() {
|
||||||
|
const { __v, _id, ...object } = this.toObject();
|
||||||
|
object.id = _id;
|
||||||
|
return object;
|
||||||
|
});
|
||||||
|
|
||||||
|
return mongoose.model("video", schema);
|
||||||
|
};
|
||||||
24
backend/app/routes/ad.routes.js
Normal file
24
backend/app/routes/ad.routes.js
Normal file
|
|
@ -0,0 +1,24 @@
|
||||||
|
const ads = require("../controllers/ad.controller");
|
||||||
|
module.exports = app => {
|
||||||
|
let router = require("express").Router();
|
||||||
|
|
||||||
|
// Create a new Ad
|
||||||
|
router.post("/user/ad", ads.create);
|
||||||
|
|
||||||
|
// Retrieve all Ads
|
||||||
|
router.get("/user/ad", ads.findAll);
|
||||||
|
|
||||||
|
// Retrieve a single Ad with id
|
||||||
|
router.get("/user/ad/:id", ads.findOne);
|
||||||
|
|
||||||
|
// Update an Ad with id
|
||||||
|
router.put("/user/ad/:id", ads.update);
|
||||||
|
|
||||||
|
// Delete an Ad with id
|
||||||
|
router.delete("/user/ad/:id", ads.delete);
|
||||||
|
|
||||||
|
// Delete all Ads
|
||||||
|
router.delete("/user/ad", ads.deleteAll);
|
||||||
|
|
||||||
|
app.use('/api', router);
|
||||||
|
};
|
||||||
24
backend/app/routes/playlist.routes.js
Normal file
24
backend/app/routes/playlist.routes.js
Normal file
|
|
@ -0,0 +1,24 @@
|
||||||
|
const playlists = require("../controllers/playlist.controller");
|
||||||
|
module.exports = app => {
|
||||||
|
let router = require("express").Router();
|
||||||
|
|
||||||
|
// Create a new Playlist
|
||||||
|
router.post("/user/playlist", playlists.create);
|
||||||
|
|
||||||
|
// Retrieve all Playlists
|
||||||
|
router.get("/user/playlists", playlists.findAll);
|
||||||
|
|
||||||
|
// Retrieve a single Playlist with id
|
||||||
|
router.get("/user/playlist/:id", playlists.findOne);
|
||||||
|
|
||||||
|
// Update a Playlist with id
|
||||||
|
router.put("/user/playlist/:id", playlists.update);
|
||||||
|
|
||||||
|
// Delete a Playlist with id
|
||||||
|
router.delete("/user/playlist/:id", playlists.delete);
|
||||||
|
|
||||||
|
// Delete all Playlists
|
||||||
|
router.delete("/user/playlists", playlists.deleteAll);
|
||||||
|
|
||||||
|
app.use('/api', router);
|
||||||
|
};
|
||||||
30
backend/app/routes/user.routes.js
Normal file
30
backend/app/routes/user.routes.js
Normal file
|
|
@ -0,0 +1,30 @@
|
||||||
|
const users = require("../controllers/user.controller");
|
||||||
|
module.exports = app => {
|
||||||
|
let router = require("express").Router();
|
||||||
|
|
||||||
|
// Create a new User
|
||||||
|
router.post("/user", users.create);
|
||||||
|
|
||||||
|
// Retrieve all Users
|
||||||
|
router.get("/users", users.findAll);
|
||||||
|
|
||||||
|
// Retrieve a single User with id
|
||||||
|
router.get("/user/:id", users.findOne);
|
||||||
|
|
||||||
|
// Update a User with id
|
||||||
|
router.put("/user/:id", users.update);
|
||||||
|
|
||||||
|
// Delete a User with id
|
||||||
|
router.delete("/user/:id", users.delete);
|
||||||
|
|
||||||
|
// Delete all Users
|
||||||
|
router.delete("/users", users.deleteAll);
|
||||||
|
|
||||||
|
// Authenticate a User
|
||||||
|
router.post("/user/auth", users.auth);
|
||||||
|
|
||||||
|
// Logout a User
|
||||||
|
router.delete("/user/logout", users.disconnect);
|
||||||
|
|
||||||
|
app.use('/api', router);
|
||||||
|
};
|
||||||
27
backend/app/routes/video.routes.js
Normal file
27
backend/app/routes/video.routes.js
Normal file
|
|
@ -0,0 +1,27 @@
|
||||||
|
const videos = require("../controllers/video.controller");
|
||||||
|
module.exports = app => {
|
||||||
|
let router = require("express").Router();
|
||||||
|
|
||||||
|
// Search Video
|
||||||
|
router.post("/videos", videos.search);
|
||||||
|
|
||||||
|
// Create a new Video
|
||||||
|
router.post("/video", videos.create);
|
||||||
|
|
||||||
|
// Retrieve all Videos
|
||||||
|
router.get("/videos", videos.findAll);
|
||||||
|
|
||||||
|
// Retrieve a single Video with id
|
||||||
|
router.get("/video/:id", videos.findOne);
|
||||||
|
|
||||||
|
// Update a Video with id
|
||||||
|
router.put("/video/:id", videos.update);
|
||||||
|
|
||||||
|
// Delete a Video with id
|
||||||
|
router.delete("/video/:id", videos.delete);
|
||||||
|
|
||||||
|
// Delete all Videos
|
||||||
|
router.delete("/videos", videos.deleteAll);
|
||||||
|
|
||||||
|
app.use('/api', router);
|
||||||
|
};
|
||||||
724
backend/package-lock.json
generated
Normal file
724
backend/package-lock.json
generated
Normal file
|
|
@ -0,0 +1,724 @@
|
||||||
|
{
|
||||||
|
"name": "backend",
|
||||||
|
"version": "1.0.0",
|
||||||
|
"lockfileVersion": 1,
|
||||||
|
"requires": true,
|
||||||
|
"dependencies": {
|
||||||
|
"@types/node": {
|
||||||
|
"version": "16.11.6",
|
||||||
|
"resolved": "https://registry.npmjs.org/@types/node/-/node-16.11.6.tgz",
|
||||||
|
"integrity": "sha512-ua7PgUoeQFjmWPcoo9khiPum3Pd60k4/2ZGXt18sm2Slk0W0xZTqt5Y0Ny1NyBiN1EVQ/+FaF9NcY4Qe6rwk5w=="
|
||||||
|
},
|
||||||
|
"@types/webidl-conversions": {
|
||||||
|
"version": "6.1.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/@types/webidl-conversions/-/webidl-conversions-6.1.1.tgz",
|
||||||
|
"integrity": "sha512-XAahCdThVuCFDQLT7R7Pk/vqeObFNL3YqRyFZg+AqAP/W1/w3xHaIxuW7WszQqTbIBOPRcItYJIou3i/mppu3Q=="
|
||||||
|
},
|
||||||
|
"@types/whatwg-url": {
|
||||||
|
"version": "8.2.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/@types/whatwg-url/-/whatwg-url-8.2.1.tgz",
|
||||||
|
"integrity": "sha512-2YubE1sjj5ifxievI5Ge1sckb9k/Er66HyR2c+3+I6VDUUg1TLPdYYTEbQ+DjRkS4nTxMJhgWfSfMRD2sl2EYQ==",
|
||||||
|
"requires": {
|
||||||
|
"@types/node": "*",
|
||||||
|
"@types/webidl-conversions": "*"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"accepts": {
|
||||||
|
"version": "1.3.7",
|
||||||
|
"resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.7.tgz",
|
||||||
|
"integrity": "sha512-Il80Qs2WjYlJIBNzNkK6KYqlVMTbZLXgHx2oT0pU/fjRHyEp+PEfEPY0R3WCwAGVOtauxh1hOxNgIf5bv7dQpA==",
|
||||||
|
"requires": {
|
||||||
|
"mime-types": "~2.1.24",
|
||||||
|
"negotiator": "0.6.2"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"array-flatten": {
|
||||||
|
"version": "1.1.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz",
|
||||||
|
"integrity": "sha1-ml9pkFGx5wczKPKgCJaLZOopVdI="
|
||||||
|
},
|
||||||
|
"base64-js": {
|
||||||
|
"version": "1.5.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz",
|
||||||
|
"integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA=="
|
||||||
|
},
|
||||||
|
"body-parser": {
|
||||||
|
"version": "1.19.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.19.0.tgz",
|
||||||
|
"integrity": "sha512-dhEPs72UPbDnAQJ9ZKMNTP6ptJaionhP5cBb541nXPlW60Jepo9RV/a4fX4XWW9CuFNK22krhrj1+rgzifNCsw==",
|
||||||
|
"requires": {
|
||||||
|
"bytes": "3.1.0",
|
||||||
|
"content-type": "~1.0.4",
|
||||||
|
"debug": "2.6.9",
|
||||||
|
"depd": "~1.1.2",
|
||||||
|
"http-errors": "1.7.2",
|
||||||
|
"iconv-lite": "0.4.24",
|
||||||
|
"on-finished": "~2.3.0",
|
||||||
|
"qs": "6.7.0",
|
||||||
|
"raw-body": "2.4.0",
|
||||||
|
"type-is": "~1.6.17"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"debug": {
|
||||||
|
"version": "2.6.9",
|
||||||
|
"resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
|
||||||
|
"integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
|
||||||
|
"requires": {
|
||||||
|
"ms": "2.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"ms": {
|
||||||
|
"version": "2.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
|
||||||
|
"integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g="
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"bson": {
|
||||||
|
"version": "4.5.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/bson/-/bson-4.5.3.tgz",
|
||||||
|
"integrity": "sha512-qVX7LX79Mtj7B3NPLzCfBiCP6RAsjiV8N63DjlaVVpZW+PFoDTxQ4SeDbSpcqgE6mXksM5CAwZnXxxxn/XwC0g==",
|
||||||
|
"requires": {
|
||||||
|
"buffer": "^5.6.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"buffer": {
|
||||||
|
"version": "5.7.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz",
|
||||||
|
"integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==",
|
||||||
|
"requires": {
|
||||||
|
"base64-js": "^1.3.1",
|
||||||
|
"ieee754": "^1.1.13"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"buffer-equal-constant-time": {
|
||||||
|
"version": "1.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz",
|
||||||
|
"integrity": "sha1-+OcRMvf/5uAaXJaXpMbz5I1cyBk="
|
||||||
|
},
|
||||||
|
"bytes": {
|
||||||
|
"version": "3.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.0.tgz",
|
||||||
|
"integrity": "sha512-zauLjrfCG+xvoyaqLoV8bLVXXNGC4JqlxFCutSDWA6fJrTo2ZuvLYTqZ7aHBLZSMOopbzwv8f+wZcVzfVTI2Dg=="
|
||||||
|
},
|
||||||
|
"content-disposition": {
|
||||||
|
"version": "0.5.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.3.tgz",
|
||||||
|
"integrity": "sha512-ExO0774ikEObIAEV9kDo50o+79VCUdEB6n6lzKgGwupcVeRlhrj3qGAfwq8G6uBJjkqLrhT0qEYFcWng8z1z0g==",
|
||||||
|
"requires": {
|
||||||
|
"safe-buffer": "5.1.2"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"content-type": {
|
||||||
|
"version": "1.0.4",
|
||||||
|
"resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.4.tgz",
|
||||||
|
"integrity": "sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA=="
|
||||||
|
},
|
||||||
|
"cookie": {
|
||||||
|
"version": "0.4.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/cookie/-/cookie-0.4.0.tgz",
|
||||||
|
"integrity": "sha512-+Hp8fLp57wnUSt0tY0tHEXh4voZRDnoIrZPqlo3DPiI4y9lwg/jqx+1Om94/W6ZaPDOUbnjOt/99w66zk+l1Xg=="
|
||||||
|
},
|
||||||
|
"cookie-parser": {
|
||||||
|
"version": "1.4.5",
|
||||||
|
"resolved": "https://registry.npmjs.org/cookie-parser/-/cookie-parser-1.4.5.tgz",
|
||||||
|
"integrity": "sha512-f13bPUj/gG/5mDr+xLmSxxDsB9DQiTIfhJS/sqjrmfAWiAN+x2O4i/XguTL9yDZ+/IFDanJ+5x7hC4CXT9Tdzw==",
|
||||||
|
"requires": {
|
||||||
|
"cookie": "0.4.0",
|
||||||
|
"cookie-signature": "1.0.6"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"cookie-signature": {
|
||||||
|
"version": "1.0.6",
|
||||||
|
"resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz",
|
||||||
|
"integrity": "sha1-4wOogrNCzD7oylE6eZmXNNqzriw="
|
||||||
|
},
|
||||||
|
"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"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"debug": {
|
||||||
|
"version": "4.3.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/debug/-/debug-4.3.2.tgz",
|
||||||
|
"integrity": "sha512-mOp8wKcvj7XxC78zLgw/ZA+6TSgkoE2C/ienthhRD298T7UNwAg9diBpLRxC0mOezLl4B0xV7M0cCO6P/O0Xhw==",
|
||||||
|
"requires": {
|
||||||
|
"ms": "2.1.2"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"denque": {
|
||||||
|
"version": "2.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/denque/-/denque-2.0.1.tgz",
|
||||||
|
"integrity": "sha512-tfiWc6BQLXNLpNiR5iGd0Ocu3P3VpxfzFiqubLgMfhfOw9WyvgJBd46CClNn9k3qfbjvT//0cf7AlYRX/OslMQ=="
|
||||||
|
},
|
||||||
|
"depd": {
|
||||||
|
"version": "1.1.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz",
|
||||||
|
"integrity": "sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak="
|
||||||
|
},
|
||||||
|
"destroy": {
|
||||||
|
"version": "1.0.4",
|
||||||
|
"resolved": "https://registry.npmjs.org/destroy/-/destroy-1.0.4.tgz",
|
||||||
|
"integrity": "sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA="
|
||||||
|
},
|
||||||
|
"dotenv": {
|
||||||
|
"version": "10.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/dotenv/-/dotenv-10.0.0.tgz",
|
||||||
|
"integrity": "sha512-rlBi9d8jpv9Sf1klPjNfFAuWDjKLwTIJJ/VxtoTwIR6hnZxcEOQCZg2oIL3MWBYw5GpUDKOEnND7LXTbIpQ03Q=="
|
||||||
|
},
|
||||||
|
"ecdsa-sig-formatter": {
|
||||||
|
"version": "1.0.11",
|
||||||
|
"resolved": "https://registry.npmjs.org/ecdsa-sig-formatter/-/ecdsa-sig-formatter-1.0.11.tgz",
|
||||||
|
"integrity": "sha512-nagl3RYrbNv6kQkeJIpt6NJZy8twLB/2vtz6yN9Z4vRKHN4/QZJIEbqohALSgwKdnksuY3k5Addp5lg8sVoVcQ==",
|
||||||
|
"requires": {
|
||||||
|
"safe-buffer": "^5.0.1"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"ee-first": {
|
||||||
|
"version": "1.1.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz",
|
||||||
|
"integrity": "sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0="
|
||||||
|
},
|
||||||
|
"encodeurl": {
|
||||||
|
"version": "1.0.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz",
|
||||||
|
"integrity": "sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k="
|
||||||
|
},
|
||||||
|
"escape-html": {
|
||||||
|
"version": "1.0.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz",
|
||||||
|
"integrity": "sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg="
|
||||||
|
},
|
||||||
|
"etag": {
|
||||||
|
"version": "1.8.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz",
|
||||||
|
"integrity": "sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc="
|
||||||
|
},
|
||||||
|
"express": {
|
||||||
|
"version": "4.17.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/express/-/express-4.17.1.tgz",
|
||||||
|
"integrity": "sha512-mHJ9O79RqluphRrcw2X/GTh3k9tVv8YcoyY4Kkh4WDMUYKRZUq0h1o0w2rrrxBqM7VoeUVqgb27xlEMXTnYt4g==",
|
||||||
|
"requires": {
|
||||||
|
"accepts": "~1.3.7",
|
||||||
|
"array-flatten": "1.1.1",
|
||||||
|
"body-parser": "1.19.0",
|
||||||
|
"content-disposition": "0.5.3",
|
||||||
|
"content-type": "~1.0.4",
|
||||||
|
"cookie": "0.4.0",
|
||||||
|
"cookie-signature": "1.0.6",
|
||||||
|
"debug": "2.6.9",
|
||||||
|
"depd": "~1.1.2",
|
||||||
|
"encodeurl": "~1.0.2",
|
||||||
|
"escape-html": "~1.0.3",
|
||||||
|
"etag": "~1.8.1",
|
||||||
|
"finalhandler": "~1.1.2",
|
||||||
|
"fresh": "0.5.2",
|
||||||
|
"merge-descriptors": "1.0.1",
|
||||||
|
"methods": "~1.1.2",
|
||||||
|
"on-finished": "~2.3.0",
|
||||||
|
"parseurl": "~1.3.3",
|
||||||
|
"path-to-regexp": "0.1.7",
|
||||||
|
"proxy-addr": "~2.0.5",
|
||||||
|
"qs": "6.7.0",
|
||||||
|
"range-parser": "~1.2.1",
|
||||||
|
"safe-buffer": "5.1.2",
|
||||||
|
"send": "0.17.1",
|
||||||
|
"serve-static": "1.14.1",
|
||||||
|
"setprototypeof": "1.1.1",
|
||||||
|
"statuses": "~1.5.0",
|
||||||
|
"type-is": "~1.6.18",
|
||||||
|
"utils-merge": "1.0.1",
|
||||||
|
"vary": "~1.1.2"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"debug": {
|
||||||
|
"version": "2.6.9",
|
||||||
|
"resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
|
||||||
|
"integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
|
||||||
|
"requires": {
|
||||||
|
"ms": "2.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"ms": {
|
||||||
|
"version": "2.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
|
||||||
|
"integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g="
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"finalhandler": {
|
||||||
|
"version": "1.1.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.1.2.tgz",
|
||||||
|
"integrity": "sha512-aAWcW57uxVNrQZqFXjITpW3sIUQmHGG3qSb9mUah9MgMC4NeWhNOlNjXEYq3HjRAvL6arUviZGGJsBg6z0zsWA==",
|
||||||
|
"requires": {
|
||||||
|
"debug": "2.6.9",
|
||||||
|
"encodeurl": "~1.0.2",
|
||||||
|
"escape-html": "~1.0.3",
|
||||||
|
"on-finished": "~2.3.0",
|
||||||
|
"parseurl": "~1.3.3",
|
||||||
|
"statuses": "~1.5.0",
|
||||||
|
"unpipe": "~1.0.0"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"debug": {
|
||||||
|
"version": "2.6.9",
|
||||||
|
"resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
|
||||||
|
"integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
|
||||||
|
"requires": {
|
||||||
|
"ms": "2.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"ms": {
|
||||||
|
"version": "2.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
|
||||||
|
"integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g="
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"forwarded": {
|
||||||
|
"version": "0.2.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz",
|
||||||
|
"integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow=="
|
||||||
|
},
|
||||||
|
"fresh": {
|
||||||
|
"version": "0.5.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz",
|
||||||
|
"integrity": "sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac="
|
||||||
|
},
|
||||||
|
"http-errors": {
|
||||||
|
"version": "1.7.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.7.2.tgz",
|
||||||
|
"integrity": "sha512-uUQBt3H/cSIVfch6i1EuPNy/YsRSOUBXTVfZ+yR7Zjez3qjBz6i9+i4zjNaoqcoFVI4lQJ5plg63TvGfRSDCRg==",
|
||||||
|
"requires": {
|
||||||
|
"depd": "~1.1.2",
|
||||||
|
"inherits": "2.0.3",
|
||||||
|
"setprototypeof": "1.1.1",
|
||||||
|
"statuses": ">= 1.5.0 < 2",
|
||||||
|
"toidentifier": "1.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"iconv-lite": {
|
||||||
|
"version": "0.4.24",
|
||||||
|
"resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz",
|
||||||
|
"integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==",
|
||||||
|
"requires": {
|
||||||
|
"safer-buffer": ">= 2.1.2 < 3"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"ieee754": {
|
||||||
|
"version": "1.2.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz",
|
||||||
|
"integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA=="
|
||||||
|
},
|
||||||
|
"inherits": {
|
||||||
|
"version": "2.0.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz",
|
||||||
|
"integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4="
|
||||||
|
},
|
||||||
|
"ipaddr.js": {
|
||||||
|
"version": "1.9.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz",
|
||||||
|
"integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g=="
|
||||||
|
},
|
||||||
|
"jsonwebtoken": {
|
||||||
|
"version": "8.5.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/jsonwebtoken/-/jsonwebtoken-8.5.1.tgz",
|
||||||
|
"integrity": "sha512-XjwVfRS6jTMsqYs0EsuJ4LGxXV14zQybNd4L2r0UvbVnSF9Af8x7p5MzbJ90Ioz/9TI41/hTCvznF/loiSzn8w==",
|
||||||
|
"requires": {
|
||||||
|
"jws": "^3.2.2",
|
||||||
|
"lodash.includes": "^4.3.0",
|
||||||
|
"lodash.isboolean": "^3.0.3",
|
||||||
|
"lodash.isinteger": "^4.0.4",
|
||||||
|
"lodash.isnumber": "^3.0.3",
|
||||||
|
"lodash.isplainobject": "^4.0.6",
|
||||||
|
"lodash.isstring": "^4.0.1",
|
||||||
|
"lodash.once": "^4.0.0",
|
||||||
|
"ms": "^2.1.1",
|
||||||
|
"semver": "^5.6.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"jwa": {
|
||||||
|
"version": "1.4.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/jwa/-/jwa-1.4.1.tgz",
|
||||||
|
"integrity": "sha512-qiLX/xhEEFKUAJ6FiBMbes3w9ATzyk5W7Hvzpa/SLYdxNtng+gcurvrI7TbACjIXlsJyr05/S1oUhZrc63evQA==",
|
||||||
|
"requires": {
|
||||||
|
"buffer-equal-constant-time": "1.0.1",
|
||||||
|
"ecdsa-sig-formatter": "1.0.11",
|
||||||
|
"safe-buffer": "^5.0.1"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"jws": {
|
||||||
|
"version": "3.2.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/jws/-/jws-3.2.2.tgz",
|
||||||
|
"integrity": "sha512-YHlZCB6lMTllWDtSPHz/ZXTsi8S00usEV6v1tjq8tOUZzw7DpSDWVXjXDre6ed1w/pd495ODpHZYSdkRTsa0HA==",
|
||||||
|
"requires": {
|
||||||
|
"jwa": "^1.4.1",
|
||||||
|
"safe-buffer": "^5.0.1"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"kareem": {
|
||||||
|
"version": "2.3.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/kareem/-/kareem-2.3.2.tgz",
|
||||||
|
"integrity": "sha512-STHz9P7X2L4Kwn72fA4rGyqyXdmrMSdxqHx9IXon/FXluXieaFA6KJ2upcHAHxQPQ0LeM/OjLrhFxifHewOALQ=="
|
||||||
|
},
|
||||||
|
"lodash.includes": {
|
||||||
|
"version": "4.3.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/lodash.includes/-/lodash.includes-4.3.0.tgz",
|
||||||
|
"integrity": "sha1-YLuYqHy5I8aMoeUTJUgzFISfVT8="
|
||||||
|
},
|
||||||
|
"lodash.isboolean": {
|
||||||
|
"version": "3.0.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/lodash.isboolean/-/lodash.isboolean-3.0.3.tgz",
|
||||||
|
"integrity": "sha1-bC4XHbKiV82WgC/UOwGyDV9YcPY="
|
||||||
|
},
|
||||||
|
"lodash.isinteger": {
|
||||||
|
"version": "4.0.4",
|
||||||
|
"resolved": "https://registry.npmjs.org/lodash.isinteger/-/lodash.isinteger-4.0.4.tgz",
|
||||||
|
"integrity": "sha1-YZwK89A/iwTDH1iChAt3sRzWg0M="
|
||||||
|
},
|
||||||
|
"lodash.isnumber": {
|
||||||
|
"version": "3.0.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/lodash.isnumber/-/lodash.isnumber-3.0.3.tgz",
|
||||||
|
"integrity": "sha1-POdoEMWSjQM1IwGsKHMX8RwLH/w="
|
||||||
|
},
|
||||||
|
"lodash.isplainobject": {
|
||||||
|
"version": "4.0.6",
|
||||||
|
"resolved": "https://registry.npmjs.org/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz",
|
||||||
|
"integrity": "sha1-fFJqUtibRcRcxpC4gWO+BJf1UMs="
|
||||||
|
},
|
||||||
|
"lodash.isstring": {
|
||||||
|
"version": "4.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/lodash.isstring/-/lodash.isstring-4.0.1.tgz",
|
||||||
|
"integrity": "sha1-1SfftUVuynzJu5XV2ur4i6VKVFE="
|
||||||
|
},
|
||||||
|
"lodash.once": {
|
||||||
|
"version": "4.1.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/lodash.once/-/lodash.once-4.1.1.tgz",
|
||||||
|
"integrity": "sha1-DdOXEhPHxW34gJd9UEyI+0cal6w="
|
||||||
|
},
|
||||||
|
"media-typer": {
|
||||||
|
"version": "0.3.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz",
|
||||||
|
"integrity": "sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g="
|
||||||
|
},
|
||||||
|
"memory-pager": {
|
||||||
|
"version": "1.5.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/memory-pager/-/memory-pager-1.5.0.tgz",
|
||||||
|
"integrity": "sha512-ZS4Bp4r/Zoeq6+NLJpP+0Zzm0pR8whtGPf1XExKLJBAczGMnSi3It14OiNCStjQjM6NU1okjQGSxgEZN8eBYKg==",
|
||||||
|
"optional": true
|
||||||
|
},
|
||||||
|
"merge-descriptors": {
|
||||||
|
"version": "1.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz",
|
||||||
|
"integrity": "sha1-sAqqVW3YtEVoFQ7J0blT8/kMu2E="
|
||||||
|
},
|
||||||
|
"methods": {
|
||||||
|
"version": "1.1.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz",
|
||||||
|
"integrity": "sha1-VSmk1nZUE07cxSZmVoNbD4Ua/O4="
|
||||||
|
},
|
||||||
|
"mime": {
|
||||||
|
"version": "1.6.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz",
|
||||||
|
"integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg=="
|
||||||
|
},
|
||||||
|
"mime-db": {
|
||||||
|
"version": "1.50.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.50.0.tgz",
|
||||||
|
"integrity": "sha512-9tMZCDlYHqeERXEHO9f/hKfNXhre5dK2eE/krIvUjZbS2KPcqGDfNShIWS1uW9XOTKQKqK6qbeOci18rbfW77A=="
|
||||||
|
},
|
||||||
|
"mime-types": {
|
||||||
|
"version": "2.1.33",
|
||||||
|
"resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.33.tgz",
|
||||||
|
"integrity": "sha512-plLElXp7pRDd0bNZHw+nMd52vRYjLwQjygaNg7ddJ2uJtTlmnTCjWuPKxVu6//AdaRuME84SvLW91sIkBqGT0g==",
|
||||||
|
"requires": {
|
||||||
|
"mime-db": "1.50.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"mongodb": {
|
||||||
|
"version": "4.1.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/mongodb/-/mongodb-4.1.3.tgz",
|
||||||
|
"integrity": "sha512-lHvTqODBiSpuqjpCj48DOyYWS6Iq6ElJNUiH9HWdQtONyOfjgsKzJULipWduMGsSzaNO4nFi/kmlMFCLvjox/Q==",
|
||||||
|
"requires": {
|
||||||
|
"bson": "^4.5.2",
|
||||||
|
"denque": "^2.0.1",
|
||||||
|
"mongodb-connection-string-url": "^2.0.0",
|
||||||
|
"saslprep": "^1.0.3"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"mongodb-connection-string-url": {
|
||||||
|
"version": "2.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/mongodb-connection-string-url/-/mongodb-connection-string-url-2.1.0.tgz",
|
||||||
|
"integrity": "sha512-Qf9Zw7KGiRljWvMrrUFDdVqo46KIEiDuCzvEN97rh/PcKzk2bd6n9KuzEwBwW9xo5glwx69y1mI6s+jFUD/aIQ==",
|
||||||
|
"requires": {
|
||||||
|
"@types/whatwg-url": "^8.2.1",
|
||||||
|
"whatwg-url": "^9.1.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"mongoose": {
|
||||||
|
"version": "6.0.12",
|
||||||
|
"resolved": "https://registry.npmjs.org/mongoose/-/mongoose-6.0.12.tgz",
|
||||||
|
"integrity": "sha512-BvsZk7zEEhb1AgQFLtxN9C+7qgy5edRuA3ZDDwHU+kHG/HM44vI6FdKV5m6HVdAUeCHHQTiVv+YQh8BRsToSHw==",
|
||||||
|
"requires": {
|
||||||
|
"bson": "^4.2.2",
|
||||||
|
"kareem": "2.3.2",
|
||||||
|
"mongodb": "4.1.3",
|
||||||
|
"mpath": "0.8.4",
|
||||||
|
"mquery": "4.0.0",
|
||||||
|
"ms": "2.1.2",
|
||||||
|
"regexp-clone": "1.0.0",
|
||||||
|
"sift": "13.5.2",
|
||||||
|
"sliced": "1.0.1"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"mpath": {
|
||||||
|
"version": "0.8.4",
|
||||||
|
"resolved": "https://registry.npmjs.org/mpath/-/mpath-0.8.4.tgz",
|
||||||
|
"integrity": "sha512-DTxNZomBcTWlrMW76jy1wvV37X/cNNxPW1y2Jzd4DZkAaC5ZGsm8bfGfNOthcDuRJujXLqiuS6o3Tpy0JEoh7g=="
|
||||||
|
},
|
||||||
|
"mquery": {
|
||||||
|
"version": "4.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/mquery/-/mquery-4.0.0.tgz",
|
||||||
|
"integrity": "sha512-nGjm89lHja+T/b8cybAby6H0YgA4qYC/lx6UlwvHGqvTq8bDaNeCwl1sY8uRELrNbVWJzIihxVd+vphGGn1vBw==",
|
||||||
|
"requires": {
|
||||||
|
"debug": "4.x",
|
||||||
|
"regexp-clone": "^1.0.0",
|
||||||
|
"sliced": "1.0.1"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"ms": {
|
||||||
|
"version": "2.1.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
|
||||||
|
"integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w=="
|
||||||
|
},
|
||||||
|
"negotiator": {
|
||||||
|
"version": "0.6.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.2.tgz",
|
||||||
|
"integrity": "sha512-hZXc7K2e+PgeI1eDBe/10Ard4ekbfrrqG8Ep+8Jmf4JID2bNg7NvCPOZN+kfF574pFQI7mum2AUqDidoKqcTOw=="
|
||||||
|
},
|
||||||
|
"object-assign": {
|
||||||
|
"version": "4.1.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz",
|
||||||
|
"integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM="
|
||||||
|
},
|
||||||
|
"on-finished": {
|
||||||
|
"version": "2.3.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz",
|
||||||
|
"integrity": "sha1-IPEzZIGwg811M3mSoWlxqi2QaUc=",
|
||||||
|
"requires": {
|
||||||
|
"ee-first": "1.1.1"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"parseurl": {
|
||||||
|
"version": "1.3.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz",
|
||||||
|
"integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ=="
|
||||||
|
},
|
||||||
|
"path-to-regexp": {
|
||||||
|
"version": "0.1.7",
|
||||||
|
"resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz",
|
||||||
|
"integrity": "sha1-32BBeABfUi8V60SQ5yR6G/qmf4w="
|
||||||
|
},
|
||||||
|
"proxy-addr": {
|
||||||
|
"version": "2.0.7",
|
||||||
|
"resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz",
|
||||||
|
"integrity": "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==",
|
||||||
|
"requires": {
|
||||||
|
"forwarded": "0.2.0",
|
||||||
|
"ipaddr.js": "1.9.1"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"punycode": {
|
||||||
|
"version": "2.1.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz",
|
||||||
|
"integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A=="
|
||||||
|
},
|
||||||
|
"qs": {
|
||||||
|
"version": "6.7.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/qs/-/qs-6.7.0.tgz",
|
||||||
|
"integrity": "sha512-VCdBRNFTX1fyE7Nb6FYoURo/SPe62QCaAyzJvUjwRaIsc+NePBEniHlvxFmmX56+HZphIGtV0XeCirBtpDrTyQ=="
|
||||||
|
},
|
||||||
|
"range-parser": {
|
||||||
|
"version": "1.2.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz",
|
||||||
|
"integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg=="
|
||||||
|
},
|
||||||
|
"raw-body": {
|
||||||
|
"version": "2.4.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.4.0.tgz",
|
||||||
|
"integrity": "sha512-4Oz8DUIwdvoa5qMJelxipzi/iJIi40O5cGV1wNYp5hvZP8ZN0T+jiNkL0QepXs+EsQ9XJ8ipEDoiH70ySUJP3Q==",
|
||||||
|
"requires": {
|
||||||
|
"bytes": "3.1.0",
|
||||||
|
"http-errors": "1.7.2",
|
||||||
|
"iconv-lite": "0.4.24",
|
||||||
|
"unpipe": "1.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"regexp-clone": {
|
||||||
|
"version": "1.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/regexp-clone/-/regexp-clone-1.0.0.tgz",
|
||||||
|
"integrity": "sha512-TuAasHQNamyyJ2hb97IuBEif4qBHGjPHBS64sZwytpLEqtBQ1gPJTnOaQ6qmpET16cK14kkjbazl6+p0RRv0yw=="
|
||||||
|
},
|
||||||
|
"safe-buffer": {
|
||||||
|
"version": "5.1.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz",
|
||||||
|
"integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g=="
|
||||||
|
},
|
||||||
|
"safer-buffer": {
|
||||||
|
"version": "2.1.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz",
|
||||||
|
"integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg=="
|
||||||
|
},
|
||||||
|
"saslprep": {
|
||||||
|
"version": "1.0.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/saslprep/-/saslprep-1.0.3.tgz",
|
||||||
|
"integrity": "sha512-/MY/PEMbk2SuY5sScONwhUDsV2p77Znkb/q3nSVstq/yQzYJOH/Azh29p9oJLsl3LnQwSvZDKagDGBsBwSooag==",
|
||||||
|
"optional": true,
|
||||||
|
"requires": {
|
||||||
|
"sparse-bitfield": "^3.0.3"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"semver": {
|
||||||
|
"version": "5.7.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz",
|
||||||
|
"integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ=="
|
||||||
|
},
|
||||||
|
"send": {
|
||||||
|
"version": "0.17.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/send/-/send-0.17.1.tgz",
|
||||||
|
"integrity": "sha512-BsVKsiGcQMFwT8UxypobUKyv7irCNRHk1T0G680vk88yf6LBByGcZJOTJCrTP2xVN6yI+XjPJcNuE3V4fT9sAg==",
|
||||||
|
"requires": {
|
||||||
|
"debug": "2.6.9",
|
||||||
|
"depd": "~1.1.2",
|
||||||
|
"destroy": "~1.0.4",
|
||||||
|
"encodeurl": "~1.0.2",
|
||||||
|
"escape-html": "~1.0.3",
|
||||||
|
"etag": "~1.8.1",
|
||||||
|
"fresh": "0.5.2",
|
||||||
|
"http-errors": "~1.7.2",
|
||||||
|
"mime": "1.6.0",
|
||||||
|
"ms": "2.1.1",
|
||||||
|
"on-finished": "~2.3.0",
|
||||||
|
"range-parser": "~1.2.1",
|
||||||
|
"statuses": "~1.5.0"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"debug": {
|
||||||
|
"version": "2.6.9",
|
||||||
|
"resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
|
||||||
|
"integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
|
||||||
|
"requires": {
|
||||||
|
"ms": "2.0.0"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"ms": {
|
||||||
|
"version": "2.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
|
||||||
|
"integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g="
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"ms": {
|
||||||
|
"version": "2.1.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz",
|
||||||
|
"integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg=="
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"serve-static": {
|
||||||
|
"version": "1.14.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.14.1.tgz",
|
||||||
|
"integrity": "sha512-JMrvUwE54emCYWlTI+hGrGv5I8dEwmco/00EvkzIIsR7MqrHonbD9pO2MOfFnpFntl7ecpZs+3mW+XbQZu9QCg==",
|
||||||
|
"requires": {
|
||||||
|
"encodeurl": "~1.0.2",
|
||||||
|
"escape-html": "~1.0.3",
|
||||||
|
"parseurl": "~1.3.3",
|
||||||
|
"send": "0.17.1"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"setprototypeof": {
|
||||||
|
"version": "1.1.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.1.tgz",
|
||||||
|
"integrity": "sha512-JvdAWfbXeIGaZ9cILp38HntZSFSo3mWg6xGcJJsd+d4aRMOqauag1C63dJfDw7OaMYwEbHMOxEZ1lqVRYP2OAw=="
|
||||||
|
},
|
||||||
|
"sift": {
|
||||||
|
"version": "13.5.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/sift/-/sift-13.5.2.tgz",
|
||||||
|
"integrity": "sha512-+gxdEOMA2J+AI+fVsCqeNn7Tgx3M9ZN9jdi95939l1IJ8cZsqS8sqpJyOkic2SJk+1+98Uwryt/gL6XDaV+UZA=="
|
||||||
|
},
|
||||||
|
"sliced": {
|
||||||
|
"version": "1.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/sliced/-/sliced-1.0.1.tgz",
|
||||||
|
"integrity": "sha1-CzpmK10Ewxd7GSa+qCsD+Dei70E="
|
||||||
|
},
|
||||||
|
"sparse-bitfield": {
|
||||||
|
"version": "3.0.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/sparse-bitfield/-/sparse-bitfield-3.0.3.tgz",
|
||||||
|
"integrity": "sha1-/0rm5oZWBWuks+eSqzM004JzyhE=",
|
||||||
|
"optional": true,
|
||||||
|
"requires": {
|
||||||
|
"memory-pager": "^1.0.2"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"statuses": {
|
||||||
|
"version": "1.5.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz",
|
||||||
|
"integrity": "sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow="
|
||||||
|
},
|
||||||
|
"toidentifier": {
|
||||||
|
"version": "1.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.0.tgz",
|
||||||
|
"integrity": "sha512-yaOH/Pk/VEhBWWTlhI+qXxDFXlejDGcQipMlyxda9nthulaxLZUNcUqFxokp0vcYnvteJln5FNQDRrxj3YcbVw=="
|
||||||
|
},
|
||||||
|
"tr46": {
|
||||||
|
"version": "2.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/tr46/-/tr46-2.1.0.tgz",
|
||||||
|
"integrity": "sha512-15Ih7phfcdP5YxqiB+iDtLoaTz4Nd35+IiAv0kQ5FNKHzXgdWqPoTIqEDDJmXceQt4JZk6lVPT8lnDlPpGDppw==",
|
||||||
|
"requires": {
|
||||||
|
"punycode": "^2.1.1"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"type-is": {
|
||||||
|
"version": "1.6.18",
|
||||||
|
"resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz",
|
||||||
|
"integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==",
|
||||||
|
"requires": {
|
||||||
|
"media-typer": "0.3.0",
|
||||||
|
"mime-types": "~2.1.24"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"unpipe": {
|
||||||
|
"version": "1.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz",
|
||||||
|
"integrity": "sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw="
|
||||||
|
},
|
||||||
|
"utils-merge": {
|
||||||
|
"version": "1.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz",
|
||||||
|
"integrity": "sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM="
|
||||||
|
},
|
||||||
|
"vary": {
|
||||||
|
"version": "1.1.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz",
|
||||||
|
"integrity": "sha1-IpnwLG3tMNSllhsLn3RSShj2NPw="
|
||||||
|
},
|
||||||
|
"webidl-conversions": {
|
||||||
|
"version": "6.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-6.1.0.tgz",
|
||||||
|
"integrity": "sha512-qBIvFLGiBpLjfwmYAaHPXsn+ho5xZnGvyGvsarywGNc8VyQJUMHJ8OBKGGrPER0okBeMDaan4mNBlgBROxuI8w=="
|
||||||
|
},
|
||||||
|
"whatwg-url": {
|
||||||
|
"version": "9.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-9.1.0.tgz",
|
||||||
|
"integrity": "sha512-CQ0UcrPHyomtlOCot1TL77WyMIm/bCwrJ2D6AOKGwEczU9EpyoqAokfqrf/MioU9kHcMsmJZcg1egXix2KYEsA==",
|
||||||
|
"requires": {
|
||||||
|
"tr46": "^2.1.0",
|
||||||
|
"webidl-conversions": "^6.1.0"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
21
backend/package.json
Normal file
21
backend/package.json
Normal file
|
|
@ -0,0 +1,21 @@
|
||||||
|
{
|
||||||
|
"name": "backend",
|
||||||
|
"version": "1.0.0",
|
||||||
|
"description": "",
|
||||||
|
"main": "server.js",
|
||||||
|
"scripts": {
|
||||||
|
"test": "echo \"Error: no test specified\" && exit 1"
|
||||||
|
},
|
||||||
|
"author": "Yûki Vachot",
|
||||||
|
"license": "ISC",
|
||||||
|
"dependencies": {
|
||||||
|
"body-parser": "^1.19.0",
|
||||||
|
"cookie-parser": "^1.4.5",
|
||||||
|
"cors": "^2.8.5",
|
||||||
|
"dotenv": "^10.0.0",
|
||||||
|
"express": "^4.17.1",
|
||||||
|
"jsonwebtoken": "^8.5.1",
|
||||||
|
"mongoose": "^6.0.12"
|
||||||
|
},
|
||||||
|
"devDependencies": {}
|
||||||
|
}
|
||||||
36
backend/server.js
Normal file
36
backend/server.js
Normal file
|
|
@ -0,0 +1,36 @@
|
||||||
|
const express = require('express');
|
||||||
|
const app = express();
|
||||||
|
const port = process.env.PORT || 3000;
|
||||||
|
|
||||||
|
const cookieParser = require('cookie-parser');
|
||||||
|
app.use(cookieParser());
|
||||||
|
|
||||||
|
const bodyParser = require('body-parser');
|
||||||
|
app.use(bodyParser.urlencoded({extended:true}));
|
||||||
|
app.use(bodyParser.json());
|
||||||
|
|
||||||
|
const cors = require('cors');
|
||||||
|
app.use(cors({origin: 'http://localhost:4200', credentials: true}));
|
||||||
|
|
||||||
|
const db = require("./app/models/mongodb.model");
|
||||||
|
db.mongoose
|
||||||
|
.connect(db.url, {
|
||||||
|
useNewUrlParser: true,
|
||||||
|
useUnifiedTopology: true
|
||||||
|
}, function (err){
|
||||||
|
if(err){
|
||||||
|
console.log("Cannot connect to the database!", err);
|
||||||
|
process.exit();
|
||||||
|
} else{
|
||||||
|
console.log("Connected to the database!", db.url);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
require("./app/routes/user.routes")(app);
|
||||||
|
require("./app/routes/playlist.routes")(app);
|
||||||
|
require("./app/routes/video.routes")(app);
|
||||||
|
require("./app/routes/ad.routes")(app);
|
||||||
|
|
||||||
|
app.listen(port, '0.0.0.0',() => {
|
||||||
|
console.log (`listening on port ${port}`);
|
||||||
|
});
|
||||||
41
docker-compose.yml
Normal file
41
docker-compose.yml
Normal file
|
|
@ -0,0 +1,41 @@
|
||||||
|
version: '3.8'
|
||||||
|
|
||||||
|
services:
|
||||||
|
frontend:
|
||||||
|
container_name: frontend
|
||||||
|
build: .
|
||||||
|
command: ng serve --host 0.0.0.0
|
||||||
|
volumes:
|
||||||
|
- ./src:/data/frontend/
|
||||||
|
- ./node_modules:/data/frontend/node_modules
|
||||||
|
ports:
|
||||||
|
- 4200:4200
|
||||||
|
depends_on:
|
||||||
|
- backend
|
||||||
|
links:
|
||||||
|
- backend
|
||||||
|
|
||||||
|
backend:
|
||||||
|
container_name: backend
|
||||||
|
build: ./backend
|
||||||
|
command: node server.js
|
||||||
|
volumes:
|
||||||
|
- ./backend:/data/backend
|
||||||
|
- ./backend/node_modules:/data/backend/node_modules
|
||||||
|
- ./backend/keys:/data/backend/keys
|
||||||
|
ports:
|
||||||
|
- 3000:3000
|
||||||
|
depends_on:
|
||||||
|
- mongodb
|
||||||
|
links:
|
||||||
|
- mongodb
|
||||||
|
environment:
|
||||||
|
NODE_ENV: development
|
||||||
|
|
||||||
|
mongodb:
|
||||||
|
image: mongo
|
||||||
|
container_name: mongodb
|
||||||
|
volumes:
|
||||||
|
- ./backend/database:/data/db
|
||||||
|
ports:
|
||||||
|
- 27017:27017
|
||||||
37
e2e/protractor.conf.js
Normal file
37
e2e/protractor.conf.js
Normal file
|
|
@ -0,0 +1,37 @@
|
||||||
|
// @ts-check
|
||||||
|
// Protractor configuration file, see link for more information
|
||||||
|
// https://github.com/angular/protractor/blob/master/lib/config.ts
|
||||||
|
|
||||||
|
const { SpecReporter, StacktraceOption } = require('jasmine-spec-reporter');
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @type { import("protractor").Config }
|
||||||
|
*/
|
||||||
|
exports.config = {
|
||||||
|
allScriptsTimeout: 11000,
|
||||||
|
specs: [
|
||||||
|
'./src/**/*.e2e-spec.ts'
|
||||||
|
],
|
||||||
|
capabilities: {
|
||||||
|
browserName: 'chrome'
|
||||||
|
},
|
||||||
|
directConnect: true,
|
||||||
|
SELENIUM_PROMISE_MANAGER: false,
|
||||||
|
baseUrl: 'http://localhost:4200/',
|
||||||
|
framework: 'jasmine',
|
||||||
|
jasmineNodeOpts: {
|
||||||
|
showColors: true,
|
||||||
|
defaultTimeoutInterval: 30000,
|
||||||
|
print: function() {}
|
||||||
|
},
|
||||||
|
onPrepare() {
|
||||||
|
require('ts-node').register({
|
||||||
|
project: require('path').join(__dirname, './tsconfig.json')
|
||||||
|
});
|
||||||
|
jasmine.getEnv().addReporter(new SpecReporter({
|
||||||
|
spec: {
|
||||||
|
displayStacktrace: StacktraceOption.PRETTY
|
||||||
|
}
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
};
|
||||||
23
e2e/src/app.e2e-spec.ts
Normal file
23
e2e/src/app.e2e-spec.ts
Normal file
|
|
@ -0,0 +1,23 @@
|
||||||
|
import { browser, logging } from 'protractor';
|
||||||
|
import { AppPage } from './app.po';
|
||||||
|
|
||||||
|
describe('workspace-project App', () => {
|
||||||
|
let page: AppPage;
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
page = new AppPage();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should display welcome message', async () => {
|
||||||
|
await page.navigateTo();
|
||||||
|
expect(await page.getTitleText()).toEqual('frontend app is running!');
|
||||||
|
});
|
||||||
|
|
||||||
|
afterEach(async () => {
|
||||||
|
// Assert that there are no errors emitted from the browser
|
||||||
|
const logs = await browser.manage().logs().get(logging.Type.BROWSER);
|
||||||
|
expect(logs).not.toContain(jasmine.objectContaining({
|
||||||
|
level: logging.Level.SEVERE,
|
||||||
|
} as logging.Entry));
|
||||||
|
});
|
||||||
|
});
|
||||||
11
e2e/src/app.po.ts
Normal file
11
e2e/src/app.po.ts
Normal file
|
|
@ -0,0 +1,11 @@
|
||||||
|
import { browser, by, element } from 'protractor';
|
||||||
|
|
||||||
|
export class AppPage {
|
||||||
|
async navigateTo(): Promise<unknown> {
|
||||||
|
return browser.get(browser.baseUrl);
|
||||||
|
}
|
||||||
|
|
||||||
|
async getTitleText(): Promise<string> {
|
||||||
|
return element(by.css('app-root .content span')).getText();
|
||||||
|
}
|
||||||
|
}
|
||||||
13
e2e/tsconfig.json
Normal file
13
e2e/tsconfig.json
Normal file
|
|
@ -0,0 +1,13 @@
|
||||||
|
/* To learn more about this file see: https://angular.io/config/tsconfig. */
|
||||||
|
{
|
||||||
|
"extends": "../tsconfig.json",
|
||||||
|
"compilerOptions": {
|
||||||
|
"outDir": "../out-tsc/e2e",
|
||||||
|
"module": "commonjs",
|
||||||
|
"target": "es2018",
|
||||||
|
"types": [
|
||||||
|
"jasmine",
|
||||||
|
"node"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
4
heroku.yml
Normal file
4
heroku.yml
Normal file
|
|
@ -0,0 +1,4 @@
|
||||||
|
build:
|
||||||
|
docker:
|
||||||
|
frontend: Dockerfile
|
||||||
|
backend: backend/Dockerfile
|
||||||
44
karma.conf.js
Normal file
44
karma.conf.js
Normal file
|
|
@ -0,0 +1,44 @@
|
||||||
|
// Karma configuration file, see link for more information
|
||||||
|
// https://karma-runner.github.io/1.0/config/configuration-file.html
|
||||||
|
|
||||||
|
module.exports = function (config) {
|
||||||
|
config.set({
|
||||||
|
basePath: '',
|
||||||
|
frameworks: ['jasmine', '@angular-devkit/build-angular'],
|
||||||
|
plugins: [
|
||||||
|
require('karma-jasmine'),
|
||||||
|
require('karma-chrome-launcher'),
|
||||||
|
require('karma-jasmine-html-reporter'),
|
||||||
|
require('karma-coverage'),
|
||||||
|
require('@angular-devkit/build-angular/plugins/karma')
|
||||||
|
],
|
||||||
|
client: {
|
||||||
|
jasmine: {
|
||||||
|
// you can add configuration options for Jasmine here
|
||||||
|
// the possible options are listed at https://jasmine.github.io/api/edge/Configuration.html
|
||||||
|
// for example, you can disable the random execution with `random: false`
|
||||||
|
// or set a specific seed with `seed: 4321`
|
||||||
|
},
|
||||||
|
clearContext: false // leave Jasmine Spec Runner output visible in browser
|
||||||
|
},
|
||||||
|
jasmineHtmlReporter: {
|
||||||
|
suppressAll: true // removes the duplicated traces
|
||||||
|
},
|
||||||
|
coverageReporter: {
|
||||||
|
dir: require('path').join(__dirname, './coverage/frontend'),
|
||||||
|
subdir: '.',
|
||||||
|
reporters: [
|
||||||
|
{ type: 'html' },
|
||||||
|
{ type: 'text-summary' }
|
||||||
|
]
|
||||||
|
},
|
||||||
|
reporters: ['progress', 'kjhtml'],
|
||||||
|
port: 9876,
|
||||||
|
colors: true,
|
||||||
|
logLevel: config.LOG_INFO,
|
||||||
|
autoWatch: true,
|
||||||
|
browsers: ['Chrome'],
|
||||||
|
singleRun: false,
|
||||||
|
restartOnFileChange: true
|
||||||
|
});
|
||||||
|
};
|
||||||
16068
package-lock.json
generated
Normal file
16068
package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load diff
50
package.json
Normal file
50
package.json
Normal file
|
|
@ -0,0 +1,50 @@
|
||||||
|
{
|
||||||
|
"name": "frontend",
|
||||||
|
"version": "0.0.0",
|
||||||
|
"scripts": {
|
||||||
|
"ng": "ng",
|
||||||
|
"start": "ng serve",
|
||||||
|
"build": "ng build",
|
||||||
|
"test": "ng test",
|
||||||
|
"lint": "ng lint",
|
||||||
|
"e2e": "ng e2e"
|
||||||
|
},
|
||||||
|
"private": true,
|
||||||
|
"dependencies": {
|
||||||
|
"@angular/animations": "^12.2.11",
|
||||||
|
"@angular/cdk": "^12.2.11",
|
||||||
|
"@angular/common": "^12.2.11",
|
||||||
|
"@angular/compiler": "^12.2.11",
|
||||||
|
"@angular/core": "^12.2.11",
|
||||||
|
"@angular/forms": "^12.2.11",
|
||||||
|
"@angular/material": "^12.2.11",
|
||||||
|
"@angular/platform-browser": "^12.2.11",
|
||||||
|
"@angular/platform-browser-dynamic": "^12.2.11",
|
||||||
|
"@angular/router": "^12.2.11",
|
||||||
|
"bootstrap": "^5.1.3",
|
||||||
|
"jquery": "^3.6.0",
|
||||||
|
"popper": "^1.0.1",
|
||||||
|
"rxjs": "~6.6.0",
|
||||||
|
"tslib": "^2.0.0",
|
||||||
|
"zone.js": "~0.11.3"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"@angular-devkit/build-angular": "~12.2.11",
|
||||||
|
"@angular/cli": "~12.2.11",
|
||||||
|
"@angular/compiler-cli": "~12.2.11",
|
||||||
|
"@types/jasmine": "~3.6.0",
|
||||||
|
"@types/node": "^12.11.1",
|
||||||
|
"codelyzer": "^6.0.0",
|
||||||
|
"jasmine-core": "~3.6.0",
|
||||||
|
"jasmine-spec-reporter": "~5.0.0",
|
||||||
|
"karma": "~6.3.5",
|
||||||
|
"karma-chrome-launcher": "~3.1.0",
|
||||||
|
"karma-coverage": "~2.0.3",
|
||||||
|
"karma-jasmine": "~4.0.0",
|
||||||
|
"karma-jasmine-html-reporter": "^1.5.0",
|
||||||
|
"protractor": "~7.0.0",
|
||||||
|
"ts-node": "~8.3.0",
|
||||||
|
"tslint": "~6.1.0",
|
||||||
|
"typescript": "~4.3.5"
|
||||||
|
}
|
||||||
|
}
|
||||||
22
src/app/app-routing.module.ts
Normal file
22
src/app/app-routing.module.ts
Normal file
|
|
@ -0,0 +1,22 @@
|
||||||
|
import { NgModule } from '@angular/core';
|
||||||
|
import { RouterModule, Routes } from '@angular/router';
|
||||||
|
import {PageConnexionComponent} from './pourLes3Roles/page-connexion/page-connexion.component';
|
||||||
|
import {PageRegisterComponent} from './pourLes3Roles/register/page-register/page-register.component';
|
||||||
|
import {PageSearchComponent} from "./user/search/page-search/page-search.component";
|
||||||
|
import {PageMyPlaylistsComponent} from "./user/myPlaylists/page-my-playlists/page-my-playlists.component";
|
||||||
|
|
||||||
|
|
||||||
|
const routes: Routes = [
|
||||||
|
{ path: '', component: PageConnexionComponent },
|
||||||
|
{ path: 'connexion', component: PageConnexionComponent },
|
||||||
|
{ path: 'register', component: PageRegisterComponent },
|
||||||
|
{ path: 'search', component: PageSearchComponent },
|
||||||
|
{ path: 'myPlaylists', component: PageMyPlaylistsComponent }
|
||||||
|
];
|
||||||
|
|
||||||
|
|
||||||
|
@NgModule({
|
||||||
|
imports: [RouterModule.forRoot(routes)],
|
||||||
|
exports: [RouterModule]
|
||||||
|
})
|
||||||
|
export class AppRoutingModule { }
|
||||||
1
src/app/app.component.html
Normal file
1
src/app/app.component.html
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
<router-outlet></router-outlet>
|
||||||
7
src/app/app.component.scss
Normal file
7
src/app/app.component.scss
Normal file
|
|
@ -0,0 +1,7 @@
|
||||||
|
::ng-deep snack-bar-container.custom-class {
|
||||||
|
//background: yellow;
|
||||||
|
}
|
||||||
|
::ng-deep .custom-class .mat-simple-snackbar {
|
||||||
|
//color: green;
|
||||||
|
justify-content: center;
|
||||||
|
}
|
||||||
35
src/app/app.component.spec.ts
Normal file
35
src/app/app.component.spec.ts
Normal file
|
|
@ -0,0 +1,35 @@
|
||||||
|
import { TestBed } from '@angular/core/testing';
|
||||||
|
import { RouterTestingModule } from '@angular/router/testing';
|
||||||
|
import { AppComponent } from './app.component';
|
||||||
|
|
||||||
|
describe('AppComponent', () => {
|
||||||
|
beforeEach(async () => {
|
||||||
|
await TestBed.configureTestingModule({
|
||||||
|
imports: [
|
||||||
|
RouterTestingModule
|
||||||
|
],
|
||||||
|
declarations: [
|
||||||
|
AppComponent
|
||||||
|
],
|
||||||
|
}).compileComponents();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should create the app', () => {
|
||||||
|
const fixture = TestBed.createComponent(AppComponent);
|
||||||
|
const app = fixture.componentInstance;
|
||||||
|
expect(app).toBeTruthy();
|
||||||
|
});
|
||||||
|
|
||||||
|
it(`should have as title 'frontend'`, () => {
|
||||||
|
const fixture = TestBed.createComponent(AppComponent);
|
||||||
|
const app = fixture.componentInstance;
|
||||||
|
expect(app.title).toEqual('frontend');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should render title', () => {
|
||||||
|
const fixture = TestBed.createComponent(AppComponent);
|
||||||
|
fixture.detectChanges();
|
||||||
|
const compiled = fixture.nativeElement;
|
||||||
|
expect(compiled.querySelector('.content span').textContent).toContain('frontend app is running!');
|
||||||
|
});
|
||||||
|
});
|
||||||
12
src/app/app.component.ts
Normal file
12
src/app/app.component.ts
Normal file
|
|
@ -0,0 +1,12 @@
|
||||||
|
import { Component } from '@angular/core';
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'app-root',
|
||||||
|
templateUrl: './app.component.html',
|
||||||
|
styleUrls: ['./app.component.scss']
|
||||||
|
})
|
||||||
|
export class AppComponent {
|
||||||
|
title = 'frontend';
|
||||||
|
|
||||||
|
themeIsLight = true;
|
||||||
|
}
|
||||||
74
src/app/app.module.ts
Normal file
74
src/app/app.module.ts
Normal file
|
|
@ -0,0 +1,74 @@
|
||||||
|
import { NgModule } from '@angular/core';
|
||||||
|
import { BrowserModule } from '@angular/platform-browser';
|
||||||
|
|
||||||
|
import { AppRoutingModule } from './app-routing.module';
|
||||||
|
import { AppComponent } from './app.component';
|
||||||
|
import { PageConnexionComponent } from './pourLes3Roles/page-connexion/page-connexion.component';
|
||||||
|
import { PageRegisterComponent } from './pourLes3Roles/register/page-register/page-register.component';
|
||||||
|
import { NavBarComponent } from './utils/components/nav-bar/nav-bar.component';
|
||||||
|
import {BrowserAnimationsModule} from '@angular/platform-browser/animations';
|
||||||
|
import {MatSlideToggleModule} from '@angular/material/slide-toggle';
|
||||||
|
import {FormsModule} from "@angular/forms";
|
||||||
|
import { PageSearchComponent } from './user/search/page-search/page-search.component';
|
||||||
|
import {HttpClientModule} from "@angular/common/http";
|
||||||
|
import { PopupConfirmationComponent } from './pourLes3Roles/register/popup-confirmation/popup-confirmation.component';
|
||||||
|
import {MatDialogModule} from '@angular/material/dialog';
|
||||||
|
import {MatButtonModule} from "@angular/material/button";
|
||||||
|
import { AdvertComponent } from './utils/components/advert/advert.component';
|
||||||
|
import { VideoCellComponent } from './user/search/video-cell/video-cell.component';
|
||||||
|
import { VideoGridComponent } from './user/search/video-grid/video-grid.component';
|
||||||
|
import {MatIconModule} from "@angular/material/icon";
|
||||||
|
import { PopupAddVideoToPlaylistsComponent } from './utils/components/popup-add-video-to-playlists/popup-add-video-to-playlists.component';
|
||||||
|
import {MatInputModule} from "@angular/material/input";
|
||||||
|
import {MatDividerModule} from "@angular/material/divider";
|
||||||
|
import {MatCheckboxModule} from "@angular/material/checkbox";
|
||||||
|
import {MatFormFieldModule} from "@angular/material/form-field";
|
||||||
|
import {MatSnackBarModule} from "@angular/material/snack-bar";
|
||||||
|
import { IframeTrackerDirective } from './utils/directives/iframe-tracker/iframe-tracker.directive';
|
||||||
|
import {MatGridListModule} from "@angular/material/grid-list";
|
||||||
|
import { PageMyPlaylistsComponent } from './user/myPlaylists/page-my-playlists/page-my-playlists.component';
|
||||||
|
import { PlaylistListComponent } from './user/myPlaylists/playlist-list/playlist-list.component';
|
||||||
|
import {VideoListComponent} from "./user/myPlaylists/video-list/video-list.component";
|
||||||
|
import { PopupCreatePlaylistComponent } from './utils/components/popup-create-playlist/popup-create-playlist.component';
|
||||||
|
|
||||||
|
|
||||||
|
@NgModule({
|
||||||
|
declarations: [
|
||||||
|
AppComponent,
|
||||||
|
PageConnexionComponent,
|
||||||
|
PageRegisterComponent,
|
||||||
|
NavBarComponent,
|
||||||
|
PageSearchComponent,
|
||||||
|
PopupConfirmationComponent,
|
||||||
|
AdvertComponent,
|
||||||
|
VideoCellComponent,
|
||||||
|
VideoGridComponent,
|
||||||
|
PopupAddVideoToPlaylistsComponent,
|
||||||
|
IframeTrackerDirective,
|
||||||
|
PageMyPlaylistsComponent,
|
||||||
|
VideoListComponent,
|
||||||
|
PlaylistListComponent,
|
||||||
|
VideoListComponent,
|
||||||
|
PopupCreatePlaylistComponent,
|
||||||
|
],
|
||||||
|
imports: [
|
||||||
|
BrowserModule,
|
||||||
|
AppRoutingModule,
|
||||||
|
BrowserAnimationsModule,
|
||||||
|
MatSlideToggleModule,
|
||||||
|
FormsModule,
|
||||||
|
HttpClientModule,
|
||||||
|
MatDialogModule,
|
||||||
|
MatButtonModule,
|
||||||
|
MatIconModule,
|
||||||
|
MatInputModule,
|
||||||
|
MatDividerModule,
|
||||||
|
MatCheckboxModule,
|
||||||
|
MatFormFieldModule,
|
||||||
|
MatSnackBarModule,
|
||||||
|
MatGridListModule
|
||||||
|
],
|
||||||
|
providers: [],
|
||||||
|
bootstrap: [AppComponent]
|
||||||
|
})
|
||||||
|
export class AppModule { }
|
||||||
|
|
@ -0,0 +1,41 @@
|
||||||
|
<div [class]="themeService.getClassTheme()">
|
||||||
|
<div class="myContainer">
|
||||||
|
|
||||||
|
<app-nav-bar pour="3roles"></app-nav-bar>
|
||||||
|
|
||||||
|
<div class="boite">
|
||||||
|
<h1> Connexion </h1>
|
||||||
|
|
||||||
|
<!-- Email -->
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-4 label"> Email: </div>
|
||||||
|
<div class="col-8 champ">
|
||||||
|
<input type="text" [(ngModel)]="email">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Mot de passe -->
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-4 label"> Mot de passe: </div>
|
||||||
|
<div class="col-8 champ">
|
||||||
|
<input type="text" [(ngModel)]="password">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Boutons -->
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-6">
|
||||||
|
<button (click)="onSeConnecter()"> Se connecter </button>
|
||||||
|
</div>
|
||||||
|
<div class="col-6" style="text-align: right">
|
||||||
|
<button routerLink="/register"> S'inscrire </button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Mot de passe oublié -->
|
||||||
|
<div style="text-align: right">
|
||||||
|
<a class="lien" href="https://pixar.fandom.com/wiki/Sadness"> Mot de passe oublié ? </a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
@ -0,0 +1,64 @@
|
||||||
|
.myContainer {
|
||||||
|
max-width: 100vw;
|
||||||
|
height: 100vh;
|
||||||
|
overflow-x: hidden;
|
||||||
|
font-size: x-large;
|
||||||
|
}
|
||||||
|
|
||||||
|
h1 {
|
||||||
|
text-align: center;
|
||||||
|
margin-bottom: 30px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.boite {
|
||||||
|
margin-left: auto;
|
||||||
|
margin-right: auto;
|
||||||
|
width: 30%;
|
||||||
|
margin-top: 50vh;
|
||||||
|
transform: translateY(-100%);
|
||||||
|
border: solid 3px;
|
||||||
|
border-radius: 10px;
|
||||||
|
padding: 20px 40px 20px 20px;
|
||||||
|
background-color: #dcdcdc;
|
||||||
|
}
|
||||||
|
.lightTheme .boite {
|
||||||
|
border-color: black;
|
||||||
|
}
|
||||||
|
.darkTheme .boite {
|
||||||
|
border-color: white;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
.row {
|
||||||
|
margin: 25px 0px 25px 0px
|
||||||
|
}
|
||||||
|
|
||||||
|
.label {
|
||||||
|
text-align: right;
|
||||||
|
margin-right: 0px;
|
||||||
|
padding: 0px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.champ {
|
||||||
|
margin: 0px;
|
||||||
|
padding: 0px;
|
||||||
|
}
|
||||||
|
|
||||||
|
input {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
button {
|
||||||
|
width: 100%;
|
||||||
|
margin-right: 0px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.col-6 {
|
||||||
|
//text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.lien {
|
||||||
|
text-decoration: underline;
|
||||||
|
color: black;
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,25 @@
|
||||||
|
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||||
|
|
||||||
|
import { PageConnexionComponent } from './page-connexion.component';
|
||||||
|
|
||||||
|
describe('PageConnexionComponent', () => {
|
||||||
|
let component: PageConnexionComponent;
|
||||||
|
let fixture: ComponentFixture<PageConnexionComponent>;
|
||||||
|
|
||||||
|
beforeEach(async () => {
|
||||||
|
await TestBed.configureTestingModule({
|
||||||
|
declarations: [ PageConnexionComponent ]
|
||||||
|
})
|
||||||
|
.compileComponents();
|
||||||
|
});
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
fixture = TestBed.createComponent(PageConnexionComponent);
|
||||||
|
component = fixture.componentInstance;
|
||||||
|
fixture.detectChanges();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should create', () => {
|
||||||
|
expect(component).toBeTruthy();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
@ -0,0 +1,45 @@
|
||||||
|
import { Component, OnInit } from '@angular/core';
|
||||||
|
import {MessageService} from "../../utils/services/message/message.service";
|
||||||
|
import {Router} from "@angular/router";
|
||||||
|
import {ThemeService} from "../../utils/services/theme/theme.service";
|
||||||
|
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'app-page-connexion',
|
||||||
|
templateUrl: './page-connexion.component.html',
|
||||||
|
styleUrls: ['./page-connexion.component.scss']
|
||||||
|
})
|
||||||
|
export class PageConnexionComponent implements OnInit
|
||||||
|
{
|
||||||
|
email: string = ""
|
||||||
|
password: string = ""
|
||||||
|
|
||||||
|
constructor( private messageService: MessageService,
|
||||||
|
private router: Router,
|
||||||
|
public themeService: ThemeService ) { }
|
||||||
|
|
||||||
|
|
||||||
|
ngOnInit(): void {}
|
||||||
|
|
||||||
|
|
||||||
|
onSeConnecter(): void
|
||||||
|
{
|
||||||
|
let data = {
|
||||||
|
"email": this.email,
|
||||||
|
"password": this.password
|
||||||
|
};
|
||||||
|
this.messageService
|
||||||
|
.sendMessage('connexion', data)
|
||||||
|
.subscribe( retour => this.maCallback(retour))
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
maCallback(retour): void
|
||||||
|
{
|
||||||
|
if(retour.status === "error") console.log(retour.data)
|
||||||
|
else {
|
||||||
|
console.log(retour.data)
|
||||||
|
//this.router.navigateByUrl( '/search' );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,53 @@
|
||||||
|
<div [class]="themeService.getClassTheme()">
|
||||||
|
<div class="myContainer">
|
||||||
|
|
||||||
|
<app-nav-bar pour="3roles"></app-nav-bar>
|
||||||
|
|
||||||
|
<div class="boite">
|
||||||
|
<h1> Inscription </h1>
|
||||||
|
|
||||||
|
<!-- Pseudo -->
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-6 label"> Pseudo: </div>
|
||||||
|
<div class="col-6 champ">
|
||||||
|
<input type="text" [(ngModel)]="pseudo">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Email -->
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-6 label"> Email: </div>
|
||||||
|
<div class="col-6 champ">
|
||||||
|
<input type="email" [(ngModel)]="email">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Mot de passe -->
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-6 label"> Mot de passe: </div>
|
||||||
|
<div class="col-6 champ">
|
||||||
|
<input type="password" [(ngModel)]="password">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Confirmation mot de passe -->
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-6 label"> Confirmer le mot de passe: </div>
|
||||||
|
<div class="col-6 champ">
|
||||||
|
<input type="password" [(ngModel)]="confirmPassword">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Bouton valider -->
|
||||||
|
<div style="width: 100%; margin-top: 30px">
|
||||||
|
<button (click)="onValider()"> Valider </button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Message d'erreur -->
|
||||||
|
<div *ngIf="hasError" style="text-align: center">
|
||||||
|
<span class="mat-error"> {{errorMessage}} </span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
@ -0,0 +1,58 @@
|
||||||
|
.myContainer {
|
||||||
|
max-width: 100vw;
|
||||||
|
height: 100vh;
|
||||||
|
overflow-x: hidden;
|
||||||
|
font-size: x-large;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
h1 {
|
||||||
|
text-align: center;
|
||||||
|
margin-bottom: 30px;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
.boite {
|
||||||
|
margin-left: auto;
|
||||||
|
margin-right: auto;
|
||||||
|
width: 35%;
|
||||||
|
margin-top: 50vh;
|
||||||
|
transform: translateY(-100%);
|
||||||
|
border: solid 3px;
|
||||||
|
border-radius: 10px;
|
||||||
|
padding: 20px 40px 20px 40px;
|
||||||
|
background-color: #dcdcdc;
|
||||||
|
}
|
||||||
|
.lightTheme .boite {
|
||||||
|
border-color: black;
|
||||||
|
}
|
||||||
|
.darkTheme .boite {
|
||||||
|
border-color: white;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
input {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.row {
|
||||||
|
margin: 15px 0px 15px 0px
|
||||||
|
}
|
||||||
|
|
||||||
|
.label {
|
||||||
|
text-align: right;
|
||||||
|
margin-right: 0px;
|
||||||
|
padding: 0px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.champ {
|
||||||
|
margin: 0px;
|
||||||
|
padding: 0px
|
||||||
|
}
|
||||||
|
|
||||||
|
button {
|
||||||
|
width: 100%;
|
||||||
|
margin-right: 0px;
|
||||||
|
background-color: #969696;
|
||||||
|
border: solid 2px black;
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,25 @@
|
||||||
|
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||||
|
|
||||||
|
import { PageRegisterComponent } from './page-register.component';
|
||||||
|
|
||||||
|
describe('PageRegisterComponent', () => {
|
||||||
|
let component: PageRegisterComponent;
|
||||||
|
let fixture: ComponentFixture<PageRegisterComponent>;
|
||||||
|
|
||||||
|
beforeEach(async () => {
|
||||||
|
await TestBed.configureTestingModule({
|
||||||
|
declarations: [ PageRegisterComponent ]
|
||||||
|
})
|
||||||
|
.compileComponents();
|
||||||
|
});
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
fixture = TestBed.createComponent(PageRegisterComponent);
|
||||||
|
component = fixture.componentInstance;
|
||||||
|
fixture.detectChanges();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should create', () => {
|
||||||
|
expect(component).toBeTruthy();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
@ -0,0 +1,97 @@
|
||||||
|
import { Component, OnInit } from '@angular/core';
|
||||||
|
import {MessageService} from "../../../utils/services/message/message.service";
|
||||||
|
import {Router} from "@angular/router";
|
||||||
|
import {MatDialog} from "@angular/material/dialog";
|
||||||
|
import {PopupConfirmationComponent} from "../popup-confirmation/popup-confirmation.component";
|
||||||
|
import {ThemeService} from "../../../utils/services/theme/theme.service";
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'app-page-register',
|
||||||
|
templateUrl: './page-register.component.html',
|
||||||
|
styleUrls: ['./page-register.component.scss']
|
||||||
|
})
|
||||||
|
export class PageRegisterComponent implements OnInit
|
||||||
|
{
|
||||||
|
pseudo: string = "";
|
||||||
|
email: string = "" ;
|
||||||
|
password: string = "";
|
||||||
|
confirmPassword: string = "";
|
||||||
|
hasError: boolean = false;
|
||||||
|
errorMessage: string = "";
|
||||||
|
|
||||||
|
|
||||||
|
constructor( private messageService: MessageService,
|
||||||
|
private router: Router,
|
||||||
|
public dialog: MatDialog,
|
||||||
|
public themeService: ThemeService ) { }
|
||||||
|
|
||||||
|
|
||||||
|
ngOnInit(): void {}
|
||||||
|
|
||||||
|
|
||||||
|
isValidEmail(email)
|
||||||
|
{
|
||||||
|
let re = /^(([^<>()[\]\\.,;:\s@\"]+(\.[^<>()[\]\\.,;:\s@\"]+)*)|(\".+\"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/;
|
||||||
|
return re.test(email);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
verifierChamps(): void
|
||||||
|
{
|
||||||
|
if(this.pseudo.length === 0) {
|
||||||
|
this.errorMessage = "Veuillez remplir le champ 'pseudo'"
|
||||||
|
this.hasError = true;
|
||||||
|
}
|
||||||
|
else if(this.email.length === 0)
|
||||||
|
{
|
||||||
|
this.errorMessage = "Veuillez remplir le champ 'email'"
|
||||||
|
this.hasError = true;
|
||||||
|
}
|
||||||
|
else if(!this.isValidEmail(this.email))
|
||||||
|
{
|
||||||
|
this.errorMessage = "Email invalide"
|
||||||
|
this.hasError = true;
|
||||||
|
}
|
||||||
|
else if(this.password.length === 0)
|
||||||
|
{
|
||||||
|
this.errorMessage = "Veuillez remplir le champ 'mot de passe'"
|
||||||
|
this.hasError = true;
|
||||||
|
}
|
||||||
|
else if(this.password !== this.confirmPassword)
|
||||||
|
{
|
||||||
|
this.errorMessage = "Le mot de passe est différent de sa confirmation"
|
||||||
|
this.hasError = true;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
this.hasError = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
onValider(): void
|
||||||
|
{
|
||||||
|
this.verifierChamps()
|
||||||
|
console.log(this.hasError)
|
||||||
|
if(!this.hasError)
|
||||||
|
{
|
||||||
|
let data = { "pseudo": this.pseudo, "email": this.email, "password": this.password }
|
||||||
|
this.messageService
|
||||||
|
.sendMessage('register', data)
|
||||||
|
.subscribe(retour => this.maCallback(retour))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
maCallback(retour): void
|
||||||
|
{
|
||||||
|
if(retour.status === "error") console.log(retour.data)
|
||||||
|
else
|
||||||
|
{
|
||||||
|
const config = { width: '25%', data: {} }
|
||||||
|
this.dialog
|
||||||
|
.open(PopupConfirmationComponent, config )
|
||||||
|
.afterClosed()
|
||||||
|
.subscribe(result => this.router.navigateByUrl( '/connexion' ));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,4 @@
|
||||||
|
<p> Votre inscription a bien été effectué. </p>
|
||||||
|
<div style="text-align: right">
|
||||||
|
<button mat-button mat-dialog-close> Continuer </button>
|
||||||
|
</div>
|
||||||
|
|
@ -0,0 +1,25 @@
|
||||||
|
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||||
|
|
||||||
|
import { PopupConfirmationComponent } from './popup-confirmation.component';
|
||||||
|
|
||||||
|
describe('PopupConfirmationComponent', () => {
|
||||||
|
let component: PopupConfirmationComponent;
|
||||||
|
let fixture: ComponentFixture<PopupConfirmationComponent>;
|
||||||
|
|
||||||
|
beforeEach(async () => {
|
||||||
|
await TestBed.configureTestingModule({
|
||||||
|
declarations: [ PopupConfirmationComponent ]
|
||||||
|
})
|
||||||
|
.compileComponents();
|
||||||
|
});
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
fixture = TestBed.createComponent(PopupConfirmationComponent);
|
||||||
|
component = fixture.componentInstance;
|
||||||
|
fixture.detectChanges();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should create', () => {
|
||||||
|
expect(component).toBeTruthy();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
@ -0,0 +1,18 @@
|
||||||
|
import {Component, Inject, OnInit} from '@angular/core';
|
||||||
|
import {MAT_DIALOG_DATA, MatDialogRef} from "@angular/material/dialog";
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'app-popup-confirmation',
|
||||||
|
templateUrl: './popup-confirmation.component.html',
|
||||||
|
styleUrls: ['./popup-confirmation.component.scss']
|
||||||
|
})
|
||||||
|
export class PopupConfirmationComponent
|
||||||
|
{
|
||||||
|
constructor( public dialogRef: MatDialogRef<PopupConfirmationComponent>,
|
||||||
|
@Inject(MAT_DIALOG_DATA) public data) {}
|
||||||
|
|
||||||
|
onClick(): void
|
||||||
|
{
|
||||||
|
this.dialogRef.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,38 @@
|
||||||
|
<div [class]="themeService.getClassTheme()">
|
||||||
|
<div class="myContainer">
|
||||||
|
|
||||||
|
<!-- Navbar -->
|
||||||
|
<div style="margin-bottom: 50px">
|
||||||
|
<app-nav-bar pour="user"></app-nav-bar>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- --------------------------------------------------------------------- -->
|
||||||
|
|
||||||
|
<!-- [liste des videos] + [liste des playlist] + [pub] -->
|
||||||
|
<mat-grid-list cols="10" rowHeight="85vh">
|
||||||
|
|
||||||
|
<!-- liste des videos -->
|
||||||
|
<mat-grid-tile colspan="4" rowspan="1" class="celluleListeVideo">
|
||||||
|
<div class="videoListContainer">
|
||||||
|
<app-video-list [playlist]="playlist"></app-video-list>
|
||||||
|
</div>
|
||||||
|
</mat-grid-tile>
|
||||||
|
|
||||||
|
<!-- liste des playlist -->
|
||||||
|
<mat-grid-tile colspan="4" rowspan="1" class="celluleListePlaylist">
|
||||||
|
<div class="playlistListContainer">
|
||||||
|
<app-playlist-list [allPlaylists]="allPlaylists" (eventEmitter)="transmitToVideoList($event)"></app-playlist-list>
|
||||||
|
</div>
|
||||||
|
</mat-grid-tile>
|
||||||
|
|
||||||
|
<!-- pub -->
|
||||||
|
<mat-grid-tile colspan="2" rowspan="1" class="cellulePub">
|
||||||
|
<div class="conteneurPub">
|
||||||
|
<app-advert [ad]="ad"></app-advert>
|
||||||
|
</div>
|
||||||
|
</mat-grid-tile>
|
||||||
|
|
||||||
|
</mat-grid-list>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
@ -0,0 +1,51 @@
|
||||||
|
.lightTheme {
|
||||||
|
border-color: black;
|
||||||
|
}
|
||||||
|
.darkTheme {
|
||||||
|
border-color: white;
|
||||||
|
}
|
||||||
|
.myContainer {
|
||||||
|
text-align: center;
|
||||||
|
max-width: 100vw;
|
||||||
|
height: 100vh;
|
||||||
|
overflow-x: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Liste des vidéos -------------------------------------------------
|
||||||
|
|
||||||
|
.celluleListeVideo {
|
||||||
|
margin: 0px;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Liste des playlists ---------------------------------------------
|
||||||
|
|
||||||
|
.celluleListePlaylist {
|
||||||
|
margin: 0px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.playlistListContainer {
|
||||||
|
}
|
||||||
|
|
||||||
|
// Pub -------------------------------------------------------------
|
||||||
|
|
||||||
|
.cellulePub {
|
||||||
|
padding: 0px 10px 0px 10px;
|
||||||
|
width: 100%;
|
||||||
|
text-align: center;
|
||||||
|
justify-content: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.conteneurPub {
|
||||||
|
height: 85vh;
|
||||||
|
text-align: center;
|
||||||
|
justify-content: center;
|
||||||
|
vertical-align: middle;
|
||||||
|
display: block;
|
||||||
|
width: 75%;
|
||||||
|
margin-left: auto;
|
||||||
|
margin-right: auto;
|
||||||
|
position: absolute;
|
||||||
|
top: 50%;
|
||||||
|
-ms-transform: translateY(-50%);
|
||||||
|
transform: translateY(-50%);
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,25 @@
|
||||||
|
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||||
|
|
||||||
|
import { PageMyPlaylistsComponent } from './page-my-playlists.component';
|
||||||
|
|
||||||
|
describe('PageMesPlaylistsComponent', () => {
|
||||||
|
let component: PageMyPlaylistsComponent;
|
||||||
|
let fixture: ComponentFixture<PageMyPlaylistsComponent>;
|
||||||
|
|
||||||
|
beforeEach(async () => {
|
||||||
|
await TestBed.configureTestingModule({
|
||||||
|
declarations: [ PageMyPlaylistsComponent ]
|
||||||
|
})
|
||||||
|
.compileComponents();
|
||||||
|
});
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
fixture = TestBed.createComponent(PageMyPlaylistsComponent);
|
||||||
|
component = fixture.componentInstance;
|
||||||
|
fixture.detectChanges();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should create', () => {
|
||||||
|
expect(component).toBeTruthy();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
@ -0,0 +1,52 @@
|
||||||
|
import { Component, OnInit } from '@angular/core';
|
||||||
|
import {ThemeService} from "../../../utils/services/theme/theme.service";
|
||||||
|
import {Advert} from "../../../utils/interfaces/advert";
|
||||||
|
import {FictitiousDatasService} from "../../../utils/services/fictitiousDatas/fictitious-datas.service";
|
||||||
|
import {MessageService} from "../../../utils/services/message/message.service";
|
||||||
|
import {Playlist} from "../../../utils/interfaces/playlist";
|
||||||
|
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'app-page-my-playlists',
|
||||||
|
templateUrl: './page-my-playlists.component.html',
|
||||||
|
styleUrls: ['./page-my-playlists.component.scss']
|
||||||
|
})
|
||||||
|
export class PageMyPlaylistsComponent implements OnInit
|
||||||
|
{
|
||||||
|
allPlaylists: Playlist[]; // toutes les playlists
|
||||||
|
ad: Advert; // pub
|
||||||
|
playlist: Playlist; // la playlist sélectionnée
|
||||||
|
|
||||||
|
|
||||||
|
constructor( public themeService: ThemeService,
|
||||||
|
private messageService: MessageService,
|
||||||
|
private fictitioousData: FictitiousDatasService ) { }
|
||||||
|
|
||||||
|
|
||||||
|
ngOnInit(): void
|
||||||
|
{
|
||||||
|
// --- FAUX CODE ---
|
||||||
|
this.allPlaylists = this.fictitioousData.getTabPlaylist(10, 10);
|
||||||
|
this.ad = this.fictitioousData.getAdvert();
|
||||||
|
|
||||||
|
// --- VRAI CODE ---
|
||||||
|
/*
|
||||||
|
this.messageService
|
||||||
|
.sendMessage("user/get/playlists", null)
|
||||||
|
.subscribe( retour => {
|
||||||
|
|
||||||
|
if(retour.status === "error") console.log(retour.data);
|
||||||
|
else {
|
||||||
|
this.tabPlaylists = retour.data.playlists;
|
||||||
|
this.ad = retour.data.ad;
|
||||||
|
}
|
||||||
|
})
|
||||||
|
*/
|
||||||
|
}
|
||||||
|
|
||||||
|
transmitToVideoList(playlist: Playlist): void
|
||||||
|
{
|
||||||
|
this.playlist = playlist;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,36 @@
|
||||||
|
<div [class]="themeService.getClassTheme()">
|
||||||
|
<div class="myContainer">
|
||||||
|
|
||||||
|
<!-- Search bar -->
|
||||||
|
<div class="row" style="margin: 0px">
|
||||||
|
<div class="searchBarContainer">
|
||||||
|
<input type="search" placeholder="recherche..." class="inputSearchBar" [(ngModel)]="search" (ngModelChange)="whileSearch()">
|
||||||
|
<!--
|
||||||
|
<button class="btnRechercher" (click)="onSearch()"> Rechercher </button>
|
||||||
|
-->
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
<!-- Liste des playlist -->
|
||||||
|
<div class="row" style="margin: 0px">
|
||||||
|
<div class="playlistListContainer">
|
||||||
|
<div *ngFor="let playlist of tabPlaylist" class="playlistContainer">
|
||||||
|
<button class="btnPlaylist" (click)="eventEmitter.emit(playlist)">
|
||||||
|
<span class="playlistName"> {{playlist.name}} </span><br>
|
||||||
|
<span class="playListCount"> {{playlist.videos.length}} vidéos </span>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
<!-- Bouton creer playlist-->
|
||||||
|
<div class="row" style="margin: 0px">
|
||||||
|
<div class="btnCreerPlaylistContainer">
|
||||||
|
<button class="btnCreerPlaylist" (click)="onCreatePlaylist()"> Creer playlist </button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
@ -0,0 +1,75 @@
|
||||||
|
.myContainer {
|
||||||
|
background-color: white ;
|
||||||
|
text-align: center;
|
||||||
|
width: 35vw;
|
||||||
|
height: 79vh;
|
||||||
|
margin: 3vh 0vh 3vh 0vh;
|
||||||
|
padding: 0px;
|
||||||
|
border: solid 2px black;
|
||||||
|
}
|
||||||
|
|
||||||
|
// SearchBar -----------------------------------------------------------
|
||||||
|
|
||||||
|
.searchBarContainer {
|
||||||
|
background-color: #dcdcdc;
|
||||||
|
border-bottom: solid 2px black;
|
||||||
|
height: 5vh;
|
||||||
|
padding: 15px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.inputSearchBar {
|
||||||
|
width: 50%;
|
||||||
|
}
|
||||||
|
.btnRechercher {
|
||||||
|
border: solid black 1px;
|
||||||
|
border-radius: 5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Liste des playlists -------------------------------------------------
|
||||||
|
|
||||||
|
.playlistListContainer {
|
||||||
|
max-width: 100%;
|
||||||
|
height: 70vh;
|
||||||
|
overflow-y: scroll;
|
||||||
|
padding: 0px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.playlistContainer {
|
||||||
|
max-width: 100%;
|
||||||
|
padding: 0px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.btnPlaylist {
|
||||||
|
background-color: white;
|
||||||
|
padding: 20px;
|
||||||
|
border-bottom: solid 2px black;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
.btnPlaylist:hover {
|
||||||
|
background-color: #f0f0f0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.playListCount {
|
||||||
|
color: gray;
|
||||||
|
font-style: italic;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Bouton creer playlist -------------------------------------------------
|
||||||
|
|
||||||
|
.btnCreerPlaylistContainer {
|
||||||
|
height: 4vh;
|
||||||
|
margin: 0px;
|
||||||
|
padding: 0px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.btnCreerPlaylist {
|
||||||
|
background-color: #dcdcdc;
|
||||||
|
border-top: solid 2px black;
|
||||||
|
border-bottom: solid 2px black;
|
||||||
|
height: 100%;
|
||||||
|
width: 100%;
|
||||||
|
padding: 10px;
|
||||||
|
}
|
||||||
|
.btnCreerPlaylist:hover {
|
||||||
|
background-color: #969696;
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,25 @@
|
||||||
|
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||||
|
|
||||||
|
import { PlaylistListComponent } from './playlist-list.component';
|
||||||
|
|
||||||
|
describe('PlaylistListComponent', () => {
|
||||||
|
let component: PlaylistListComponent;
|
||||||
|
let fixture: ComponentFixture<PlaylistListComponent>;
|
||||||
|
|
||||||
|
beforeEach(async () => {
|
||||||
|
await TestBed.configureTestingModule({
|
||||||
|
declarations: [ PlaylistListComponent ]
|
||||||
|
})
|
||||||
|
.compileComponents();
|
||||||
|
});
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
fixture = TestBed.createComponent(PlaylistListComponent);
|
||||||
|
component = fixture.componentInstance;
|
||||||
|
fixture.detectChanges();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should create', () => {
|
||||||
|
expect(component).toBeTruthy();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
@ -0,0 +1,67 @@
|
||||||
|
import {Component, EventEmitter, Input, OnInit, Output} from '@angular/core';
|
||||||
|
import {ThemeService} from "../../../utils/services/theme/theme.service";
|
||||||
|
import {Playlist} from "../../../utils/interfaces/playlist";
|
||||||
|
import {MessageService} from "../../../utils/services/message/message.service";
|
||||||
|
import {MatDialog} from "@angular/material/dialog";
|
||||||
|
import {PopupAddVideoToPlaylistsComponent} from "../../../utils/components/popup-add-video-to-playlists/popup-add-video-to-playlists.component";
|
||||||
|
import {MatSnackBar} from "@angular/material/snack-bar";
|
||||||
|
import {PopupCreatePlaylistComponent} from "../../../utils/components/popup-create-playlist/popup-create-playlist.component";
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'app-playlist-list',
|
||||||
|
templateUrl: './playlist-list.component.html',
|
||||||
|
styleUrls: ['./playlist-list.component.scss']
|
||||||
|
})
|
||||||
|
export class PlaylistListComponent implements OnInit
|
||||||
|
{
|
||||||
|
@Input() allPlaylists: Playlist[] = []; // toutes les playlists
|
||||||
|
@Output() eventEmitter = new EventEmitter<Playlist>(); // pour envoyer au parent la playlist selectionner
|
||||||
|
search: string = "" ; // contenu de la barre de recherche
|
||||||
|
tabPlaylist: Playlist[] = []; // playlist affichées
|
||||||
|
|
||||||
|
|
||||||
|
constructor( public themeService: ThemeService,
|
||||||
|
public dialog: MatDialog,
|
||||||
|
public snackBar: MatSnackBar ) { }
|
||||||
|
|
||||||
|
|
||||||
|
ngOnInit(): void
|
||||||
|
{
|
||||||
|
this.tabPlaylist = [].concat(this.allPlaylists);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
whileSearch()
|
||||||
|
{
|
||||||
|
console.log("whileSearch");
|
||||||
|
this.tabPlaylist = [];
|
||||||
|
for(let playlist of this.allPlaylists)
|
||||||
|
{
|
||||||
|
if(playlist.name.includes(this.search)) this.tabPlaylist.push(playlist);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
onCreatePlaylist(): void
|
||||||
|
{
|
||||||
|
const config = { width: '15%', data: this.tabPlaylist };
|
||||||
|
this.dialog
|
||||||
|
.open(PopupCreatePlaylistComponent, config )
|
||||||
|
.afterClosed()
|
||||||
|
.subscribe(playlist => {
|
||||||
|
|
||||||
|
const config = { duration: 1000, panelClass: "custom-class" };
|
||||||
|
if((playlist === null) || (playlist === undefined)) {
|
||||||
|
this.snackBar.open("Opération annulée ❌", "", config);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
this.allPlaylists.push(playlist);
|
||||||
|
this.tabPlaylist.push(playlist);
|
||||||
|
this.snackBar.open("La playlist a bien été créée ✔", "", config);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,74 @@
|
||||||
|
<div [class]="themeService.getClassTheme()">
|
||||||
|
<div class="myContainer">
|
||||||
|
|
||||||
|
<!-- Bordure haute -->
|
||||||
|
<div class="row" style="margin: 0px; padding: 0px">
|
||||||
|
<div class="topBorder">
|
||||||
|
|
||||||
|
<!-- Playlist existe ? -->
|
||||||
|
<div *ngIf="(playlist !== null) && (playlist !== undefined); then ok1 else nope1"></div>
|
||||||
|
|
||||||
|
<!-- oui -->
|
||||||
|
<ng-template #ok1>
|
||||||
|
<span class="spanPlayListTitle"> {{playlist.name}} </span>
|
||||||
|
</ng-template>
|
||||||
|
|
||||||
|
<!-- non -->
|
||||||
|
<ng-template #nope1>
|
||||||
|
<span class="spanPlayListTitle"> Aucune playlist selectionnée </span>
|
||||||
|
</ng-template>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
<!-- --------------------------------------------------------------------------------------------------------------------- -->
|
||||||
|
|
||||||
|
|
||||||
|
<!-- Liste des videos -->
|
||||||
|
<div class="row" style="margin: 0px; padding: 0px">
|
||||||
|
<div class="listVideoContainer">
|
||||||
|
|
||||||
|
<!-- Playlist existe ? -->
|
||||||
|
<div *ngIf="(playlist !== null) && (playlist !== undefined); then ok2 else nope2"></div>
|
||||||
|
|
||||||
|
<!-- oui -->
|
||||||
|
<ng-template #ok2>
|
||||||
|
<div *ngFor="let video of playlist.videos ; let i = index" class="videoContainer">
|
||||||
|
<!-- bouton add -->
|
||||||
|
<button mat-icon-button (click)="onAdd(video)">
|
||||||
|
<mat-icon > add_circle </mat-icon>
|
||||||
|
</button>
|
||||||
|
<!-- video -->
|
||||||
|
<iframe appIframeTracker
|
||||||
|
[src]=videoUrlService.safeUrl(this.video.url)
|
||||||
|
allowfullscreen
|
||||||
|
(iframeClick)="onIframeClick(this.video.url)"></iframe>
|
||||||
|
<!-- bouton delete -->
|
||||||
|
<button mat-icon-button (click)="onDelete(video, i)">
|
||||||
|
<mat-icon>delete</mat-icon>
|
||||||
|
</button><br/>
|
||||||
|
<!-- titre video -->
|
||||||
|
<span>{{video.title}}</span>
|
||||||
|
</div>
|
||||||
|
</ng-template>
|
||||||
|
|
||||||
|
<!-- non -->
|
||||||
|
<ng-template #nope2>
|
||||||
|
<div></div>
|
||||||
|
</ng-template>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
<!-- --------------------------------------------------------------------------------------------------------------------- -->
|
||||||
|
|
||||||
|
|
||||||
|
<!-- Bordure basse -->
|
||||||
|
<div class="row" style="margin: 0px; padding: 0px">
|
||||||
|
<div class="bottomBorder"></div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
@ -0,0 +1,52 @@
|
||||||
|
.myContainer {
|
||||||
|
background-color: white ;
|
||||||
|
text-align: center;
|
||||||
|
width: 35vw;
|
||||||
|
height: 79vh;
|
||||||
|
margin: 3vh 0vh 3vh 0vh;
|
||||||
|
padding: 0px;
|
||||||
|
border: solid 1px black;
|
||||||
|
}
|
||||||
|
|
||||||
|
// TopBorder --------------------------------------------------------
|
||||||
|
|
||||||
|
.topBorder {
|
||||||
|
height: 4vh;
|
||||||
|
background-color: #dcdcdc;
|
||||||
|
text-align: left;
|
||||||
|
padding: 7px;
|
||||||
|
display: inline-block;
|
||||||
|
border-bottom: solid 1px black;
|
||||||
|
}
|
||||||
|
|
||||||
|
.spanPlayListTitle {
|
||||||
|
height: 100%;
|
||||||
|
padding: 0px;
|
||||||
|
font-size: x-large;
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// Liste des videos ------------------------------------------------
|
||||||
|
|
||||||
|
.listVideoContainer {
|
||||||
|
height: 73vh;
|
||||||
|
background-color: white;
|
||||||
|
padding: 0px;
|
||||||
|
overflow-y: scroll;
|
||||||
|
}
|
||||||
|
|
||||||
|
.videoContainer {
|
||||||
|
border-bottom: solid 2px black;
|
||||||
|
padding: 25px;
|
||||||
|
}
|
||||||
|
|
||||||
|
// BottomBorder --------------------------------------------------------
|
||||||
|
|
||||||
|
.bottomBorder {
|
||||||
|
height: 2vh;
|
||||||
|
background-color: #dcdcdc;
|
||||||
|
border-top: solid 1px black;
|
||||||
|
border-bottom: solid 1px black;
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,25 @@
|
||||||
|
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||||
|
|
||||||
|
import { VideoListComponent } from './video-list.component';
|
||||||
|
|
||||||
|
describe('VideoListComponent', () => {
|
||||||
|
let component: VideoListComponent;
|
||||||
|
let fixture: ComponentFixture<VideoListComponent>;
|
||||||
|
|
||||||
|
beforeEach(async () => {
|
||||||
|
await TestBed.configureTestingModule({
|
||||||
|
declarations: [ VideoListComponent ]
|
||||||
|
})
|
||||||
|
.compileComponents();
|
||||||
|
});
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
fixture = TestBed.createComponent(VideoListComponent);
|
||||||
|
component = fixture.componentInstance;
|
||||||
|
fixture.detectChanges();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should create', () => {
|
||||||
|
expect(component).toBeTruthy();
|
||||||
|
});
|
||||||
|
});
|
||||||
69
src/app/user/myPlaylists/video-list/video-list.component.ts
Normal file
69
src/app/user/myPlaylists/video-list/video-list.component.ts
Normal file
|
|
@ -0,0 +1,69 @@
|
||||||
|
import {Component, Input, OnInit} from '@angular/core';
|
||||||
|
import {ThemeService} from "../../../utils/services/theme/theme.service";
|
||||||
|
import {FictitiousDatasService} from "../../../utils/services/fictitiousDatas/fictitious-datas.service";
|
||||||
|
import {Video} from "../../../utils/interfaces/video";
|
||||||
|
import {VideoUrlService} from "../../../utils/services/videoUrl/video-url.service";
|
||||||
|
import {AddVideoToPlaylistsService} from "../../../utils/services/addVideoToPlaylists/add-video-to-playlists.service";
|
||||||
|
import {MessageService} from "../../../utils/services/message/message.service";
|
||||||
|
import {Playlist} from "../../../utils/interfaces/playlist";
|
||||||
|
import {MatSnackBar} from "@angular/material/snack-bar";
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'app-video-list',
|
||||||
|
templateUrl: './video-list.component.html',
|
||||||
|
styleUrls: ['./video-list.component.scss']
|
||||||
|
})
|
||||||
|
export class VideoListComponent
|
||||||
|
{
|
||||||
|
@Input() playlist: Playlist;
|
||||||
|
|
||||||
|
|
||||||
|
constructor( private messageService: MessageService,
|
||||||
|
public themeService: ThemeService,
|
||||||
|
private fictitiousDatasService: FictitiousDatasService,
|
||||||
|
public videoUrlService: VideoUrlService,
|
||||||
|
private addVideoToPlaylistService: AddVideoToPlaylistsService,
|
||||||
|
private snackBar: MatSnackBar ) { }
|
||||||
|
|
||||||
|
|
||||||
|
onAdd(video: Video): void
|
||||||
|
{
|
||||||
|
this.addVideoToPlaylistService.run(video);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
onDelete(video0: Video, indexVideo: number): void
|
||||||
|
{
|
||||||
|
// --- FAUX CODE ---
|
||||||
|
let message = "La video a bien été supprimé de la playlist" ;
|
||||||
|
this.playlist.videos.splice(indexVideo, 1);
|
||||||
|
const config = { duration: 1000, panelClass: "custom-class" };
|
||||||
|
this.snackBar.open( message, "", config);
|
||||||
|
|
||||||
|
// --- VRAI CODE ---
|
||||||
|
/*
|
||||||
|
this.messageService
|
||||||
|
.sendMessage("user/delete/video", {video: video0, playlist: this.playlist})
|
||||||
|
.subscribe( retour => {
|
||||||
|
|
||||||
|
let message = "" ;
|
||||||
|
if(retour.status === "error") message = "Echec de l'opération" ;
|
||||||
|
else {
|
||||||
|
message = "La video a bien été supprimé de la playlist" ;
|
||||||
|
this.playlist.videos.splice(index, 1);
|
||||||
|
}
|
||||||
|
const config = { duration: 1000, panelClass: "custom-class" };
|
||||||
|
this.snackBar.open( message, "", config);
|
||||||
|
})
|
||||||
|
*/
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
onIframeClick(videoUrl: string): void
|
||||||
|
{
|
||||||
|
console.log(videoUrl)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
75
src/app/user/search/page-search/page-search.component.html
Normal file
75
src/app/user/search/page-search/page-search.component.html
Normal file
|
|
@ -0,0 +1,75 @@
|
||||||
|
<div [class]="themeService.getClassTheme()">
|
||||||
|
<div class="myContainer">
|
||||||
|
|
||||||
|
<!-- Navbar -->
|
||||||
|
<div style="margin-bottom: 50px">
|
||||||
|
<app-nav-bar pour="user"></app-nav-bar>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
<!-- --------------------------------------------------------------------- -->
|
||||||
|
|
||||||
|
|
||||||
|
<!-- [Search bar] + [Site de streaming] -->
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-2"></div>
|
||||||
|
<div class="col-8" style="margin-bottom: 20px">
|
||||||
|
|
||||||
|
<!-- Search bar -->
|
||||||
|
<div class="row" style="margin-bottom: 10px">
|
||||||
|
<div>
|
||||||
|
<input type="search" placeholder="recherche..." class="inputSearchBar" [(ngModel)]="search">
|
||||||
|
<button class="btnRechercher" (click)="onSearch()"> Rechercher </button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Site de streaming -->
|
||||||
|
<div class="row" style="margin-bottom: 10px">
|
||||||
|
<div>
|
||||||
|
<span *ngFor="let plateforme of tabPlateform">
|
||||||
|
|
||||||
|
<input type="checkbox" [id]="plateforme.name" [name]="plateforme.name" style="margin-left: 5px" [(ngModel)]="plateforme.isSelected">
|
||||||
|
<img [src]="'/assets/logo_plateforms/'+plateforme.name+'.png'" alt="image" width="25px" height="25px" style="margin-left: 5px">
|
||||||
|
<label [for]="plateforme.name" style="margin-left: 5px"> {{plateforme.name}}</label>
|
||||||
|
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
<div class="col-2"></div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
<!-- --------------------------------------------------------------------- -->
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<!-- [pub gauche] + [Grilles des videos] + [pub droite] -->
|
||||||
|
<mat-grid-list cols="11" rowHeight="75vh">
|
||||||
|
|
||||||
|
<!-- pub gauche -->
|
||||||
|
<mat-grid-tile colspan="2" rowspan="1" class="cellulePub">
|
||||||
|
<div class="conteneurPub">
|
||||||
|
<app-advert [ad]="ad1"></app-advert>
|
||||||
|
</div>
|
||||||
|
</mat-grid-tile>
|
||||||
|
|
||||||
|
<!-- Grilles des videos -->
|
||||||
|
<mat-grid-tile colspan="7" rowspan="1" class="celluleGrilleVideo">
|
||||||
|
<div class="conteneurVideosGrid">
|
||||||
|
<app-video-grid [tabVideo]="tabVideo"></app-video-grid>
|
||||||
|
</div>
|
||||||
|
</mat-grid-tile>
|
||||||
|
|
||||||
|
<!-- pub droite -->
|
||||||
|
<mat-grid-tile colspan="2" rowspan="1" class="cellulePub">
|
||||||
|
<div class="conteneurPub">
|
||||||
|
<app-advert [ad]="ad1"></app-advert>
|
||||||
|
</div>
|
||||||
|
</mat-grid-tile>
|
||||||
|
|
||||||
|
</mat-grid-list>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
68
src/app/user/search/page-search/page-search.component.scss
Normal file
68
src/app/user/search/page-search/page-search.component.scss
Normal file
|
|
@ -0,0 +1,68 @@
|
||||||
|
.lightTheme {
|
||||||
|
color: black;
|
||||||
|
border-color: black;
|
||||||
|
}
|
||||||
|
.darkTheme {
|
||||||
|
color: white;
|
||||||
|
border-color: white;
|
||||||
|
}
|
||||||
|
.myContainer {
|
||||||
|
text-align: center;
|
||||||
|
max-width: 100vw;
|
||||||
|
height: 100vh;
|
||||||
|
overflow-x: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
.inputSearchBar {
|
||||||
|
width: 50%;
|
||||||
|
font-size: x-large;
|
||||||
|
}
|
||||||
|
.btnRechercher {
|
||||||
|
border: solid black 1px;
|
||||||
|
border-radius: 5px;
|
||||||
|
font-size: x-large;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
.celluleGrilleVideo {
|
||||||
|
border: solid 4px;
|
||||||
|
border-radius: 5px;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
.lightTheme .celluleGrilleVideo{
|
||||||
|
border-color: black;
|
||||||
|
background-color: #f0f0f0;
|
||||||
|
}
|
||||||
|
.darkTheme .celluleGrilleVideo{
|
||||||
|
border-color: white;
|
||||||
|
background-color: #646464;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
.conteneurVideosGrid {
|
||||||
|
height: 75vh;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.cellulePub {
|
||||||
|
padding: 0px 10px 0px 10px;
|
||||||
|
width: 100%;
|
||||||
|
text-align: center;
|
||||||
|
justify-content: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.conteneurPub {
|
||||||
|
height: 75vh;
|
||||||
|
text-align: center;
|
||||||
|
justify-content: center;
|
||||||
|
vertical-align: middle;
|
||||||
|
display: block;
|
||||||
|
width: 75%;
|
||||||
|
margin-left: auto;
|
||||||
|
margin-right: auto;
|
||||||
|
position: absolute;
|
||||||
|
top: 50%;
|
||||||
|
-ms-transform: translateY(-50%);
|
||||||
|
transform: translateY(-50%);
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,25 @@
|
||||||
|
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||||
|
|
||||||
|
import { PageSearchComponent } from './page-search.component';
|
||||||
|
|
||||||
|
describe('PageSearchComponent', () => {
|
||||||
|
let component: PageSearchComponent;
|
||||||
|
let fixture: ComponentFixture<PageSearchComponent>;
|
||||||
|
|
||||||
|
beforeEach(async () => {
|
||||||
|
await TestBed.configureTestingModule({
|
||||||
|
declarations: [ PageSearchComponent ]
|
||||||
|
})
|
||||||
|
.compileComponents();
|
||||||
|
});
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
fixture = TestBed.createComponent(PageSearchComponent);
|
||||||
|
component = fixture.componentInstance;
|
||||||
|
fixture.detectChanges();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should create', () => {
|
||||||
|
expect(component).toBeTruthy();
|
||||||
|
});
|
||||||
|
});
|
||||||
96
src/app/user/search/page-search/page-search.component.ts
Normal file
96
src/app/user/search/page-search/page-search.component.ts
Normal file
|
|
@ -0,0 +1,96 @@
|
||||||
|
import { Component, OnInit } from '@angular/core';
|
||||||
|
import {MessageService} from "../../../utils/services/message/message.service";
|
||||||
|
import {FictitiousDatasService} from "../../../utils/services/fictitiousDatas/fictitious-datas.service";
|
||||||
|
import {AddVideoToPlaylistsService} from "../../../utils/services/addVideoToPlaylists/add-video-to-playlists.service";
|
||||||
|
import {Video} from "../../../utils/interfaces/video";
|
||||||
|
import {Advert} from "../../../utils/interfaces/advert";
|
||||||
|
import {ThemeService} from "../../../utils/services/theme/theme.service";
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
let TAB_PLATEFORM = [
|
||||||
|
{ name: "Youtube", isSelected: false },
|
||||||
|
{ name: "Dailymotion", isSelected: false }
|
||||||
|
];
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'app-page-search',
|
||||||
|
templateUrl: './page-search.component.html',
|
||||||
|
styleUrls: ['./page-search.component.scss']
|
||||||
|
})
|
||||||
|
export class PageSearchComponent implements OnInit
|
||||||
|
{
|
||||||
|
tabPlateform = TAB_PLATEFORM;
|
||||||
|
tabVideo: Video[] = [];
|
||||||
|
search: string = "";
|
||||||
|
ad1: Advert;
|
||||||
|
ad2: Advert;
|
||||||
|
|
||||||
|
|
||||||
|
constructor( private messageService: MessageService,
|
||||||
|
private fictitiousDatasService: FictitiousDatasService,
|
||||||
|
public themeService: ThemeService ) { }
|
||||||
|
|
||||||
|
|
||||||
|
ngOnInit(): void
|
||||||
|
{
|
||||||
|
// --- FAUX CODE ---
|
||||||
|
this.tabVideo = this.fictitiousDatasService.getTabVideo(11);
|
||||||
|
this.ad1 = this.fictitiousDatasService.getAdvert();
|
||||||
|
this.ad2 = this.fictitiousDatasService.getAdvert();
|
||||||
|
|
||||||
|
// --- VRAI CODE ---
|
||||||
|
/*
|
||||||
|
let tabPlateformName = [];
|
||||||
|
for(let plateform of this.tabPlateform) tabPlateformName.push(plateform.name);
|
||||||
|
let data = { search: "", plaateforms: tabPlateformName };
|
||||||
|
this.messageService
|
||||||
|
.sendMessage("user/searchVideo", data)
|
||||||
|
.subscribe( retour => {
|
||||||
|
if(retour.status === "error") console.log(retour.data);
|
||||||
|
else {
|
||||||
|
this.tabVideo = retour.data.videos;
|
||||||
|
this.ad1 = retour.data.ad1;
|
||||||
|
this.ad2 = retour.data.ad2;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
*/
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
onSearch()
|
||||||
|
{
|
||||||
|
// --- FAUX CODE ---
|
||||||
|
this.tabVideo = this.fictitiousDatasService.getTabVideo(4);
|
||||||
|
|
||||||
|
// --- VRAI CODE ---
|
||||||
|
/*
|
||||||
|
let tabPlateformName = [];
|
||||||
|
for(let plateform of this.tabPlateform)
|
||||||
|
{
|
||||||
|
if(plateform.isSelected) tabPlateformName.push(plateform.name);
|
||||||
|
}
|
||||||
|
let data = { "search": this.search, "plateforms": tabPlateformName };
|
||||||
|
this.messageService
|
||||||
|
.sendMessage("user/searchVideo", data)
|
||||||
|
.subscribe(retour => {
|
||||||
|
if(retour.status === "error") console.log(retour.data);
|
||||||
|
else {
|
||||||
|
this.tabVideo = retour.data.videos;
|
||||||
|
this.ad1 = retour.data.ad1;
|
||||||
|
this.ad2 = retour.data.ad2;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
*/
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
tiles = [
|
||||||
|
{text: 'One', cols: 2, rows: 1, color: 'lightblue'},
|
||||||
|
{text: 'Two', cols: 7, rows: 1, color: 'lightgreen'},
|
||||||
|
{text: 'Three', cols: 2, rows: 1, color: 'lightpink'},
|
||||||
|
];
|
||||||
|
|
||||||
|
}
|
||||||
11
src/app/user/search/video-cell/video-cell.component.html
Normal file
11
src/app/user/search/video-cell/video-cell.component.html
Normal file
|
|
@ -0,0 +1,11 @@
|
||||||
|
<link href="https://fonts.googleapis.com/icon?family=Material+Icons" rel="stylesheet">
|
||||||
|
|
||||||
|
<div [class]="themeService.getClassTheme()">
|
||||||
|
<div class="conteneur">
|
||||||
|
<iframe appIframeTracker [src]=safeUrl allowfullscreen (iframeClick)="onIframeClick(this.video.url)"></iframe><br/>
|
||||||
|
<span>{{video.title}}</span>
|
||||||
|
<button mat-icon-button (click)="onAdd()">
|
||||||
|
<mat-icon > add_circle </mat-icon>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
18
src/app/user/search/video-cell/video-cell.component.scss
Normal file
18
src/app/user/search/video-cell/video-cell.component.scss
Normal file
|
|
@ -0,0 +1,18 @@
|
||||||
|
.conteneur {
|
||||||
|
text-align: center;
|
||||||
|
border: solid 2px;
|
||||||
|
border-radius: 5px;
|
||||||
|
padding-top: 15px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.lightTheme .conteneur {
|
||||||
|
background-color: #ffffff;
|
||||||
|
border-color: black;
|
||||||
|
font-color: black;
|
||||||
|
}
|
||||||
|
|
||||||
|
.darkTheme .conteneur {
|
||||||
|
background-color: #c8c8c8;
|
||||||
|
border-color: #ffffff;
|
||||||
|
font-color: white;
|
||||||
|
}
|
||||||
25
src/app/user/search/video-cell/video-cell.component.spec.ts
Normal file
25
src/app/user/search/video-cell/video-cell.component.spec.ts
Normal file
|
|
@ -0,0 +1,25 @@
|
||||||
|
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||||
|
|
||||||
|
import { VideoCellComponent } from './video-cell.component';
|
||||||
|
|
||||||
|
describe('RectangleVideoComponent', () => {
|
||||||
|
let component: VideoCellComponent;
|
||||||
|
let fixture: ComponentFixture<VideoCellComponent>;
|
||||||
|
|
||||||
|
beforeEach(async () => {
|
||||||
|
await TestBed.configureTestingModule({
|
||||||
|
declarations: [ VideoCellComponent ]
|
||||||
|
})
|
||||||
|
.compileComponents();
|
||||||
|
});
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
fixture = TestBed.createComponent(VideoCellComponent);
|
||||||
|
component = fixture.componentInstance;
|
||||||
|
fixture.detectChanges();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should create', () => {
|
||||||
|
expect(component).toBeTruthy();
|
||||||
|
});
|
||||||
|
});
|
||||||
38
src/app/user/search/video-cell/video-cell.component.ts
Normal file
38
src/app/user/search/video-cell/video-cell.component.ts
Normal file
|
|
@ -0,0 +1,38 @@
|
||||||
|
import {
|
||||||
|
Component,
|
||||||
|
Input,
|
||||||
|
OnInit,
|
||||||
|
} from '@angular/core';
|
||||||
|
import {VideoUrlService} from "../../../utils/services/videoUrl/video-url.service";
|
||||||
|
import {AddVideoToPlaylistsService} from "../../../utils/services/addVideoToPlaylists/add-video-to-playlists.service";
|
||||||
|
import {Video} from "../../../utils/interfaces/video";
|
||||||
|
import {ThemeService} from "../../../utils/services/theme/theme.service";
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'app-video-cell',
|
||||||
|
templateUrl: './video-cell.component.html',
|
||||||
|
styleUrls: ['./video-cell.component.scss']
|
||||||
|
})
|
||||||
|
export class VideoCellComponent implements OnInit
|
||||||
|
{
|
||||||
|
@Input() video: Video;
|
||||||
|
safeUrl;
|
||||||
|
|
||||||
|
constructor( private videoUrlService: VideoUrlService,
|
||||||
|
private addVideoToPlaylistsService: AddVideoToPlaylistsService,
|
||||||
|
public themeService: ThemeService) {}
|
||||||
|
|
||||||
|
ngOnInit(): void
|
||||||
|
{
|
||||||
|
this.safeUrl = this.videoUrlService.safeUrl(this.video.url);
|
||||||
|
}
|
||||||
|
|
||||||
|
onAdd(): void
|
||||||
|
{
|
||||||
|
this.addVideoToPlaylistsService.run(this.video);
|
||||||
|
}
|
||||||
|
|
||||||
|
onIframeClick(videoUrl: string) {
|
||||||
|
console.log("test click iframe "+ videoUrl);
|
||||||
|
}
|
||||||
|
}
|
||||||
11
src/app/user/search/video-grid/video-grid.component.html
Normal file
11
src/app/user/search/video-grid/video-grid.component.html
Normal file
|
|
@ -0,0 +1,11 @@
|
||||||
|
<div class="conteneur">
|
||||||
|
<nav>
|
||||||
|
<ul>
|
||||||
|
<li class="row ligne" *ngFor="let triplet of tabTriplet">
|
||||||
|
<div class="col-4" *ngFor="let video0 of triplet">
|
||||||
|
<app-video-cell [video]="video0"></app-video-cell>
|
||||||
|
</div>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</nav>
|
||||||
|
</div>
|
||||||
14
src/app/user/search/video-grid/video-grid.component.scss
Normal file
14
src/app/user/search/video-grid/video-grid.component.scss
Normal file
|
|
@ -0,0 +1,14 @@
|
||||||
|
.conteneur {
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
nav ul {
|
||||||
|
overflow: hidden;
|
||||||
|
overflow-y: scroll;
|
||||||
|
height: 75vh;
|
||||||
|
padding: 30px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ligne {
|
||||||
|
margin: 30px 0px 30px 0px;
|
||||||
|
}
|
||||||
25
src/app/user/search/video-grid/video-grid.component.spec.ts
Normal file
25
src/app/user/search/video-grid/video-grid.component.spec.ts
Normal file
|
|
@ -0,0 +1,25 @@
|
||||||
|
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||||
|
|
||||||
|
import { VideoGridComponent } from './video-grid.component';
|
||||||
|
|
||||||
|
describe('VideoGridComponent', () => {
|
||||||
|
let component: VideoGridComponent;
|
||||||
|
let fixture: ComponentFixture<VideoGridComponent>;
|
||||||
|
|
||||||
|
beforeEach(async () => {
|
||||||
|
await TestBed.configureTestingModule({
|
||||||
|
declarations: [ VideoGridComponent ]
|
||||||
|
})
|
||||||
|
.compileComponents();
|
||||||
|
});
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
fixture = TestBed.createComponent(VideoGridComponent);
|
||||||
|
component = fixture.componentInstance;
|
||||||
|
fixture.detectChanges();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should create', () => {
|
||||||
|
expect(component).toBeTruthy();
|
||||||
|
});
|
||||||
|
});
|
||||||
34
src/app/user/search/video-grid/video-grid.component.ts
Normal file
34
src/app/user/search/video-grid/video-grid.component.ts
Normal file
|
|
@ -0,0 +1,34 @@
|
||||||
|
import {Component, Input, OnChanges, OnInit, SimpleChanges} from '@angular/core';
|
||||||
|
import {Video} from "../../../utils/interfaces/video";
|
||||||
|
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'app-video-grid',
|
||||||
|
templateUrl: './video-grid.component.html',
|
||||||
|
styleUrls: ['./video-grid.component.scss']
|
||||||
|
})
|
||||||
|
export class VideoGridComponent implements OnChanges
|
||||||
|
{
|
||||||
|
@Input() tabVideo: Video[] = [];
|
||||||
|
tabTriplet = [];
|
||||||
|
|
||||||
|
ngOnChanges(changes: SimpleChanges): void
|
||||||
|
{
|
||||||
|
this.tabTriplet = [];
|
||||||
|
let n = this.tabVideo.length;
|
||||||
|
let i = 0;
|
||||||
|
while(i < n)
|
||||||
|
{
|
||||||
|
let triplet = []
|
||||||
|
let compteur = 0;
|
||||||
|
while((compteur < 3) && (i < n))
|
||||||
|
{
|
||||||
|
triplet.push(this.tabVideo[i]);
|
||||||
|
i++ ;
|
||||||
|
compteur++ ;
|
||||||
|
}
|
||||||
|
this.tabTriplet.push(triplet)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
6
src/app/utils/components/advert/advert.component.html
Normal file
6
src/app/utils/components/advert/advert.component.html
Normal file
|
|
@ -0,0 +1,6 @@
|
||||||
|
<div [class]="themeService.getClassTheme()">
|
||||||
|
<div class="myContainer">
|
||||||
|
<span class="helper"></span>
|
||||||
|
<img [src]="'assets/pub/'+ad.images[idxImage].url" [alt]="ad.images[idxImage].url">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
28
src/app/utils/components/advert/advert.component.scss
Normal file
28
src/app/utils/components/advert/advert.component.scss
Normal file
|
|
@ -0,0 +1,28 @@
|
||||||
|
.myContainer {
|
||||||
|
margin: 0;
|
||||||
|
position: absolute;
|
||||||
|
top: 50%;
|
||||||
|
-ms-transform: translateY(-50%);
|
||||||
|
transform: translateY(-50%);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
img {
|
||||||
|
max-width: 100%;
|
||||||
|
max-height: 100%;
|
||||||
|
border: solid 3px;
|
||||||
|
vertical-align: middle;
|
||||||
|
}
|
||||||
|
.lightTheme img {
|
||||||
|
border-color: black;
|
||||||
|
}
|
||||||
|
.darkTheme img {
|
||||||
|
border-color: white;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
.helper {
|
||||||
|
display: inline-block;
|
||||||
|
height: 100%;
|
||||||
|
vertical-align: middle;
|
||||||
|
}
|
||||||
25
src/app/utils/components/advert/advert.component.spec.ts
Normal file
25
src/app/utils/components/advert/advert.component.spec.ts
Normal file
|
|
@ -0,0 +1,25 @@
|
||||||
|
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||||
|
|
||||||
|
import { AdvertComponent } from './advert.component';
|
||||||
|
|
||||||
|
describe('PubComponent', () => {
|
||||||
|
let component: AdvertComponent;
|
||||||
|
let fixture: ComponentFixture<AdvertComponent>;
|
||||||
|
|
||||||
|
beforeEach(async () => {
|
||||||
|
await TestBed.configureTestingModule({
|
||||||
|
declarations: [ AdvertComponent ]
|
||||||
|
})
|
||||||
|
.compileComponents();
|
||||||
|
});
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
fixture = TestBed.createComponent(AdvertComponent);
|
||||||
|
component = fixture.componentInstance;
|
||||||
|
fixture.detectChanges();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should create', () => {
|
||||||
|
expect(component).toBeTruthy();
|
||||||
|
});
|
||||||
|
});
|
||||||
27
src/app/utils/components/advert/advert.component.ts
Normal file
27
src/app/utils/components/advert/advert.component.ts
Normal file
|
|
@ -0,0 +1,27 @@
|
||||||
|
import {Component, Input, OnInit} from '@angular/core';
|
||||||
|
import {Advert} from "../../interfaces/advert";
|
||||||
|
import {ThemeService} from "../../services/theme/theme.service";
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'app-advert',
|
||||||
|
templateUrl: './advert.component.html',
|
||||||
|
styleUrls: ['./advert.component.scss']
|
||||||
|
})
|
||||||
|
export class AdvertComponent implements OnInit
|
||||||
|
{
|
||||||
|
@Input() ad: Advert;
|
||||||
|
idxImage: number = 0;
|
||||||
|
|
||||||
|
|
||||||
|
constructor(public themeService: ThemeService) { }
|
||||||
|
|
||||||
|
|
||||||
|
ngOnInit(): void
|
||||||
|
{
|
||||||
|
const nbImages = this.ad.images.length;
|
||||||
|
this.idxImage = Math.floor(Math.random() * nbImages);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
41
src/app/utils/components/nav-bar/nav-bar.component.html
Normal file
41
src/app/utils/components/nav-bar/nav-bar.component.html
Normal file
|
|
@ -0,0 +1,41 @@
|
||||||
|
<div [class]="themeService.getClassTheme()">
|
||||||
|
|
||||||
|
<!-- pour les 3 roles -->
|
||||||
|
<div *ngIf="pour === '3roles'">
|
||||||
|
<ul>
|
||||||
|
<li>
|
||||||
|
<a routerLink="/connexion" class="StreamNotFound"> StreamNotFound </a>
|
||||||
|
</li>
|
||||||
|
<li style="float:right; margin-right: 20px;">
|
||||||
|
<mat-slide-toggle (click)="onClick()"></mat-slide-toggle>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- pour User -->
|
||||||
|
<div *ngIf="pour === 'user'">
|
||||||
|
<ul>
|
||||||
|
<li>
|
||||||
|
<a routerLink="/search" class="StreamNotFound"> StreamNotFound </a>
|
||||||
|
</li>
|
||||||
|
<li class="cliquable">
|
||||||
|
<a routerLink="/search"> Rechercher </a>
|
||||||
|
</li>
|
||||||
|
<li class="cliquable">
|
||||||
|
<a routerLink="/myPlaylists"> Mes playlists </a>
|
||||||
|
</li>
|
||||||
|
<li class="cliquable">
|
||||||
|
<a routerLink="/search"> Historique </a>
|
||||||
|
</li>
|
||||||
|
<li style="float:right; margin-right: 20px;">
|
||||||
|
<a routerLink="/search">
|
||||||
|
<mat-icon>settings</mat-icon>
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
<li style="float:right; margin-right: 20px;">
|
||||||
|
<mat-slide-toggle (click)="onClick()"></mat-slide-toggle>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
69
src/app/utils/components/nav-bar/nav-bar.component.scss
Normal file
69
src/app/utils/components/nav-bar/nav-bar.component.scss
Normal file
|
|
@ -0,0 +1,69 @@
|
||||||
|
.StreamNotFound {
|
||||||
|
font-style: oblique;
|
||||||
|
font-family: cursive;
|
||||||
|
font-size: xx-large;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
mat-icon {
|
||||||
|
margin-top: 2px;
|
||||||
|
font-size: xx-large;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
mat-slide-toggle {
|
||||||
|
margin-top: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
ul {
|
||||||
|
list-style-type: none;
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
overflow: hidden;
|
||||||
|
background-color: black;
|
||||||
|
height: 70px;
|
||||||
|
color: white;
|
||||||
|
border-bottom: solid 2px white;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
li {
|
||||||
|
float: left;
|
||||||
|
font-size: x-large;
|
||||||
|
background-color: black;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
li a {
|
||||||
|
display: block;
|
||||||
|
color: white;
|
||||||
|
text-align: center;
|
||||||
|
padding: 14px 16px;
|
||||||
|
text-decoration: none;
|
||||||
|
background-color: black;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
.cliquable a:hover:not(.active) {
|
||||||
|
background-color: #c8c8c8;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
::ng-deep .mat-slide-toggle-thumb {
|
||||||
|
background-color: #c8c8c8;
|
||||||
|
}
|
||||||
|
|
||||||
|
::ng-deep .mat-slide-toggle-bar {
|
||||||
|
background-color: #ffffff;
|
||||||
|
}
|
||||||
|
|
||||||
|
::ng-deep .mat-slide-toggle.mat-checked:not(.mat-disabled) .mat-slide-toggle-thumb {
|
||||||
|
background-color: #ffffff;
|
||||||
|
}
|
||||||
|
|
||||||
|
::ng-deep .mat-slide-toggle.mat-checked:not(.mat-disabled) .mat-slide-toggle-bar {
|
||||||
|
background-color: #646464;
|
||||||
|
}
|
||||||
25
src/app/utils/components/nav-bar/nav-bar.component.spec.ts
Normal file
25
src/app/utils/components/nav-bar/nav-bar.component.spec.ts
Normal file
|
|
@ -0,0 +1,25 @@
|
||||||
|
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||||
|
|
||||||
|
import { NavBarComponent } from './nav-bar.component';
|
||||||
|
|
||||||
|
describe('NavBarComponent', () => {
|
||||||
|
let component: NavBarComponent;
|
||||||
|
let fixture: ComponentFixture<NavBarComponent>;
|
||||||
|
|
||||||
|
beforeEach(async () => {
|
||||||
|
await TestBed.configureTestingModule({
|
||||||
|
declarations: [ NavBarComponent ]
|
||||||
|
})
|
||||||
|
.compileComponents();
|
||||||
|
});
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
fixture = TestBed.createComponent(NavBarComponent);
|
||||||
|
component = fixture.componentInstance;
|
||||||
|
fixture.detectChanges();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should create', () => {
|
||||||
|
expect(component).toBeTruthy();
|
||||||
|
});
|
||||||
|
});
|
||||||
19
src/app/utils/components/nav-bar/nav-bar.component.ts
Normal file
19
src/app/utils/components/nav-bar/nav-bar.component.ts
Normal file
|
|
@ -0,0 +1,19 @@
|
||||||
|
import {Component, Input, OnInit} from '@angular/core';
|
||||||
|
import {ThemeService} from "../../services/theme/theme.service";
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'app-nav-bar',
|
||||||
|
templateUrl: './nav-bar.component.html',
|
||||||
|
styleUrls: ['./nav-bar.component.scss']
|
||||||
|
})
|
||||||
|
export class NavBarComponent
|
||||||
|
{
|
||||||
|
@Input() pour = "3roles";
|
||||||
|
|
||||||
|
constructor(public themeService: ThemeService) { }
|
||||||
|
|
||||||
|
onClick(): void {
|
||||||
|
this.themeService.isLightTheme = !this.themeService.isLightTheme
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,41 @@
|
||||||
|
<h3> Ajouter dans </h3>
|
||||||
|
|
||||||
|
|
||||||
|
<mat-divider></mat-divider><!------------------------------------------------------------------------------------------------------------->
|
||||||
|
|
||||||
|
|
||||||
|
<div class="conteneurPlaylists">
|
||||||
|
<div *ngFor="let playlist of tabPlaylistAndBool" style="margin-left: 10px">
|
||||||
|
<mat-checkbox [(ngModel)]="playlist.isSelected"> {{playlist.name}} </mat-checkbox>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
<mat-divider></mat-divider><!------------------------------------------------------------------------------------------------------------->
|
||||||
|
|
||||||
|
|
||||||
|
<div class="conteneurBtnCreerPlaylist" *ngIf="!goToCreatePlaylist">
|
||||||
|
<button mat-button (click)="goToCreatePlaylist=true">
|
||||||
|
<mat-label>Creer une playlist</mat-label>
|
||||||
|
<mat-icon>add</mat-icon>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="conteneurInputNewPlaylist" *ngIf="goToCreatePlaylist">
|
||||||
|
<mat-form-field>
|
||||||
|
<mat-label> Nom playlist </mat-label>
|
||||||
|
<input matInput type="text" [(ngModel)]="newPlaylistName">
|
||||||
|
</mat-form-field>
|
||||||
|
<button mat-icon-button (click)="goToCreatePlaylist=false">
|
||||||
|
<mat-icon>close</mat-icon>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
<mat-divider></mat-divider><!------------------------------------------------------------------------------------------------------------->
|
||||||
|
|
||||||
|
|
||||||
|
<mat-dialog-actions style="justify-content: flex-end;">
|
||||||
|
<button mat-button mat-dialog-close (click)="onAnnuler()">Annuler</button>
|
||||||
|
<button mat-button [mat-dialog-close]="true" cdkFocusInitial (click)="onValider()">Valider</button>
|
||||||
|
</mat-dialog-actions>
|
||||||
|
|
@ -0,0 +1,19 @@
|
||||||
|
h3 {
|
||||||
|
text-align: center;
|
||||||
|
margin-bottom: 10px
|
||||||
|
}
|
||||||
|
|
||||||
|
.conteneurPlaylists {
|
||||||
|
margin-top: 10px;
|
||||||
|
margin-bottom: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.conteneurBtnCreerPlaylist {
|
||||||
|
margin-top: 10px;
|
||||||
|
margin-bottom: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.conteneurInputNewPlaylist {
|
||||||
|
margin-top: 10px;
|
||||||
|
margin-bottom: 10px;
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,25 @@
|
||||||
|
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||||
|
|
||||||
|
import { PopupAddVideoToPlaylistsComponent } from './popup-add-video-to-playlists.component';
|
||||||
|
|
||||||
|
describe('PopupAddVideoToPlaylistsComponent', () => {
|
||||||
|
let component: PopupAddVideoToPlaylistsComponent;
|
||||||
|
let fixture: ComponentFixture<PopupAddVideoToPlaylistsComponent>;
|
||||||
|
|
||||||
|
beforeEach(async () => {
|
||||||
|
await TestBed.configureTestingModule({
|
||||||
|
declarations: [ PopupAddVideoToPlaylistsComponent ]
|
||||||
|
})
|
||||||
|
.compileComponents();
|
||||||
|
});
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
fixture = TestBed.createComponent(PopupAddVideoToPlaylistsComponent);
|
||||||
|
component = fixture.componentInstance;
|
||||||
|
fixture.detectChanges();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should create', () => {
|
||||||
|
expect(component).toBeTruthy();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
@ -0,0 +1,67 @@
|
||||||
|
import {Component, Inject, OnInit} from '@angular/core';
|
||||||
|
import {MAT_DIALOG_DATA, MatDialogRef} from "@angular/material/dialog";
|
||||||
|
import {Video} from "../../interfaces/video";
|
||||||
|
import {MessageService} from "../../services/message/message.service";
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'app-popup-add-video-to-playlists',
|
||||||
|
templateUrl: './popup-add-video-to-playlists.component.html',
|
||||||
|
styleUrls: ['./popup-add-video-to-playlists.component.scss']
|
||||||
|
})
|
||||||
|
export class PopupAddVideoToPlaylistsComponent implements OnInit
|
||||||
|
{
|
||||||
|
video: Video;
|
||||||
|
tabPlaylistAndBool = [];
|
||||||
|
goToCreatePlaylist = false;
|
||||||
|
newPlaylistName = "";
|
||||||
|
|
||||||
|
|
||||||
|
constructor( public dialogRef: MatDialogRef<PopupAddVideoToPlaylistsComponent>,
|
||||||
|
@Inject(MAT_DIALOG_DATA) public data,
|
||||||
|
private messageService: MessageService) { }
|
||||||
|
|
||||||
|
|
||||||
|
ngOnInit(): void
|
||||||
|
{
|
||||||
|
this.video = this.data.video;
|
||||||
|
for(let playlist of this.data.playlists)
|
||||||
|
{
|
||||||
|
playlist["isSelected"] = false;
|
||||||
|
this.tabPlaylistAndBool.push(playlist);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
onValider(): void
|
||||||
|
{
|
||||||
|
const tabPlaylist = [];
|
||||||
|
for(let playlist of this.tabPlaylistAndBool)
|
||||||
|
{
|
||||||
|
if(playlist.isSelected) {
|
||||||
|
delete playlist["isSelected"];
|
||||||
|
tabPlaylist.push(playlist);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// --- FAUX CODE ---
|
||||||
|
this.dialogRef.close("success");
|
||||||
|
|
||||||
|
// --- VRAI CODE ---
|
||||||
|
/*
|
||||||
|
if(!this.goToCreatePlaylist) this.newPlaylistName = "";
|
||||||
|
const data = { "video": this.video, "playlists": tabPlaylist, "newPlaylistName": this.newPlaylistName };
|
||||||
|
this.messageService
|
||||||
|
.sendMessage("user/add/vidéo", data)
|
||||||
|
.subscribe( retour => { this.dialogRef.close(retour.status) });
|
||||||
|
*/
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
onAnnuler(): void
|
||||||
|
{
|
||||||
|
this.dialogRef.close("annulation")
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,16 @@
|
||||||
|
<div style="text-align: center; margin: 0px; padding: 0px">
|
||||||
|
|
||||||
|
<div style="margin: 0px; padding: 0px">
|
||||||
|
<mat-form-field appearance="fill" style="margin: 0px; padding: 0px">
|
||||||
|
<mat-label> Nom de la playlist </mat-label>
|
||||||
|
<input matInput [(ngModel)]="name" style="width: 100%">
|
||||||
|
</mat-form-field>
|
||||||
|
<span *ngIf="hasError" class="mat-error"> {{errorMessage}} </span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div style="text-align: right ; margin: 0px; padding: 0px">
|
||||||
|
<button mat-button (click)="onAnnuler()">Annuler</button>
|
||||||
|
<button mat-button (click)="onValider()">Creer</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
@ -0,0 +1,25 @@
|
||||||
|
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||||
|
|
||||||
|
import { PopupCreatePlaylistComponent } from './popup-create-playlist.component';
|
||||||
|
|
||||||
|
describe('PopupCreatePlaylistComponent', () => {
|
||||||
|
let component: PopupCreatePlaylistComponent;
|
||||||
|
let fixture: ComponentFixture<PopupCreatePlaylistComponent>;
|
||||||
|
|
||||||
|
beforeEach(async () => {
|
||||||
|
await TestBed.configureTestingModule({
|
||||||
|
declarations: [ PopupCreatePlaylistComponent ]
|
||||||
|
})
|
||||||
|
.compileComponents();
|
||||||
|
});
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
fixture = TestBed.createComponent(PopupCreatePlaylistComponent);
|
||||||
|
component = fixture.componentInstance;
|
||||||
|
fixture.detectChanges();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should create', () => {
|
||||||
|
expect(component).toBeTruthy();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
@ -0,0 +1,92 @@
|
||||||
|
import {Component, Inject, OnInit} from '@angular/core';
|
||||||
|
import {MAT_DIALOG_DATA, MatDialogRef} from "@angular/material/dialog";
|
||||||
|
import {MessageService} from "../../services/message/message.service";
|
||||||
|
import {Playlist} from "../../interfaces/playlist";
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'app-popup-create-playlist',
|
||||||
|
templateUrl: './popup-create-playlist.component.html',
|
||||||
|
styleUrls: ['./popup-create-playlist.component.scss']
|
||||||
|
})
|
||||||
|
export class PopupCreatePlaylistComponent implements OnInit
|
||||||
|
{
|
||||||
|
name: string = "" ;
|
||||||
|
hasError: boolean = false;
|
||||||
|
tabNomPlaylist: string[] = [];
|
||||||
|
errorMessage: string = "" ;
|
||||||
|
|
||||||
|
|
||||||
|
constructor( public dialogRef: MatDialogRef<PopupCreatePlaylistComponent>,
|
||||||
|
@Inject(MAT_DIALOG_DATA) public data,
|
||||||
|
private messageService: MessageService) { }
|
||||||
|
|
||||||
|
|
||||||
|
ngOnInit(): void
|
||||||
|
{
|
||||||
|
this.tabNomPlaylist = this.data.map( playlist0 => playlist0.name );
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
onValider(): void
|
||||||
|
{
|
||||||
|
// --- FAUX CODE ---
|
||||||
|
//
|
||||||
|
this.checkError();
|
||||||
|
if(!this.hasError)
|
||||||
|
{
|
||||||
|
const playlist: Playlist = {
|
||||||
|
_id: "monId",
|
||||||
|
user: null,
|
||||||
|
name: this.name,
|
||||||
|
videos: [],
|
||||||
|
};
|
||||||
|
this.dialogRef.close(playlist);
|
||||||
|
}
|
||||||
|
|
||||||
|
// --- VRAI CODE ---
|
||||||
|
/*
|
||||||
|
this.checkError();
|
||||||
|
if(!this.hasError)
|
||||||
|
{
|
||||||
|
this.messageService
|
||||||
|
.sendMessage("user/create/playlist", {name: this.data.name})
|
||||||
|
.subscribe(retour => {
|
||||||
|
|
||||||
|
if (retour.status === "error") {
|
||||||
|
console.log(retour);
|
||||||
|
this.dialogRef.close(null);
|
||||||
|
} else {
|
||||||
|
this.dialogRef.close(retour.data.playlist);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
checkError(): void
|
||||||
|
{
|
||||||
|
if(this.name === "") {
|
||||||
|
this.errorMessage = "Le nom ne peut pas être vide" ;
|
||||||
|
this.hasError = true;
|
||||||
|
}
|
||||||
|
else if(this.tabNomPlaylist.includes(this.name)){
|
||||||
|
this.errorMessage = "Ce nom est déjà utilisé" ;
|
||||||
|
this.hasError = true;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
this.hasError = false;
|
||||||
|
this.errorMessage = "" ;
|
||||||
|
}
|
||||||
|
console.log("em:" + this.errorMessage);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
onAnnuler(): void
|
||||||
|
{
|
||||||
|
this.dialogRef.close(null);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,8 @@
|
||||||
|
import { IframeTrackerDirective } from './iframe-tracker.directive';
|
||||||
|
|
||||||
|
describe('IframeTrackerDirective', () => {
|
||||||
|
it('should create an instance', () => {
|
||||||
|
const directive = new IframeTrackerDirective();
|
||||||
|
expect(directive).toBeTruthy();
|
||||||
|
});
|
||||||
|
});
|
||||||
Some files were not shown because too many files have changed in this diff Show more
Reference in a new issue