Compare commits

..

32 commits

Author SHA1 Message Date
7f3b7e936e Update: User.ad randomize 2022-01-10 17:11:43 +01:00
3ff902353d Update: User.create 2022-01-10 12:25:28 +01:00
5e9e049cfc Update: Admin can create Admin or Advertiser 2022-01-10 12:22:03 +01:00
a428e5cff2 Update: Admin can create Admin or Advertiser 2022-01-10 12:07:45 +01:00
Yûki VACHOT
e6b8eef43c Update: Move Cors to server.js 2021-12-29 19:08:52 +01:00
Yûki VACHOT
32ceef171e Update: Add console log origin 2021-12-29 19:02:31 +01:00
Yûki VACHOT
f69ed4b3d4 Update: Npm Cors Doc 2021-12-29 19:01:06 +01:00
Yûki VACHOT
c6e02cf797 Update: Move Cors to Routes 2021-12-29 18:51:56 +01:00
Yûki VACHOT
3db7bfd7af Update: Add sameSite=None Cookie 2021-12-29 18:42:10 +01:00
Yûki VACHOT
96481369da Update: Add sameSite Cookie 2021-12-29 18:39:15 +01:00
Yûki VACHOT
aca78238fe Update: Add Secure 2021-12-29 18:35:33 +01:00
Yûki VACHOT
3febde57bb Update: Remove Allow from res 2021-12-29 18:20:47 +01:00
Yûki VACHOT
a9c959bf3f Update: Add console.log token 2021-12-29 18:10:05 +01:00
Yûki VACHOT
7a9ee00eb5 Update: Add Access Controls 2021-12-29 18:05:06 +01:00
Yûki VACHOT
68e212fce9 Update: Rollback Origin 2021-12-29 17:52:59 +01:00
Yûki VACHOT
e8e66fe505 Update: Allow Origin * 2021-12-29 17:50:45 +01:00
Yûki VACHOT
5ba9036289 Update: Change Cors Origin Admin 2021-12-29 17:36:46 +01:00
Yûki VACHOT
086d54a84b Update: Change Cors Origin False 2021-12-29 17:34:42 +01:00
Yûki VACHOT
b26c75f163 Update: Remove Origin 2021-12-29 17:30:37 +01:00
Yûki VACHOT
a330e71860 Update: Dev & Prod Backend explanations 2021-12-26 18:02:42 +01:00
Yûki VACHOT
5495a8321a Update: Add dev & prod local scripts 2021-12-26 18:00:43 +01:00
Yûki VACHOT
f328af51c5 Update: Cors Test 2021-12-23 13:25:35 +01:00
Yûki VACHOT
ae10848b63 Update: Cors Test 2021-12-23 13:22:11 +01:00
Yûki VACHOT
f26fcdc961 Update: Move Cors inside Routes definition 2021-12-23 13:18:04 +01:00
Yûki VACHOT
a12926f277 Update: Remove *all get request 2021-12-23 13:10:57 +01:00
Yûki VACHOT
ae0fe1f32f Update: Environment for Heroku Production 2021-12-23 13:07:36 +01:00
Yûki VACHOT
7448f6b591 Update: Environment for Heroku Production 2021-12-23 11:56:40 +01:00
965f1c03e9
Update server.js 2021-12-22 21:29:05 +01:00
6ce49daa9a
Update: Cors 2021-12-22 21:06:29 +01:00
Yûki VACHOT
97b6039ce5 Update: package.json 2021-12-22 12:04:39 +01:00
Yûki VACHOT
4f85d63bac Create: Add package.json 2021-12-22 11:17:47 +01:00
Yûki VACHOT
76ac0c292c Create: Backend branch 2021-12-22 11:09:20 +01:00
31 changed files with 2654 additions and 27 deletions

52
.gitignore vendored Normal file
View 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

1
Procfile Normal file
View file

@ -0,0 +1 @@
web: npm start

View file

