Compare commits

...
This repository has been archived on 2026-05-01. You can view files and clone it, but you cannot make any changes to it's state, such as pushing and creating new issues, pull requests or comments.

32 commits

Author SHA1 Message Date
MiharyR
d797abe90a réparation des filtres de la page 'userList' et 'adList' 2021-12-31 19:05:05 +01:00
Yûki VACHOT
7b7f934245 Update: Remove cors 2021-12-29 18:46:26 +01:00
Yûki VACHOT
d8063a02dd Update: Add Cors Admin 2021-12-29 18:25:22 +01:00
Yûki VACHOT
ab54fdb490 Update: Add Origin, Credentials 2021-12-29 18:03:41 +01:00
Yûki VACHOT
925dc1c178 Update: Add Origin, Credentials 2021-12-29 17:59:43 +01:00
Yûki VACHOT
8c1d9cd4c7 Update: Remove Cors 2021-12-29 17:54:27 +01:00
Yûki VACHOT
b883bd5156 Update: Add Credentials 2021-12-29 17:40:26 +01:00
Yûki VACHOT
520214977e Update: Add npm start in production mode 2021-12-26 18:43:03 +01:00
Yûki VACHOT
0a891e500e Update: Remove package-lock.json 2021-12-24 13:37:26 +01:00
MiharyR
c55af87a23 ajout de la guard 2021-12-24 12:14:20 +01:00
Yûki VACHOT
b9c3e7d0f3 Update: Cors Test 2021-12-23 13:33:33 +01:00
Yûki VACHOT
958b4898f0 Update: Cors Test 2021-12-23 13:29:35 +01:00
Yûki VACHOT
03d2a28544 Update: Environment for Heroku Production 2021-12-22 22:54:17 +01:00
Yûki VACHOT
f1d55dfc6b Merge remote-tracking branch 'origin/front-admin' into front-admin 2021-12-22 22:53:59 +01:00
Yûki VACHOT
65cb3ee020 Update: Environment for Heroku Production 2021-12-22 22:53:38 +01:00
Yûki VACHOT
0bb795cc11 Update: Environment for Heroku Production 2021-12-22 22:53:00 +01:00
bf6f102307
Update server.js 2021-12-22 21:29:27 +01:00
1c729b9c8d
Update package.json 2021-12-22 21:11:57 +01:00
f00762b5fe
Update: Cors 2021-12-22 21:11:16 +01:00
Yûki VACHOT
71e34ac8c0 Update: Environment for Heroku Production 2021-12-22 13:27:28 +01:00
Yûki VACHOT
5024b297ec Update: Environment for Heroku Production 2021-12-22 13:22:38 +01:00
Yûki VACHOT
d29741f9a8 Update: Environment for Heroku Production 2021-12-22 13:09:32 +01:00
Yûki VACHOT
0d6cca625c Update: Environment for Heroku Production 2021-12-22 12:15:32 +01:00
MiharyR
b7df19e1c0
Delete userAndAdvertiser directory 2021-12-21 13:34:22 +01:00
MiharyR
f80fee841f
Delete angular.json 2021-12-21 13:00:33 +01:00
MiharyR
00df25e8ff
Delete karma.conf.js 2021-12-21 12:58:25 +01:00
MiharyR
e51fabfe64
Delete tsconfig.app.json 2021-12-21 12:57:48 +01:00
MiharyR
eea9f714d6
Delete tsconfig.json 2021-12-21 12:57:30 +01:00
MiharyR
007391f124
Delete tsconfig.spec.json 2021-12-21 12:57:17 +01:00
MiharyR
006e58a922
Delete tslint.json 2021-12-21 12:57:01 +01:00
MiharyR
427d837b35
Suppression de l'ancien frontend 2021-12-21 12:56:16 +01:00
MiharyR
d62915bfe5 separation des fronts 2021-12-21 12:47:33 +01:00
203 changed files with 440 additions and 11225 deletions

8
.gitignore vendored
View file

@ -9,10 +9,10 @@
# dependencies
/node_modules
package-lock.json
# profiling files
chrome-profiler-events*.json
speed-measure-plugin*.json
# IDEs and editors
/.idea
@ -40,13 +40,7 @@ npm-debug.log
yarn-error.log
testem.log
/typings
*.env
# System Files
.DS_Store
Thumbs.db
/backend/database/
/backend/node_modules/
package-lock.json

View file

@ -1,6 +0,0 @@
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 . .

View file