@ -1,40 +1,67 @@
# PolyNotFound
# PolyNotFound - Partie Backend en local
Le projet est séparé en 3 parties :
## Lancement du Backend
- 2 Frontend :
- 1 partie Administrateur
- 1 partie pour les utilisateurs et les publicitaires
- 1 Backend
### 1.1 Installation des différentes librairies avec npm
Nous avons décidé que chaque partie du projet a sa propre branche git et non leur propre répertoire git.
Si NodeJS est installé ([téléchargeable ici](https://nodejs.org/en/download/)), il suffit de faire un `npm install`.
En effet, les branches concernées par le projet est :
- Frontend partie Administrateur : `front-admin`
- Frontend partie pour les utilisateurs et les publicitaires : `front-user-advertiser`
- Backend : `backend`
### 1.2 Création d'une base de données MongoDB en local avec Docker
Nous pouvons récupérer une branche git avec `git checkout <nom_branche>`.
Il faudra **Docker** ([téléchargeable ici](https://docs.docker.com/desktop/#download-and-install))
# Lancer le projet en Local
Puis dans un terminal, pour lancer le serveur MongoDB
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/).
`docker run -d -p 27017:27017 --ip 127.0.0.1 --name polynotfound-mongodb mongo:latest`
Pour lancer le projet en local dans son ensemble, il faut impérativement avoir les branches concernées dans leur propre dossier.
Il faudra donc __clone__ le projet 3 fois.
_L'image de Mongo sera automatiquement téléchargé si elle n'existe pas en local._
Dans un dossier nommé par exemple `Polynotfound`:
- 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`
1. Si vous avez MongoDB Compass ([téléchargeable ici](https://www.mongodb.com/try/download/compass)):
- Se connecter au serveur `mongodb://localhost:27017/?readPreference=primary&appname=MongoDB%20Compass&ssl=false`
- Create Database :
- Database Name : polynotfound
- Collection Name : users
Un README est disponible pour chaque branche pour lancer le projet en local soit en mode **production** soit en mode **développement**.
2. Sinon avec MongoShell ([téléchargeable ici](https://www.mongodb.com/try/download/shell)):
- Se connecter au serveur
- Linux: `mongo mongodb://localhost:27017/?readPreference=primary&appname=MongoDB%20Compass&ssl=false`
- Windows: `mongo.exe mongodb://localhost:27017/?readPreference=primary&appname=MongoDB%20Compass&ssl=false`
- Créer la base de données : `use polynotfound`
# Lancer le projet en ligne avec Heroku
### 1.3 Initialisation des variables d'environnements
Nous avons déployé le projet en ligne avec Heroku.
5 variables d'environnements sont nécessaires pour lancer le backend correctement.
- **DATABASE** : url de connexion à la base de données (utilisé seulement en production)
- Sur Windows : `set DATABASE=<url_bd>`
- Sur Linux : `export DATABASE=<url_bdd>`
- Token de connexion
- **JWTRS256_PUBLIC_KEY** : clé publique pour les tokens de connexion
- **JWTRS256_PRIVATE_KEY** : clé privée pour les tokens de connexion
Lancer le script de génération des clés `jwtRS256.sh`, un fichier `.env` sera créé.
Il faudra `set` ou `export` ces 2 variables dans vos variables d'environnements.
- Sur Windows :
- `set JWTRS256_PUBLIC_KEY=<public_key>`
- `set JWTRS256_PRIVATE_KEY=<private_key>`
- Sur Linux :
- `export JWTRS256_PUBLIC_KEY=<public_key>`
- `export JWTRS256_PRIVATE_KEY=<private_key>`
Le projet est disponible sur ces URL :
- Partie Utilisateurs et Publicitaires : https://polynotfound.herokuapp.com/
- Partie Administrateur : https://admin-polynotfound.herokuapp.com/
- API : https://api-polynotfound.herokuapp.com/
- **YOUTUBE_API_KEY** : Clé de connexion à l'API Youtube ([récupérable ici](https://developers.google.com/youtube/v3/getting-started?hl=fr))
- **DAILYMOTION_API_KEY** : Clé de connexion à l'API Dailymotion ([récupérable ici](https://www.dailymotion.com/profile/developer))
_A noté que la clé d'API de Dailymotion n'est pas utilisée mais cela peut changer dans le temps._
Après l'initialisation de ces variables d'environnements, il faudra surement redémarrer votre ordinateur. (Fermer et rouvrir un terminal peut être suffisant dans certain cas)
#### 1.3.1 Lancement en mode développement
Pour lancer le backend en mode développement, il faudra simplement exécuter dans un terminal:
- Windows : `npm dev-win`
- Linux & Mac : `npm dev-nix`
#### 1.3.2 Lancement en mode production
Pour lancer le backend en mode production, il faudra simplement exécuter dans un terminal:
- Windows : `npm prod-win`
- Linux & Mac : `npm prod-nix`

20
config/cors.config.js Normal file
View file

@ -0,0 +1,20 @@
const cors = require('cors');
module.exports.cors = cors;
const whitelist = [
'http://127.0.0.1:4200',
'http://127.0.0.1:4201',
'https://admin-polynotfound.herokuapp.com',
'https://polynotfound.herokuapp.com'
];
module.exports.corsOptions = {
origin: function(origin, callback) {
console.log(whitelist, origin);
if (whitelist.indexOf(origin) !== -1) {
callback(null, true);
} else {
callback(new Error('Not allowed by CORS'));
}
}
}

View file

@ -0,0 +1,26 @@
const request = require("request");
const VideoCategories = require("../models/objects/video.categories.model");
function asyncRequest(uri, option){
return new Promise(function(resolve){
request(uri, option,function (error, response, body){
resolve({response: response, body: JSON.parse(body)});
});
});
}
module.exports.asyncRequest = asyncRequest;
function asyncInterest(interest, source){
return new Promise(function(resolve){
for(const i in VideoCategories){
for(const j in VideoCategories[i].categories){
if((VideoCategories[i].categories[j].name === interest || VideoCategories[i].categories[j].id === interest)
&& VideoCategories[i].categories[j].source === source){
resolve(VideoCategories[i].interest);
}
}
}
resolve(null);
});
}
module.exports.asyncInterest = asyncInterest;

26
config/host.config.js Normal file
View file

@ -0,0 +1,26 @@
if(process.env.YOUTUBE_API_KEY === undefined ||
process.env.YOUTUBE_API_KEY === '' ||
process.env.DAILYMOTION_API_KEY === undefined ||
process.env.DAILYMOTION_API_KEY === ''){
console.log('Error Env YOUTUBE_API_KEY & DAILYMOTION_API_KEY Variables');
process.exit();
}
console.log('Env variables YOUTUBE_API_KEY & DAILYMOTION_API_KEY received');
module.exports = {
youtube: {
name: "Youtube",
shortname: "yt",
baseAPIUrl: 'https://youtube.googleapis.com/youtube/v3',
baseChannelUrl: 'https://www.youtube.com/channel/',
YOUTUBE_API_KEY: process.env.YOUTUBE_API_KEY
},
dailymotion: {
name: "Dailymotion",
shortname: "dm",
baseAPIUrl: 'https://api.dailymotion.com',
baseChannelUrl: 'https://www.dailymotion.com/',
DAILYMOTION_API_KEY: process.env.DAILYMOTION_API_KEY
}
};

4
config/mongodb.config.js Normal file
View file

@ -0,0 +1,4 @@
module.exports = {
prodUrl: process.env.DATABASE,
devUrl: "mongodb://127.0.0.1:27017/polynotfound"
};

View 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, token: token, reason: reason});
}
module.exports = { sendMessage, sendError };

110
config/sessionJWT.config.js Normal file
View file

@ -0,0 +1,110 @@
const sessionJWTConfig = require ('jsonwebtoken');
require('dotenv').config({ path: './app-backend/.env' });
const {sendError} = require ("./response.config");
if(process.env.JWTRS256_PRIVATE_KEY === undefined || process.env.JWTRS256_PUBLIC_KEY === undefined){
console.log('Error Env JWTRS256_PRIVATE_KEY & JWTRS256_PUBLIC_KEY Variables');
process.exit();
}
console.log('Env variables JWTRS256_PRIVATE_KEY & JWTRS256_PUBLIC_KEY 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, email, profileImageUrl, role) {
return sessionJWTConfig.sign(
{
id: id,
email: email,
profileImageUrl: profileImageUrl,
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.email !== 'undefined' &&
typeof payload.profileImageUrl !== '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.email, payload.profileImageUrl, payload.role);
}
res.cookie('SESSIONID', jwtToken, {httpOnly: true, sameSite: 'None', secure: process.env.NODE_ENV === 'production'});
}
function decodeSessionCookie(sessionid) {
if (typeof sessionid === 'undefined') {
return {id: -1, email: -1, profileImageUrl: -1, role: -1};
}
try {
const token = sessionJWTConfig.verify(
sessionid,
JWTRS256_PUBLIC_KEY,
{algorithms: ['RS256']});
return {token: token};
}
catch (err) {
return {id: -1, email: -1, profileImageUrl: -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);
console.log(token);
if(typeof token.email === 'undefined' ||
token.email === -1 ||
typeof token.id === 'undefined' ||
token.id === -1){
return sendError(res, 500, 102, "User not authenticated.");
} else {
token.midExp = new Date(token.midExp*1000);
token.iat = new Date(token.iat*1000);
token.exp = new Date(token.exp*1000);
if(role === null){
return token;
} else {
if(typeof token.role !== 'undefined' &&
((Array.isArray(role) && role.includes(token.role)) ||
( typeof role === 'object' && typeof token.role.permission !== 'undefined' && token.role.permission >= role.permission && token.role.isAccepted === true))){
return token;
} else {
return sendError(res, 500, 106, "User doesn't have permission.", token);
}
}
}
} else {
return sendError(res, 500, -1, "Cookies don't exist.");
}
}
module.exports.checkLogin = checkLogin;

View file

@ -0,0 +1,290 @@
const db = require("../models/mongodb.model");
const {sendError, sendMessage} = require ("../config/response.config");
const {checkLogin} = require("../config/sessionJWT.config");
const ObjectId = require('mongoose').Types.ObjectId;
const roles = require("../models/objects/role.model");
const Ad = db.ads;
// Create a new Ad
exports.create = (req, res) => {
const token = checkLogin(req, res, roles.Advertiser);
if(token && req.body.title){
Ad.exists({title: req.body.title, userId: token.id, isActive: true}, function (err, docs){
if(err){
sendError(res, 500,100,err.message || "Some error occurred while checking if the Ad already exists.", token);
} else{
if(docs === null) {
let ad;
ad = new Ad({
userId: token.id,
title: req.body.title,
images: req.body.images ? req.body.images : undefined,
url: req.body.url ? req.body.url : undefined,
interests: req.body.interests ? req.body.interests : undefined,
comment: req.body.comment ? req.body.comment : undefined,
isVisible: req.body.isVisible ? req.body.isVisible : undefined,
isActive: req.body.isActive ? req.body.isActive : undefined
});
// Save User in the database
ad
.save(ad)
.then(data => {
return sendMessage(res, 41, data, token)
})
.catch(err => {
return sendError(res, 500,100,err.message || "Some error occurred while creating the Ad.", token);
});
} else{
return sendError(res, 500, 104, err || `Ad ${req.body.title} already exists.`, token);
}
}
});
} else {
return sendError(res, 500, -1, `No title given`, token);
}
};
// Retrieve all Ad from id if admin or session id
exports.findAll = (req, res) => {
const token = checkLogin(req, res, roles.Advertiser);
if(token){
let query = {};
let condition;
const adId = req.query.adId;
condition = adId ? adId : undefined;
query._id = condition;
let userId;
if(typeof token.role !== 'undefined' &&
typeof token.role.permission !== 'undefined' &&
typeof token.role.isAccepted !== 'undefined' &&
token.role.isAccepted === true &&
token.role.permission >= roles.Admin.permission) {
userId = req.query.userId;
} else {
userId = token.id;
}
condition = userId ? userId : undefined;
query.userId = condition;
const title = req.query.title;
condition = title ? { $regex: new RegExp(title), $options: "i" } : undefined;
query.title = condition;
const url = req.query.url;
condition = url ? { $regex: new RegExp(url), $options: "i" } : undefined;
query.url = condition;
const interests = req.query.interests;
condition = interests ? {$in: interests.split(',')} : undefined;
query["interests.interest"] = condition
const comment = req.query.comment;
condition = comment ? { $regex: new RegExp(comment), $options: "i" } : undefined;
query.comment = condition;
const isVisible = req.query.isVisible;
condition = isVisible ? isVisible : undefined;
query.isVisible = condition;
const isActive = req.query.isActive;
condition = isActive ? isActive : undefined;
query.isActive = condition;
const sort = req.query.sort;
if(sort !== 'undefined'){
switch (sort){
case 'asc':
condition = {title: 1};
break;
case 'desc':
condition = {title: -1};
break;
case 'createdAtAsc':
condition = {createdAt: 1};
break;
case 'createdAtDesc':
condition = {createdAt: -1};
break;
case 'updatedAtAsc':
condition = {updatedAt: 1};
break;
case 'updatedAtDesc':
condition = {updatedAt: -1};
break;
default:
condition = {title: 1};
}
}
const query_sort = {sort: condition};
// Remove undefined key
Object.keys(query).forEach(key => query[key] === undefined ? delete query[key] : {});
console.log(query);
Ad.find(query, {}, query_sort)
.then(data => {
if(data){
return sendMessage(res, 42, data, token);
}
})
.catch(err => {
return sendError(res,500,100,err.message || "Some error occurred while finding the Ads.", token);
});
}
};
// Find single Ad from id if admin or session id
exports.findOne = (req, res) => {
const token = checkLogin(req, res, roles.Advertiser);
if(token && typeof req.params.id !== 'undefined') {
const id = req.params.id;
if(id && ObjectId.isValid(id)){
Ad.findById(id, {})
.then(data => {
if(data){
return sendMessage(res, 43, data, token);
} else {
return sendError(res,404,105,`Ad not found with id=${id}`, token);
}
})
.catch(err => {
return sendError(res,500,100,err.message || `Some error occurred while finding the Ad with id=${id}`, token);
});
} else {
return sendError(res, 500, -1, `Error id is not valid`, token);
}
} else {
return sendError(res, 500, -1, `No id given`, token);
}
};
// Update a Ad with ad id
exports.update = (req, res) => {
const token = checkLogin(req, res, roles.Advertiser);
if(token && typeof req.params.id !== 'undefined') {
const id = req.params.id;
if(typeof req.body._id !== 'undefined' || typeof req.body.id !== 'undefined'){
return sendError(res, 500, -1, `User do not have the permission to modify id or _id`, token);
} else{
let update = {};
let condition;
const title = req.body.title;
condition = title ? title : undefined;
update.title = condition;
const images = req.body.images;
condition = images ? images : undefined;
update.images = condition;
const url = req.body.url;
condition = url ? url : undefined;
update.url = condition;
let interests = req.body.interests;
condition = interests ? {interests: [...new Map(interests.map(v => [v.id, v])).values()]} : undefined;
update.$addToSet = condition;
const comment = req.body.comment;
condition = comment ? comment : undefined;
update.comment = condition;
const isVisible = req.body.isVisible;
if(typeof isVisible !== 'undefined'){
condition = isVisible;
} else{
condition = undefined;
}
update.isVisible = condition;
const isActive = req.body.isActive;
if(typeof isActive !== 'undefined'){
condition = isActive;
} else{
condition = undefined;
}
update.isActive = condition;
// Remove undefined key
Object.keys(update).forEach(key => update[key] === undefined ? delete update[key] : {});
if(id && ObjectId.isValid(id)){
Ad.updateOne({_id: id, userId: token.id}, update)
.then(data => {
if(data) {
//Object.keys(update).forEach(key => data[key] = update[key]);
return sendMessage(res, 44, update, token);
} else {
return sendError(res, 404, -1, `Ad not found with id=${id}`, token);
}
})
.catch(err => {
return sendError(res, 500, -1, err.message || `Some error occurred while updating the Ad with id=${id}`, token);
});
} else {
return sendError(res, 500, -1, `Error id is not valid`, token);
}
}
} else {
return sendError(res, 500, -1, `No id given`, token);
}
};
// Delete an Ad with ad id
exports.delete = (req, res) => {
const token = checkLogin(req, res, roles.Advertiser);
if(token && typeof req.params.id !== 'undefined') {
let match = null;
const id = req.params.id;
if(id && ObjectId.isValid(id)){
if(typeof token.role !== 'undefined' &&
typeof token.role.permission !== 'undefined' &&
typeof token.role.isAccepted !== 'undefined' &&
token.role.isAccepted === true &&
token.role.permission >= roles.Admin.permission) {
match = {_id: id, isActive: true};
} else {
match = {_id: id, userId: token.id, isActive: true};
}
Ad.findOneAndUpdate(match, {isActive: false}, {useFindAndModify: false, new: true})
.then(data => {
if(data) {
if(data.isActive !== true){
return sendMessage(res, 45, {message: `Ad ${id} was successfully deleted.`}, token);
} else {
return sendError(res, 404, 105, `Ad ${id} was not deleted.`, token);
}
} else {
return sendError(res, 404, 105, `Ad not found with id=${id}`, token);
}
})
.catch(err => {
return sendError(res, 500, 100, err.message || `Some error occurred while deleting the Ad with id=${id}`, token);
});
} else {
return sendError(res, 500, -1, `Error id is not valid`, token);
}
} else {
return sendError(res, 500, -1, `No id given`, token);
}
};
// Delete all Ad from session id
exports.deleteAll = (req, res) => {
const token = checkLogin(req, res, roles.Advertiser);
if(token) {
Ad.updateMany({userId: {$eq: token.id}, isActive: true}, {isActive: false})
.then(data => {
return sendMessage(res, 46, {
message: `${data.modifiedCount} Ads were deleted successfully.`
});
})
.catch(err => {
return sendError(res, 500, -1, err.message || "Some error occurred while removing all Ads.");
});
}
};

View file

@ -0,0 +1,7 @@
const {sendMessage} = require ("../config/response.config");
const interests = require("../models/objects/video.categories.model");
// Get all interests available
exports.getInterests = (req, res) => {
return sendMessage(res, 51, interests, null)
};

View file

@ -0,0 +1,407 @@
const db = require("../models/mongodb.model");
const {sendError, sendMessage} = require ("../config/response.config");
const {checkLogin} = require("../config/sessionJWT.config");
const {youtube, dailymotion} = require("../config/host.config");
const {asyncRequest, asyncInterest} = require("../config/functions.config");
const ObjectId = require('mongoose').Types.ObjectId;
const Playlist = db.playlists;
const Video = db.videos;
// Create a new Playlist
exports.create = (req, res) => {
const token = checkLogin(req, res);
if(token && req.body.name){
const video = req.body.video;
if(typeof video !== 'undefined' &&
video !== null &&
typeof video.videoId !== 'undefined' &&
video.videoId !== null &&
typeof video.source !== 'undefined' &&
video.source !== null &&
typeof video.interest !== 'undefined' &&
video.interest !== null
){
Video.exists({userId: token.id, videoId: video.videoId, source: video.source, isActive: true}, function (err, docs){
if(err){
sendError(res, 500,100,err.message || "Some error occurred while checking if the Video already exists.", token);
} else{
if(docs === null) {
let video;
video = new Video({
userId: token.id,
videoId: id,
source: req.body.source,
interest: req.body.interest,
watchedDates: [new Date()]
});
// Save Video in the database
video
.save(video)
.then(data => {
if(data) {
Playlist.exists({name: req.body.name, isActive: true}, function (err, docs){
if(err){
sendError(res, 500,100,err.message || "Some error occurred while checking if the Playlist already exists.", token);
} else{
if(docs === null) {
let playlist;
playlist = new Playlist({
userId: token.id,
name: req.body.name,
videoIds: data._id ? [data._id] : undefined,
isActive: true
});
// Save User in the database
playlist
.save(playlist)
.then(data => {
return sendMessage(res, 21, data, token)
})
.catch(err => {
return sendError(res, 500,100,err.message || "Some error occurred while creating the Playlist.", token);
});
} else{
return sendError(res, 500, 104, err || `Playlist ${req.body.name} already exists.`, token);
}
}
});
}
})
.catch(err => {
return sendError(res, 500,100,err.message || "Some error occurred while creating the Video.", token);
});
} else{
const id = docs._id.toString();
Playlist.exists({name: req.body.name, isActive: true}, function (err, docs){
if(err){
sendError(res, 500,100,err.message || "Some error occurred while checking if the Playlist already exists.", token);
} else{
if(docs === null) {
let playlist;
playlist = new Playlist({
userId: token.id,
name: req.body.name,
videoIds: [id],
isActive: true
});
// Save User in the database
playlist
.save(playlist)
.then(data => {
return sendMessage(res, 21, data, token)
})
.catch(err => {
return sendError(res, 500,100,err.message || "Some error occurred while creating the Playlist.", token);
});
} else{
return sendError(res, 500, 104, err || `Playlist ${req.body.name} already exists.`, token);
}
}
});
}
}
});
} else {
Playlist.exists({name: req.body.name, isActive: true}, function (err, docs){
if(err){
sendError(res, 500,100,err.message || "Some error occurred while checking if the Playlist already exists.", token);
} else{
if(docs === null) {
let playlist;
playlist = new Playlist({
userId: token.id,
name: req.body.name,
videoIds: req.body.videoIds ? req.body.videoIds : undefined,
isActive: req.body.isActive ? req.body.isActive : undefined
});
// Save User in the database
playlist
.save(playlist)
.then(data => {
return sendMessage(res, 21, data, token)
})
.catch(err => {
return sendError(res, 500,100,err.message || "Some error occurred while creating the Playlist.", token);
});
} else{
return sendError(res, 500, 104, err || `Playlist ${req.body.name} already exists.`, token);
}
}
});
}
}
};
// Retrieve all Playlist from id if admin or session id
exports.findAll = (req, res) => {
const token = checkLogin(req, res);
if(token){
let query = {};
let condition;
const playlistId = req.query.playlistId;
condition = playlistId ? playlistId : undefined;
query._id = condition;
const userId = token.id;
condition = userId ? userId : undefined;
query.userId = condition;
const videoIds = req.query.videoIds;
condition = videoIds ? {$in: videoIds} : undefined;
query.videoIds = condition;
const name = req.query.name;
condition = name ? { $regex: new RegExp(name), $options: "i" } : undefined;
query.name = condition;
const isActive = req.query.isActive;
condition = isActive ? isActive : undefined;
query.isActive = condition;
const sort = req.query.sort;
if(sort !== 'undefined'){
switch (sort){
case 'asc':
condition = {name: 1};
break;
case 'desc':
condition = {name: -1};
break;
case 'createdAtAsc':
condition = {createdAt: 1};
break;
case 'createdAtDesc':
condition = {createdAt: -1};
break;
case 'updatedAtAsc':
condition = {updatedAt: 1};
break;
case 'updatedAtDesc':
condition = {updatedAt: -1};
break;
default:
condition = {name: 1};
}
}
const query_sort = {sort: condition};
// Remove undefined key
Object.keys(query).forEach(key => query[key] === undefined ? delete query[key] : {});
console.log(query);
Playlist.find(query, {}, query_sort)
.then(data => {
return sendMessage(res, 22, data, token);
})
.catch(err => {
return sendError(res,500,100,err.message || "Some error occurred while finding the Playlists.", token);
});
}
};
// Find single Playlist from session id
exports.findOne = (req, res) => {
const token = checkLogin(req, res);
if(token && typeof req.params.id !== 'undefined') {
const id = req.params.id;
if(id && ObjectId.isValid(id)){
Playlist.aggregate([
{$match: {_id: new ObjectId(id), userId: token.id, isActive: true}},
{$unwind: '$videoIds'},
{$project: {
userId: true,
name: true,
isActive: true,
createdAt: true,
updatedAt: true,
videoIds: {$toObjectId: '$videoIds'}
}},
{$lookup: {
from: 'videos',
localField: 'videoIds',
foreignField: '_id',
as: 'videos'
}},
{$unwind: '$videos'},
{$group: {
_id: '$_id',
userId: {$first: "$userId"},
name: {$first: "$name"},
isActive: {$first: "$isActive"},
createdAt: {$first: "$createdAt"},
updatedAt: {$first: "$updatedAt"},
videos: {$push: "$videos"}
}}
])
.then(async data => {
let yt_results = [];
let dm_results = [];
let yt_videoIds = "";
let dm_videoIds = "";
for (const i in data[0].videos) {
if (data[0].videos[i].source === youtube.name) {
yt_videoIds = yt_videoIds + data[0].videos[i].videoId + ",";
} else if (data[0].videos[i].source === dailymotion.name) {
dm_videoIds = dm_videoIds + data[0].videos[i].videoId + ",";
}
}
if (yt_videoIds !== "") {
const uri = youtube.baseAPIUrl + '/videos' + '?part=snippet&part=statistics&id=' + yt_videoIds.slice(0, -1) + '&key=' + youtube.YOUTUBE_API_KEY;
const dataVideos = await asyncRequest(uri, {});
if (dataVideos.response.statusCode === 200 && dataVideos.body.items.length > 0) {
yt_results = dataVideos.body.items;
}
}
if (dm_videoIds !== "") {
const uri = dailymotion.baseAPIUrl + '/videos?ids=' + dm_videoIds.slice(0, -1) + '&fields=thumbnail_480_url%2Ctitle%2Cid';
const data = await asyncRequest(uri, {});
const response = data.response;
const jsonBody = data.body;
if (response.statusCode === 200) {
dm_results = jsonBody.list;
}
}
for (const i in data[0].videos) {
if (data[0].videos[i].source === youtube.name) {
const obj = yt_results.filter(obj => obj.id === data[0].videos[i].videoId);
data[0].videos[i].imageUrl = obj[0].snippet.thumbnails.medium.url ? obj[0].snippet.thumbnails.medium.url : null;
data[0].videos[i].interest = obj[0].snippet.categoryId ? await asyncInterest(obj[0].snippet.categoryId, youtube.name): null;
data[0].videos[i].title = obj[0].snippet.title ? obj[0].snippet.title : null;
data[0].videos[i].views = obj[0].statistics.viewCount ? parseInt(obj[0].statistics.viewCount) : null;
data[0].videos[i].publishedAt = obj[0].snippet.publishedAt ? obj[0].snippet.publishedAt : null;
} else if (data[0].videos[i].source === dailymotion.name) {
const obj = dm_results.filter(obj => obj.id === data[0].videos[i].videoId);
data[0].videos[i].imageUrl = obj[0].thumbnail_480_url ? obj[0].thumbnail_480_url : null;
data[0].videos[i].interest = obj[0]['channel.name'] ? await asyncInterest( obj[0]['channel.name'], dailymotion.name) : null;
data[0].videos[i].title = obj[0].title ? obj[0].title : null;
data[0].videos[i].views = obj[0].views_total ? parseInt(obj[0].views_total) : null;
data[0].videos[i].publishedAt = obj[0].created_time ? new Date(obj[0].created_time * 1000) : null
}
}
return sendMessage(res, 12, data[0], token)
})
.catch(err => {
return sendError(res,500,100,err.message || `Some error occurred while finding the Playlist with id=${id}`, token);
});
} else {
return sendError(res, 500, -1, `Error id is not valid`, token);
}
} else {
return sendError(res, 500, -1, `No id given`, token);
}
};
// Update a Playlist with playlist id
exports.update = (req, res) => {
const token = checkLogin(req, res);
if(token && typeof req.params.id !== 'undefined') {
const id = req.params.id;
if(typeof req.body._id !== 'undefined' || typeof req.body.id !== 'undefined'){
return sendError(res, 500, -1, `User do not have the permission to modify id or _id`, token);
} else{
const ids = id.split(',');
let update = {};
let condition;
const name = req.body.name;
condition = name ? name : undefined;
update.name = condition;
const videoIds = req.body.videoIds;
condition = videoIds ? videoIds : undefined;
update.videoIds = condition;
const videoId = req.body.videoId;
if(typeof videoId !== 'undefined' && typeof videoId.id !== 'undefined' && typeof videoId.action !== 'undefined'){
if(videoId.action === 'add'){
condition = videoId.id ? {videoIds: videoId.id} : undefined;
update.$addToSet = condition;
} else if(videoId.action === 'delete'){
condition = videoId.id ? {videoIds: videoId.id} : undefined;
update.$pull = condition;
}
}
const isActive = req.body.isActive;
if(typeof isActive !== 'undefined'){
condition = isActive;
} else{
condition = undefined;
}
update.isActive = condition;
// Remove undefined key
Object.keys(update).forEach(key => update[key] === undefined ? delete update[key] : {});
Playlist.updateMany({_id: {$in: ids}, userId: token.id, isActive: true}, update, {new: false})
.then(data => {
if(data) {
if(data.modifiedCount > 0){
return sendMessage(res, 24, update, token);
} else {
return sendError(res, 500, -1, `Video in Playlist ${data} already exists.`, token);
}
} else {
return sendError(res, 404, -1, `Playlist not found with id=${id}`, token);
}
})
.catch(err => {
return sendError(res, 500, -1, err.message || `Some error occurred while updating the Playlist with id=${id}`, token);
});
}
} else {
return sendError(res, 500, -1, `No id given`, token);
}
};
// Delete a Playlist with playlist id
exports.delete = (req, res) => {
const token = checkLogin(req, res);
if(token && typeof req.params.id !== 'undefined') {
const id = req.params.id;
if(id && ObjectId.isValid(id)){
Playlist.findByIdAndUpdate(id, {isActive: false}, {useFindAndModify: false})
.then(data => {
if(data) {
return sendMessage(res, 25, {message: `Playlist ${id} was successfully deleted.`}, token);
} else {
return sendError(res, 404, 105, `Playlist not found with id=${id}`, token);
}
})
.catch(err => {
return sendError(res, 500, 100, err.message || `Some error occurred while deleting the Playlist with id=${id}`, token);
});
} else {
return sendError(res, 500, -1, `Error id is not valid`, token);
}
} else {
return sendError(res, 500, -1, `No id given`, token);
}
};
// Delete all Playlists from session id
exports.deleteAll = (req, res) => {
const token = checkLogin(req, res);
if(token) {
Playlist.updateMany({userId: {$eq: token.id}, isActive: true}, {isActive: false})
.then(data => {
return sendMessage(res, 26, {
message: `${data.modifiedCount} Playlists were deleted successfully.`
});
})
.catch(err => {
return sendError(res, 500, -1, err.message || "Some error occurred while removing all Playlists.");
});
}
};

View file

@ -0,0 +1,544 @@
const db = require("../models/mongodb.model");
const {sendError, sendMessage} = require ("../config/response.config");
const {checkLogin, setSessionCookie} = require("../config/sessionJWT.config");
const ObjectId = require('mongoose').Types.ObjectId;
const roles = require("../models/objects/role.model");
const {youtube, dailymotion} = require("../config/host.config");
const {asyncRequest} = require("../config/functions.config");
const User = db.users;
const Video = db.videos;
const Ad = db.ads;
// Authenticate a User
exports.auth = (req, res) => {
// Validate request
if (!req.body.email || !req.body.hashPass) {
sendError(res, 400,-1,"Content can not be empty . (email and hashPass needed)");
} else{
// Check User in the database
User
.findOne({email: req.body.email, hashPass: req.body.hashPass, isActive: true, "role.isAccepted": true}, {role: true, profileImageUrl: true})
.then(data => {
if (data !== null){
User.findByIdAndUpdate(data._id.toString(), {lastConnexion: new Date()}, {useFindAndModify: false},
function (err) {
if (err){
return sendError(res, 400, 100,err.message || "Some error occurred while updating the User.");
}
else{
const dataRes = {id: data._id.toString(), email: req.body.email, profileImageUrl: data.profileImageUrl, role: data.role};
setSessionCookie(req, res, dataRes);
return sendMessage(res, 1, dataRes);
}
});
} else {
setSessionCookie(req, res, {id: -1, email: -1, profileImageUrl: -1, role: -1});
return sendError(res, 500, 101, "Invalid login or password.");
}
})
.catch(err => {
return sendError(res, 400, 100,err.message || "Some error occurred while authenticating the User.");
});
}
};
// Logout a User
exports.logout = (req, res) => {
const token = checkLogin(req, res);
if(token){
setSessionCookie(req, res, {id: -1, email: -1, profileImageUrl: -1, role: -1});
return sendMessage(res, 2, {message: "User disconnected"});
}
};
// Request password reset with email
exports.resetPass = (req, res) => {
return sendError(res, 501, -1, "User.resetPass not Implemented", null);
};
// Create and Save a new User
exports.create = (req, res) => {
// Validate request
if (!req.body.email || !req.body.hashPass || !req.body.login) {
sendError(res, 400,-1,"Content can not be empty . (email, hashPass and login needed");
}
else{
User.exists({email: req.body.email}, function (err, docs){
if(err){
sendError(res, 500,100,err.message || "Some error occurred while checking if the User already exists.");
} else{
if(docs === null) {
let user;
let var_role;
if(typeof req.body.role !== 'undefined'){
switch(req.body.role){
case 'admin':
var_role = roles.Admin;
break;
case 'advertiser':
var_role = roles.Advertiser;
break;
default:
var_role = roles.User;
}
} else{
var_role = roles.User;
}
user = new User({
email: req.body.email,
hashPass: req.body.hashPass,
login: req.body.login,
role: var_role,
company: req.body.company ? req.body.company : null,
dateOfBirth: req.body.dateOfBirth ? req.body.dateOfBirth : null,
gender: req.body.gender ? req.body.gender : null,
interests: req.body.interests ? req.body.interests : null,
});
// Save User in the database
user
.save(user)
.then(data => {
data.hashPass = undefined; // Hiding hashPass on return
return sendMessage(res, 4, data)
})
.catch(err => {
return sendError(res, 500,100,err.message || "Some error occurred while creating the User.");
});
} else{
return sendError(res, 500, 104, err || `Email ${req.body.email} already exists.`);
}
}
});
}
};
// Retrieve all Users from the database if at least admin.
exports.findAll = (req, res) => {
const token = checkLogin(req, res, roles.Admin);
if(token){
let query = {};
let condition;
const ids = req.query.userId;
condition = ids ? {$in: ids} : undefined;
query._id = condition;
const email = req.query.email;
condition = email ? { $regex: new RegExp(email), $options: "i" } : undefined;
query.email = condition;
const login = req.query.login;
condition = login ? { $regex: new RegExp(login), $options: "i" } : undefined;
query.login = condition;
const role = req.query.role;
condition = role ? role : undefined;
query["role.name"] = condition;
const company = req.query.company;
condition = company ? { $regex: new RegExp(company), $options: "i" } : undefined;
query.company = condition;
const dateOfBirth = req.query.dateOfBirth;
condition = dateOfBirth ? new Date(dateOfBirth) : undefined;
query.dateOfBirth = condition;
const gender = req.query.gender;
condition = gender ? gender : undefined;
query.gender = condition;
const isActive = req.query.isActive;
condition = isActive ? isActive : undefined;
query.isActive = condition;
const isAccepted = req.query.isAccepted;
if(isAccepted !== 'undefined'){
switch (isAccepted){
case 'true':
condition = true;
break;
case 'false':
condition = false;
break;
}
}
query["role.isAccepted"] = condition;
const sort = req.query.sort;
if(sort !== 'undefined'){
switch (sort){
case 'asc':
condition = {email: 1};
break;
case 'desc':
condition = {email: -1};
break;
case 'lastConnexionAsc':
condition = {lastConnexion: 1};
break;
case 'lastConnexionDesc':
condition = {lastConnexion: -1};
break;
case 'createdAtAsc':
condition = {createdAt: 1};
break;
case 'createdAtDesc':
condition = {createdAt: -1};
break;
case 'updatedAtAsc':
condition = {updatedAt: 1};
break;
case 'updatedAtDesc':
condition = {updatedAt: -1};
break;
default:
condition = {email: 1};
}
}
const query_sort = {sort: condition};
// Remove undefined key
Object.keys(query).forEach(key => query[key] === undefined ? delete query[key] : {});
console.log(query);
User.find(query, {hashPass: false}, query_sort)
.then(data => {
return sendMessage(res, 5, data, token);
})
.catch(err => {
return sendError(res,500,100,err.message || "Some error occurred while retrieving users.", token);
});
}
};
// Find a single User by session id
exports.findOne = (req, res) => {
const token = checkLogin(req, res);
if(token && typeof req.params.id !== 'undefined') {
let id = null;
if(typeof token.id !== 'undefined' && token.id === req.params.id){
id = req.params.id;
} else {
if(typeof token.role !== 'undefined' &&
typeof token.role.permission !== 'undefined' &&
typeof token.role.isAccepted !== 'undefined' &&
token.role.isAccepted === true &&
token.role.permission >= roles.Admin.permission) {
id = req.params.id;
} else {
return sendError(res, 500, 106, `User do not have the permission.`, token);
}
}
if(id && ObjectId.isValid(id)){
User.findById(id, {hashPass: false})
.then(data => {
if(data){
return sendMessage(res, 6, data, token);
} else {
return sendError(res,404,105,`User not found with id=${id}`, token);
}
})
.catch(err => {
return sendError(res,500,100,err.message || `Some error occurred while finding the User with id=${id}`, token);
});
} else {
sendError(res, 500, -1, `Error id is not valid`, token);
}
} else {
return sendError(res, 500, -1, `No id given`, token);
}
};
// Update a User by the id in the request
exports.update = (req, res) => {
const token = checkLogin(req, res);
if(token && typeof req.params.id !== 'undefined') {
let id = null;
if(typeof token.id !== 'undefined' && token.id === req.params.id){
id = req.params.id;
} else {
if(typeof token.role !== 'undefined' &&
typeof token.role.permission !== 'undefined' &&
typeof token.role.isAccepted !== 'undefined' &&
token.role.isAccepted === true &&
token.role.permission >= roles.Admin.permission) {
id = req.params.id;
} else {
return sendError(res, 500, 106, `User do not have the permission.`, token);
}
}
if(id && ObjectId.isValid(id)){
let update = null;
if(typeof req.body._id !== 'undefined' || typeof req.body.id !== 'undefined'){
return sendError(res, 500, -1, `User do not have the permission to modify id or _id`, token);
} else{
if(typeof req.body.role !== 'undefined' ||
typeof req.body.isActive !== 'undefined' ||
typeof req.body.lastConnexion !== 'undefined' ||
typeof req.body.createdAt !== 'undefined'||
typeof req.body.updatedAt !== 'undefined'){
if(typeof token.role !== 'undefined' &&
typeof token.role.permission !== 'undefined' &&
typeof token.role.isAccepted !== 'undefined' &&
token.role.isAccepted === true &&
token.role.permission >= roles.Admin.permission) {
update = true;
} else{
return sendError(res, 500, 106, `User do not have the permission to modify these keys.`, token);
}
} else{
update = true;
}
}
if(update === true){
User.findByIdAndUpdate(id, req.body, {useFindAndModify: false})
.then(data => {
if(data) {
data.hashPass = undefined;
Object.keys(req.body).forEach(key => data[key] = req.body[key]);
sendMessage(res, 7, data, token);
} else {
sendError(res, 404, -1, `User not found with id=${id}`, token);
}
})
.catch(err => {
sendError(res, 500, -1, err.message || `Some error occurred while updating the User with id=${id}`, token);
});
}
} else {
sendError(res, 500, -1, `Error id is not valid`, token);
}
} else {
return sendError(res, 500, -1, `No id given`, token);
}
};
// Delete a User with the specified id in the request
exports.delete = (req, res) => {
const token = checkLogin(req, res);
if(token && typeof req.params.id !== 'undefined') {
let id = null;
if(typeof token.id !== 'undefined' && token.id === req.params.id){
id = req.params.id;
} else {
if(typeof token.role !== 'undefined' &&
typeof token.role.permission !== 'undefined' &&
typeof token.role.isAccepted !== 'undefined' &&
token.role.isAccepted === true &&
token.role.permission >= roles.Admin.permission) {
id = req.params.id;
} else {
return sendError(res, 500, 106, `User do not have the permission.`, token);
}
}
if(id && ObjectId.isValid(id)){
User.findByIdAndUpdate(id, {isActive: false}, {useFindAndModify: false})
.then(data => {
if(data) {
return sendMessage(res, 8, {message: `User ${id} was successfully deleted.`}, token);
} else {
return sendError(res, 404, 105, `User not found with id=${id}`, token);
}
})
.catch(err => {
return sendError(res, 500, 100, err.message || `Some error occurred while deleting the User with id=${id}`, token);
});
} else {
return sendError(res, 500, -1, `Error id is not valid`, token);
}
} else {
return sendError(res, 500, -1, `No id given`, token);
}
};
// Delete all Users from the database except superAdmin
exports.deleteAll = (req, res) => {
const token = checkLogin(req, res, roles.SuperAdmin);
if(token) {
User.deleteMany({login: {$ne: "superAdmin"}})
.then(data => {
return sendMessage(res, 9, {
message: `${data.deletedCount} Users were deleted successfully.`
});
})
.catch(err => {
return sendError(res, 500, 100, err.message || "Some error occurred while removing all Users.");
});
}
};
// Get all Roles depending on the role of the User
exports.roles = (req, res) => {
const token = checkLogin(req, res);
if(token){
return sendMessage(res, 10, roles, token);
}
};
// Get 1 or multiple ad adapted to the User session id
exports.ad = (req, res) => {
const token = checkLogin(req, res);
if(token && typeof req.query.quantity !== 'undefined'){
const id = token.id;
const quantity = req.query.quantity;
// Interests from the user and from last 20 videos viewed if no ad matches -> find x ad from these interests + add date view to the ad
let interests = [];
const maxInterests = 20;
let limit = maxInterests;
User.findById(id, {_id: false, interests: true})
.then(data => {
if(typeof data.interests !== 'undefined' && data.interests !== null){
interests = interests.concat(data.interests);
limit = maxInterests-data.interests.length;
}
Video.aggregate([
{$match: {userId: id}},
{$project: {_id: false, interest: true}},
{$sort: {watchedDates: -1}},
{$limit: limit},
{$unwind: '$interest'},
{$group: {_id: null, interests: {$addToSet: '$interest'}}}
])
.then(data => {
if(typeof data[0] !== 'undefined' &&
typeof data[0].interests !== 'undefined' &&
data[0].interests !== [] &&
data[0].interests !== null){
interests = interests.concat(data[0].interests);
}
let match;
if(interests.length > 0){
match = {$match: {isVisible: true, isActive: true, interests: {$elemMatch: {interest: {$in: interests}}}}};
} else {
match = {$match: {isVisible: true, isActive: true}};
}
const pick = {$sample: {size: parseInt(quantity, 10)}};
Ad.aggregate([
match,
pick
])
.then(data => {
if(data.length > 0){
let ids = []
for(const i in data){ids.push(data[i]._id);}
Ad.updateMany({_id: {$in: ids}}, {$push: {views: [new Date()]}}, {timestamps: false})
.then(dataUpdate => {
if(dataUpdate && dataUpdate.modifiedCount > 0){
return sendMessage(res, 11, data, token);
} else {
return sendError(res,500,101,`Some error occurred while updating ${quantity} ad(s) for the User.`, token);
}
})
.catch(err => {
return sendError(res,500,101,err.message || `Some error occurred while updating ${quantity} ad(s) for the User.`, token);
});
} else {
Ad.aggregate([{$match: {isVisible: true, isActive: true}}, {$sample: {size: parseInt(quantity, 10)}}])
.then(data => {
let ids = []
for(const i in data){ids.push(data[i]._id);}
Ad.updateMany({_id: {$in: ids}}, {$push: {views: [new Date()]}}, {timestamps: false})
.then(dataUpdate => {
if(dataUpdate && dataUpdate.modifiedCount > 0){
return sendMessage(res, 11, data, token);
} else {
return sendError(res,500,101,`Some error occurred while updating ${quantity} ad(s) for the User.`, token);
}
})
.catch(err => {
return sendError(res,500,101,err.message || `Some error occurred while updating ${quantity} ad(s) for the User.`, token);
});
})
.catch(err => {
return sendError(res,500,101,err.message || `Some error occurred while getting ${quantity} ad(s) for the User.`, token);
});
}
})
.catch(err => {
return sendError(res,500,101,err.message || `Some error occurred while getting ${quantity} ad(s) for the User.`, token);
});
})
.catch(err => {
return sendError(res,500,102,err.message || `Some error occurred while getting ${quantity} ad(s) for the User.`, token);
});
})
.catch(err => {
return sendError(res,500,100,err.message || `Some error occurred while getting ${quantity} ad(s) for the User.`, token);
});
} else {
sendError(res, 500, -1, `No quantity given`, token);
}
};
// Get History
exports.history = (req, res) => {
const token = checkLogin(req, res);
if(token){
const id = token.id;
Video.aggregate([
{$match: {userId: id, $expr: {$gt: [{$size: "$watchedDates"}, 0]}}},
{$limit: 300},
{$project: {
videoId: true,
source: true,
tags: true,
interest: true,
views: {$size: '$watchedDates'},
watchedDate: {$arrayElemAt: ["$watchedDates", -1]},
createdAt: true,
updatedAt: true
}},
{$sort: {watchedDate: -1}}])
.then(async data => {
let yt_results = [];
let dm_results = [];
let yt_videoIds = "";
let dm_videoIds = "";
for(const i in data) {
if(data[i].source === youtube.name) {
yt_videoIds = yt_videoIds + data[i].videoId + ",";
} else if (data[i].source === dailymotion.name) {
dm_videoIds = dm_videoIds + data[i].videoId + ",";
}
}
if(yt_videoIds !== ""){
const uri = youtube.baseAPIUrl + '/videos' + '?part=snippet&part=statistics&id=' + yt_videoIds.slice(0, -1) + '&key=' + youtube.YOUTUBE_API_KEY;
const dataVideos = await asyncRequest(uri, {});
if (dataVideos.response.statusCode === 200 && dataVideos.body.items.length > 0) {
yt_results = dataVideos.body.items;
}
}
if(dm_videoIds !== ""){
const uri = dailymotion.baseAPIUrl + '/videos?ids='+dm_videoIds.slice(0, -1)+'&fields=thumbnail_480_url%2Ctitle%2Cid';
const data = await asyncRequest(uri, {});
const response = data.response;
const jsonBody = data.body;
if(response.statusCode === 200){
dm_results = jsonBody.list;
}
}
for(const i in data) {
if(data[i].source === youtube.name) {
const obj = yt_results.filter(obj => obj.id === data[i].videoId);
data[i].imageUrl = obj[0].snippet.thumbnails.medium.url ? obj[0].snippet.thumbnails.medium.url : null;
data[i].title = obj[0].snippet.title ? obj[0].snippet.title : null;
} else if (data[i].source === dailymotion.name) {
const obj = dm_results.filter(obj => obj.id === data[i].videoId);
data[i].imageUrl = obj[0].thumbnail_480_url ? obj[0].thumbnail_480_url : null;
data[i].title = obj[0].title ? obj[0].title : null;
}
}
return sendMessage(res, 12, data, token)
})
.catch(err => {
return sendError(res,500,100,err.message || "Some error occurred while getting the User history.", token);
});
}
};

View file

@ -0,0 +1,474 @@
const db = require("../models/mongodb.model");
const request = require('request');
const {sendError, sendMessage} = require ("../config/response.config");
const {checkLogin} = require("../config/sessionJWT.config");
const {youtube, dailymotion} = require("../config/host.config");
const {asyncRequest, asyncInterest} = require("../config/functions.config");
const ObjectId = require('mongoose').Types.ObjectId;
const Video = db.videos;
// Search Videos
exports.search = async (req, res) => {
const token = checkLogin(req, res);
if(token && typeof req.query.q !== 'undefined'){
const query = req.query.q;
const maxResults = req.query.maxResults ? req.query.maxResults : 45;
const pageToken = req.query.pageToken ? req.query.pageToken : undefined;
let sources;
if(typeof req.query.sources !== 'undefined' && req.query.sources !== ''){
sources = req.query.sources.split(',');
} else {
sources = ["yt", "dm"];
}
let yt_results = [];
let dm_results = [];
for(const i in sources){
if(sources[i] === youtube.shortname){
if(youtube.YOUTUBE_API_KEY !== 'undefined' && youtube.YOUTUBE_API_KEY !== ''){
let uri;
if(query !== ''){
if(typeof pageToken !== 'undefined'){
uri = youtube.baseAPIUrl+'/search'+'?part=snippet&maxResults='+maxResults+'&q='+query+'&pageToken='+pageToken+'&key='+youtube.YOUTUBE_API_KEY;
} else{
uri = youtube.baseAPIUrl+'/search'+'?part=snippet&maxResults='+maxResults+'&q='+query+'&key='+youtube.YOUTUBE_API_KEY;
}
const dataIds = await asyncRequest(uri, {});
if(dataIds.response.statusCode === 200 && dataIds.body.items.length > 0){
let yt_videoIds = "";
dataIds.body.items.forEach(item => yt_videoIds = yt_videoIds+item.id.videoId+",");
uri = youtube.baseAPIUrl+'/videos'+'?part=snippet&part=statistics&id='+yt_videoIds.slice(0, -1)+'&key='+youtube.YOUTUBE_API_KEY;
const dataVideos = await asyncRequest(uri, {});
if(dataVideos.response.statusCode === 200 && dataVideos.body.items.length > 0){
yt_results = dataVideos.body.items;
}
}
} else {
uri = youtube.baseAPIUrl+'/videos'+'?part=snippet&part=statistics&chart=mostPopular&maxResults='+maxResults+'&key='+youtube.YOUTUBE_API_KEY;
const dataVideos = await asyncRequest(uri, {});
if(dataVideos.response.statusCode === 200 && dataVideos.body.items.length > 0){
yt_results = dataVideos.body.items;
}
}
} else{
return sendError(res, 500, -1, `Error Env Variable DAILYMOTION_API_KEY missing, please contact the admin.`, token);
}
} else if(sources[i] === dailymotion.shortname){
if(dailymotion.DAILYMOTION_API_KEY !== 'undefined' && dailymotion.DAILYMOTION_API_KEY !== '') {
let uri;
if(query !== ''){
uri = dailymotion.baseAPIUrl + '/videos?limit='+maxResults+'&search='+query+'&fields=created_time%2Cdescription%2Cthumbnail_480_url%2Clikes_total%2Ctitle%2Cid%2Cembed_url%2Cviews_total%2Cowner.username%2Cowner.id%2Cchannel.name';
} else {
uri = dailymotion.baseAPIUrl + '/videos?limit='+maxResults+'&sort=trending&fields=created_time%2Cdescription%2Cthumbnail_480_url%2Clikes_total%2Ctitle%2Cid%2Cembed_url%2Cviews_total%2Cowner.username%2Cowner.id%2Cchannel.name';
}
const data = await asyncRequest(uri, {});
const response = data.response;
const jsonBody = data.body;
if(response.statusCode === 200){
dm_results = jsonBody.list;
}
} else{
return sendError(res, 500, -1, `Error Env Variable DAILYMOTION_API_KEY missing, please contact the admin.`, token);
}
}
}
let results = [];
for(let i = 0; i < Math.max(dm_results.length, yt_results.length); i++){
// Youtube
if(yt_results.length > i){
const yt_data = {
videoId: yt_results[i].id,
source: youtube.name,
imageUrl: yt_results[i].snippet.thumbnails.medium.url ? yt_results[i].snippet.thumbnails.medium.url : null,
title: yt_results[i].snippet.title ? yt_results[i].snippet.title : null,
channelTitle: yt_results[i].snippet.channelTitle ? yt_results[i].snippet.channelTitle : null,
channelUrl: youtube.baseChannelUrl+yt_results[i].snippet.channelId ? yt_results[i].snippet.channelId : null,
description: yt_results[i].snippet.description ? yt_results[i].snippet.description : null,
embedUrl: 'https://www.youtube.com/embed/'+yt_results[i].id,
interest: await asyncInterest(yt_results[i].snippet.categoryId, youtube.name),
views: yt_results[i].statistics.viewCount ? parseInt(yt_results[i].statistics.viewCount) : null,
likes: yt_results[i].statistics.likeCount ? parseInt(yt_results[i].statistics.likeCount) : null,
dislikes: yt_results[i].statistics.dislikeCount ? parseInt(yt_results[i].statistics.dislikeCount) : null,
publishedAt: yt_results[i].snippet.publishedAt ? yt_results[i].snippet.publishedAt : null
};
results.push(yt_data);
}
// Dailymotion
if(dm_results.length > i) {
const channelTitle = dm_results[i]['owner.username'] ? dm_results[i]['owner.username'] : null;
const dm_data = {
videoId: dm_results[i].id ? dm_results[i].id : null,
source: dailymotion.name,
imageUrl: dm_results[i].thumbnail_480_url ? dm_results[i].thumbnail_480_url : null,
title: dm_results[i].title ? dm_results[i].title : null,
channelTitle: channelTitle.charAt(0).toUpperCase() + channelTitle.slice(1),
channelUrl: dailymotion.baseChannelUrl + channelTitle,
description: dm_results[i].description ? dm_results[i].description : null,
embedUrl: dm_results[i].embed_url ? dm_results[i].embed_url : null,
interest: await asyncInterest(dm_results[i]['channel.name'], dailymotion.name),
views: dm_results[i].views_total ? parseInt(dm_results[i].views_total) : null,
likes: dm_results[i].likes_total ? parseInt(dm_results[i].likes_total) : null,
dislikes: null,
publishedAt: dm_results[i].created_time ? new Date(dm_results[i].created_time * 1000) : null
};
results.push(dm_data);
}
}
return sendMessage(res, 31, results, token);
} else{
return sendError(res, 500, -1, `No q given`, token);
}
};
// Get Video with id of source
exports.get = (req, res) => {
if(typeof req.query.source !== 'undefined' && typeof req.params.id !== 'undefined'){
const source = req.query.source;
const id = req.params.id;
if(source === youtube.shortname){
if(youtube.YOUTUBE_API_KEY !== 'undefined' && youtube.YOUTUBE_API_KEY !== ''){
const uri = youtube.baseAPIUrl+'/videos'+'?part=snippet&part=statistics&id='+id+'&key='+youtube.YOUTUBE_API_KEY;
request(uri,{},async function (error, response, body){
if(typeof body !== 'undefined'){
const jsonBody = JSON.parse(body);
if(jsonBody.items.length !== 0 &&
typeof jsonBody.items[0] !== 'undefined' &&
typeof jsonBody.items[0].id !== 'undefined' &&
jsonBody.items[0].id === id){
const imageUrl = jsonBody.items[0].snippet.thumbnails.standard.url ? jsonBody.items[0].snippet.thumbnails.standard.url : null;
const title = jsonBody.items[0].snippet.title ? jsonBody.items[0].snippet.title : null;
const channelId = jsonBody.items[0].snippet.channelId ? jsonBody.items[0].snippet.channelId : null;
const channelTitle = jsonBody.items[0].snippet.channelTitle ? jsonBody.items[0].snippet.channelTitle : null;
const description = jsonBody.items[0].snippet.description ? jsonBody.items[0].snippet.description : null;
//const embedUrl = jsonBody.embed_url ? jsonBody.embed_url : null;
const publishedAt = jsonBody.items[0].snippet.publishedAt ? jsonBody.items[0].snippet.publishedAt : null;
const interest = jsonBody.items[0].snippet.categoryId ? await asyncInterest(jsonBody.items[0].snippet.categoryId, youtube.name): null;
const views = jsonBody.items[0].statistics.viewCount ? parseInt(jsonBody.items[0].statistics.viewCount) : null;
const likes = jsonBody.items[0].statistics.likeCount ? parseInt(jsonBody.items[0].statistics.likeCount) : null;
const dislikes = jsonBody.items[0].statistics.dislikeCount ? parseInt(jsonBody.items[0].statistics.dislikeCount) : null;
const data = {
videoId: id,
source: youtube.name,
imageUrl: imageUrl,
title: title,
channelTitle: channelTitle,
channelUrl: youtube.baseChannelUrl+channelId,
description: description,
embedUrl: 'https://www.youtube.com/embed/'+id,
interest: interest,
views: views,
likes: likes,
dislikes: dislikes,
publishedAt: publishedAt
};
return sendMessage(res, 32, data);
} else{
return sendError(res, 404, -1, `No result`);
}
} else{
return sendError(res, 500, -1, error);
}
});
} else{
return sendError(res, 500, -1, `Error Env Variable YOUTUBE_API_KEY missing, please contact the admin.`);
}
} else if(source === dailymotion.shortname){
if(dailymotion.DAILYMOTION_API_KEY !== 'undefined' && dailymotion.DAILYMOTION_API_KEY !== ''){
const uri = dailymotion.baseAPIUrl+'/video/'+id+'?fields=created_time%2Cdescription%2Cthumbnail_480_url%2Clikes_total%2Ctitle%2Cid%2Cembed_url%2Cviews_total%2Cowner.username%2Cowner.id%2Cchannel.name';
request(uri,{},async function (error, response, body) {
if (typeof body !== 'undefined') {
const jsonBody = JSON.parse(body);
if(response.statusCode === 200 &&
typeof jsonBody.id !== 'undefined' &&
jsonBody.id === id){
const imageUrl = jsonBody.thumbnail_480_url ? jsonBody.thumbnail_480_url : null;
const title = jsonBody.title ? jsonBody.title : null;
//const channelId = jsonBody['owner.id'] ? jsonBody['owner.id'] : null;
const channelTitle = jsonBody['owner.username'] ? jsonBody['owner.username'] : null;
const description = jsonBody.description ? jsonBody.description : null;
const embedUrl = jsonBody.embed_url ? jsonBody.embed_url : null;
const publishedAt = jsonBody.created_time ? new Date(jsonBody.created_time * 1000) : null;
const interest = jsonBody['channel.name'] ? await asyncInterest(jsonBody['channel.name'], dailymotion.name) : null;
const views = jsonBody.views_total ? parseInt(jsonBody.views_total) : null;
const likes = jsonBody.likes_total ? parseInt(jsonBody.likes_total) : null;
const dislikes = null;
const data = {
videoId: id,
source: dailymotion.name,
imageUrl: imageUrl,
title: title,
channelTitle: channelTitle.charAt(0).toUpperCase() + channelTitle.slice(1),
channelUrl: dailymotion.baseChannelUrl+channelTitle,
description: description,
embedUrl: embedUrl,
interest: interest,
views: views,
likes: likes,
dislikes: dislikes,
publishedAt: publishedAt
};
return sendMessage(res, 32, data);
} else{
return sendError(res, 404, -1, jsonBody.error.message);
}
}
});
} else{
return sendError(res, 500, -1, `Error Env Variable DAILYMOTION_API_KEY missing, please contact the admin.`);
}
} else{
return sendError(res, 500, -1, `Wrong source name`);
}
} else{
return sendError(res, 500, -1, `No source or/and id given`);
}
};
// Create a new Video
exports.create = (req, res) => {
const token = checkLogin(req, res);
if(token &&
typeof req.body.source !== 'undefined' &&
typeof req.body.interest !== 'undefined' &&
typeof req.params.id !== 'undefined'){
const id = req.params.id;
Video.exists({userId: token.id, videoId: id, source: req.body.source, isActive: true}, function (err, docs){
if(err){
sendError(res, 500,100,err.message || "Some error occurred while checking if the Video already exists.", token);
} else{
if(docs === null) {
let video;
video = new Video({
userId: token.id,
videoId: id,
source: req.body.source,
interest: req.body.interest,
watchedDates: [new Date()]
});
// Save Video in the database
video
.save(video)
.then(data => {
return sendMessage(res, 33, data, token)
})
.catch(err => {
return sendError(res, 500,100,err.message || "Some error occurred while creating the Video.", token);
});
} else{
const id = docs._id.toString();
Video.findByIdAndUpdate(id, {$push: {watchedDates: [new Date()]}}, {useFindAndModify: false, new: true})
.then(data => {
if(data) {
return sendMessage(res, 33, data, token);
} else {
return sendError(res, 404, 105, `Video not found with id=${id}`, token);
}
})
.catch(err => {
return sendError(res, 500, 100, err.message || `Some error occurred while updating the Video with id=${id}`, token);
});
}
}
});
} else {
return sendError(res, 500, -1, `No source or interest or id given`, token);
}
};
// Retrieve all Videos
exports.findAll = (req, res) => {
const token = checkLogin(req, res);
if(token){
let query = {};
let condition;
const userId = req.query.userId;
condition = userId ? userId : undefined;
query.userId = condition;
const videoId = req.query.videoId;
condition = videoId ? videoId : undefined;
query.videoId = condition;
const source = req.query.source;
condition = source ? source : undefined;
query.source = condition;
const interests = req.query.interests;
condition = interests ? {$in: interests} : undefined;
query["interests.interest"] = condition
const isActive = req.query.isActive;
condition = isActive ? isActive : undefined;
query.isActive = condition;
const sort = req.query.sort;
if(sort !== 'undefined'){
switch (sort){
case 'asc':
condition = {videoId: 1};
break;
case 'desc':
condition = {videoId: -1};
break;
case 'createdAtAsc':
condition = {createdAt: 1};
break;
case 'createdAtDesc':
condition = {createdAt: -1};
break;
case 'updatedAtAsc':
condition = {updatedAt: 1};
break;
case 'updatedAtDesc':
condition = {updatedAt: -1};
break;
default:
condition = {createdAt: -1};
}
}
const query_sort = {sort: condition};
// Remove undefined key
Object.keys(query).forEach(key => query[key] === undefined ? delete query[key] : {});
console.log(query);
Video.find(query, {}, query_sort)
.then(data => {
return sendMessage(res, 34, data, token);
})
.catch(err => {
return sendError(res,500,100,err.message || "Some error occurred while finding the Videos.", token);
});
}
};
// Find single Video with id
exports.findOne = (req, res) => {
const token = checkLogin(req, res);
if(token && typeof req.params.id !== 'undefined') {
const id = req.params.id;
if(id && ObjectId.isValid(id)){
Video.findById(id, {})
.then(data => {
if(data){
return sendMessage(res, 35, data, token);
} else {
return sendError(res,404,105,`Video not found with id=${id}`, token);
}
})
.catch(err => {
return sendError(res,500,100,err.message || `Some error occurred while finding the Video with id=${id}`, token);
});
} else {
return sendError(res, 500, -1, `Error id is not valid`, token);
}
} else {
return sendError(res, 500, -1, `No id given`, token);
}
};
// Update Video with id
exports.update = (req, res) => {
const token = checkLogin(req, res);
if(token && typeof req.params.id !== 'undefined') {
const id = req.params.id;
if(typeof req.body._id !== 'undefined' || typeof req.body.id !== 'undefined'){
return sendError(res, 500, -1, `User do not have the permission to modify id or _id`, token);
} else{
let update = {};
let condition;
const watchedDate = req.body.watchedDate;
if(typeof watchedDate !== 'undefined'){
if(watchedDate){
condition = {watchedDates: [new Date()]}
} else {
condition = undefined;
}
} else{
condition = undefined;
}
update.$push = condition;
const watchedDates = req.body.watchedDates;
condition = watchedDates ? watchedDates : undefined;
update.watchedDates = condition;
const isActive = req.body.isActive;
if(typeof isActive !== 'undefined'){
condition = isActive;
} else{
condition = undefined;
}
update.isActive = condition;
// Remove undefined key
Object.keys(update).forEach(key => update[key] === undefined ? delete update[key] : {});
if(id && ObjectId.isValid(id)){
Video.updateOne({_id: id, userId: token.id, isActive: true}, update)
.then(data => {
if(data) {
return sendMessage(res, 36, update, token);
} else {
return sendError(res, 404, -1, `Video not found with id=${id}`, token);
}
})
.catch(err => {
return sendError(res, 500, -1, err.message || `Some error occurred while updating the Video with id=${id}`, token);
});
} else {
return sendError(res, 500, -1, `Error id is not valid`, token);
}
}
} else {
return sendError(res, 500, -1, `No id given`, token);
}
};
// Delete Video with id
exports.delete = (req, res) => {
const token = checkLogin(req, res);
if(token && typeof req.params.id !== 'undefined') {
const id = req.params.id;
if(id && ObjectId.isValid(id)){
Video.updateOne({_id: id, userId: token.id, isActive: true}, {isActive: false}, {useFindAndModify: false})
.then(data => {
if(data.modifiedCount > 0) {
return sendMessage(res, 37, {message: `Video ${id} was successfully deleted.`}, token);
} else {
return sendError(res, 404, 105, `Video not found with id=${id}`, token);
}
})
.catch(err => {
return sendError(res, 500, 100, err.message || `Some error occurred while deleting the Video with id=${id}`, token);
});
} else {
return sendError(res, 500, -1, `Error id is not valid`, token);
}
} else {
return sendError(res, 500, -1, `No id given`, token);
}
};
// Delete all Videos
exports.deleteAll = (req, res) => {
const token = checkLogin(req, res);
if(token) {
Video.updateMany({userId: {$eq: token.id}, isActive: true}, {isActive: false})
.then(data => {
return sendMessage(res, 38, {
message: `${data.modifiedCount} Videos were deleted successfully.`,
});
})
.catch(err => {
return sendError(res, 500, 100, err.message || "Some error occurred while removing all Videos.");
});
}
};

14
jwtRS256.key.pub Normal file
View file

@ -0,0 +1,14 @@
-----BEGIN PUBLIC KEY-----
MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAtW31Xj62sjbJVBxnn0G2
Habc22q7/pFIBdfn8+OsajdNVnmtfRNOsSXZP8sNhXt1QLPSgxZ/wogG0fLXIX2+
ewzPgqrwTnr+quJ1DZ6RqOY3G1PGOibgk25aHkIXJ/gTPk1yTT6pjUmKiaGKM8pt
M2wGwugCdEH5Wndgby8Jej30v/PPzyPxTSXrIWDeaSMX+jQyFZTGgEdgL7JvjkTj
qLtfWKIAcEeO4PzOlRXVvbzBoYphBiZqkbzEeuOjSLPxgy4cQdbqVMlJ/lZt0SBO
MLiIUBTufLcJS3ApesiZWWfUCq+pFFdhEABc9qrtVumzhmzWAv2rKVrHRXbguxc/
eHKlRjAE4qmnNnTP2fsAuQIPkXVHOPWdXM1IBwnhXVB+XhxEHSANx/2oeKS6fO/e
1oNJCiVkHin9gC8vkU9seEN73lNKZ5wPXMqTYUGA65dCY+8li+n/1pveJOJozFk7
amkmOAPTi44lBJmxRm88XBHC3TXz6tFqX3phMqFDcQs2D9s3/2UylK0dSH5MSLnb
9x24/ykO4RlPRVCC90vwlxzbnb0rfQVlT4dKcE6OIyXw3UsqIqFnXWmm+hnGu4QH
Ysr+i1VIhPOs9YdZwlqhzcPTuNcdxmxy9ZfZ8KlLIWbAMbSH+obwm4w+HYTZjspe
2MwrKGgzpl4YW7ct/ViqeQMCAwEAAQ==
-----END PUBLIC KEY-----

8
jwtRS256.sh Normal file
View 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

View file

@ -0,0 +1,44 @@
module.exports = mongoose => {
let schema = mongoose.Schema({
userId: String,
title: String,
images: {
type: Array,
default: []
},
url: {
type: String,
default: null
},
interests: {
type: Array,
default: []
},
comment: {
type: String,
default: null
},
views: {
type: Array,
default: []
},
isVisible: {
type: Boolean,
default: true
},
isActive: {
type: Boolean,
default: true
}
},
{ timestamps: true }
);
schema.method("toJSON", function() {
const { __v, _id, ...object } = this.toObject();
object.id = _id;
return object;
});
return mongoose.model("ads", schema);
};

View file

@ -0,0 +1,24 @@
module.exports = mongoose => {
let schema = mongoose.Schema({
userId: String,
videoIds: {
type: Array,
default: []
},
name: String,
isActive: {
type: Boolean,
default: true
}
},
{ timestamps: true }
);
schema.method("toJSON", function() {
const { __v, _id, ...object } = this.toObject();
object.id = _id;
return object;
});
return mongoose.model("playlists", schema);
};

View file

@ -0,0 +1,48 @@
const roles = require("../objects/role.model");
module.exports = mongoose => {
let schema = mongoose.Schema({
email: String,
hashPass: String, // WARNING: We don't want to send back the hashPass
login: String,
role: {
type: Object,
default: roles.User
},
company: String,
profileImageUrl: {
type: String,
default: "https://www.handiclubnimois.fr/wp-content/uploads/2020/10/blank-profile-picture-973460_1280.png"
},
dateOfBirth: {
type: Date,
default: null
},
gender: {
type: String,
default: null
},
interests: {
type: Array,
default: null
},
isActive: {
type: Boolean,
default: true
},
lastConnexion: {
type: Date,
default: null
}
},
{ timestamps: true }
);
schema.method("toJSON", function() {
const { __v, _id, ...object } = this.toObject();
object.id = _id;
return object;
});
return mongoose.model("users", schema);
};

View file

@ -0,0 +1,29 @@
module.exports = mongoose => {
let schema = mongoose.Schema({
userId: String,
videoId: String,
source: String,
interest: {
type: String,
default: null
},
watchedDates: {
type: Array,
default: null
},
isActive: {
type: Boolean,
default: true
}
},
{ timestamps: true }
);
schema.method("toJSON", function() {
const { __v, _id, ...object } = this.toObject();
object.id = _id;
return object;
});
return mongoose.model("videos", schema);
};

19
models/mongodb.model.js Normal file
View file

@ -0,0 +1,19 @@
const dbConfig = require("../config/mongodb.config");
const mongoose = require("mongoose");
mongoose.Promise = global.Promise;
const db = {};
db.mongoose = mongoose;
if(typeof process.env.NODE_ENV !== 'undefined' && process.env.NODE_ENV === 'production'){
db.url = dbConfig.prodUrl;
} else {
db.url = dbConfig.devUrl;
}
db.users = require("./database/users.model")(mongoose);
db.playlists = require("./database/playlists.model")(mongoose);
db.videos = require("./database/videos.model")(mongoose);
db.ads = require("./database/ads.model")(mongoose);
module.exports = db;

View file

@ -0,0 +1,10 @@
class Image {
constructor(base64, url, description, type){
this.base64 = base64;
this.url = url;
this.description = description;
this.type = type;
}
}
module.exports = Image;

View file

@ -0,0 +1,22 @@
module.exports = {
User: {
name: "user",
permission: 0,
isAccepted: true
},
Advertiser: {
name: "advertiser",
permission: 5,
isAccepted: false
},
Admin: {
name: "admin",
permission: 10,
isAccepted: false
},
SuperAdmin: {
name: "superAdmin",
permission: 1000,
isAccepted: true
}
};

View file

@ -0,0 +1,157 @@
const {youtube, dailymotion} = require('../../config/host.config');
module.exports = [
{
id: 0,
interest: "Actualités",
categories: [
{id: "news", name: "News", source: dailymotion.name},
{id: "25", name: "News & Politics", source: youtube.name},
]
},
{
id: 1,
interest: "Animaux",
categories: [
{id: "animals", name: "animaux", source: dailymotion.name},
{id: "15", name: "Pets & Animals", source: youtube.name},
]
},
{
id: 2,
interest: "Arts",
categories: [
{id: "creation", name: "Art", source: dailymotion.name},
{id: "", name: "", source: youtube.name},
]
},
{
id: 3,
interest: "Autos",
categories: [
{id: "auto", name: "Auto-Moto", source: dailymotion.name},
{id: "2", name: "Autos & Vehicles", source: youtube.name},
]
},
{
id: 4,
interest: "Divertissements",
categories: [
{id: "tv", name: "TV", source: dailymotion.name},
{id: "fun", name: "Humour & Divertissement", source: dailymotion.name},
{id: "webcam", name: "Webcam", source: dailymotion.name},
{id: "23", name: "Comedy", source: youtube.name},
{id: "24", name: "Entertainment", source: youtube.name},
{id: "43", name: "Shows", source: youtube.name}
]
},
{
id: 5,
interest: "Éducation",
categories: [
{id: "school", name: "Éducation", source: dailymotion.name},
{id: "27", name: "Education", source: youtube.name}
]
},
{
id: 6,
interest: "Événements",
categories: [
{id: "", name: "", source: dailymotion.name},
{id: "19", name: "Travel & Events", source: youtube.name},
]
},
{
id: 7,
interest: "Films",
categories: [
{id: "shortfilms", name: "Cinéma", source: dailymotion.name},
{id: "1", name: "Film & Animation", source: youtube.name},
{id: "18", name: "Short Movies", source: youtube.name},
{id: "30", name: "Movies", source: youtube.name},
{id: "31", name: "Anime/Animation", source: youtube.name},
{id: "32", name: "Action/Adventure", source: youtube.name},
{id: "33", name: "Comedy", source: youtube.name},
{id: "35", name: "Documentary", source: youtube.name},
{id: "36", name: "Drama", source: youtube.name},
{id: "39", name: "Horror", source: youtube.name},
{id: "40", name: "Sci-Fi/Fantasy", source: youtube.name},
{id: "41", name: "Thriller", source: youtube.name},
{id: "42", name: "Shorts", source: youtube.name},
{id: "44", name: "Trailers", source: youtube.name}
]
},
{
id: 8,
interest: "Jeux vidéo",
categories: [
{id: "videogames", name: "Jeux vidéo", source: dailymotion.name},
{id: "20", name: "Gaming", source: youtube.name},
]
},
{
id: 9,
interest: "Kids",
categories: [
{id: "kids", name: "Kids", source: dailymotion.name},
{id: "", name: "", source: youtube.name},
]
},
{
id: 10,
interest: "Modes de vie",
categories: [
{id: "lifestyle", name: "Lifestyle & Tutoriels", source: dailymotion.name},
{id: "26", name: "Howto & Style", source: youtube.name},
]
},
{
id: 11,
interest: "Musiques",
categories: [
{id: "music", name: "Musique", source: dailymotion.name},
{id: "10", name: "Music", source: youtube.name},
]
},
{
id: 12,
interest: "People",
categories: [
{id: "people", name: "Amis & Famille", source: dailymotion.name},
{id: "21", name: "Videoblogging", source: youtube.name},
{id: "22", name: "People & Blogs", source: youtube.name},
{id: "37", name: "Family", source: youtube.name},
]
},
{
id: 13,
interest: "Science et Technologie",
categories: [
{id: "tech", name: "Tech", source: dailymotion.name},
{id: "28", name: "Science & Technology", source: youtube.name},
]
},
{
id: 14,
interest: "Sports",
categories: [
{id: "sport", name: "Sport", source: dailymotion.name},
{id: "17", name: "Sports", source: youtube.name},
]
},
{
id: 15,
interest: "Voyages",
categories: [
{id: "travel", name: "Voyages", source: dailymotion.name},
{id: "38", name: "Foreign", source: youtube.name},
]
},
{
id: 16,
interest: "Autres",
categories: [
{id: "29", name: "Nonprofits & Activism", source: youtube.name},
{id: "33", name: "Classics", source: youtube.name}
]
}
];

29
package.json Normal file
View file

@ -0,0 +1,29 @@
{
"name": "backend",
"version": "1.0.0",
"scripts": {
"ng": "ng",
"start": "node server.js",
"dev-win": "set NODE_ENV=development && node server.js",
"dev-nix": "export NODE_ENV=development && node server.js",
"prod-win": "set NODE_ENV=production && node server.js",
"prod-nix": "export NODE_ENV=production && node server.js"
},
"private": true,
"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",
"request": "^2.88.2",
"rxjs": "~6.6.0",
"tslib": "^2.0.0",
"typescript": "~4.3.5",
"zone.js": "~0.11.3"
},
"devDependencies": {
}
}

24
routes/ad.routes.js Normal file
View 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("/ad/create", ads.create);
// Retrieve all Ad from id if admin or session id
router.get("/ad/findAll", ads.findAll);
// Find single Ad from id if admin or session id
router.get("/ad/findOne/:id", ads.findOne);
// Update a Ad with ad id
router.put("/ad/update/:id", ads.update);
// Delete a Ad with ad id
router.delete("/ad/delete/:id", ads.delete);
// Delete all Ad from id if admin or session id
router.delete("/ad/deleteAll", ads.deleteAll);
app.use('/api', router);
};

9
routes/misc.routes.js Normal file
View file

@ -0,0 +1,9 @@
const misc = require("../controllers/misc.controller");
module.exports = app => {
let router = require("express").Router();
// Get all interests available
router.get("/misc/getInterests", misc.getInterests);
app.use('/api', router);
};

24
routes/playlist.routes.js Normal file
View 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("/playlist/create", playlists.create);
// Retrieve all Playlist from id if admin or session id
router.get("/playlist/findAll", playlists.findAll);
// Find single Playlist from id if admin or session id
router.get("/playlist/findOne/:id", playlists.findOne);
// Update a Playlist with playlist id
router.put("/playlist/update/:id", playlists.update);
// Delete a Playlist with playlist id
router.delete("/playlist/delete/:id", playlists.delete);
// Delete all Playlists from id if admin or session id
router.delete("/playlist/deleteAll", playlists.deleteAll);
app.use('/api', router);
};