@ -1,18 +1,19 @@
# Frontend
# Admin
This project was generated with [Angular CLI](https://github.com/angular/angular-cli) version 11.2.7.
This project was generated with [Angular CLI](https://github.com/angular/angular-cli) version 12.2.10.
## Development server
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.
## Code scaffolding
à
Run `ng generate component component-title` to generate a new component. You can also use `ng generate directive|pipe|service|class|guard|interface|enum|module`.
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`.
## Build
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.
Run `ng build` to build the project. The build artifacts will be stored in the `dist/` directory.
Then run `npm start`
## Running unit tests
@ -20,7 +21,7 @@ Run `ng test` to execute the unit tests via [Karma](https://karma-runner.github.
## Running end-to-end tests
Run `ng e2e` to execute the end-to-end tests via [Protractor](http://www.protractortest.org/).
Run `ng e2e` to execute the end-to-end tests via a platform of your choice. To use this command, you need to first add a package that implements end-to-end testing capabilities.
## Further help

View file

@ -3,11 +3,14 @@
"version": 1,
"newProjectRoot": "projects",
"projects": {
"frontend": {
"admin": {
"projectType": "application",
"schematics": {
"@schematics/angular:component": {
"style": "scss"
},
"@schematics/angular:application": {
"strict": true
}
},
"root": "",
@ -17,12 +20,12 @@
"build": {
"builder": "@angular-devkit/build-angular:browser",
"options": {
"outputPath": "dist/frontend",
"outputPath": "dist/frontend-admin",
"index": "src/index.html",
"main": "src/main.ts",
"polyfills": "src/polyfills.ts",
"tsConfig": "tsconfig.app.json",
"aot": true,
"inlineStyleLanguage": "scss",
"assets": [
"src/favicon.ico",
"src/assets"
@ -32,56 +35,57 @@
"src/styles.scss",
"node_modules/bootstrap/scss/bootstrap.scss"
],
"scripts": [
"node_modules/jquery/dist/jquery.js",
"node_modules/bootstrap/dist/js/bootstrap.js"
]
"scripts": []
},
"configurations": {
"production": {
"budgets": [
{
"type": "initial",
"maximumWarning": "1mb",
"maximumError": "2mb"
},
{
"type": "anyComponentStyle",
"maximumWarning": "2kb",
"maximumError": "4kb"
}
],
"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"
}
]
"outputHashing": "all"
},
"development": {
"buildOptimizer": false,
"optimization": false,
"vendorChunk": true,
"extractLicenses": false,
"sourceMap": true,
"namedChunks": true
}
}
},
"defaultConfiguration": "production"
},
"serve": {
"builder": "@angular-devkit/build-angular:dev-server",
"options": {
"browserTarget": "frontend:build"
},
"configurations": {
"production": {
"browserTarget": "frontend:build:production"
"browserTarget": "admin:build:production"
},
"development": {
"browserTarget": "admin:build:development"
}
}
},
"defaultConfiguration": "development"
},
"extract-i18n": {
"builder": "@angular-devkit/build-angular:extract-i18n",
"options": {
"browserTarget": "frontend:build"
"browserTarget": "admin:build"
}
},
"test": {
@ -91,44 +95,19 @@
"polyfills": "src/polyfills.ts",
"tsConfig": "tsconfig.spec.json",
"karmaConfig": "karma.conf.js",
"inlineStyleLanguage": "scss",
"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"
"defaultProject": "admin"
}

View file

@ -1,26 +0,0 @@
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;

View file

@ -1,26 +0,0 @@
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
}
};

View file

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

View file

@ -1,9 +0,0 @@
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 };

View file

@ -1,109 +0,0 @@
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, secure:false});
}
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);
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

@ -1,290 +0,0 @@
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

@ -1,7 +0,0 @@
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

@ -1,407 +0,0 @@
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

@ -1,546 +0,0 @@
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: {$push: '$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, pick;
if(interests.length > 0){
match = {$match: {isVisible: true, isActive: true, interests: {$elemMatch: {interest: {$in: interests}}}}};
pick = {$limit: parseInt(quantity, 10)}
} else {
match = {$match: {isVisible: true, isActive: true}};
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()]}})
.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()]}})
.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

@ -1,473 +0,0 @@
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 ? req.body.watchedDates : undefined;
update.watchedDates = watchedDates;
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.");
});
}
};

View file

@ -1,14 +0,0 @@
-----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-----

View file

@ -1,8 +0,0 @@
#!/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

@ -1,44 +0,0 @@
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

@ -1,24 +0,0 @@
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

@ -1,48 +0,0 @@
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

@ -1,29 +0,0 @@
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);
};

View file

@ -1,19 +0,0 @@
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

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

View file

@ -1,22 +0,0 @@
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

@ -1,157 +0,0 @@
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}
]
}
];

View file

@ -1,24 +0,0 @@
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);
};

View file

@ -1,9 +0,0 @@
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);
};

View file

@ -1,24 +0,0 @@
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);
};

View file

@ -1,42 +0,0 @@
const users = require("../controllers/user.controller");
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);
};

View file

@ -1,30 +0,0 @@
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);
};

View file

@ -1,41 +0,0 @@
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/app:/data/backend/app
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

View file

@ -3,7 +3,7 @@
module.exports = function (config) {
config.set({
basePath: '',
basePath: 'admin',
frameworks: ['jasmine', '@angular-devkit/build-angular'],
plugins: [
require('karma-jasmine'),
@ -25,7 +25,7 @@ module.exports = function (config) {
suppressAll: true // removes the duplicated traces
},
coverageReporter: {
dir: require('path').join(__dirname, './coverage/frontend'),
dir: require('path').join(__dirname, './coverage/admin'),
subdir: '.',
reporters: [
{ type: 'html' },

View file

@ -1,67 +1,45 @@
{
"name": "frontend",
"version": "1.0.0",
"name": "frontend-admin",
"version": "0.0.0",
"scripts": {
"ng": "ng",
"start": "node server.js",
"dev": "ng serve",
"build": "ng build --configuration production",
"test": "ng test",
"lint": "ng lint",
"e2e": "ng e2e"
"build": "ng build",
"watch": "ng build --watch --configuration development",
"test": "ng test"
},
"private": true,
"dependencies": {
"@angular/animations": "^12.2.11",
"@angular/cdk": "^12.2.11",
"@angular/cli": "~12.2.11",
"@angular/common": "^12.2.11",
"@angular/compiler": "^12.2.11",
"@angular/compiler-cli": "~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",
"@ng-bootstrap/ng-bootstrap": "^10.0.0",
"angular-responsive-carousel": "^2.1.2",
"body-parser": "^1.19.0",
"@angular/animations": "~12.2.0",
"@angular/cdk": "^13.1.1",
"@angular/common": "~12.2.0",
"@angular/compiler": "~12.2.0",
"@angular/core": "~12.2.0",
"@angular/forms": "~12.2.0",
"@angular/material": "^13.1.1",
"@angular/platform-browser": "~12.2.0",
"@angular/platform-browser-dynamic": "~12.2.0",
"@angular/router": "~12.2.0",
"bootstrap": "^5.1.3",
"chart.js": "^2.9.3",
"cookie-parser": "^1.4.5",
"cors": "^2.8.5",
"dotenv": "^10.0.0",
"express": "^4.17.1",
"jquery": "^3.6.0",
"jsonwebtoken": "^8.5.1",
"mongoose": "^6.0.12",
"ng2-charts": "^2.2.3",
"popper": "^1.0.1",
"request": "^2.88.2",
"rxjs": "~6.6.0",
"tslib": "^2.0.0",
"typescript": "~4.3.5",
"zone.js": "~0.11.3"
"tslib": "^2.3.0",
"zone.js": "~0.11.4"
},
"devDependencies": {
"@angular-devkit/build-angular": "~12.2.11",
"@angular/cli": "~12.2.11",
"@angular/compiler-cli": "~12.2.11",
"@angular/localize": "^12.2.11",
"@types/jasmine": "~3.6.0",
"@angular-devkit/build-angular": "~12.2.10",
"@angular/cli": "~12.2.10",
"@angular/compiler-cli": "~12.2.0",
"@types/jasmine": "~3.8.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",
"jasmine-core": "~3.8.0",
"karma": "~6.3.0",
"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",
"karma-jasmine-html-reporter": "~1.7.0",
"typescript": "~4.3.5"
}
}

View file

@ -3,80 +3,9 @@ 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://127.0.0.1:4200', credentials: true}));
const db = require("./app-backend/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("./app-backend/routes/user.routes")(app);
require("./app-backend/routes/playlist.routes")(app);
require("./app-backend/routes/video.routes")(app);
require("./app-backend/routes/ad.routes")(app);
require("./app-backend/routes/misc.routes")(app);
const roles = require("./app-backend/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.get('/*all', function(req,res) {
res.sendFile(path.join(__dirname+ '/dist/index.html'));
});
app.use(express.static(__dirname + '/dist/frontend'));
app.use(express.static(__dirname + '/dist/frontend-admin'));
app.get('/*', function(req,res) {
res.sendFile(path.join(__dirname+ '/dist/frontend/index.html'));
res.sendFile(path.join(__dirname+ '/dist/frontend-admin/index.html'));
});
app.listen(port, '0.0.0.0',() => {

View file

@ -18,7 +18,7 @@
<!-- filtre textuelle-->
<div style="margin: 10px 0px 20px 2%;">
<input class="textFilter" (keyup)="applyFilter($event)" placeholder="Rechercher par mots-clés...">
<input class="textFilter" [(ngModel)]="filteredText" (ngModelChange)="onFilter()" placeholder="Rechercher par mots-clés...">
</div>
<!-- visible + interests + période -->
@ -50,30 +50,30 @@
</div>
<!-- période -->
<div class="col-6" style="text-align: right;">
Période de création: &nbsp;
<mat-form-field appearance="fill" style="width: 140px; font-size: small;">
<mat-label>Date de début</mat-label>
<input matInput type="date"
style="font-size: small; width: 140px;"
[ngModel] ="startDate | date:'yyyy-MM-dd'"
(ngModelChange)="onNewStartDate($event); onFilter();">
</mat-form-field>
&nbsp; - &nbsp;
<mat-form-field appearance="fill" style="width: 140px; font-size: small;">
<mat-label>Date de fin</mat-label>
<input matInput type="date"
style="font-size: small; width: 140px;"
[ngModel] ="endDate | date:'yyyy-MM-dd'"
(ngModelChange)="onNewEndDate($event); onFilter();">
<div class="col-6" style="text-align: right; font-size: small;">
<mat-form-field appearance="fill">
<mat-label>Période de date de création</mat-label>
<mat-date-range-input
[formGroup]="campaignOne"
[rangePicker]="campaignOnePicker">
<input matStartDate placeholder="Start date" formControlName="start" style="font-size: small;">
<input matEndDate placeholder="End date" formControlName="end" style="font-size: small;">
</mat-date-range-input>
<mat-datepicker-toggle matSuffix [for]="campaignOnePicker"></mat-datepicker-toggle>
<mat-date-range-picker #campaignOnePicker></mat-date-range-picker>
</mat-form-field>
<button mat-icon-button (click)="onFilter()">
<mat-icon>keyboard_tab</mat-icon>
</button>
<button mat-icon-button (click)="onEffacerDate()">
<mat-icon>close</mat-icon>
</button>
</div>
</div>
</div>
<!-- table -->
<table mat-table [dataSource]="dataSource" matSort class="mat-elevation-z8">
@ -85,7 +85,7 @@
</td>
</ng-container>
<!-- Advertiser Column -->
<!-- company Column -->
<ng-container matColumnDef="company">
<th mat-header-cell *matHeaderCellDef mat-sort-header> Entreprise </th>
<td mat-cell *matCellDef="let advert">
@ -93,6 +93,14 @@
</td>
</ng-container>
<!-- email Column -->
<ng-container matColumnDef="email">
<th mat-header-cell *matHeaderCellDef mat-sort-header> Email </th>
<td mat-cell *matCellDef="let advert">
{{advert.email}}
</td>
</ng-container>
<!-- Tags Column -->
<ng-container matColumnDef="interests">
<th mat-header-cell *matHeaderCellDef> Sujets </th>
@ -153,9 +161,6 @@
<!-- Directives -->
<tr mat-header-row *matHeaderRowDef="displayedColumns"></tr>
<tr mat-row *matRowDef="let row; columns: displayedColumns;"></tr>
<tr class="mat-row" *matNoDataRow>
<td class="mat-cell" colspan="4"> Aucune vidéo ne correspond au filtre: "{{input.value}}" </td>
</tr>
</table>
<div style="width: 94%; margin: auto auto">

View file

@ -44,7 +44,7 @@ td {
}
input {
width: 30%;
//width: 30%;
font-size: large;
border-radius: 5px;
}

View file

@ -1,16 +1,16 @@
import {AfterViewInit, Component, ViewChild} from '@angular/core';
import {MatSort} from "@angular/material/sort";
import {MatPaginator} from "@angular/material/paginator";
import {ThemeService} from "../../../utils/services/theme/theme.service";
import {MatDialog} from "@angular/material/dialog";
import {MatSnackBar} from "@angular/material/snack-bar";
import {MatTableDataSource} from "@angular/material/table";
import {Advert} from "../../../utils/interfaces/advert";
import {PopupDeleteAdAdminComponent} from "../popup-delete-ad-admin/popup-delete-ad-admin.component";
import {PopupVisualizeImagesAdminComponent} from "../popup-visualize-images-admin/popup-visualize-images-admin.component";
import {FormControl} from "@angular/forms";
import {MessageService} from "../../../utils/services/message/message.service";
import {FormControl, FormGroup} from "@angular/forms";
import {HttpParams} from "@angular/common/http";
import {ThemeService} from "../../../utils/theme/theme.service";
import {MessageService} from "../../../utils/message/message.service";
import {DatePipe} from "@angular/common";
@ -18,6 +18,7 @@ export interface AdvertWithCountViewsAndCompany {
id: string,
userId: string,
company: string,
email: string,
title: string,
url: string,
images: {
@ -35,25 +36,27 @@ export interface AdvertWithCountViewsAndCompany {
}
@Component({
selector: 'app-page-ad-list-admin',
templateUrl: './page-ad-list-admin.component.html',
styleUrls: ['./page-ad-list-admin.component.scss']
selector: 'app-page-ad-list-admin',
templateUrl: './page-ad-list-admin.component.html',
styleUrls: ['./page-ad-list-admin.component.scss']
})
export class PageAdListAdminComponent implements AfterViewInit
{
tabAdvertWithCountViews: AdvertWithCountViewsAndCompany[] = [];
tabAdvertiser: any[];
displayedColumns: string[] = [ 'title', 'company', 'interests', 'createdAt', 'updatedAt', 'countViews', 'isVisible', 'actions' ];
displayedColumns: string[] = [ 'title', 'company', 'email', 'interests', 'createdAt', 'updatedAt', 'countViews', 'isVisible', 'actions' ];
dataSource ;
@ViewChild(MatSort) sort: MatSort;
@ViewChild(MatPaginator) paginator: MatPaginator;
filteredText: string = "" ;
visible: boolean = true;
noVisible: boolean = true;
startDate: Date = null;
endDate: Date = null;
campaignOne = new FormGroup({
start: new FormControl(null),
end: new FormControl(null),
});
formControlInterests = new FormControl();
allInterests: string[] = [];
@ -102,7 +105,7 @@ export class PageAdListAdminComponent implements AfterViewInit
else {
this.tabAdvertiser = retour.data.filter(x => x.role.name === "advertiser");
for(let advert of tabAdvert) this.tabAdvertWithCountViews.push(this.advertToAdvertWithCountViewsAndCompany(advert));
this.dataSource = new MatTableDataSource<Advert>();
this.dataSource = new MatTableDataSource<any>();
this.onFilter();
}
}
@ -120,13 +123,6 @@ export class PageAdListAdminComponent implements AfterViewInit
}
applyFilter(event: Event): void
{
const filterValue = (event.target as HTMLInputElement).value;
this.dataSource.filter = filterValue.trim().toLowerCase();
}
onVisualizeImages(advert: AdvertWithCountViewsAndCompany)
{
if(advert.images.length !== 0)
@ -178,29 +174,42 @@ export class PageAdListAdminComponent implements AfterViewInit
onFilter(): void
{
const startDate = this.campaignOne.get("start").value;
const endDate = this.campaignOne.get("end").value;
this.dataSource.data = [];
for(let advert of this.tabAdvertWithCountViews)
{
let valide: boolean = true;
if(advert.isVisible && this.visible) valide = true;
else if((!advert.isVisible) && this.noVisible) valide = true;
else valide = false;
// filtre textuelle
let valide: boolean = this.isTextFiltrationValid(advert);;
// filtre actif
if(valide)
{
if ((advert.createdAt === null) && (this.startDate !== null)) valide = false;
else if ((advert.createdAt === null) && (this.endDate !== null)) valide = false;
else if (this.startDate !== null)
if(advert.isVisible && this.visible) valide = true;
else if((!advert.isVisible) && this.noVisible) valide = true;
else valide = false;
}
// filtre date
if(valide)
{
if ((advert.createdAt === null) && (startDate !== null)) valide = false;
else if ((advert.createdAt === null) && (endDate !== null)) valide = false;
else if (startDate !== null)
{
if(this.startDate.getTime() > advert.createdAt.getTime()) valide = false;
else if (this.endDate !== null)
let timeCreatedAt = 0;
if(advert.createdAt !== null) timeCreatedAt = (new Date(advert.createdAt)).getTime();
if(startDate.getTime() > timeCreatedAt) valide = false;
else if (endDate !== null)
{
if(this.endDate.getTime() < advert.createdAt.getTime()) valide = false;
if(endDate.getTime() < timeCreatedAt) valide = false;
}
}
}
// filtre interests
if(valide) {
if(this.formControlInterests.value !== null) {
for (let interest of this.formControlInterests.value) {
@ -221,22 +230,30 @@ export class PageAdListAdminComponent implements AfterViewInit
}
onNewStartDate(event): void {
this.startDate = new Date(event);
}
onNewEndDate(event): void {
this.endDate = new Date(event);
isTextFiltrationValid(advert): boolean
{
let datePipe = new DatePipe('en-GB');
if(advert.title.includes(this.filteredText)) return true;
if(advert.company.includes(this.filteredText)) return true;
if(advert.email.includes(this.filteredText)) return true;
const createdAt = datePipe.transform(new Date(advert.createdAt), 'dd/MM/yyyy à HH:mm:ss');
if(createdAt.includes(this.filteredText)) return true;
const updatedAt = datePipe.transform(new Date(advert.updatedAt), 'dd/MM/yyyy à HH:mm:ss');
if(updatedAt.includes(this.filteredText)) return true;
if(advert.countViews.toString().includes(this.filteredText)) return true;
return false;
}
advertToAdvertWithCountViewsAndCompany(advert): AdvertWithCountViewsAndCompany
{
let company0 = "company" ;
let email0 = "email" ;
for(let advertiser of this.tabAdvertiser)
{
if(advert.userId === advertiser.id) {
company0 = advertiser.company;
email0 = advertiser.email;
break;
}
}
@ -246,6 +263,7 @@ export class PageAdListAdminComponent implements AfterViewInit
userId: advert.userId,
title: advert.title,
company: company0,
email: email0,
url: advert.url,
images: advert.images,
interests: advert.interests,
@ -259,4 +277,10 @@ export class PageAdListAdminComponent implements AfterViewInit
}
}
onEffacerDate(): void {
this.campaignOne.setValue({start: null, end: null });
this.onFilter();
}
}

View file

@ -1,13 +1,11 @@
import {Component, Inject, OnInit} from '@angular/core';
import {MAT_DIALOG_DATA, MatDialogRef} from "@angular/material/dialog";
import {MessageService} from "../../../utils/services/message/message.service";
import {MessageService} from "../../../utils/message/message.service";
@Component({
selector: 'app-popup-delete-ad-admin',
templateUrl: './popup-delete-ad-admin.component.html',
styleUrls: ['./popup-delete-ad-admin.component.scss']
selector: 'app-popup-delete-ad-admin',
templateUrl: './popup-delete-ad-admin.component.html',
styleUrls: ['./popup-delete-ad-admin.component.scss']
})
export class PopupDeleteAdAdminComponent implements OnInit
{

View file

@ -1,15 +1,12 @@
import {Component, Inject, OnInit} from '@angular/core';
import {MAT_DIALOG_DATA, MatDialogRef} from "@angular/material/dialog";
@Component({
selector: 'app-popup-visualize-images-admin',
templateUrl: './popup-visualize-images-admin.component.html',
styleUrls: ['./popup-visualize-images-admin.component.scss']
})
export class PopupVisualizeImagesAdminComponent implements OnInit
{
export class PopupVisualizeImagesAdminComponent implements OnInit {
tabImages = [];
index: number = 0;
nbImage: number = 0;

View file

@ -1,22 +1,19 @@
import { Component, OnInit } from '@angular/core';
import {User} from "../../../utils/interfaces/user";
import {ThemeService} from "../../../utils/services/theme/theme.service";
import {ThemeService} from "../../../utils/theme/theme.service";
import {MatDialog} from "@angular/material/dialog";
import {MatSnackBar} from "@angular/material/snack-bar";
import {MessageService} from "../../../utils/message/message.service";
import {ProfilService} from "../../../utils/profil/profil.service";
import {PopupUpdateAdminComponent} from "../popup-update-admin/popup-update-admin.component";
import {MessageService} from "../../../utils/services/message/message.service";
import {ProfilService} from "../../../utils/services/profil/profil.service";
@Component({
selector: 'app-page-profil-admin',
templateUrl: './page-profil-admin.component.html',
styleUrls: ['./page-profil-admin.component.scss']
selector: 'app-page-profil-admin',
templateUrl: './page-profil-admin.component.html',
styleUrls: ['./page-profil-admin.component.scss']
})
export class PageProfilAdminComponent implements OnInit
{
admin: User = {
admin = {
_id: "",
login: "",
hashPass: "",

View file

@ -1,19 +1,17 @@
import {Component, Inject, OnInit} from '@angular/core';
import {User} from "../../../utils/interfaces/user";
import {MAT_DIALOG_DATA, MatDialogRef} from "@angular/material/dialog";
import {MessageService} from "../../../utils/services/message/message.service";
import {ProfilService} from "../../../utils/services/profil/profil.service";
import {MessageService} from "../../../utils/message/message.service";
import {ProfilService} from "../../../utils/profil/profil.service";
@Component({
selector: 'app-popup-update-admin',
templateUrl: './popup-update-admin.component.html',
styleUrls: ['./popup-update-admin.component.scss']
selector: 'app-popup-update-admin',
templateUrl: './popup-update-admin.component.html',
styleUrls: ['./popup-update-admin.component.scss']
})
export class PopupUpdateAdminComponent implements OnInit
{
adminCopy: User;
adminCopy;
newPassword: string = "";
confirmNewPassword: string = "" ;
changePassword: boolean = false ;

View file

@ -2,10 +2,10 @@ import {Component, ElementRef, EventEmitter, Input, OnInit, Output, ViewChild} f
import {COMMA, ENTER} from "@angular/cdk/keycodes";
import {FormControl} from "@angular/forms";
import {Observable} from "rxjs";
import {MessageService} from "../../../utils/services/message/message.service";
import {map, startWith} from "rxjs/operators";
import {MatChipInputEvent} from "@angular/material/chips";
import {MatAutocompleteSelectedEvent} from "@angular/material/autocomplete";
import {MessageService} from "../../../utils/message/message.service";

View file

@ -23,7 +23,7 @@
<!-- filtre textuelle-->
<div style="margin: 10px 0px 20px 2%;">
<input class="textFilter" (keyup)="applyFilter($event)" placeholder="Rechercher par mots-clés...">
<input class="textFilter" [(ngModel)]="filteredText" (ngModelChange)="onFilter()" placeholder="Rechercher par mots-clés...">
</div>
<!-- role + actif + période -->
@ -52,20 +52,23 @@
<!-- période -->
<div class="col-8" style="text-align: right;">
Période de dernière connexion: &nbsp;
<mat-form-field appearance="fill" style="width: 140px;">
<mat-label>Date de début</mat-label>
<input matInput type="date"
[ngModel] ="startDate | date:'yyyy-MM-dd'"
(ngModelChange)="onNewStartDate($event); onFilter();">
</mat-form-field>
&nbsp; - &nbsp;
<mat-form-field appearance="fill" style="width: 140px;">
<mat-label>Date de fin</mat-label>
<input matInput type="date"
[ngModel] ="endDate | date:'yyyy-MM-dd'"
(ngModelChange)="onNewEndDate($event); onFilter();">
<mat-form-field appearance="fill">
<mat-label>Période de dernière connexion</mat-label>
<mat-date-range-input
[formGroup]="campaignOne"
[rangePicker]="campaignOnePicker">
<input matStartDate placeholder="Start date" formControlName="start">
<input matEndDate placeholder="End date" formControlName="end">
</mat-date-range-input>
<mat-datepicker-toggle matSuffix [for]="campaignOnePicker"></mat-datepicker-toggle>
<mat-date-range-picker #campaignOnePicker></mat-date-range-picker>
</mat-form-field>
<button mat-icon-button (click)="onFilter()">
<mat-icon>keyboard_tab</mat-icon>
</button>
<button mat-icon-button (click)="onEffacerDate()">
<mat-icon>close</mat-icon>
</button>
</div>
</div>
@ -114,6 +117,14 @@
</td>
</ng-container>
<!-- Company Column -->
<ng-container matColumnDef="company">
<th mat-header-cell *matHeaderCellDef mat-sort-header> Entreprise </th>
<td mat-cell *matCellDef="let user">
{{user.company}}
</td>
</ng-container>
<!-- DateOfBirth Column -->
<ng-container matColumnDef="dateOfBirth">
<th mat-header-cell *matHeaderCellDef mat-sort-header> Date de naissance </th>
@ -179,9 +190,6 @@
<!-- Directives -->
<tr mat-header-row *matHeaderRowDef="displayedColumns"></tr>
<tr mat-row *matRowDef="let row; columns: displayedColumns;"></tr>
<tr class="mat-row" *matNoDataRow>
<td class="mat-cell" colspan="4"> Aucune vidéo ne correspond au filtre: "{{input.value}}" </td>
</tr>
</table>
<div style="width: 94%; margin: auto auto">

View file

@ -1,26 +1,27 @@
import {AfterViewInit, Component, ViewChild} from '@angular/core';
import {MatSort} from "@angular/material/sort";
import {MatPaginator} from "@angular/material/paginator";
import {ThemeService} from "../../../utils/services/theme/theme.service";
import {MatDialog} from "@angular/material/dialog";
import {MatSnackBar} from "@angular/material/snack-bar";
import {MatTableDataSource} from "@angular/material/table";
import {PopupDeleteUserComponent} from "../popup-delete-user/popup-delete-user.component";
import {PopupCreateUserComponent} from "../popup-create-user/popup-create-user.component";
import {MessageService} from "../../../utils/services/message/message.service";
import {ThemeService} from "../../../utils/theme/theme.service";
import {MessageService} from "../../../utils/message/message.service";
import {FormControl, FormGroup} from "@angular/forms";
import {DatePipe} from "@angular/common";
@Component({
selector: 'app-page-user-list',
templateUrl: './page-user-list.component.html',
styleUrls: ['./page-user-list.component.scss']
selector: 'app-page-user-list',
templateUrl: './page-user-list.component.html',
styleUrls: ['./page-user-list.component.scss']
})
export class PageUserListComponent implements AfterViewInit
{
displayedColumns: string[];
displayedColumnsUser: string[] = [ 'isActive', 'login', 'email', 'dateOfBirth', 'age', 'sexe', 'interests', 'createdAt', 'lastConnexion' ];
displayedColumnsAdvertiser: string[] = [ 'isActive', 'login', 'email', 'createdAt', 'lastConnexion', 'isAccepted' ];
displayedColumnsAdvertiser: string[] = [ 'isActive', 'login', 'email', 'company', 'createdAt', 'lastConnexion', 'isAccepted' ];
displayedColumnsAdmin: string[] = [ 'isActive', 'login', 'email', 'createdAt', 'lastConnexion' ];
tabUser: any[] = [];
@ -32,10 +33,14 @@ export class PageUserListComponent implements AfterViewInit
@ViewChild(MatSort) sort: MatSort;
@ViewChild(MatPaginator) paginator: MatPaginator;
filteredText: string = "" ;
active: boolean = true;
noActive: boolean = false;
startDate: Date = null;
endDate: Date = null;
campaignOne = new FormGroup({
start: new FormControl(null),
end: new FormControl(null),
});
constructor( public themeService: ThemeService,
@ -62,6 +67,7 @@ export class PageUserListComponent implements AfterViewInit
{
if(person.role.name === "user") {
person["age"] = this.getAge(person.dateOfBirth);
delete person.profileImageUrl;
this.tabUser.push(person);
}
else if(person.role.name === "advertiser") this.tabAdvertiser.push(person);
@ -72,40 +78,6 @@ export class PageUserListComponent implements AfterViewInit
}
applyFilter(event: Event): void
{
const filterValue = (event.target as HTMLInputElement).value;
this.dataSource.filter = filterValue.trim().toLowerCase();
}
onDelete(user: any): void
{
const config = {
data: { user: user }
};
this.dialog
.open(PopupDeleteUserComponent, config)
.afterClosed()
.subscribe( retour => {
const config = { duration: 1000, panelClass: "custom-class" };
let message = "" ;
if((retour === undefined) || (retour === null)) {
message = "Opération annulée" ;
}
else {
const index = this.dataSource.data.findIndex( elt => (elt.id === user.id));
this.dataSource.data.splice(index, 1);
this.dataSource.data = this.dataSource.data;
this.dataSource = this.dataSource;
message = user.login + " a bien été supprimée ✔" ;
}
this.snackBar.open(message, "", config);
});
}
onCreateUser(): void
{
const config = { width: '50%' };
@ -177,6 +149,9 @@ export class PageUserListComponent implements AfterViewInit
onFilter(): void
{
const startDate = this.campaignOne.get("start").value;
const endDate = this.campaignOne.get("end").value;
let tab1 = [];
if(this.roleName === "user") {
this.displayedColumns = this.displayedColumnsUser;
@ -194,21 +169,31 @@ export class PageUserListComponent implements AfterViewInit
let tab2 = [];
for(let user of tab1)
{
let valide: boolean = true;
// filtre textuelle
let valide: boolean = this.isTextFiltrationValid(user);;
if(user.isActive && this.active) valide = true;
else if((!user.isActive) && this.noActive) valide = true;
else valide = false;
// filtre actif
if(valide)
{
if ((user.lastConnexion === null) && (this.startDate !== null)) valide = false;
else if ((user.lastConnexion === null) && (this.endDate !== null)) valide = false;
else if (this.startDate !== null)
if(user.isActive && this.active) valide = true;
else if((!user.isActive) && this.noActive) valide = true;
else valide = false;
}
// filtre date
if(valide)
{
if ((user.lastConnexion === null) && (startDate !== null)) valide = false;
else if ((user.lastConnexion === null) && (endDate !== null)) valide = false;
else if (startDate !== null)
{
if(this.startDate.getTime() > user.lastConnexion.getTime()) valide = false;
else if (this.endDate !== null)
let timeLastConnexion = 0;
if(user.lastConnexion !== null) timeLastConnexion = (new Date(user.lastConnexion)).getTime();
if(startDate.getTime() > timeLastConnexion) valide = false;
else if (endDate !== null)
{
if(this.endDate.getTime() < user.lastConnexion.getTime()) valide = false;
if(endDate.getTime() < timeLastConnexion) valide = false;
}
}
}
@ -222,12 +207,36 @@ export class PageUserListComponent implements AfterViewInit
}
onNewStartDate(event): void {
this.startDate = new Date(event);
isTextFiltrationValid(user): boolean
{
let datePipe = new DatePipe('en-GB');
if(user.login.includes(this.filteredText)) return true;
if(user.email.includes(this.filteredText)) return true;
const createdAt = datePipe.transform(new Date(user.createdAt), 'dd/MM/yyyy à HH:mm:ss');
if(createdAt.includes(this.filteredText)) return true;
const lastConnexion = datePipe.transform(new Date(user.lastConnexion), 'dd/MM/yyyy à HH:mm:ss');
if(lastConnexion.includes(this.filteredText)) return true;
if(this.roleName === 'user')
{
const dateOfBirth = datePipe.transform(new Date(user.dateOfBirth), 'dd/MM/yyyy à HH:mm:ss');
if(dateOfBirth.includes(this.filteredText)) return true;
if(user.age.toString().includes(this.filteredText)) return true;
if((user.sexe === 'man') && (this.filteredText === 'M')) return true;
if((user.sexe === 'woman') && (this.filteredText === 'F')) return true;
if(user.interests.toString().includes(this.filteredText)) return true;
}
else if(this.roleName === 'advertiser')
{
if(user.company.includes(this.filteredText)) return true;
}
return false;
}
onNewEndDate(event): void {
this.endDate = new Date(event);
onEffacerDate(): void {
this.campaignOne.setValue({start: null, end: null });
this.onFilter();
}
}

View file

@ -1,8 +1,6 @@
import {Component, Inject, OnInit} from '@angular/core';
import {MAT_DIALOG_DATA, MatDialogRef} from "@angular/material/dialog";
import {MessageService} from "../../../utils/services/message/message.service";
import {MessageService} from "../../../utils/message/message.service";
@Component({
selector: 'app-popup-create-user',

View file

@ -1,8 +0,0 @@
<mat-dialog-content class="mat-typography">
Êtes-vous sûr de vouloir supprimer <i>{{user.login}}</i> ?
</mat-dialog-content>
<mat-dialog-actions align="end">
<button mat-button (click)="dialogRef.close();">Annuler</button>
<button mat-button (click)="onValidate()" cdkFocusInitial>Valider</button>
</mat-dialog-actions>

View file

@ -1,25 +0,0 @@
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { PopupDeleteUserComponent } from './popup-delete-user.component';
describe('PopupDeleteUserComponent', () => {
let component: PopupDeleteUserComponent;
let fixture: ComponentFixture<PopupDeleteUserComponent>;
beforeEach(async () => {
await TestBed.configureTestingModule({
declarations: [ PopupDeleteUserComponent ]
})
.compileComponents();
});
beforeEach(() => {
fixture = TestBed.createComponent(PopupDeleteUserComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});

View file

@ -1,47 +0,0 @@
import {Component, Inject, OnInit} from '@angular/core';
import {MAT_DIALOG_DATA, MatDialogRef} from "@angular/material/dialog";
import {MessageService} from "../../../utils/services/message/message.service";
@Component({
selector: 'app-popup-delete-user',
templateUrl: './popup-delete-user.component.html',
styleUrls: ['./popup-delete-user.component.scss']
})
export class PopupDeleteUserComponent implements OnInit
{
user;
constructor( public dialogRef: MatDialogRef<PopupDeleteUserComponent>,
@Inject(MAT_DIALOG_DATA) public data,
private messageService: MessageService ) { }
ngOnInit(): void
{
this.user = this.data.user;
}
onValidate(): void
{
// --- FAUX CODE ---
this.dialogRef.close(true);
// --- VRAI CODE ---
/*
this.messageService
.sendMessage("user/delete", {"advert": this.advert})
.subscribe( retour => {
if(retour.status === "error") {
console.log(retour);
this.dialogRef.close();
}
else {
this.dialogRef.close(true);
}
});
*/
}
}

View file

@ -1,9 +1,7 @@
import {Component} from '@angular/core';
import { Component } from '@angular/core';
import {Router} from "@angular/router";
import {ProfilService} from "../../../utils/services/profil/profil.service";
import {MessageService} from "../../../utils/services/message/message.service";
import {ProfilService} from "../../../utils/profil/profil.service";
import {MessageService} from "../../../utils/message/message.service";
@Component({
selector: 'app-navbar-admin',
@ -35,6 +33,7 @@ export class NavbarAdminComponent
onDeconnexionCallback(retour: any): void
{
if(retour.status !== "success") console.log(retour);
this.profilService.setId("");
}
}

View file

@ -1,33 +0,0 @@
<div title="bobo" class="container" appDragAndDrop (fileDropped)="onFileDropped($event)">
<input type="file" #fileDropRef id="fileDropRef" multiple (change)="fileBrowseHandler($event.target.files)" />
<div style="font-weight: bold">Images</div>
<img src="/assets/uploadFile.png" width="50" height="50" style="margin-top: 5px">
<div style="font-style: italic; margin-top: 10px">Glisser déposer</div>
<div style="font-style: italic">ou</div>
<div style="font-style: italic" for="fileDropRef">Cliquer pour selectionner</div>
</div>
<div style="text-align: center;">
<mat-icon [title]=info_image>info</mat-icon>
</div>
<div class="files-list">
<div class="single-file" *ngFor="let file of files; let i = index">
<img src="/assets/uploadFile.png" width="45px" alt="file">
<div class="info">
<h4 class="name">
{{ file?.name }}
</h4>
<p class="size">
{{ formatBytes(file?.size) }}
</p>
<div class="progress-cont">
<div class="progress" [style.width]="file?.progress + '%'">
</div>
</div>
</div>
<button mat-icon-button class="delete" width="20px" alt="file" (click)="deleteFile(i)">
<mat-icon>delete</mat-icon>
</button>
</div>
</div>

View file

@ -1,135 +0,0 @@
.container {
width: 450px;
height: 180px;
padding: 20px 0px 20px 0px;
text-align: center;
border: dashed 1px #979797;
position: relative;
margin: 0 auto;
}
input {
opacity: 0;
position: absolute;
z-index: 2;
width: 100%;
height: 100%;
top: 0;
left: 0;
}
.fileover {
animation: shake 1s;
animation-iteration-count: infinite;
}
.files-list {
margin-top: 1.5rem;
.single-file {
display: flex;
padding: 0.5rem;
justify-content: space-between;
align-items: center;
border: dashed 1px #979797;
margin-bottom: 1rem;
img.delete {
margin-left: 0.5rem;
cursor: pointer;
align-self: flex-end;
}
display: flex;
flex-grow: 1;
.name {
font-size: 14px;
font-weight: 500;
color: #353f4a;
margin: 0;
}
.size {
font-size: 12px;
font-weight: 500;
color: #a4a4a4;
margin: 0;
margin-bottom: 0.25rem;
}
.info {
width: 100%
}
}
}
/* Shake animation */
@keyframes shake {
0% {
transform: translate(1px, 1px) rotate(0deg);
}
10% {
transform: translate(-1px, -2px) rotate(-1deg);
}
20% {
transform: translate(-3px, 0px) rotate(1deg);
}
30% {
transform: translate(3px, 2px) rotate(0deg);
}
40% {
transform: translate(1px, -1px) rotate(1deg);
}
50% {
transform: translate(-1px, 2px) rotate(-1deg);
}
60% {
transform: translate(-3px, 1px) rotate(0deg);
}
70% {
transform: translate(3px, 1px) rotate(-1deg);
}
80% {
transform: translate(-1px, -1px) rotate(1deg);
}
90% {
transform: translate(1px, 2px) rotate(0deg);
}
100% {
transform: translate(1px, -2px) rotate(-1deg);
}
}
.progress-cont {
height: 7px;
width: 100%;
border-radius: 4px;
background-color: #d0d0d0;
position: relative;
.progress {
width: 0;
height: 100%;
position: absolute;
z-index: 1;
top: 0;
left: 0;
border-radius: 4px;
background-color: #4c97cb;
transition: 0.5s all;
}
}

View file

@ -1,25 +0,0 @@
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { DragAndDropComponent } from './drag-and-drop.component';
describe('DragAndDropComponent', () => {
let component: DragAndDropComponent;
let fixture: ComponentFixture<DragAndDropComponent>;
beforeEach(async () => {
await TestBed.configureTestingModule({
declarations: [ DragAndDropComponent ]
})
.compileComponents();
});
beforeEach(() => {
fixture = TestBed.createComponent(DragAndDropComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});

View file

@ -1,93 +0,0 @@
import {Component, ElementRef, EventEmitter, OnInit, Output, ViewChild} from '@angular/core';
@Component({
selector: 'app-drag-and-drop',
templateUrl: './drag-and-drop.component.html',
styleUrls: ['./drag-and-drop.component.scss']
})
export class DragAndDropComponent
{
@ViewChild("fileDropRef", { static: false }) fileDropEl: ElementRef;
info_image = "Vos annonces seront affichées dans un rectangle de rapport 1/5 avec: \n • 1 la largeur du rectangle \n • 5 la hauteur du rectangle" ;
files: any[] = [];
@Output() eventEmitter = new EventEmitter<any>();
/**
* on file drop handler
*/
onFileDropped($event) {
this.prepareFilesList($event);
this.eventEmitter.emit(this.files);
}
/**
* handle file from browsing
*/
fileBrowseHandler(files) {
this.prepareFilesList(files);
this.eventEmitter.emit(this.files);
}
/**
* Delete file from files list
* @param index (File index)
*/
deleteFile(index: number) {
if (this.files[index].progress < 100) {
console.log("Upload in progress.");
return;
}
this.files.splice(index, 1);
this.eventEmitter.emit(this.files);
}
/**
* Simulate the upload process
*/
uploadFilesSimulator(index: number) {
setTimeout(() => {
if (index === this.files.length) {
return;
} else {
const progressInterval = setInterval(() => {
if (this.files[index].progress === 100) {
clearInterval(progressInterval);
this.uploadFilesSimulator(index + 1);
} else {
this.files[index].progress += 5;
}
}, 200);
}
}, 1000);
}
/**
* Convert Files list to normal array list
* @param files (Files List)
*/
prepareFilesList(files: Array<any>) {
for (const item of files) {
item.progress = 0;
this.files.push(item);
}
this.fileDropEl.nativeElement.value = "";
this.uploadFilesSimulator(0);
}
/**
* format bytes
* @param bytes (File size in bytes)
* @param decimals (Decimals point)
*/
formatBytes(bytes, decimals = 2) {
if (bytes === 0) {
return "0 Bytes";
}
const k = 1024;
const dm = decimals <= 0 ? 0 : decimals;
const sizes = ["Bytes", "KB", "MB", "GB", "TB", "PB", "EB", "ZB", "YB"];
const i = Math.floor(Math.log(bytes) / Math.log(k));
return parseFloat((bytes / Math.pow(k, i)).toFixed(dm)) + " " + sizes[i];
}
}

View file

@ -1,43 +0,0 @@
<mat-form-field class="example-chip-list" appearance="fill">
<!-- ------------------------------------------------------------------------------------ -->
<mat-label>Sujets</mat-label>
<!-- ------------------------------------------------------------------------------------ -->
<mat-chip-list #chipList aria-label="Fruit selection">
<mat-chip
*ngFor="let interest of myInterests"
[selectable]="selectable"
[removable]="removable"
(removed)="remove(interest)">
{{interest}}
<button matChipRemove *ngIf="removable">
<mat-icon>cancel</mat-icon>
</button>
</mat-chip>
<input
placeholder="Tapez un centre d'intérêt et pressez 'Entrer' pour l'inserer"
#tagInput
[formControl]="formControl"
[matAutocomplete]="auto"
[matChipInputFor]="chipList"
[matChipInputSeparatorKeyCodes]="separatorKeysCodes"
(matChipInputTokenEnd)="add($event)">
</mat-chip-list>
<!-- ------------------------------------------------------------------------------------ -->
<mat-autocomplete #auto="matAutocomplete" (optionSelected)="selected($event)">
<mat-option *ngFor="let interest of filteredInterests | async" [value]="interest">
{{interest}}
</mat-option>
</mat-autocomplete>
<!-- ------------------------------------------------------------------------------------ -->
</mat-form-field>

View file

@ -1,16 +0,0 @@
mat-form-field {
width: 100%;
font-size: small;
}
mat-chip-list {
font-size: small;
}
mat-chip {
font-size: small;
}
input {
font-size: small;
}

View file

@ -1,25 +0,0 @@
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { InputInterestsAdComponent } from './input-interests-ad.component';
describe('BarTagsComponent', () => {
let component: InputInterestsAdComponent;
let fixture: ComponentFixture<InputInterestsAdComponent>;
beforeEach(async () => {
await TestBed.configureTestingModule({
declarations: [ InputInterestsAdComponent ]
})
.compileComponents();
});
beforeEach(() => {
fixture = TestBed.createComponent(InputInterestsAdComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});

View file

@ -1,121 +0,0 @@
import {Component, ElementRef, EventEmitter, Input, OnInit, Output, ViewChild} from '@angular/core';
import {COMMA, ENTER} from "@angular/cdk/keycodes";
import {FormControl} from "@angular/forms";
import {Observable} from "rxjs";
import {map, startWith} from "rxjs/operators";
import {MatChipInputEvent} from "@angular/material/chips";
import {MatAutocompleteSelectedEvent} from "@angular/material/autocomplete";
import {MessageService} from "../../../utils/services/message/message.service";
@Component({
selector: 'app-input-interests-ad',
templateUrl: './input-interests-ad.component.html',
styleUrls: ['./input-interests-ad.component.scss']
})
export class InputInterestsAdComponent implements OnInit
{
selectable = true;
removable = true;
separatorKeysCodes: number[] = [ENTER, COMMA];
formControl = new FormControl();
filteredInterests: Observable<string[]>;
@Input() myInterests: string[] = [];
allInterests: string[] = [];
@Output() eventEmitter = new EventEmitter<string[]>();
@ViewChild('tagInput') tagInput: ElementRef<HTMLInputElement>;
interestsNotSelected: string[] = [];
constructor( private messageService: MessageService ) {}
ngOnInit(): void
{
this.filteredInterests = this.formControl.valueChanges.pipe(
startWith(null),
map((fruit: string | null) => fruit ? this._filter(fruit) : this.interestsNotSelected.slice()));
this.messageService
.get("misc/getInterests")
.subscribe( retour => {
if(retour.status !== "success") {
console.log(retour);
}
else {
this.allInterests = [];
for(let elt of retour.data)
{
this.allInterests.push(elt.interest);
this.interestsNotSelected.push(elt.interest);
}
}
});
}
add(event: MatChipInputEvent): void
{
const value = (event.value || '').trim();
const index = this.interestsNotSelected.indexOf(value);
if (value && (index !== -1) && (!this.myInterests.includes(value)))
{
this.myInterests.push(value);
event.chipInput!.clear();
this.formControl.setValue(null);
this.eventEmitter.emit(this.myInterests);
this.interestsNotSelected.splice(index, 1);
}
}
remove(interest: string): void
{
// supprimer 'interest' de 'myInterest'
const index = this.myInterests.indexOf(interest);
if (index >= 0) this.myInterests.splice(index, 1);
this.eventEmitter.emit(this.myInterests);
// remmettre 'interest' dans 'interestsNotSelected'
if(!this.interestsNotSelected.includes(interest))
{
const indexOfAutres = this.interestsNotSelected.indexOf("Autres");
if(indexOfAutres !== -1)
{
this.interestsNotSelected.splice(indexOfAutres, 1);
if(interest !== "Autres") this.interestsNotSelected.push(interest);
this.interestsNotSelected.sort();
this.interestsNotSelected.push("Autres");
}
else {
this.interestsNotSelected.push(interest);
if(interest !== "Autres") this.interestsNotSelected.sort();
}
}
}
selected(event: MatAutocompleteSelectedEvent): void
{
const value = event.option.viewValue;
if(!this.myInterests.includes(value))
{
this.myInterests.push(value);
const index = this.interestsNotSelected.indexOf(value);
this.interestsNotSelected.splice(index, 1);
}
this.tagInput.nativeElement.value = '';
this.formControl.setValue(null);
this.eventEmitter.emit(this.myInterests);
}
private _filter(value: string): string[]
{
const filterValue = value.toLowerCase();
return this.interestsNotSelected.filter(fruit => fruit.toLowerCase().includes(filterValue));
}
}

View file

@ -1,185 +0,0 @@
<div [class]="themeService.getClassTheme()">
<div class="myContainer">
<!-- Navbar -->
<app-navbar-advertiser></app-navbar-advertiser><br><br>
<!-- filtre + btnAddUser -->
<div class="row" style="margin: 20px 3% 20px 3%">
<!-- filtre -->
<div class="col-10" style="padding: 0px 0px 0px 0px;">
<div class="filtersContainer mat-elevation-z8">
<!-- titre -->
<div style="font-weight: bold; margin-bottom: 10px;">
Filtre
</div>
<mat-divider></mat-divider>
<!-- filtre textuelle-->
<div style="margin: 10px 0px 20px 2%;">
<input class="textFilter" (keyup)="applyFilter($event)" placeholder="filtre...">
</div>
<!-- role + actif + période -->
<div class="row myRow">
<!-- visible -->
<div class="col-2">
<mat-checkbox [(ngModel)]="visible" (change)="onFilter()">visible</mat-checkbox><br>
<mat-checkbox [(ngModel)]="noVisible" (change)="onFilter()">non visible</mat-checkbox>
</div>
<!-- sujets -->
<div class="col-4">
<mat-form-field appearance="fill">
<mat-label>Sujets</mat-label>
<mat-select [formControl]="formControlInterests" multiple>
<mat-select-trigger>
{{formControlInterests.value ? formControlInterests.value[0] : ''}}
<span *ngIf="formControlInterests.value?.length > 1">
(+{{formControlInterests.value.length - 1}} {{formControlInterests.value?.length === 2 ? 'autre' : 'autres'}})
</span>
</mat-select-trigger>
<mat-option *ngFor="let topping of allInterests" [value]="topping">{{topping}}</mat-option>
</mat-select>
</mat-form-field>
<button mat-icon-button (click)="onFilter()">
<mat-icon>keyboard_tab</mat-icon>
</button>
</div>
<!-- période -->
<div class="col-6" style="text-align: right;">
Période de création: &nbsp;
<mat-form-field appearance="fill" style="width: 140px;">
<mat-label>Date de début</mat-label>
<input matInput type="date"
style="font-size: small; width: 140px;"
[ngModel] ="startDate | date:'yyyy-MM-dd'"
(ngModelChange)="onNewStartDate($event); onFilter();">
</mat-form-field>
&nbsp; - &nbsp;
<mat-form-field appearance="fill" style="width: 140px;">
<mat-label>Date de fin</mat-label>
<input matInput type="date"
style="font-size: small; width: 140px;"
[ngModel] ="endDate | date:'yyyy-MM-dd'"
(ngModelChange)="onNewEndDate($event); onFilter();">
</mat-form-field>
</div>
</div>
</div>
</div>
<!-- btnAdd -->
<div class="col-2" style="text-align: right; position: relative;">
<button mat-button class="btnAjouter" (click)="onAdd()" style="position: absolute; bottom: 0; right: 0;">
<mat-icon>add_circle</mat-icon> Ajouter une annonce
</button>
</div>
</div>
<!-- Table -->
<table mat-table [dataSource]="dataSource" matSort class="mat-elevation-z8">
<!-- IsActive Column -->
<ng-container matColumnDef="isVisible">
<th mat-header-cell *matHeaderCellDef mat-sort-header>
<mat-icon>power_settings_new</mat-icon>
</th>
<td mat-cell *matCellDef="let advert">
<mat-slide-toggle [(ngModel)]="advert.isVisible" (click)="onSliderIsVisible(advert)"></mat-slide-toggle>
</td>
</ng-container>
<!-- Title Column -->
<ng-container matColumnDef="title">
<th mat-header-cell *matHeaderCellDef mat-sort-header> Titre </th>
<td mat-cell *matCellDef="let advert">
{{advert.title}}
</td>
</ng-container>
<!-- Subject Column -->
<ng-container matColumnDef="interests">
<th mat-header-cell *matHeaderCellDef> Sujets </th>
<td mat-cell *matCellDef="let advert">
<span *ngFor="let interest of advert.interests; let isLast = last;">
<span *ngIf="!isLast"> {{interest}}, </span>
<span *ngIf="isLast"> {{interest}} </span>
</span>
</td>
</ng-container>
<!-- CreatedAt Column -->
<ng-container matColumnDef="createdAt">
<th mat-header-cell *matHeaderCellDef mat-sort-header> Date de création </th>
<td mat-cell *matCellDef="let advert">
{{ advert.createdAt | date:'dd/LL/YYYY à HH:mm:ss' }}
</td>
</ng-container>
<!-- LastUpdate Column -->
<ng-container matColumnDef="updatedAt">
<th mat-header-cell *matHeaderCellDef mat-sort-header> Dernière modification </th>
<td mat-cell *matCellDef="let advert">
{{ advert.updatedAt | date:'dd/LL/YYYY à HH:mm:ss' }}
</td>
</ng-container>
<!-- Views Column -->
<ng-container matColumnDef="countViews">
<th mat-header-cell *matHeaderCellDef mat-sort-header> Vues </th>
<td mat-cell *matCellDef="let advert">
{{advert.countViews}}
</td>
</ng-container>
<!-- Actions Column -->
<ng-container matColumnDef="actions">
<th mat-header-cell *matHeaderCellDef> Actions </th>
<td mat-cell *matCellDef="let advert">
<button mat-icon-button (click)="onVisualizeImages(advert)">
<mat-icon> insert_photo</mat-icon>
</button>
<button mat-icon-button (click)="onUpdate(advert)">
<mat-icon>edit</mat-icon>
</button>
<button mat-icon-button (click)="onDelete(advert)">
<mat-icon>delete</mat-icon>
</button>
</td>
</ng-container>
<!-- Directives -->
<tr mat-header-row *matHeaderRowDef="displayedColumns"></tr>
<tr mat-row *matRowDef="let row; columns: displayedColumns;"></tr>
<tr class="mat-row" *matNoDataRow>
<td class="mat-cell" colspan="4"> Aucune vidéo ne correspond au filtre: "{{input.value}}" </td>
</tr>
</table>
<div style="width: 94%; margin: auto auto">
<mat-paginator [pageSizeOptions]="[10, 20, 50, 100]" showFirstLastButtons aria-label="Select page of periodic elements"></mat-paginator>
</div>
<br><br>
</div>
</div>

View file

@ -1,87 +0,0 @@
.myContainer {
max-width: 100vw;
height: 100vh;
overflow-x: hidden;
font-size: small;
}
// ----------------------------------------------------------
.filtersContainer {
width: 95%;
background-color: white;
padding: 10px 10px 10px 10px;
}
.myRow {
margin-left: 1%;
}
.textFilter {
width: 50%;
font-size: medium;
border-radius: 5px;
}
.btnAjouter {
background-color: white;
border: solid 1px black;
}
// ----------------------------------------------------------
table {
margin: 0 auto;
width: 94%;
font-size: small;
}
.darkTheme table { border: solid 2px white; }
th.mat-sort-header-sorted {
color: black;
}
td {
font-size: small;
}
input {
width: 30%;
font-size: large;
border-radius: 5px;
}
// --------------------------------------------------------------------
// rong gauche
::ng-deep .mat-slide-toggle-thumb {
background-color: white !important;
}
// trait droite
::ng-deep .mat-slide-toggle-bar {
background-color: gray !important;
}
// rond droite
::ng-deep .mat-slide-toggle.mat-checked:not(.mat-disabled) .mat-slide-toggle-thumb {
background-color: white !important;
}
// trait gauche
::ng-deep .mat-slide-toggle.mat-checked:not(.mat-disabled) .mat-slide-toggle-bar {
background-color: cornflowerblue !important;
}
// -------------------------------------------------------------------------
::ng-deep .mat-pseudo-checkbox-checked {
background-color: black !important;
}

View file

@ -1,25 +0,0 @@
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { PageAdListAdvertiserComponent } from './page-ad-list-advertiser.component';
describe('PageAdvertiserComponent', () => {
let component: PageAdListAdvertiserComponent;
let fixture: ComponentFixture<PageAdListAdvertiserComponent>;
beforeEach(async () => {
await TestBed.configureTestingModule({
declarations: [ PageAdListAdvertiserComponent ]
})
.compileComponents();
});
beforeEach(() => {
fixture = TestBed.createComponent(PageAdListAdvertiserComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});

View file

@ -1,309 +0,0 @@
import {AfterViewInit, Component, OnInit, ViewChild} from '@angular/core';
import {MatSort} from "@angular/material/sort";
import {ThemeService} from "../../../utils/services/theme/theme.service";
import {MatTableDataSource} from "@angular/material/table";
import {AdvertWithCountViews} from "../../../utils/interfaces/advert";
import {MatDialog} from "@angular/material/dialog";
import {PopupAddOrUpdateAdComponent} from "../popup-add-or-update-ad/popup-add-or-update-ad.component";
import {MatSnackBar} from "@angular/material/snack-bar";
import {PopupDeleteAdAdvertiserComponent} from "../popup-delete-ad-advertiser/popup-delete-ad-advertiser.component";
import {MatPaginator} from "@angular/material/paginator";
import {PopupVisualizeImagesAdvertiserComponent} from "../popup-visualize-images-advertiser/popup-visualize-images-advertiser.component";
import {FictitiousAdvertsService} from "../../../utils/services/fictitiousDatas/fictitiousAdverts/fictitious-adverts.service";
import {FormControl} from "@angular/forms";
import {FictitiousUtilsService} from "../../../utils/services/fictitiousDatas/fictitiousUtils/fictitious-utils.service";
import {MessageService} from "../../../utils/services/message/message.service";
import {HttpParams} from "@angular/common/http";
@Component({
selector: 'app-page-ad-list-advertiser',
templateUrl: './page-ad-list-advertiser.component.html',
styleUrls: ['./page-ad-list-advertiser.component.scss']
})
export class PageAdListAdvertiserComponent implements AfterViewInit
{
displayedColumns: string[] = [ 'isVisible', 'title', 'interests', 'createdAt', 'updatedAt', 'countViews', 'actions' ];
tabAdvertWithCountViews: AdvertWithCountViews[] = [];
dataSource;
@ViewChild(MatSort) sort: MatSort;
@ViewChild(MatPaginator) paginator: MatPaginator;
visible: boolean = true;
noVisible: boolean = true;
startDate: Date = null;
endDate: Date = null;
formControlInterests = new FormControl();
allVideoCategorie = [];
allInterests: string[] = [];
constructor( public themeService: ThemeService,
private fictitiousAdvertsService: FictitiousAdvertsService,
private fictitiousUtilsService: FictitiousUtilsService,
public dialog: MatDialog,
private snackBar: MatSnackBar,
private messageService: MessageService ) { }
ngAfterViewInit(): void
{
// Ask interests
this.messageService
.get("misc/getInterests")
.subscribe(ret => this.afterReceivingInterests(ret), err => this.afterReceivingInterests(err) );
// Ask ads
let params = new HttpParams();
params = params.append("isActive", true);
this.messageService
.get("ad/findAll", params)
.subscribe(ret => this.afterReceivingAds(ret), err => this.afterReceivingAds(err));
}
afterReceivingInterests(retour: any): void
{
if(retour.status !== "success") {
console.log("afterReceivingInterests");
console.log(retour);
}
else {
this.allVideoCategorie = retour.data;
this.allInterests = retour.data.map(x => x.interest);
this.allInterests.sort();
}
}
afterReceivingAds(retour: any): void
{
if(retour.status !== "success") {
console.log(retour);
}
else {
if(retour.data.length !== 0)
{
for(let advert of retour.data) this.tabAdvertWithCountViews.push(this.advertToAdvertWithCountViews(advert));
this.dataSource = new MatTableDataSource<AdvertWithCountViews>();
this.onFilter();
}
}
}
applyFilter(event: Event): void
{
const filterValue = (event.target as HTMLInputElement).value;
this.dataSource.filter = filterValue.trim().toLowerCase();
}
onVisualizeImages(advert: AdvertWithCountViews)
{
if(advert.images.length !== 0)
{
const config = {
width: '30%',
height: '90%',
data: { images: advert.images }
};
this.dialog
.open(PopupVisualizeImagesAdvertiserComponent, config)
.afterClosed()
.subscribe(retour => {});
}
else {
const config = { duration: 2000, panelClass: "custom-class" };
const message = "Cette annonce ne contient aucune image" ;
this.snackBar.open( message, "", config);
}
}
onAdd(): void
{
const config = {
width: '75%',
//height: '80%',
panelClass: 'custom-dialog-container',
data: {
action: "add",
advert: null,
allVideoCategorie: this.allVideoCategorie,
allTitle: this.tabAdvertWithCountViews.map(x => x.title)
}
};
this.dialog
.open(PopupAddOrUpdateAdComponent, config)
.afterClosed()
.subscribe( advertAdded => {
const config = { duration: 1000, panelClass: "custom-class" };
let message = "" ;
if((advertAdded === undefined) || (advertAdded === null)) {
message = "Opération annulée" ;
}
else {
this.tabAdvertWithCountViews.push(this.advertToAdvertWithCountViews(advertAdded));
this.onFilter();
message = "L'annonce a bien été ajoutée ✔" ;
}
this.snackBar.open( message, "", config);
});
}
onUpdate(advertToUpdate: AdvertWithCountViews): void
{
const config = {
width: '75%',
//height: '80%',
panelClass: 'custom-dialog-container',
data: {
action: "update",
advert: advertToUpdate,
allVideoCategorie: this.allVideoCategorie,
allTitle: this.tabAdvertWithCountViews.map(x => x.title)
}
};
this.dialog
.open(PopupAddOrUpdateAdComponent, config)
.afterClosed()
.subscribe( advertUpdated => {
const config = { duration: 1000, panelClass: "custom-class" };
let message = "" ;
if((advertUpdated === undefined) || (advertUpdated === null)) {
message = "Opération annulée" ;
}
else {
const index = this.tabAdvertWithCountViews.findIndex(elt => (elt.id === advertToUpdate.id));
this.tabAdvertWithCountViews.splice(index, 1, this.advertToAdvertWithCountViews(advertUpdated));
this.onFilter();
message = "L'annonce a bien été modifiée ✔" ;
}
this.snackBar.open( message, "", config);
});
}
onDelete(advert: AdvertWithCountViews): void
{
const config = {
data: { advert: advert }
};
this.dialog
.open(PopupDeleteAdAdvertiserComponent, config)
.afterClosed()
.subscribe( retour => {
const config = { duration: 1000, panelClass: "custom-class" };
let message = "" ;
if((retour === undefined) || (retour === null)) {
message = "Opération annulée" ;
}
else {
const index = this.dataSource.data.findIndex( elt => (elt.id === advert.id));
this.dataSource.data.splice(index, 1);
this.dataSource.data = this.dataSource.data;
this.dataSource = this.dataSource;
message = advert.title + " a bien été supprimée ✔" ;
}
this.snackBar.open( message, "", config);
});
}
onFilter(): void
{
if(this.dataSource === null || this.dataSource === undefined) this.dataSource = new MatTableDataSource();
this.dataSource.data = [];
for(let advert of this.tabAdvertWithCountViews)
{
let valide: boolean = true;
if(advert.isVisible && this.visible) valide = true;
else if((!advert.isVisible) && this.noVisible) valide = true;
else valide = false;
if(valide)
{
if ((advert.createdAt === null) && (this.startDate !== null)) valide = false;
else if ((advert.createdAt === null) && (this.endDate !== null)) valide = false;
else if (this.startDate !== null)
{
if(this.startDate.getTime() > advert.createdAt.getTime()) valide = false;
else if (this.endDate !== null)
{
if(this.endDate.getTime() < advert.createdAt.getTime()) valide = false;
}
}
}
if(valide) {
if(this.formControlInterests.value !== null) {
for (let interest of this.formControlInterests.value) {
if (advert.interests.indexOf(interest) === -1) {
valide = false;
break;
}
}
}
}
if(valide) this.dataSource.data.push(advert);
}
this.dataSource = new MatTableDataSource(this.dataSource.data);
this.dataSource.sort = this.sort;
this.dataSource.paginator = this.paginator;
}
onNewStartDate(event): void {
this.startDate = new Date(event);
}
onNewEndDate(event): void {
this.endDate = new Date(event);
}
onSliderIsVisible(advert: any): void
{
// il faut envoyer la négation de user.isActive
this.messageService
.put("ad/update/"+advert.id, { isVisible: !advert.isVisible })
.subscribe(
ret => {},
err => {
console.log("onSliderIsVisible");
console.log(err);
}
);
}
advertToAdvertWithCountViews(advert): AdvertWithCountViews
{
return {
id: advert.id,
userId: advert.userId,
title: advert.title,
url: advert.url,
images: advert.images,
interests: advert.interests.map(x => x.interest),
comment: advert.comment,
views: advert.views,
countViews: advert.views.length,
isVisible: advert.isVisible,
isActive: advert.isActive,
createdAt: advert.createdAt,
updatedAt: advert.updatedAt,
}
}
}

View file

@ -1,83 +0,0 @@
<div class="myContainer1">
<div class="myContainer2">
<!-- titre popup -->
<h1 mat-dialog-title>{{title}}</h1>
<mat-divider></mat-divider><br>
<!-- tous les champs -->
<div class="row">
<!-- title + interests + comments + isVisible -->
<div class="col-6">
<!-- Title -->
<mat-form-field class="titleContainer" appearance="fill">
<mat-label> Titre annonce </mat-label>
<input matInput type="text" [(ngModel)]="advert.title" required>
</mat-form-field>
<!-- Interests -->
<app-input-interests-ad [myInterests]="advert.interests" (eventEmitter)="onEventInputTags($event)"></app-input-interests-ad>
<!-- Comments -->
<mat-form-field class="commentContainer" appearance="fill">
<mat-label> Commentaire </mat-label>
<textarea matInput [(ngModel)]="advert.comment" rows="5" style="resize: none;"></textarea>
</mat-form-field><br>
<!-- url -->
<mat-form-field class="commentContainer" appearance="fill">
<mat-label> URL </mat-label>
<input matInput [(ngModel)]="advert.url">
</mat-form-field><br>
<!-- IsVisible -->
<mat-checkbox [(ngModel)]="advert.isVisible"> Visible </mat-checkbox><br><br>
<!-- Images déjà présentes -->
<div *ngIf="advert.images.length !== 0">
<div style="font-weight: bold; margin-bottom: 5px;">
Images déjà associées:
</div>
<div style="margin-left: 20px; padding-left: 2px; border-left: solid 1px #a4a4a4">
<div *ngFor="let image of advert.images" style="padding: 2px 0px 2px 0px;">
<mat-chip [selectable]="true" [removable]="true" style="font-size: small;">
{{image.description}}
<button matChipRemove (click)="onRemoveImgAlreadyPresent(image)">
<mat-icon>cancel</mat-icon>
</button>
</mat-chip>
</div>
</div>
</div>
</div>
<!-- nouvelles images -->
<div class="col-6" style="overflow-x: hidden; overflow-y: scroll; max-height: 70vh;">
<app-drag-and-drop (eventEmitter)="onReceiveNewImages($event)"></app-drag-and-drop>
</div>
</div>
<br><mat-divider></mat-divider>
<!-- message d'erreur -->
<div *ngIf="hasError" style="text-align: center; margin-bottom: 20px;">
<span class="mat-error">{{errorMessage}}</span>
</div>
<!-- Actions -->
<mat-dialog-actions align="end">
<button mat-button (click)="dialogRef.close()">Annuler</button>
<button mat-button (click)="onValidate()">Valider</button>
</mat-dialog-actions>
</div>
</div>

View file

@ -1,90 +0,0 @@
.myContainer1 {
padding: 10px 10px 0px 25px;
margin: 0px 0px 0px 0px;
font-size: small;
}
.myContainer2 {
padding: 0px 0px 0px 0px;
margin: 0px 0px 0px 0px;
overflow-y: hidden;
overflow-x: hidden;
-ms-overflow-style: none;
scrollbar-width: none;
}
.myContainer2::-webkit-scrollbar {
display: none;
}
h1 {
text-align: center;
font-size: large;
}
.col-6, .col-8 {
border-left: solid 1px #a4a4a4;
}
// -------------------------------------------------------------------------
.titleContainer {
width: 100%;
}
.commentContainer {
width: 100%;
}
.imageContainer {
border: solid 1px grey;
}
mat-dialog-actions {
margin-bottom: 0px;
}
button {
font-size: small;
}
// -------------------------------------------------------------------------
// --- LightTheme ---
// aura
.lightTheme ::ng-deep .mat-checkbox-ripple .mat-ripple-element {
background-color: grey !important;
}
// contenu coche
.lightTheme ::ng-deep .mat-checkbox-checked.mat-accent .mat-checkbox-background {
background-color: black !important;
}
// indeterminate
.lightTheme ::ng-deep .mat-checkbox .mat-checkbox-frame {
border-color: black !important;
background-color: white !important;
}
// --- DarkTheme ---
// aura
.darTheme ::ng-deep .mat-checkbox-ripple .mat-ripple-element {
background-color: grey !important;
}
// contenu coche
.darkTheme ::ng-deep .mat-checkbox-checked.mat-accent .mat-checkbox-background {
background-color: black !important;
}
// indeterminate
.darkTheme ::ng-deep .mat-checkbox .mat-checkbox-frame {
border-color: white !important;
//background-color: white !important;
}

View file

@ -1,25 +0,0 @@
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { PopupAddOrUpdateAdComponent } from './popup-add-or-update-ad.component';
describe('PopupAddOrUpdateAdComponent', () => {
let component: PopupAddOrUpdateAdComponent;
let fixture: ComponentFixture<PopupAddOrUpdateAdComponent>;
beforeEach(async () => {
await TestBed.configureTestingModule({
declarations: [ PopupAddOrUpdateAdComponent ]
})
.compileComponents();
});
beforeEach(() => {
fixture = TestBed.createComponent(PopupAddOrUpdateAdComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});

View file

@ -1,221 +0,0 @@
import {Component, Inject, OnInit} from '@angular/core';
import {Advert} from "../../../utils/interfaces/advert";
import {MAT_DIALOG_DATA, MatDialogRef} from "@angular/material/dialog";
import {MessageService} from "../../../utils/services/message/message.service";
import {ThemeService} from "../../../utils/services/theme/theme.service";
const ADVERT_VIDE: Advert = {
_id: "",
userId: "",
title: "",
url: "",
images: [],
interests: [],
comment: "",
views: [],
isVisible: true,
isActive: true,
createdAt: new Date(),
updatedAt: new Date(),
}
@Component({
selector: 'app-popup-add-or-update-ad',
templateUrl: './popup-add-or-update-ad.component.html',
styleUrls: ['./popup-add-or-update-ad.component.scss']
})
export class PopupAddOrUpdateAdComponent implements OnInit
{
advert: any;
title: string = "" ;
allVideoCategorie = [];
allTitle = [];
tabOfNewImagesBase64 = [];
tabOfNewImagesName = [];
hasError: boolean = false;
errorMessage: string = "" ;
constructor( public dialogRef: MatDialogRef<PopupAddOrUpdateAdComponent>,
@Inject(MAT_DIALOG_DATA) public data,
private messageService: MessageService,
public themeService: ThemeService ) { }
ngOnInit(): void
{
this.allVideoCategorie = this.data.allVideoCategorie;
this.allTitle = this.data.allTitle.slice();
if(this.data.action === "add")
{
this.advert = Object.assign({}, ADVERT_VIDE);
this.advert.images = [];
this.advert.interests = [];
this.title = "Ajouter annonce" ;
}
else
{
this.advert = Object.assign({}, this.data.advert);
this.advert.interests = this.data.advert.interests.slice();
this.title = "Modifier annonce" ;
const indexOldTitle = this.allTitle.findIndex(title => title == this.advert.title);
this.allTitle.splice(indexOldTitle, 1);
}
}
onValidate(): void
{
this.checkField();
if(!this.hasError)
{
// preparation des donnees
this.prepareAdvertInterests();
this.prepareAdvertImages();
// si creation
if (this.data.action === "add")
{
this.messageService
.post("ad/create", this.advert)
.subscribe(ret => this.onCreateCallback(ret), err => this.onCreateCallback(err));
}
// si update
else
{
const id = this.advert.id;
Reflect.deleteProperty(this.advert, "id");
Reflect.deleteProperty(this.advert, "_id");
this.messageService
.put("ad/update/" + id, this.advert)
.subscribe(ret => this.onUpdateCallback(ret, id), err => this.onUpdateCallback(err, id));
}
}
}
checkField()
{
if(this.advert.title.length === 0) {
this.errorMessage = "Veuillez remplir le champ 'titre'." ;
this.hasError = true;
}
else if(this.allTitle.includes(this.advert.title)) {
this.errorMessage = "Ce titre est déjà pris." ;
this.hasError = true;
}
else if((this.advert.images.length === 0) && (this.tabOfNewImagesName.length === 0)) {
this.errorMessage = "Veuillez uploader au moins une image." ;
this.hasError = true;
}
else {
this.errorMessage = "";
this.hasError = false;
}
}
onCreateCallback(retour: any): void
{
if(retour.status !== "success") {
console.log(retour);
this.dialogRef.close();
}
else {
this.dialogRef.close(retour.data);
}
}
onUpdateCallback(retour: any, id: string): void
{
if(retour.status !== "success") {
console.log(retour);
this.dialogRef.close();
}
else {
this.advert.id = id;
this.dialogRef.close(this.advert);
}
}
onEventInputTags(myTags: string[]): void
{
this.advert.interests = myTags;
}
onRemoveImgAlreadyPresent(image)
{
const index = this.advert.images.indexOf(image);
this.advert.images.splice(index, 1);
}
onReceiveNewImages(files: any): void
{
this.tabOfNewImagesBase64 = [];
this.tabOfNewImagesName = [];
if(files)
{
for(let file of files)
{
if(file)
{
const reader = new FileReader();
reader.onload = this.handleReaderLoaded.bind(this);
this.tabOfNewImagesName.push(file.name)
reader.readAsBinaryString(file);
}
}
}
}
handleReaderLoaded(e)
{
this.tabOfNewImagesBase64.push('data:image/png;base64,' + btoa(e.target.result))
}
// Met bien en forme les "images" avant d'être envoyer
prepareAdvertImages(): void
{
for(let i=0; i<this.tabOfNewImagesName.length ; i++)
{
let newImagePrepared = {
base64: this.tabOfNewImagesBase64[i],
url: "",
description: this.tabOfNewImagesName[i],
type: 0,
};
this.advert.images.push(newImagePrepared);
}
}
// Met bien en forme les "interests" avant d'être envoyer
prepareAdvertInterests(): void
{
let interests = [];
for (let interest of this.advert.interests) {
for (let videoCategorie of this.allVideoCategorie) {
if (videoCategorie.interest === interest) {
interests.push(videoCategorie);
break;
}
}
}
this.advert.interests = interests;
}
}

View file

@ -1,8 +0,0 @@
<mat-dialog-content class="mat-typography">
Êtes-vous sûr de vouloir supprimer l'annonce <i>{{advert.title}}</i> ?
</mat-dialog-content>
<mat-dialog-actions align="end">
<button mat-button (click)="dialogRef.close();">Annuler</button>
<button mat-button (click)="onValidate()" cdkFocusInitial>Valider</button>
</mat-dialog-actions>

View file

@ -1,25 +0,0 @@
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { PopupDeleteAdAdvertiserComponent } from './popup-delete-ad-advertiser.component';
describe('PopupDeleteAdComponent', () => {
let component: PopupDeleteAdAdvertiserComponent;
let fixture: ComponentFixture<PopupDeleteAdAdvertiserComponent>;
beforeEach(async () => {
await TestBed.configureTestingModule({
declarations: [ PopupDeleteAdAdvertiserComponent ]
})
.compileComponents();
});
beforeEach(() => {
fixture = TestBed.createComponent(PopupDeleteAdAdvertiserComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});

View file

@ -1,47 +0,0 @@
import {Component, Inject, OnInit} from '@angular/core';
import {MAT_DIALOG_DATA, MatDialogRef} from "@angular/material/dialog";
import {MessageService} from "../../../utils/services/message/message.service";
@Component({
selector: 'app-popup-delete-ad-advertiser',
templateUrl: './popup-delete-ad-advertiser.component.html',
styleUrls: ['./popup-delete-ad-advertiser.component.scss']
})
export class PopupDeleteAdAdvertiserComponent implements OnInit
{
advert: any;
constructor( public dialogRef: MatDialogRef<PopupDeleteAdAdvertiserComponent>,
@Inject(MAT_DIALOG_DATA) public data,
private messageService: MessageService) { }
ngOnInit(): void
{
this.advert = this.data.advert;
}
onValidate(): void
{
this.messageService
.delete("ad/delete/"+this.advert.id)
.subscribe(ret => this.onValidateCallback(ret), err => this.onValidateCallback(err));
}
onValidateCallback(retour: any): void
{
if(retour.status !== "success") {
console.log(retour);
this.dialogRef.close();
}
else {
this.dialogRef.close(true);
}
}
}

View file

@ -1,71 +0,0 @@
<div [class]="themeService.getClassTheme()">
<h1 mat-dialog-title>{{advert.title}}</h1>
<!-- ----------------------------------------------------------------------------------------------------------------- -->
<mat-divider></mat-divider>
<mat-dialog-content>
<!-- Images -->
<div class="row myRow">
<div class="col-6 myLabel"> Images: </div>
<div class="col-6 myValue" style="border-left: solid 1px #e6e6e6">
<div *ngFor="let image of advert.images"> {{image.url}} </div>
</div>
</div>
<!-- Tags -->
<div class="row myRow">
<div class="col-6 myLabel"> Centre d'intérêt :</div>
<div class="col-6 myValue" style="border-left: solid 1px #e6e6e6">
<div *ngFor="let tag of advert.interests"> • {{tag}} </div>
</div>
</div>
<!-- Comment -->
<div class="row myRow">
<div class="col-6 myLabel"> Commentaire: </div>
<div class="col-6 myValue"> {{advert.comment}} </div>
</div>
<!-- Views -->
<div class="row myRow">
<label class="col-6 myLabel"> Vues: </label>
<div class="col-6 myValue"> {{advert.views}} </div>
</div>
<!-- Created at -->
<div class="row myRow">
<label class="col-6 myLabel"> Date de création: </label>
<div class="col-6 myValue">
{{ advert.createdAt | date:'dd/LL/YYYY à HH:mm:ss' }}
</div>
</div>
<!-- Last updtade -->
<div class="row myRow">
<label class="col-6 myLabel"> Date de dernière modification: </label>
<div class="col-6 myValue">
{{ advert.updatedAt | date:'dd/LL/YYYY à HH:mm:ss' }}
</div>
</div>
<!-- IsVisible -->
<div class="row myRow">
<label class="col-6 myLabel"> Visibilité: </label>
<div class="col-6 myValue">
<mat-icon *ngIf="advert.isVisible">checked</mat-icon>
<mat-icon *ngIf="!advert.isVisible">close</mat-icon>
</div>
</div>
</mat-dialog-content>
<!-- ----------------------------------------------------------------------------------------------------------------- -->
<mat-dialog-actions align="end">
<button mat-button (click)="dialogRef.close()">Fermer</button>
</mat-dialog-actions>
</div>

View file

@ -1,28 +0,0 @@
.lightTheme, .darkTheme {
background-image: none;
}
h1 {
text-align: center;
font-size: xx-large;
}
.myRow {
margin: 15px 0px 15px 0px;
}
.myLabel {
text-align: right;
padding: 0px 5px 0px 0px;
margin: 0px;
font-weight: bold;
}
.myValue {
text-align: left;
padding: 0px 0px 0px 5px;
margin: 0px;
}

View file

@ -1,25 +0,0 @@
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { PopupVisualizeAdAdvertiserComponent } from './popup-visualize-ad-advertiser.component';
describe('PopupVisualizeAdComponent', () => {
let component: PopupVisualizeAdAdvertiserComponent;
let fixture: ComponentFixture<PopupVisualizeAdAdvertiserComponent>;
beforeEach(async () => {
await TestBed.configureTestingModule({
declarations: [ PopupVisualizeAdAdvertiserComponent ]
})
.compileComponents();
});
beforeEach(() => {
fixture = TestBed.createComponent(PopupVisualizeAdAdvertiserComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});

View file

@ -1,27 +0,0 @@
import {Component, Inject, OnInit} from '@angular/core';
import {ThemeService} from "../../../utils/services/theme/theme.service";
import {MAT_DIALOG_DATA, MatDialog, MatDialogRef} from "@angular/material/dialog";
import {Advert} from "../../../utils/interfaces/advert";
@Component({
selector: 'app-popup-visualize-ad-advertiser',
templateUrl: './popup-visualize-ad-advertiser.component.html',
styleUrls: ['./popup-visualize-ad-advertiser.component.scss']
})
export class PopupVisualizeAdAdvertiserComponent implements OnInit
{
advert: Advert;
constructor( public dialogRef: MatDialogRef<PopupVisualizeAdAdvertiserComponent>,
@Inject(MAT_DIALOG_DATA) public data,
public themeService: ThemeService,
public dialog: MatDialog ) { }
ngOnInit(): void
{
this.advert = this.data.advert;
}
}

View file

@ -1,20 +0,0 @@
<div mat-dialog-title class="dialog-title">
<h2></h2>
<button mat-icon-button aria-label="close dialog" mat-dialog-close>
<mat-icon>close</mat-icon>
</button>
</div>
<mat-grid-list cols="12" rowHeight="500">
<mat-grid-tile colspan="1" rowspan="1" (click)="onPrecedent()">
<button> < </button>
</mat-grid-tile>
<mat-grid-tile colspan="10" rowspan="1">
<img [src]="tabImages[index].base64" [alt]="tabImages[index].description">
</mat-grid-tile>
<mat-grid-tile colspan="1" rowspan="1" (click)="onSuivant()">
<button> > </button>
</mat-grid-tile>
</mat-grid-list>

View file

@ -1,14 +0,0 @@
carousel {
width: 100%;
margin: 0 auto;
text-align: center;
justify-content: center
}
.dialog-title {
display: flex;
justify-content: space-between;
align-items: center;
}

View file

@ -1,25 +0,0 @@
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { PopupVisualizeImagesAdvertiserComponent } from './popup-visualize-images-advertiser.component';
describe('PopupVisualizeImagesComponent', () => {
let component: PopupVisualizeImagesAdvertiserComponent;
let fixture: ComponentFixture<PopupVisualizeImagesAdvertiserComponent>;
beforeEach(async () => {
await TestBed.configureTestingModule({
declarations: [ PopupVisualizeImagesAdvertiserComponent ]
})
.compileComponents();
});
beforeEach(() => {
fixture = TestBed.createComponent(PopupVisualizeImagesAdvertiserComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});

View file

@ -1,38 +0,0 @@
import {Component, Inject, OnInit} from '@angular/core';
import {MAT_DIALOG_DATA, MatDialogRef} from "@angular/material/dialog";
@Component({
selector: 'app-popup-visualize-images-advertiser',
templateUrl: './popup-visualize-images-advertiser.component.html',
styleUrls: ['./popup-visualize-images-advertiser.component.scss']
})
export class PopupVisualizeImagesAdvertiserComponent implements OnInit
{
tabImages = [];
index: number = 0;
nbImage: number = 0;
constructor( public dialogRef: MatDialogRef<PopupVisualizeImagesAdvertiserComponent>,
@Inject(MAT_DIALOG_DATA) public data ) { }
ngOnInit(): void
{
this.tabImages = this.data.images;
this.nbImage = this.tabImages.length;
}
onPrecedent(): void
{
if(this.index !== 0) this.index -= 1;
}
onSuivant(): void
{
if(this.index !== (this.nbImage-1)) this.index += 1;
}
}

View file

@ -1,49 +0,0 @@
<div [class]="themeService.getClassTheme()">
<div class="myContainer">
<!-- NavBar -->
<app-navbar-advertiser></app-navbar-advertiser>
<!-- Boite -->
<div class="boite">
<!-- Photo de profil -->
<div style="text-align: center">
<img [src]="advertiser.profileImageUrl"
onerror="this.onerror=null; this.src='assets/profil.png'">
</div>
<!-- entreprise -->
<div class="row myRow">
<div class="col-6 myLabel">Entreprise:</div>
<div class="col-6 myValue"> {{advertiser.company}} </div>
</div>
<!-- login -->
<div class="row myRow">
<div class="col-6 myLabel">Pseudo:</div>
<div class="col-6 myValue"> {{advertiser.login}} </div>
</div>
<!-- email -->
<div class="row myRow">
<div class="col-6 myLabel">Mail:</div>
<div class="col-6 myValue"> {{advertiser.email}} </div>
</div>
<!-- createdAt -->
<div class="row myRow">
<div class="col-6 myLabel">Date de création:</div>
<div class="col-6 myValue">{{advertiser.createdAt | date:'dd/LL/YYYY'}}</div>
</div>
<!-- Modifier profil -->
<div class="btnContainer">
<button mat-button class="myBtn" (click)="onModifier()">Modifier profil</button>
</div>
</div>
</div>
</div>

View file

@ -1,61 +0,0 @@
.myContainer {
max-width: 100vw;
height: 100vh;
overflow-x: hidden;
}
.boite {
margin-left: auto;
margin-right: auto;
width: 25%;
margin-top: 10vh;
border: solid 3px;
border-radius: 10px;
padding: 20px 40px 20px 40px;
background-color: #ffffff;
text-align: center;
box-shadow: 10px 5px 5px black;
}
.lightTheme .boite {
border-color: black;
}
.darkTheme .boite {
border-color: white;
}
img {
margin: 0px 0px 10px 0px;
width: 5vw;
height: 5vw;
border: solid 2px black;
border-radius: 50%;
font-size: xxx-large;
}
.myRow {
margin: 15px 0px 15px 0px;
}
.myLabel {
text-align: right;
padding: 0px 5px 0px 0px;
margin: 0px;
font-weight: bold;
}
.myValue {
text-align: left;
padding: 0px 0px 0px 5px;
margin: 0px;
}
.btnContainer {
text-align: center;
margin-top: 40px;
}
.myBtn {
border: solid 1px black;
background-color: white;
}

View file

@ -1,25 +0,0 @@
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { PageProfilAdvertiserComponent } from './page-profil-advertiser.component';
describe('PageProfilAdvertiserComponent', () => {
let component: PageProfilAdvertiserComponent;
let fixture: ComponentFixture<PageProfilAdvertiserComponent>;
beforeEach(async () => {
await TestBed.configureTestingModule({
declarations: [ PageProfilAdvertiserComponent ]
})
.compileComponents();
});
beforeEach(() => {
fixture = TestBed.createComponent(PageProfilAdvertiserComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});

View file

@ -1,90 +0,0 @@
import { Component, OnInit } from '@angular/core';
import {User} from "../../../utils/interfaces/user";
import {ThemeService} from "../../../utils/services/theme/theme.service";
import {MatDialog} from "@angular/material/dialog";
import {MatSnackBar} from "@angular/material/snack-bar";
import {PopupUpdateAdvertiserComponent} from "../popup-update-advertiser/popup-update-advertiser.component";
import {MessageService} from "../../../utils/services/message/message.service";
import {ProfilService} from "../../../utils/services/profil/profil.service";
@Component({
selector: 'app-page-profil-advertiser',
templateUrl: './page-profil-advertiser.component.html',
styleUrls: ['./page-profil-advertiser.component.scss']
})
export class PageProfilAdvertiserComponent implements OnInit
{
advertiser: User = {
_id: "",
login: "",
hashPass: "",
email: "",
role: {
name: "advertiser",
permission: 5,
isAccepted: true,
},
profileImageUrl: "",
dateOfBirth: null,
gender: "man",
interests: [],
company: "",
isActive: true,
createdAt: new Date(),
updatedAt: new Date(),
lastConnexion: null
};
constructor( public themeService: ThemeService,
public dialog: MatDialog,
private snackBar: MatSnackBar,
private messageService: MessageService,
private profilService: ProfilService ) { }
ngOnInit(): void
{
this.messageService
.get( "user/findOne/"+this.profilService.getId())
.subscribe( retour => this.ngOnInitCallback(retour), err => this.ngOnInitCallback(err) )
}
ngOnInitCallback(retour: any)
{
if(retour.status !== "success") {
console.log(retour);
}
else {
this.advertiser = retour.data;
}
}
onModifier()
{
const config = {
width: '25%',
data: { advertiser: this.advertiser }
};
this.dialog
.open(PopupUpdateAdvertiserComponent, config)
.afterClosed()
.subscribe(retour => {
if((retour === null) || (retour === undefined))
{
const config = { duration: 1000, panelClass: "custom-class" };
this.snackBar.open( "Opération annulé", "", config);
}
else
{
this.advertiser = retour;
}
});
}
}

View file

@ -1,65 +0,0 @@
<div class="myContainer">
<div class="boite">
<!-- photo de profil -->
<div style="text-align: center">
<img [src]="advertiserCopy.profileImageUrl" onerror="this.onerror=null; this.src='assets/profil.png'"><br>
<input title="lien vers image" type="text" [(ngModel)]="advertiserCopy.profileImageUrl" style="width: 90%">
</div>
<!-- divider -->
<br><mat-divider></mat-divider><br>
<!-- entreprise -->
<mat-form-field appearance="fill">
<mat-label>Entreprise</mat-label>
<input matInput type="text" [(ngModel)]="advertiserCopy.company">
</mat-form-field><br>
<!-- login -->
<mat-form-field appearance="fill">
<mat-label>Pseudo</mat-label>
<input matInput type="text" [(ngModel)]="advertiserCopy.login">
</mat-form-field><br>
<!-- divider -->
<mat-divider></mat-divider><br>
<!-- Modifier mot de passe -->
<div>
Modifier mot de passe:
<mat-checkbox [(ngModel)]="changePassword"></mat-checkbox>
</div>
<!-- nouveau mot de passe -->
<div *ngIf="changePassword" style="margin-top: 10px">
<!-- Nouveau mot de passe -->
<mat-form-field appearance="fill">
<mat-label>Nouveau mot de passe</mat-label>
<input matInput type="password" [(ngModel)]="newPassword">
</mat-form-field>
<br>
<!-- Confirmation nouveau mot de passe -->
<mat-form-field appearance="fill">
<mat-label>Confirmation nouveau mot de passe</mat-label>
<input matInput type="password" [(ngModel)]="confirmNewPassword">
</mat-form-field>
</div>
<div *ngIf="!changePassword"><br></div>
<!-- divider -->
<mat-divider></mat-divider><br>
<!-- message d'erreur -->
<div *ngIf="hasError" style="text-align: center; margin-bottom: 20px;">
<span class="mat-error">{{errorMessage}}</span>
</div>
<!-- boutons -->
<div style="width: 100%; text-align: right">
<button mat-button (click)="this.dialogRef.close(null)"> Annuler </button>
<button mat-button (click)="onValider()"> Enregistrer </button>
</div>
</div>
</div>

View file

@ -1,33 +0,0 @@
.boite {
font-size: small;
}
button {
font-size: small;
}
img {
margin: 0px 0px 10px 0px;
width: 5vw;
height: 5vw;
border: solid 2px black;
border-radius: 50%;
font-size: xxx-large;
}
// -------------------------------------------------------------------------
// aura
::ng-deep .mat-checkbox-ripple .mat-ripple-element {
background-color: grey !important;
}
// contenu coche
::ng-deep .mat-checkbox-checked.mat-accent .mat-checkbox-background {
background-color: black !important;
}
// indeterminate
::ng-deep .mat-checkbox .mat-checkbox-frame {
background-color: white !important;
}

View file

@ -1,25 +0,0 @@
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { PopupUpdateAdvertiserComponent } from './popup-update-advertiser.component';
describe('PopupUpdateAdvertiserComponent', () => {
let component: PopupUpdateAdvertiserComponent;
let fixture: ComponentFixture<PopupUpdateAdvertiserComponent>;
beforeEach(async () => {
await TestBed.configureTestingModule({
declarations: [ PopupUpdateAdvertiserComponent ]
})
.compileComponents();
});
beforeEach(() => {
fixture = TestBed.createComponent(PopupUpdateAdvertiserComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});

View file

@ -1,125 +0,0 @@
import {Component, Inject, OnInit} from '@angular/core';
import {User} from "../../../utils/interfaces/user";
import {MAT_DIALOG_DATA, MatDialogRef} from "@angular/material/dialog";
import {MessageService} from "../../../utils/services/message/message.service";
import {ProfilService} from "../../../utils/services/profil/profil.service";
@Component({
selector: 'app-popup-update-advertiser',
templateUrl: './popup-update-advertiser.component.html',
styleUrls: ['./popup-update-advertiser.component.scss']
})
export class PopupUpdateAdvertiserComponent implements OnInit
{
advertiserCopy: User;
newPassword: string = "";
confirmNewPassword: string = "" ;
changePassword: boolean = false ;
hasError: boolean = false;
errorMessage: string = "" ;
constructor( public dialogRef: MatDialogRef<PopupUpdateAdvertiserComponent>,
@Inject(MAT_DIALOG_DATA) public data,
private messageService: MessageService,
private profilService: ProfilService ) { }
ngOnInit(): void
{
const advertiser0 = this.data.advertiser;
this.advertiserCopy = {
_id: advertiser0._id,
login: advertiser0.login,
hashPass: advertiser0.hashPass,
email: advertiser0.email,
role: {
name: advertiser0.role.name,
permission: advertiser0.role.permission,
isAccepted: advertiser0.role.isAccepted,
},
profileImageUrl: advertiser0.profileImageUrl,
dateOfBirth: advertiser0.dateOfBirth,
gender: advertiser0.gender,
interests: [],
company: advertiser0.company,
isActive: advertiser0.isActive,
createdAt: advertiser0.createdAt,
updatedAt: advertiser0.updatedAt,
lastConnexion: new Date()
};
for(let interest of advertiser0.interests) this.advertiserCopy.interests.push(interest);
}
onValider()
{
this.checkField();
if(!this.hasError)
{
if(this.changePassword) this.advertiserCopy.hashPass = this.newPassword;
const data = {
login: this.advertiserCopy.login,
hashPass: this.advertiserCopy.hashPass,
email: this.advertiserCopy.email,
profileImageUrl: this.advertiserCopy.profileImageUrl,
company: this.advertiserCopy.company
};
this.messageService
.put("user/update/"+this.profilService.getId(), data)
.subscribe( ret => this.onValiderCallback(ret), err => this.onValiderCallback(err) );
}
}
onValiderCallback(retour: any)
{
if(retour.status !== "success") {
console.log(retour);
this.dialogRef.close(null);
}
else {
this.profilService.setProfileImageUrl(this.advertiserCopy.profileImageUrl);
this.dialogRef.close(this.advertiserCopy);
}
}
checkField()
{
if(this.advertiserCopy.login.length === 0) {
this.errorMessage = "Veuillez remplir le champ 'pseudo'" ;
this.hasError = true;
}
else if(this.advertiserCopy.email.length === 0) {
this.errorMessage = "Veuillez remplir le champ 'email'" ;
this.hasError = true;
}
else if(!this.isValidEmail(this.advertiserCopy.email)) {
this.errorMessage = "Email invalide" ;
this.hasError = true;
}
else if((this.changePassword) && (this.newPassword.length === 0)) {
this.errorMessage = "Veuillez remplir le champ 'mot de passe'" ;
this.hasError = true;
}
else if((this.changePassword) && (this.newPassword !== this.confirmNewPassword)) {
this.errorMessage = "Le mot de passe est différent de sa confirmation" ;
this.hasError = true;
}
else {
this.errorMessage = "" ;
this.hasError = false;
}
}
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);
}
}

View file

@ -1,94 +0,0 @@
<div [class]="themeService.getClassTheme()">
<div class="myContainer">
<!-- Navbar -->
<app-navbar-advertiser></app-navbar-advertiser>
<!-- Filter -->
<div class="filtersContainer mat-elevation-z8">
<div style="font-weight: bold;">Filtre</div>
<mat-divider></mat-divider><br>
<div *ngIf="true; then colPeriode"></div>
<br><mat-divider style="width: 60%"></mat-divider><br>
<div style="text-align: right; font-size: small;">
<button mat-button (click)="onApplyFilter()" style="font-size: small">Appliquer</button>
</div>
</div>
<!-- chart -->
<div *ngIf="isDisplayable" class="chartContainer">
<canvas baseChart
[datasets]="lineChartData"
[labels]="lineChartLabels"
[options]="chartOptions"
[colors]="[]"
[legend]="true"
[chartType]="'line'">
</canvas>
</div>
</div>
</div>
<!-- ------------------------------------------------------------------------------------------------------------------- -->
<ng-template #colPeriode>
<!-- startDate -->
<mat-form-field appearance="fill" style="width: 140px;">
<mat-label>début</mat-label>
<input matInput type="date" [ngModel] ="startDate | date:'yyyy-MM-dd'" (ngModelChange)="onNewStartDate($event);">
</mat-form-field>
&nbsp; - &nbsp;
<!-- endDate -->
<mat-form-field appearance="fill" style="width: 140px;">
<mat-label>fin</mat-label>
<input matInput type="date" [ngModel] ="endDate | date:'yyyy-MM-dd'" (ngModelChange)="onNewEndDate($event);">
</mat-form-field>
&nbsp; - &nbsp;
<!-- step -->
<mat-form-field appearance="fill" style="width: 140px;">
<mat-label>pas d'affichage</mat-label>
<input matInput type="number" [(ngModel)] =step>
</mat-form-field>
&nbsp; - &nbsp;
<!-- step unity -->
<mat-form-field appearance="fill">
<mat-label>unité du pas d'affichage</mat-label>
<mat-select [(ngModel)]="stepUnity">
<mat-option value="jour">jour</mat-option>
<mat-option value="semaine">semaine</mat-option>
<mat-option value="mois">mois</mat-option>
</mat-select>
</mat-form-field><br>
<!-- ads -->
<mat-select [formControl]="formControl" multiple style="padding-top: 10px; width: 60%;">
<mat-select-trigger>
<span *ngIf="formControl.value?.length > 0">
<span *ngFor="let coupleNameViews of formControl.value"> {{coupleNameViews.name}}, </span>
</span>
</mat-select-trigger>
<mat-option *ngFor="let coupleNameViews of allCoupleNameViews" [value]="coupleNameViews">{{coupleNameViews.name}}</mat-option>
</mat-select>
<button mat-button class="btnToutSelectionner" (click)="onSelectAll()">Tout sélectionner</button>
<button mat-button class="btnToutDeselectionner" (click)="onDeSelectAll()">Tout désélectionner</button>
</ng-template>

View file

@ -1,53 +0,0 @@
.myContainer {
font-size: small;
max-width: 100vw;
height: 100vh;
overflow-x: hidden;
overflow-y: scroll;
}
input {
font-size: small;
width: 140px;
}
.filtersContainer {
background-color: white;
width: 60%;
margin: 50px 50px 50px 50px;
padding: 20px 20px 20px 20px;
}
.chartContainer {
background-color: white;
border: solid 1px black;
padding: 10px 10px 10px 10px;
margin: 50px 50px 50px 50px;
}
// ---------------------------------------------
// periode
.periode {
padding: 10px 10px 0px 10px;
}
.periode .titleContainer {
text-align: right;
border-right: solid 1px #dcdcdc;
font-weight: bold;
}
.btnToutSelectionner {
font-size: small;
}
.btnToutDeselectionner {
font-size: small;
}
// -------------------------------------------------------------------------
::ng-deep .mat-pseudo-checkbox-checked {
background-color: black !important;
}

View file

@ -1,25 +0,0 @@
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { PagesPopularityComponent } from './pages-popularity.component';
describe('SubjectsPopularityComponent', () => {
let component: PagesPopularityComponent;
let fixture: ComponentFixture<PagesPopularityComponent>;
beforeEach(async () => {
await TestBed.configureTestingModule({
declarations: [ PagesPopularityComponent ]
})
.compileComponents();
});
beforeEach(() => {
fixture = TestBed.createComponent(PagesPopularityComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});

View file

@ -1,308 +0,0 @@
import { Component, OnInit } from '@angular/core';
import {FormControl} from "@angular/forms";
import {ChartDataSets} from "chart.js";
import {Label} from "ng2-charts";
import { Router} from "@angular/router";
import {FictitiousAdvertsService} from "../../utils/services/fictitiousDatas/fictitiousAdverts/fictitious-adverts.service";
import {FictitiousVideosService} from "../../utils/services/fictitiousDatas/fictitiousVideos/fictitious-videos.service";
import {ThemeService} from "../../utils/services/theme/theme.service";
import {MessageService} from "../../utils/services/message/message.service";
import {HttpParams} from "@angular/common/http";
interface CoupleNameViews {
name: string,
views: Date[],
}
@Component({
selector: 'app-subjects-popularity',
templateUrl: './pages-popularity.component.html',
styleUrls: ['./pages-popularity.component.scss']
})
export class PagesPopularityComponent implements OnInit
{
formControl: FormControl = new FormControl();
allCoupleNameViews: CoupleNameViews[] = [];
allInterests: string[] = [];
startDate: Date = null;
endDate: Date = null;
step: number = 1;
stepUnity: string = "jour" ;
oneDay: number = 24*60*60*1000;
oneWeek: number = 7*24*60*60*1000;
lineChartData: ChartDataSets[] = [];
lineChartLabels: Label[] = [];
chartOptions: any = {
responsive: true,
scales: {
yAxes: [{ display: true, scaleLabel: { display: true, labelString: "vues" } }],
xAxes: [{ scaleLabel: { display: true, labelString: "temps" } }],
}
};
isDisplayable: boolean = false;
constructor( private router: Router,
public themeService: ThemeService,
private fictitiousAdvertsService: FictitiousAdvertsService,
private fictitiousVideosService: FictitiousVideosService,
private messageService: MessageService ) {}
// -----------------------------------------------------------------------------------------------------
ngOnInit(): void
{
// Sera excuté si on est sur la page 'adsPopularity'
// Remplie l'attribut 'allCoupleNameViews'
if(this.router.url.includes("ads"))
{
let params = new HttpParams();
params = params.append("isActive", true);
this.messageService
.get("ad/findAll", params )
.subscribe(ret => this.afterReceivingAds(ret), err => this.afterReceivingAds(err));
}
// Sera excuté si on est sur la page 'subjectsPopularity'
// Remplie l'attribut 'allCoupleNameViews'
else if(this.router.url.includes("subjects"))
{
this.messageService
.get("misc/getInterests")
.subscribe( retour => {
if(retour.status !== "success") {
console.log(retour);
}
else {
this.allInterests = retour.data.map(x => x.interest);
this.allInterests.sort();
this.messageService
.get("video/findAll")
.subscribe(ret => this.afterReceivingVideos(ret), err => this.afterReceivingVideos(err));
}
});
}
}
// Callback: Sera excuté si on est sur la page 'adsPopularity'
afterReceivingAds(retour: any): void
{
if(retour.status !== "success") {
console.log(retour);
}
else {
const allAdverts = retour.data;
for(let advert of allAdverts)
{
let couple = {name: advert.title, views: advert.views }
this.allCoupleNameViews.push(couple);
}
this.formControl = new FormControl(this.allCoupleNameViews);
this.onApplyFilter();
}
}
// Callback: Sera excuté si on est sur la page 'subjectsPopularity'
afterReceivingVideos(retour: any): void
{
if(retour.status !== "success") {
console.log(retour);
}
else {
const allVideos = retour.data;
let myMap: Map<string,Date[]> = new Map();
// parcours des interest de chaque video
for(let video of allVideos)
{
const key = video.interest;
if(!myMap.has(key)) myMap.set(key, video.watchedDates);
else {
let tabDate = myMap.get(key);
for(let date0 of video.watchedDates) tabDate = this.insertInOrder(tabDate, date0);
myMap.set(key, tabDate);
}
}
// parcours les interest qui n'ont pas p été vu dans les videos
for(let interest of this.allInterests)
{
if(!myMap.has(interest)) myMap.set(interest, []);
}
// parcours de la map pour remplir 'allCoupleNameViews'
for(const [key, value] of myMap.entries())
{
let couple = {name: key, views: value }
this.allCoupleNameViews.push(couple);
}
this.formControl = new FormControl(this.allCoupleNameViews);
this.onApplyFilter();
}
}
// -----------------------------------------------------------------------------------------------------
// Applique le filtre
onApplyFilter(): void
{
// --- initialisation ---
this.lineChartData = [];
this.lineChartLabels = [];
if(this.step <= 0) this.step = 0;
if((this.endDate === null) || (this.endDate === undefined)) this.endDate = new Date();
if((this.startDate === null) || (this.startDate === undefined)) this.startDate = new Date(this.endDate.getTime() - this.oneWeek); // date d'il y a une semaine
const startTime = this.startDate.getTime();
const endTime = this.endDate.getTime();
// --- remplissage de 'lineChartLabels' ---
let dataWithZeros = [];
let time = startTime;
const intervals = [];
while(time <= endTime)
{
dataWithZeros.push(0);
this.lineChartLabels.push(this.getLabel(new Date(time)));
intervals.push(time);
time = this.addStep(time);
}
intervals.push(time);
// --- remplissage de 'lineChartLabels' ---
for(let coupleNameViews of this.formControl.value)
{
let data = dataWithZeros.slice();
let label = coupleNameViews.name;
let index = 0;
for(let date0 of coupleNameViews.views)
{
const time0 = (new Date(date0)).getTime();
if(time0 > endTime) break;
if((startTime <= time0) && (time0 <= endTime))
{
while((index < intervals.length) && (time0 >= intervals[index])) index += 1;
index = index - 1;
data[index] += 1;
}
}
this.lineChartData.push({"data": data.slice(), "label": label});
}
this.isDisplayable = true;
}
onNewStartDate(event): void {
this.startDate = new Date(event);
}
onNewEndDate(event): void {
this.endDate = new Date(event);
}
// Renvoie le bon label pour le graph
getLabel(date0: Date): string
{
if((this.stepUnity === 'jour') && (this.step === 1))
{
return date0.toLocaleDateString();
}
else {
const time2 = this.addStep((new Date(date0)).getTime()) - this.oneDay;
let date2 = new Date(time2);
return date0.toLocaleDateString() + " à " + date2.toLocaleDateString();
}
}
// Ajoute le bon pas à la date 'new Date(time)'
addStep(time: number): number
{
let newDate;
if(this.stepUnity === 'jour') {
newDate = new Date(time + this.step*this.oneDay);
}
else if(this.stepUnity === 'semaine') {
newDate = new Date(time + this.step*this.oneWeek);
}
else
{
const oldDate = new Date(time);
let newMonth = oldDate.getMonth() + this.step;
const newYear = oldDate.getFullYear() + (newMonth / 12);
newMonth = newMonth % 12;
const day = this.startDate.getDate();
if((newMonth === 1) && ([29, 30, 31].includes(day))) { // si fevrier et si jour n'existe pas
newDate = new Date(newYear, newMonth, 28);
}
else if((day === 31) && ([3, 5, 9, 10].includes(newMonth))) { // si 31 et mois à 30 jours
newDate = new Date(newYear, newMonth, 30);
}
else {
newDate = new Date(newYear, newMonth, day);
}
}
const _1h = 60*60*1000;
if(newDate.getHours() === 23) return newDate.getTime() + _1h;
else if(newDate.getHours() === 1) return newDate.getTime() - _1h;
else return newDate.getTime();
}
// Insere la date0 dans le tableau tabDate par ordre croissant
insertInOrder(tabDate: Date[], date0: Date): Date[]
{
let i = 0;
let n = tabDate.length;
let time0 = (new Date(date0)).getTime();
while((i <n) && (time0 > (new Date(tabDate[i])).getTime())) i++;
if(i === n) tabDate.push(date0);
else tabDate.splice(i, 0, date0);
return tabDate;
}
onSelectAll(): void
{
this.formControl = new FormControl(this.allCoupleNameViews);
}
onDeSelectAll(): void
{
this.formControl = new FormControl([]);
}
}

View file

@ -1,8 +0,0 @@
import { DragAndDropDirective } from './drag-and-drop.directive';
describe('DragAndDropDirective', () => {
it('should create an instance', () => {
const directive = new DragAndDropDirective();
expect(directive).toBeTruthy();
});
});

View file

@ -1,36 +0,0 @@
import {Directive, EventEmitter, HostBinding, HostListener, Output} from '@angular/core';
@Directive({
selector: '[appDragAndDrop]'
})
export class DragAndDropDirective
{
@HostBinding('class.fileover') fileOver: boolean;
@Output() fileDropped = new EventEmitter<any>();
// Dragover listener
@HostListener('dragover', ['$event']) onDragOver(evt) {
evt.preventDefault();
evt.stopPropagation();
this.fileOver = true;
}
// Dragleave listener
@HostListener('dragleave', ['$event']) public onDragLeave(evt) {
evt.preventDefault();
evt.stopPropagation();
this.fileOver = false;
}
// Drop listener
@HostListener('drop', ['$event']) public ondrop(evt) {
evt.preventDefault();
evt.stopPropagation();
this.fileOver = false;
let files = evt.dataTransfer.files;
if (files.length > 0) {
this.fileDropped.emit(files);
}
}
}

View file

@ -1,41 +0,0 @@
<nav class="navbar navbar-expand-lg">
<!-- PolyNotFound -->
<a class="navbar-brand" routerLink="/url/adList"> StreamNotFound </a>
<button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarNavDropdown" aria-controls="navbarNavDropdown" aria-expanded="false" aria-label="Toggle navigation">
<span class="navbar-toggler-icon"></span>
</button>
<!-- [adList] [adsPopularity] [subjectsPopularity] -->
<div class="collapse navbar-collapse">
<ul class="navbar-nav">
<li class="nav-item active monLi">
<a *ngIf="(url !== routes[0]) && (url !== routes[1])" [routerLink]="routes[1]" class="nav-link">Gestion des annonces</a>
<a *ngIf="(url === routes[0]) || (url === routes[1])" [routerLink]="routes[1]" class="nav-link myActiveLink">Gestion des annonces</a>
</li>
<li class="nav-item active monLi">
<a *ngIf="url !== routes[2]" [routerLink]="routes[2]" class="nav-link">Popularité des annonces</a>
<a *ngIf="url === routes[2]" [routerLink]="routes[2]" class="nav-link myActiveLink">Popularité des annonces</a>
</li>
<li class="nav-item active monLi">
<a *ngIf="url !== routes[3]" [routerLink]="routes[3]" class="nav-link">Popularité des domaines</a>
<a *ngIf="url === routes[3]" [routerLink]="routes[3]" class="nav-link myActiveLink">Popularité des domaines</a>
</li>
</ul>
</div>
<!-- Mon profil -->
<img [src]=profilService.getProfileImageUrl()
onerror="this.onerror=null; this.src='assets/profil.png'"
[routerLink]="routes[4]"
alt="">
<!-- Deconnexion -->
<button mat-button class="btnDeconnexion" (click)="onDeconnexion()" routerLink="/">
Déconnexion
</button>
</nav>

View file

@ -1,80 +0,0 @@
.navbar {
background-color: black;
height: 60px;
font-size: medium;
color: white;
}
.navbar-expand-lg {
border-bottom: solid;
border-color: white;
border-bottom-width: 2px;
}
// PolyNotFound
.navbar-brand {
font-family: cursive;
font-weight: bold;
font-size: x-large;
margin-left: 15px;
color: white;
}
.monLi {
margin: 0px 10px 0px 10px;
}
.nav-link {
color: white;
}
.nav-link:hover {
color: grey;
}
.myActiveLink {
text-decoration: underline;
}
.btnDeconnexion {
font-size: medium;
margin: 0px 10px 0px 10px
}
.btnDeconnexion:hover {
color: grey;
}
img {
border: solid 2px white;
border-radius: 50px;
margin: 0px 10px 0px 15px;
width: 40px;
height: 40px;
}
img:hover {
cursor: pointer;
}
// --------------------------------------------------------------------
::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;
}

View file

@ -1,25 +0,0 @@
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { NavbarAdvertiserComponent } from './navbar-advertiser.component';
describe('NavbarAdvertiserComponent', () => {
let component: NavbarAdvertiserComponent;
let fixture: ComponentFixture<NavbarAdvertiserComponent>;
beforeEach(async () => {
await TestBed.configureTestingModule({
declarations: [ NavbarAdvertiserComponent ]
})
.compileComponents();
});
beforeEach(() => {
fixture = TestBed.createComponent(NavbarAdvertiserComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});

View file

@ -1,41 +0,0 @@
import { Component } from '@angular/core';
import {Router} from "@angular/router";
import {ProfilService} from "../../../utils/services/profil/profil.service";
import {MessageService} from "../../../utils/services/message/message.service";
@Component({
selector: 'app-navbar-advertiser',
templateUrl: './navbar-advertiser.component.html',
styleUrls: ['./navbar-advertiser.component.scss']
})
export class NavbarAdvertiserComponent
{
routes: string[] = [
"/advertiser", // 0
"/advertiser/adList", // 1
"/advertiser/adsPopularity", // 2
"/advertiser/subjectsPopularity", // 3
"/advertiser/myProfil" // 4
];
url = this.router.url;
constructor( private router: Router,
public profilService: ProfilService,
private messageService: MessageService ) { }
onDeconnexion(): void
{
this.messageService
.delete('user/logout')
.subscribe(retour => this.onDeconnexionCallback(retour), err => this.onDeconnexionCallback(err));
}
onDeconnexionCallback(retour: any): void
{
if(retour.status !== "success") console.log(retour);
}
}

View file

@ -1,19 +1,11 @@
import { NgModule } from '@angular/core';
import { RouterModule, Routes } from '@angular/router';
import {PageLoginComponent} from './beforeConnexion/login/page-login/page-login.component';
import {PageLoginComponent} from "./beforeConnexion/login/page-login/page-login.component";
import {PageRegisterComponent} from "./beforeConnexion/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";
import {PageHistoryUserComponent} from "./user/history/page-history-user/page-history-user.component";
import {PageAdListAdvertiserComponent} from "./advertiser/adList/page-ad-list-advertiser/page-ad-list-advertiser.component";
import {PageProfilUserComponent} from "./user/myProfil/page-profil-user/page-profil-user.component";
import {PageProfilAdvertiserComponent} from "./advertiser/myProfil/page-profil-advertiser/page-profil-advertiser.component";
import {PageProfilAdminComponent} from "./admin/myProfil/page-profil-admin/page-profil-admin.component";
import {PageAdListAdminComponent} from "./admin/adList/page-ad-list-admin/page-ad-list-admin.component";
import {PageProfilAdminComponent} from "./admin/myProfil/page-profil-admin/page-profil-admin.component";
import {PageUserListComponent} from "./admin/userList/page-user-list/page-user-list.component";
import {PageWatchingVideoComponent} from "./user/watching/page-watching-video/page-watching-video.component";
import {PagesPopularityComponent} from "./advertiser/pages-popularity/pages-popularity.component";
import {MyGuardGuard} from "./utils/my-guard/my-guard.guard";
const routes: Routes = [
@ -22,30 +14,13 @@ const routes: Routes = [
{ path: 'login', component: PageLoginComponent },
{ path: 'register', component: PageRegisterComponent },
// User
{ path: 'user', component: PageSearchComponent },
{ path: 'user/search', component: PageSearchComponent },
{ path: 'user/myPlaylists', component: PageMyPlaylistsComponent },
{ path: 'user/history', component: PageHistoryUserComponent },
{ path: 'user/myProfil', component: PageProfilUserComponent },
{ path: 'user/watching', component: PageWatchingVideoComponent },
// Advertiser
{ path: 'advertiser', component: PageAdListAdvertiserComponent },
{ path: 'advertiser/adList', component: PageAdListAdvertiserComponent },
{ path: 'advertiser/myProfil', component: PageProfilAdvertiserComponent },
{ path: 'advertiser/adsPopularity', component: PagesPopularityComponent },
{ path: 'advertiser/subjectsPopularity', component: PagesPopularityComponent },
// Admin
{ path: 'admin', component: PageUserListComponent },
{ path: 'admin/userList', component: PageUserListComponent },
{ path: 'admin/adList', component: PageAdListAdminComponent },
{ path: 'admin/myProfil', component: PageProfilAdminComponent },
{ path: 'admin', component: PageUserListComponent, canActivate: [MyGuardGuard] },
{ path: 'admin/userList', component: PageUserListComponent, canActivate: [MyGuardGuard] },
{ path: 'admin/adList', component: PageAdListAdminComponent, canActivate: [MyGuardGuard] },
{ path: 'admin/myProfil', component: PageProfilAdminComponent, canActivate: [MyGuardGuard] },
];
@NgModule({
imports: [RouterModule.forRoot(routes)],
exports: [RouterModule]

View file

@ -1 +1,2 @@
<link href="https://fonts.googleapis.com/icon?family=Material+Icons" rel="stylesheet">
<router-outlet></router-outlet>

View file

@ -20,16 +20,16 @@ describe('AppComponent', () => {
expect(app).toBeTruthy();
});
it(`should have as title 'frontend'`, () => {
it(`should have as title 'admin'`, () => {
const fixture = TestBed.createComponent(AppComponent);
const app = fixture.componentInstance;
expect(app.title).toEqual('frontend');
expect(app.title).toEqual('admin');
});
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!');
const compiled = fixture.nativeElement as HTMLElement;
expect(compiled.querySelector('.content span')?.textContent).toContain('admin app is running!');
});
});

View file

@ -6,7 +6,5 @@ import { Component } from '@angular/core';
styleUrls: ['./app.component.scss']
})
export class AppComponent {
title = 'frontend';
themeIsLight = true;
title = 'admin';
}

View file

@ -4,154 +4,92 @@ import { BrowserModule } from '@angular/platform-browser';
import { AppRoutingModule } from './app-routing.module';
import { AppComponent } from './app.component';
import { PageLoginComponent } from './beforeConnexion/login/page-login/page-login.component';
import { PageRegisterComponent } from './beforeConnexion/register/page-register/page-register.component';
import {BrowserAnimationsModule} from '@angular/platform-browser/animations';
import {MatSlideToggleModule} from '@angular/material/slide-toggle';
import {FormsModule, ReactiveFormsModule} from "@angular/forms";
import { PageSearchComponent } from './user/search/page-search/page-search.component';
import { PopupForgottenPasswordComponent } from './beforeConnexion/login/popup-forgotten-password/popup-forgotten-password.component';
import {BrowserAnimationsModule} from "@angular/platform-browser/animations";
import {HttpClientModule} from "@angular/common/http";
import { PopupConfirmationComponent } from './beforeConnexion/register/popup-confirmation/popup-confirmation.component';
import {MatDialogModule} from '@angular/material/dialog';
import {MatButtonModule} from "@angular/material/button";
import { AdvertComponent } from './user/utils/components/advert/advert.component';
import { VideoGridComponent } from './user/search/video-grid/video-grid.component';
import {MatIconModule} from "@angular/material/icon";
import { PopupAddVideoToPlaylistsComponent } from './user/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 {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 { PopupCreateOrUpdatePlaylistComponent } from './user/myPlaylists/popup-create-or-update-playlist/popup-create-or-update-playlist.component';
import { PageHistoryUserComponent } from './user/history/page-history-user/page-history-user.component';
import {MatTableModule} from '@angular/material/table';
import { NgbModule } from '@ng-bootstrap/ng-bootstrap';
import {FormsModule, ReactiveFormsModule} from "@angular/forms";
import {MatTableModule} from "@angular/material/table";
import {MatSortModule} from "@angular/material/sort";
import { PageAdListAdvertiserComponent } from './advertiser/adList/page-ad-list-advertiser/page-ad-list-advertiser.component';
import { PopupDeleteAdAdvertiserComponent } from './advertiser/adList/popup-delete-ad-advertiser/popup-delete-ad-advertiser.component';
import { PopupAddOrUpdateAdComponent } from './advertiser/adList/popup-add-or-update-ad/popup-add-or-update-ad.component';
import { PopupVisualizeAdAdvertiserComponent } from './advertiser/adList/popup-visualize-ad-advertiser/popup-visualize-ad-advertiser.component';
import { InputInterestsAdComponent } from './advertiser/adList/input-interests-ad/input-interests-ad.component';
import {MatChipsModule} from "@angular/material/chips";
import {MatAutocompleteModule} from "@angular/material/autocomplete";
import {MatSelectModule} from "@angular/material/select";
import { PopupVisualizeImagesAdvertiserComponent } from './advertiser/adList/popup-visualize-images-advertiser/popup-visualize-images-advertiser.component';
import {IvyCarouselModule} from "angular-responsive-carousel";
import { DragAndDropComponent } from './advertiser/adList/drag-and-drop/drag-and-drop.component';
import { DragAndDropDirective } from './advertiser/utils/dragAndDrop/drag-and-drop.directive';
import { PageProfilUserComponent } from './user/myProfil/page-profil-user/page-profil-user.component';
import { NavbarUserComponent } from './user/utils/components/navbar-user/navbar-user.component';
import { NavbarAdvertiserComponent } from './advertiser/utils/navbar-advertiser/navbar-advertiser.component';
import { NavbarAdminComponent } from './admin/utils/navbar-admin/navbar-admin.component';
import { PageProfilAdvertiserComponent } from './advertiser/myProfil/page-profil-advertiser/page-profil-advertiser.component';
import { PopupUpdateAdvertiserComponent } from './advertiser/myProfil/popup-update-advertiser/popup-update-advertiser.component';
import { PopupUpdateUserComponent } from './user/myProfil/popup-update-user/popup-update-user.component';
import { NavbarBeforeConnexionComponent } from './beforeConnexion/utils/navbar-before-connexion/navbar-before-connexion.component';
import {MatRadioModule} from "@angular/material/radio";
import { InputInterestsProfilComponent } from './user/myProfil/input-interests-profil/input-interests-profil.component';
import {MatDialogModule} from "@angular/material/dialog";
import {MatSnackBarModule} from "@angular/material/snack-bar";
import {MatButtonModule} from "@angular/material/button";
import {MatCheckboxModule} from "@angular/material/checkbox";
import { PageRegisterComponent } from './beforeConnexion/register/page-register/page-register.component';
import { PopupConfirmationComponent } from './beforeConnexion/register/popup-confirmation/popup-confirmation.component';
import { InputInterestsRegisterComponent } from './beforeConnexion/register/input-interests-register/input-interests-register.component';
import {MatFormFieldModule} from "@angular/material/form-field";
import {MatChipsModule} from "@angular/material/chips";
import {MatIconModule} from "@angular/material/icon";
import {MatAutocompleteModule} from "@angular/material/autocomplete";
import {MatStepperModule} from "@angular/material/stepper";
import { NavbarBeforeConnexionComponent } from './beforeConnexion/utils/navbar-before-connexion/navbar-before-connexion.component';
import { PageProfilAdminComponent } from './admin/myProfil/page-profil-admin/page-profil-admin.component';
import { PopupUpdateAdminComponent } from './admin/myProfil/popup-update-admin/popup-update-admin.component';
import {MatStepperModule} from "@angular/material/stepper";
import { InputInterestsRegisterComponent } from './beforeConnexion/register/input-interests-register/input-interests-register.component';
import {MatPaginatorModule} from "@angular/material/paginator";
import { PageAdListAdminComponent } from './admin/adList/page-ad-list-admin/page-ad-list-admin.component';
import { PopupDeleteAdAdminComponent } from './admin/adList/popup-delete-ad-admin/popup-delete-ad-admin.component';
import { PopupVisualizeImagesAdminComponent } from './admin/adList/popup-visualize-images-admin/popup-visualize-images-admin.component';
import {MatDividerModule} from "@angular/material/divider";
import {MatSelectModule} from "@angular/material/select";
import {MatPaginatorModule} from "@angular/material/paginator";
import {MatGridListModule} from "@angular/material/grid-list";
import { PageUserListComponent } from './admin/userList/page-user-list/page-user-list.component';
import { PopupDeleteUserComponent } from './admin/userList/popup-delete-user/popup-delete-user.component';
import { PopupCreateUserComponent } from './admin/userList/popup-create-user/popup-create-user.component';
import { InputInterestsAdminComponent } from './admin/userList/input-interests-admin/input-interests-admin.component';
import { PageWatchingVideoComponent } from './user/watching/page-watching-video/page-watching-video.component';
import { PopupCreateUserComponent } from './admin/userList/popup-create-user/popup-create-user.component';
import {MatSlideToggleModule} from "@angular/material/slide-toggle";
import { NavbarAdminComponent } from './admin/utils/navbar-admin/navbar-admin.component';
import {MatInputModule} from "@angular/material/input";
import {MatDatepickerModule} from "@angular/material/datepicker";
import { PagesPopularityComponent } from './advertiser/pages-popularity/pages-popularity.component';
import { ChartsModule } from 'ng2-charts';
import { PopupDeletePlaylistComponent } from './user/myPlaylists/popup-delete-playlist/popup-delete-playlist.component';
import { PopupForgottenPasswordComponent } from './beforeConnexion/login/popup-forgotten-password/popup-forgotten-password.component';
import {MAT_DATE_LOCALE, MatNativeDateModule} from "@angular/material/core";
@NgModule({
declarations: [
AppComponent,
PageLoginComponent,
PageRegisterComponent,
PageSearchComponent,
PopupConfirmationComponent,
AdvertComponent,
VideoGridComponent,
PopupAddVideoToPlaylistsComponent,
PageMyPlaylistsComponent,
VideoListComponent,
PlaylistListComponent,
VideoListComponent,
PopupCreateOrUpdatePlaylistComponent,
PageHistoryUserComponent,
PageAdListAdvertiserComponent,
PopupDeleteAdAdvertiserComponent,
PopupAddOrUpdateAdComponent,
PopupVisualizeAdAdvertiserComponent,
InputInterestsAdComponent,
PopupVisualizeImagesAdvertiserComponent,
DragAndDropComponent,
DragAndDropDirective,
PageProfilUserComponent,
NavbarUserComponent,
NavbarAdvertiserComponent,
NavbarAdminComponent,
PageProfilAdvertiserComponent,
PopupUpdateAdvertiserComponent,
PopupUpdateUserComponent,
NavbarBeforeConnexionComponent,
InputInterestsProfilComponent,
PageProfilAdminComponent,
PopupUpdateAdminComponent,
InputInterestsRegisterComponent,
PageAdListAdminComponent,
PopupDeleteAdAdminComponent,
PopupVisualizeImagesAdminComponent,
PageUserListComponent,
PopupDeleteUserComponent,
PopupCreateUserComponent,
InputInterestsAdminComponent,
PageWatchingVideoComponent,
PagesPopularityComponent,
PopupDeletePlaylistComponent,
PopupForgottenPasswordComponent,
],
declarations: [
AppComponent,
PageLoginComponent,
PopupForgottenPasswordComponent,
PageRegisterComponent,
PopupConfirmationComponent,
InputInterestsRegisterComponent,
NavbarBeforeConnexionComponent,
PageProfilAdminComponent,
PopupUpdateAdminComponent,
PageAdListAdminComponent,
PopupDeleteAdAdminComponent,
PopupVisualizeImagesAdminComponent,
PageUserListComponent,
InputInterestsAdminComponent,
PopupCreateUserComponent,
NavbarAdminComponent
],
imports: [
BrowserModule,
AppRoutingModule,
BrowserAnimationsModule,
MatSlideToggleModule,
MatTableModule,
MatSortModule,
MatRadioModule,
FormsModule,
HttpClientModule,
MatDialogModule,
MatButtonModule,
MatIconModule,
MatInputModule,
MatDividerModule,
MatCheckboxModule,
MatFormFieldModule,
MatSnackBarModule,
MatGridListModule,
MatTableModule,
NgbModule,
MatSortModule,
MatFormFieldModule,
MatInputModule,
MatChipsModule,
ReactiveFormsModule,
MatIconModule,
MatAutocompleteModule,
MatSelectModule,
IvyCarouselModule,
MatRadioModule,
ReactiveFormsModule,
MatStepperModule,
MatDividerModule,
MatSelectModule,
MatPaginatorModule,
MatGridListModule,
MatSlideToggleModule,
MatDatepickerModule,
ChartsModule
MatNativeDateModule,
],
providers: [],
providers: [{ provide: MAT_DATE_LOCALE, useValue: 'en-GB' }],
bootstrap: [AppComponent]
})
export class AppModule { }

Some files were not shown because too many files have changed in this diff Show more