43
routes/user.routes.js Normal file
View file

@ -0,0 +1,43 @@
const users = require("../controllers/user.controller");
//const {cors, corsOptions} = require("../config/cors.config");
module.exports = app => {
let router = require("express").Router();
// Authenticate a User
router.post("/user/auth", users.auth);
// Logout a User
router.delete("/user/logout", users.logout);
// Request password reset with email
router.post("/user/resetPass", users.resetPass);
// Create and Save a new User
router.post("/user/create", users.create);
// Retrieve all Users if admin
router.get("/user/findAll", users.findAll);
// Find single User from id if admin or session id
router.get("/user/findOne/:id", users.findOne);
// Update a User from id if admin or session id
router.put("/user/update/:id", users.update);
// Delete a User from id if admin or session id
router.delete("/user/delete/:id", users.delete);
// Delete all Users if superAdmin
router.delete("/user/deleteAll", users.deleteAll);
// Get all Roles depending on the User session id
router.get("/user/roles", users.roles);
// Get 1 or multiple ad adapted to the User session id
router.get("/user/ad", users.ad);
// Get History
router.get("/user/history", users.history);
app.use('/api', router);
};

30
routes/video.routes.js Normal file
View file

@ -0,0 +1,30 @@
const videos = require("../controllers/video.controller");
module.exports = app => {
let router = require("express").Router();
// Search Videos
router.get("/video/search", videos.search);
// Get Video with id of source
router.get("/video/get/:id", videos.get);
// Create a new Video
router.post("/video/create/:id", videos.create);
// Retrieve all Videos
router.get("/video/findAll", videos.findAll);
// Find single Video with id
router.get("/video/findOne/:id", videos.findOne);
// Update Video with id
router.put("/video/update/:id", videos.update);
// Delete Video with id
router.delete("/video/delete/:id", videos.delete);
// Delete all Videos
router.delete("/video/deleteAll", videos.deleteAll);
app.use('/api', router);
};

96
server.js Normal file
View file

@ -0,0 +1,96 @@
const express = require('express');
const app = express();
const port = process.env.PORT || 3000;
const cors = require('cors');
const whitelist = [
'http://127.0.0.1:4200',
'http://127.0.0.1:4201',
'https://admin-polynotfound.herokuapp.com',
'https://polynotfound.herokuapp.com'
];
const corsOptionsDelegate = (req, callback) => {
let corsOptions;
if (whitelist.indexOf(req.header('Origin')) !== -1) {
corsOptions = {
origin: true,
credentials: true
}
} else {
corsOptions = {
origin: false,
credentials: true
}
}
callback(null, corsOptions)
}
app.use(cors(corsOptionsDelegate));
const cookieParser = require('cookie-parser');
app.use(cookieParser());
const bodyParser = require('body-parser');
app.use(bodyParser.urlencoded({extended:true}));
app.use(bodyParser.json());
const db = require("./models/mongodb.model");
console.log("Db Url: ",db.url);
db.mongoose
.connect(db.url, {
useNewUrlParser: true,
useUnifiedTopology: true
}, function (err){
const admin = new db.mongoose.mongo.Admin(db.mongoose.connection.db);
admin.buildInfo(function (err, info) {
console.log("MongoDB Version: "+info.version);
});
if(err){
console.log("Cannot connect to the database!", err);
process.exit();
} else{
console.log("Connected to the database!", db.url);
}
});
require("./routes/user.routes")(app);
require("./routes/playlist.routes")(app);
require("./routes/video.routes")(app);
require("./routes/ad.routes")(app);
require("./routes/misc.routes")(app);
const roles = require("./models/objects/role.model");
const User = db.users;
const login = 'superAdmin';
const hashPass = 'hashPassSuperAdmin';
const mail = 'superAdmin@email.admin';
User.exists({role: roles.SuperAdmin}, function (err, docs){
if(err){
console.log("Some error occurred while checking if superAdmin already exists.");
} else{
if(docs === null){
const user = new User({
login: login,
hashPass: hashPass,
email: mail,
role: roles.SuperAdmin
});
user
.save(user)
.then(data => {
data.hashPass = undefined; // Hiding hashPass on return
console.log(data);
})
.catch(err => {
console.log(err.message || "Some error occurred while creating superAdmin.");
});
} else {
console.log("superAdmin already exist !");
}
}
});
app.listen(port, '0.0.0.0',() => {
console.log (`listening on port ${port}`);
});