From 76ac0c292c44eb70ebfa5e54234e5b1c9790eef8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Y=C3=BBki=20VACHOT?= Date: Wed, 22 Dec 2021 11:09:20 +0100 Subject: [PATCH 01/35] Create: Backend branch --- .browserslistrc | 17 - .editorconfig | 16 - Dockerfile | 6 - angular.json | 134 -------- .../config => config}/functions.config.js | 0 {app-backend/config => config}/host.config.js | 0 .../config => config}/mongodb.config.js | 0 .../config => config}/response.config.js | 0 .../config => config}/sessionJWT.config.js | 0 .../ad.controller.js | 0 .../misc.controller.js | 0 .../playlist.controller.js | 0 .../user.controller.js | 0 .../video.controller.js | 5 +- docker-compose.yml | 41 --- e2e/protractor.conf.js | 37 --- e2e/src/app.e2e-spec.ts | 23 -- e2e/src/app.po.ts | 11 - e2e/tsconfig.json | 13 - .../jwtRS256.key.pub => jwtRS256.key.pub | 0 app-backend/jwtRS256.sh => jwtRS256.sh | 0 karma.conf.js | 44 --- .../models => models}/database/ads.model.js | 0 .../database/playlists.model.js | 0 .../models => models}/database/users.model.js | 0 .../database/videos.model.js | 0 .../models => models}/mongodb.model.js | 0 .../models => models}/objects/image.model.js | 0 .../models => models}/objects/role.model.js | 0 .../objects/video.categories.model.js | 0 package.json | 67 ---- {app-backend/routes => routes}/ad.routes.js | 0 {app-backend/routes => routes}/misc.routes.js | 0 .../routes => routes}/playlist.routes.js | 0 {app-backend/routes => routes}/user.routes.js | 0 .../routes => routes}/video.routes.js | 0 server.js | 19 +- .../page-ad-list-admin.component.html | 167 ---------- .../page-ad-list-admin.component.scss | 74 ----- .../page-ad-list-admin.component.spec.ts | 25 -- .../page-ad-list-admin.component.ts | 262 --------------- .../popup-delete-ad-admin.component.html | 8 - .../popup-delete-ad-admin.component.scss | 0 .../popup-delete-ad-admin.component.spec.ts | 25 -- .../popup-delete-ad-admin.component.ts | 49 --- ...opup-visualize-images-admin.component.html | 20 -- ...opup-visualize-images-admin.component.scss | 14 - ...p-visualize-images-admin.component.spec.ts | 25 -- .../popup-visualize-images-admin.component.ts | 38 --- .../page-profil-admin.component.html | 43 --- .../page-profil-admin.component.scss | 61 ---- .../page-profil-admin.component.spec.ts | 25 -- .../page-profil-admin.component.ts | 90 ----- .../popup-update-admin.component.html | 59 ---- .../popup-update-admin.component.scss | 33 -- .../popup-update-admin.component.spec.ts | 25 -- .../popup-update-admin.component.ts | 124 ------- .../input-interests-admin.component.html | 43 --- .../input-interests-admin.component.scss | 3 - .../input-interests-admin.component.spec.ts | 25 -- .../input-interests-admin.component.ts | 121 ------- .../page-user-list.component.html | 193 ----------- .../page-user-list.component.scss | 99 ------ .../page-user-list.component.spec.ts | 25 -- .../page-user-list.component.ts | 233 ------------- .../popup-create-user.component.html | 160 --------- .../popup-create-user.component.scss | 16 - .../popup-create-user.component.spec.ts | 25 -- .../popup-create-user.component.ts | 127 ------- .../popup-delete-user.component.html | 8 - .../popup-delete-user.component.scss | 0 .../popup-delete-user.component.spec.ts | 25 -- .../popup-delete-user.component.ts | 47 --- .../navbar-admin/navbar-admin.component.html | 37 --- .../navbar-admin/navbar-admin.component.scss | 80 ----- .../navbar-admin.component.spec.ts | 25 -- .../navbar-admin/navbar-admin.component.ts | 40 --- .../drag-and-drop.component.html | 33 -- .../drag-and-drop.component.scss | 135 -------- .../drag-and-drop.component.spec.ts | 25 -- .../drag-and-drop/drag-and-drop.component.ts | 93 ------ .../input-interests-ad.component.html | 43 --- .../input-interests-ad.component.scss | 16 - .../input-interests-ad.component.spec.ts | 25 -- .../input-interests-ad.component.ts | 121 ------- .../page-ad-list-advertiser.component.html | 185 ----------- .../page-ad-list-advertiser.component.scss | 87 ----- .../page-ad-list-advertiser.component.spec.ts | 25 -- .../page-ad-list-advertiser.component.ts | 309 ------------------ .../popup-add-or-update-ad.component.html | 83 ----- .../popup-add-or-update-ad.component.scss | 90 ----- .../popup-add-or-update-ad.component.spec.ts | 25 -- .../popup-add-or-update-ad.component.ts | 221 ------------- .../popup-delete-ad-advertiser.component.html | 8 - .../popup-delete-ad-advertiser.component.scss | 0 ...pup-delete-ad-advertiser.component.spec.ts | 25 -- .../popup-delete-ad-advertiser.component.ts | 47 --- ...pup-visualize-ad-advertiser.component.html | 71 ---- ...pup-visualize-ad-advertiser.component.scss | 28 -- ...-visualize-ad-advertiser.component.spec.ts | 25 -- ...popup-visualize-ad-advertiser.component.ts | 27 -- ...visualize-images-advertiser.component.html | 20 -- ...visualize-images-advertiser.component.scss | 14 - ...ualize-images-advertiser.component.spec.ts | 25 -- ...p-visualize-images-advertiser.component.ts | 38 --- .../page-profil-advertiser.component.html | 49 --- .../page-profil-advertiser.component.scss | 61 ---- .../page-profil-advertiser.component.spec.ts | 25 -- .../page-profil-advertiser.component.ts | 90 ----- .../popup-update-advertiser.component.html | 65 ---- .../popup-update-advertiser.component.scss | 33 -- .../popup-update-advertiser.component.spec.ts | 25 -- .../popup-update-advertiser.component.ts | 125 ------- .../pages-popularity.component.html | 94 ------ .../pages-popularity.component.scss | 53 --- .../pages-popularity.component.spec.ts | 25 -- .../pages-popularity.component.ts | 308 ----------------- .../drag-and-drop.directive.spec.ts | 8 - .../dragAndDrop/drag-and-drop.directive.ts | 36 -- .../navbar-advertiser.component.html | 41 --- .../navbar-advertiser.component.scss | 80 ----- .../navbar-advertiser.component.spec.ts | 25 -- .../navbar-advertiser.component.ts | 41 --- src/app/app-routing.module.ts | 53 --- src/app/app.component.html | 1 - src/app/app.component.scss | 24 -- src/app/app.component.spec.ts | 35 -- src/app/app.component.ts | 12 - src/app/app.module.ts | 157 --------- .../page-login/page-login.component.html | 36 -- .../page-login/page-login.component.scss | 271 --------------- .../page-login/page-login.component.spec.ts | 25 -- .../login/page-login/page-login.component.ts | 101 ------ .../popup-forgotten-password.component.html | 24 -- .../popup-forgotten-password.component.scss | 12 - ...popup-forgotten-password.component.spec.ts | 25 -- .../popup-forgotten-password.component.ts | 47 --- .../input-interests-register.component.html | 43 --- .../input-interests-register.component.scss | 3 - ...input-interests-register.component.spec.ts | 25 -- .../input-interests-register.component.ts | 121 ------- .../page-register.component.html | 161 --------- .../page-register.component.scss | 47 --- .../page-register.component.spec.ts | 25 -- .../page-register/page-register.component.ts | 135 -------- .../popup-confirmation.component.html | 11 - .../popup-confirmation.component.scss | 7 - .../popup-confirmation.component.spec.ts | 25 -- .../popup-confirmation.component.ts | 15 - .../navbar-before-connexion.component.html | 40 --- .../navbar-before-connexion.component.scss | 79 ----- .../navbar-before-connexion.component.spec.ts | 25 -- .../navbar-before-connexion.component.ts | 12 - .../page-history-user.component.html | 70 ---- .../page-history-user.component.scss | 46 --- .../page-history-user.component.spec.ts | 25 -- .../page-history-user.component.ts | 116 ------- .../page-my-playlists.component.html | 35 -- .../page-my-playlists.component.scss | 48 --- .../page-my-playlists.component.spec.ts | 25 -- .../page-my-playlists.component.ts | 69 ---- .../playlist-list.component.html | 48 --- .../playlist-list.component.scss | 94 ------ .../playlist-list.component.spec.ts | 25 -- .../playlist-list/playlist-list.component.ts | 164 ---------- ...p-create-or-update-playlist.component.html | 19 -- ...p-create-or-update-playlist.component.scss | 0 ...reate-or-update-playlist.component.spec.ts | 25 -- ...pup-create-or-update-playlist.component.ts | 92 ------ .../popup-delete-playlist.component.html | 8 - .../popup-delete-playlist.component.scss | 0 .../popup-delete-playlist.component.spec.ts | 25 -- .../popup-delete-playlist.component.ts | 41 --- .../video-list/video-list.component.html | 91 ------ .../video-list/video-list.component.scss | 83 ----- .../video-list/video-list.component.spec.ts | 25 -- .../video-list/video-list.component.ts | 92 ------ .../input-interests-profil.component.html | 39 --- .../input-interests-profil.component.scss | 20 -- .../input-interests-profil.component.spec.ts | 25 -- .../input-interests-profil.component.ts | 121 ------- .../page-profil-user.component.html | 92 ------ .../page-profil-user.component.scss | 80 ----- .../page-profil-user.component.spec.ts | 25 -- .../page-profil-user.component.ts | 90 ----- .../popup-update-user.component.html | 125 ------- .../popup-update-user.component.scss | 81 ----- .../popup-update-user.component.spec.ts | 25 -- .../popup-update-user.component.ts | 133 -------- .../page-search/page-search.component.html | 80 ----- .../page-search/page-search.component.scss | 90 ----- .../page-search/page-search.component.spec.ts | 25 -- .../page-search/page-search.component.ts | 119 ------- .../video-grid/video-grid.component.html | 76 ----- .../video-grid/video-grid.component.scss | 84 ----- .../video-grid/video-grid.component.spec.ts | 25 -- .../search/video-grid/video-grid.component.ts | 129 -------- .../components/advert/advert.component.html | 26 -- .../components/advert/advert.component.scss | 41 --- .../advert/advert.component.spec.ts | 25 -- .../components/advert/advert.component.ts | 40 --- .../navbar-user/navbar-user.component.html | 41 --- .../navbar-user/navbar-user.component.scss | 80 ----- .../navbar-user/navbar-user.component.spec.ts | 25 -- .../navbar-user/navbar-user.component.ts | 41 --- ...opup-add-video-to-playlists.component.html | 42 --- ...opup-add-video-to-playlists.component.scss | 39 --- ...p-add-video-to-playlists.component.spec.ts | 25 -- .../popup-add-video-to-playlists.component.ts | 141 -------- .../add-video-to-playlists.service.spec.ts | 16 - .../add-video-to-playlists.service.ts | 102 ------ .../page-watching-video.component.html | 233 ------------- .../page-watching-video.component.scss | 159 --------- .../page-watching-video.component.spec.ts | 25 -- .../page-watching-video.component.ts | 264 --------------- src/app/utils/interfaces/advert.ts | 39 --- src/app/utils/interfaces/playlist.ts | 10 - src/app/utils/interfaces/user.ts | 33 -- src/app/utils/interfaces/video.ts | 32 -- .../fictitious-adverts.service.spec.ts | 16 - .../fictitious-adverts.service.ts | 130 -------- .../fictitious-users.service.spec.ts | 16 - .../fictitious-users.service.ts | 128 -------- .../fictitious-utils.service.spec.ts | 16 - .../fictitious-utils.service.ts | 33 -- .../fictitious-videos.service.spec.ts | 16 - .../fictitious-videos.service.ts | 289 ---------------- .../services/message/message.service.spec.ts | 16 - .../utils/services/message/message.service.ts | 40 --- .../services/profil/profil.service.spec.ts | 16 - .../utils/services/profil/profil.service.ts | 30 -- .../services/theme/theme.service.spec.ts | 16 - src/app/utils/services/theme/theme.service.ts | 15 - src/assets/.gitkeep | 0 src/assets/darkBackground.webp | Bin 712 -> 0 bytes src/assets/lightBackground.jpg | Bin 5902 -> 0 bytes src/assets/logo.png | Bin 5798 -> 0 bytes src/assets/logo_plateforms/dailymotion.png | Bin 6478 -> 0 bytes src/assets/logo_plateforms/youtube.png | Bin 7858 -> 0 bytes src/assets/play.png | Bin 3586 -> 0 bytes src/assets/profil.png | Bin 18287 -> 0 bytes src/assets/pub/nutella_v_1.jpeg | Bin 60880 -> 0 bytes src/assets/pub/nutella_v_2.png | Bin 57279 -> 0 bytes src/assets/pub/nutella_v_3.jpg | Bin 36018 -> 0 bytes src/assets/pub/rolex_v_1.jpg | Bin 72794 -> 0 bytes src/assets/pub/rolex_v_2.png | Bin 50514 -> 0 bytes src/assets/uploadFile.png | Bin 8853 -> 0 bytes src/environments/environment.prod.ts | 4 - src/environments/environment.ts | 17 - src/favicon.ico | Bin 948 -> 0 bytes src/index.html | 16 - src/main.ts | 12 - src/polyfills.ts | 65 ---- src/proxy.conf.json | 7 - src/styles.scss | 57 ---- src/test.ts | 25 -- tsconfig.app.json | 15 - tsconfig.json | 23 -- tsconfig.spec.json | 18 - tslint.json | 152 --------- 260 files changed, 10 insertions(+), 12964 deletions(-) delete mode 100644 .browserslistrc delete mode 100644 .editorconfig delete mode 100644 Dockerfile delete mode 100644 angular.json rename {app-backend/config => config}/functions.config.js (100%) rename {app-backend/config => config}/host.config.js (100%) rename {app-backend/config => config}/mongodb.config.js (100%) rename {app-backend/config => config}/response.config.js (100%) rename {app-backend/config => config}/sessionJWT.config.js (100%) rename {app-backend/controllers => controllers}/ad.controller.js (100%) rename {app-backend/controllers => controllers}/misc.controller.js (100%) rename {app-backend/controllers => controllers}/playlist.controller.js (100%) rename {app-backend/controllers => controllers}/user.controller.js (100%) rename {app-backend/controllers => controllers}/video.controller.js (99%) delete mode 100644 docker-compose.yml delete mode 100644 e2e/protractor.conf.js delete mode 100644 e2e/src/app.e2e-spec.ts delete mode 100644 e2e/src/app.po.ts delete mode 100644 e2e/tsconfig.json rename app-backend/jwtRS256.key.pub => jwtRS256.key.pub (100%) rename app-backend/jwtRS256.sh => jwtRS256.sh (100%) mode change 100755 => 100644 delete mode 100644 karma.conf.js rename {app-backend/models => models}/database/ads.model.js (100%) rename {app-backend/models => models}/database/playlists.model.js (100%) rename {app-backend/models => models}/database/users.model.js (100%) rename {app-backend/models => models}/database/videos.model.js (100%) rename {app-backend/models => models}/mongodb.model.js (100%) rename {app-backend/models => models}/objects/image.model.js (100%) rename {app-backend/models => models}/objects/role.model.js (100%) rename {app-backend/models => models}/objects/video.categories.model.js (100%) delete mode 100644 package.json rename {app-backend/routes => routes}/ad.routes.js (100%) rename {app-backend/routes => routes}/misc.routes.js (100%) rename {app-backend/routes => routes}/playlist.routes.js (100%) rename {app-backend/routes => routes}/user.routes.js (100%) rename {app-backend/routes => routes}/video.routes.js (100%) delete mode 100644 src/app/admin/adList/page-ad-list-admin/page-ad-list-admin.component.html delete mode 100644 src/app/admin/adList/page-ad-list-admin/page-ad-list-admin.component.scss delete mode 100644 src/app/admin/adList/page-ad-list-admin/page-ad-list-admin.component.spec.ts delete mode 100644 src/app/admin/adList/page-ad-list-admin/page-ad-list-admin.component.ts delete mode 100644 src/app/admin/adList/popup-delete-ad-admin/popup-delete-ad-admin.component.html delete mode 100644 src/app/admin/adList/popup-delete-ad-admin/popup-delete-ad-admin.component.scss delete mode 100644 src/app/admin/adList/popup-delete-ad-admin/popup-delete-ad-admin.component.spec.ts delete mode 100644 src/app/admin/adList/popup-delete-ad-admin/popup-delete-ad-admin.component.ts delete mode 100644 src/app/admin/adList/popup-visualize-images-admin/popup-visualize-images-admin.component.html delete mode 100644 src/app/admin/adList/popup-visualize-images-admin/popup-visualize-images-admin.component.scss delete mode 100644 src/app/admin/adList/popup-visualize-images-admin/popup-visualize-images-admin.component.spec.ts delete mode 100644 src/app/admin/adList/popup-visualize-images-admin/popup-visualize-images-admin.component.ts delete mode 100644 src/app/admin/myProfil/page-profil-admin/page-profil-admin.component.html delete mode 100644 src/app/admin/myProfil/page-profil-admin/page-profil-admin.component.scss delete mode 100644 src/app/admin/myProfil/page-profil-admin/page-profil-admin.component.spec.ts delete mode 100644 src/app/admin/myProfil/page-profil-admin/page-profil-admin.component.ts delete mode 100644 src/app/admin/myProfil/popup-update-admin/popup-update-admin.component.html delete mode 100644 src/app/admin/myProfil/popup-update-admin/popup-update-admin.component.scss delete mode 100644 src/app/admin/myProfil/popup-update-admin/popup-update-admin.component.spec.ts delete mode 100644 src/app/admin/myProfil/popup-update-admin/popup-update-admin.component.ts delete mode 100644 src/app/admin/userList/input-interests-admin/input-interests-admin.component.html delete mode 100644 src/app/admin/userList/input-interests-admin/input-interests-admin.component.scss delete mode 100644 src/app/admin/userList/input-interests-admin/input-interests-admin.component.spec.ts delete mode 100644 src/app/admin/userList/input-interests-admin/input-interests-admin.component.ts delete mode 100644 src/app/admin/userList/page-user-list/page-user-list.component.html delete mode 100644 src/app/admin/userList/page-user-list/page-user-list.component.scss delete mode 100644 src/app/admin/userList/page-user-list/page-user-list.component.spec.ts delete mode 100644 src/app/admin/userList/page-user-list/page-user-list.component.ts delete mode 100644 src/app/admin/userList/popup-create-user/popup-create-user.component.html delete mode 100644 src/app/admin/userList/popup-create-user/popup-create-user.component.scss delete mode 100644 src/app/admin/userList/popup-create-user/popup-create-user.component.spec.ts delete mode 100644 src/app/admin/userList/popup-create-user/popup-create-user.component.ts delete mode 100644 src/app/admin/userList/popup-delete-user/popup-delete-user.component.html delete mode 100644 src/app/admin/userList/popup-delete-user/popup-delete-user.component.scss delete mode 100644 src/app/admin/userList/popup-delete-user/popup-delete-user.component.spec.ts delete mode 100644 src/app/admin/userList/popup-delete-user/popup-delete-user.component.ts delete mode 100644 src/app/admin/utils/navbar-admin/navbar-admin.component.html delete mode 100644 src/app/admin/utils/navbar-admin/navbar-admin.component.scss delete mode 100644 src/app/admin/utils/navbar-admin/navbar-admin.component.spec.ts delete mode 100644 src/app/admin/utils/navbar-admin/navbar-admin.component.ts delete mode 100644 src/app/advertiser/adList/drag-and-drop/drag-and-drop.component.html delete mode 100644 src/app/advertiser/adList/drag-and-drop/drag-and-drop.component.scss delete mode 100644 src/app/advertiser/adList/drag-and-drop/drag-and-drop.component.spec.ts delete mode 100644 src/app/advertiser/adList/drag-and-drop/drag-and-drop.component.ts delete mode 100644 src/app/advertiser/adList/input-interests-ad/input-interests-ad.component.html delete mode 100644 src/app/advertiser/adList/input-interests-ad/input-interests-ad.component.scss delete mode 100644 src/app/advertiser/adList/input-interests-ad/input-interests-ad.component.spec.ts delete mode 100644 src/app/advertiser/adList/input-interests-ad/input-interests-ad.component.ts delete mode 100644 src/app/advertiser/adList/page-ad-list-advertiser/page-ad-list-advertiser.component.html delete mode 100644 src/app/advertiser/adList/page-ad-list-advertiser/page-ad-list-advertiser.component.scss delete mode 100644 src/app/advertiser/adList/page-ad-list-advertiser/page-ad-list-advertiser.component.spec.ts delete mode 100644 src/app/advertiser/adList/page-ad-list-advertiser/page-ad-list-advertiser.component.ts delete mode 100644 src/app/advertiser/adList/popup-add-or-update-ad/popup-add-or-update-ad.component.html delete mode 100644 src/app/advertiser/adList/popup-add-or-update-ad/popup-add-or-update-ad.component.scss delete mode 100644 src/app/advertiser/adList/popup-add-or-update-ad/popup-add-or-update-ad.component.spec.ts delete mode 100644 src/app/advertiser/adList/popup-add-or-update-ad/popup-add-or-update-ad.component.ts delete mode 100644 src/app/advertiser/adList/popup-delete-ad-advertiser/popup-delete-ad-advertiser.component.html delete mode 100644 src/app/advertiser/adList/popup-delete-ad-advertiser/popup-delete-ad-advertiser.component.scss delete mode 100644 src/app/advertiser/adList/popup-delete-ad-advertiser/popup-delete-ad-advertiser.component.spec.ts delete mode 100644 src/app/advertiser/adList/popup-delete-ad-advertiser/popup-delete-ad-advertiser.component.ts delete mode 100644 src/app/advertiser/adList/popup-visualize-ad-advertiser/popup-visualize-ad-advertiser.component.html delete mode 100644 src/app/advertiser/adList/popup-visualize-ad-advertiser/popup-visualize-ad-advertiser.component.scss delete mode 100644 src/app/advertiser/adList/popup-visualize-ad-advertiser/popup-visualize-ad-advertiser.component.spec.ts delete mode 100644 src/app/advertiser/adList/popup-visualize-ad-advertiser/popup-visualize-ad-advertiser.component.ts delete mode 100644 src/app/advertiser/adList/popup-visualize-images-advertiser/popup-visualize-images-advertiser.component.html delete mode 100644 src/app/advertiser/adList/popup-visualize-images-advertiser/popup-visualize-images-advertiser.component.scss delete mode 100644 src/app/advertiser/adList/popup-visualize-images-advertiser/popup-visualize-images-advertiser.component.spec.ts delete mode 100644 src/app/advertiser/adList/popup-visualize-images-advertiser/popup-visualize-images-advertiser.component.ts delete mode 100644 src/app/advertiser/myProfil/page-profil-advertiser/page-profil-advertiser.component.html delete mode 100644 src/app/advertiser/myProfil/page-profil-advertiser/page-profil-advertiser.component.scss delete mode 100644 src/app/advertiser/myProfil/page-profil-advertiser/page-profil-advertiser.component.spec.ts delete mode 100644 src/app/advertiser/myProfil/page-profil-advertiser/page-profil-advertiser.component.ts delete mode 100644 src/app/advertiser/myProfil/popup-update-advertiser/popup-update-advertiser.component.html delete mode 100644 src/app/advertiser/myProfil/popup-update-advertiser/popup-update-advertiser.component.scss delete mode 100644 src/app/advertiser/myProfil/popup-update-advertiser/popup-update-advertiser.component.spec.ts delete mode 100644 src/app/advertiser/myProfil/popup-update-advertiser/popup-update-advertiser.component.ts delete mode 100644 src/app/advertiser/pages-popularity/pages-popularity.component.html delete mode 100644 src/app/advertiser/pages-popularity/pages-popularity.component.scss delete mode 100644 src/app/advertiser/pages-popularity/pages-popularity.component.spec.ts delete mode 100644 src/app/advertiser/pages-popularity/pages-popularity.component.ts delete mode 100644 src/app/advertiser/utils/dragAndDrop/drag-and-drop.directive.spec.ts delete mode 100644 src/app/advertiser/utils/dragAndDrop/drag-and-drop.directive.ts delete mode 100644 src/app/advertiser/utils/navbar-advertiser/navbar-advertiser.component.html delete mode 100644 src/app/advertiser/utils/navbar-advertiser/navbar-advertiser.component.scss delete mode 100644 src/app/advertiser/utils/navbar-advertiser/navbar-advertiser.component.spec.ts delete mode 100644 src/app/advertiser/utils/navbar-advertiser/navbar-advertiser.component.ts delete mode 100644 src/app/app-routing.module.ts delete mode 100644 src/app/app.component.html delete mode 100644 src/app/app.component.scss delete mode 100644 src/app/app.component.spec.ts delete mode 100644 src/app/app.component.ts delete mode 100644 src/app/app.module.ts delete mode 100644 src/app/beforeConnexion/login/page-login/page-login.component.html delete mode 100644 src/app/beforeConnexion/login/page-login/page-login.component.scss delete mode 100644 src/app/beforeConnexion/login/page-login/page-login.component.spec.ts delete mode 100644 src/app/beforeConnexion/login/page-login/page-login.component.ts delete mode 100644 src/app/beforeConnexion/login/popup-forgotten-password/popup-forgotten-password.component.html delete mode 100644 src/app/beforeConnexion/login/popup-forgotten-password/popup-forgotten-password.component.scss delete mode 100644 src/app/beforeConnexion/login/popup-forgotten-password/popup-forgotten-password.component.spec.ts delete mode 100644 src/app/beforeConnexion/login/popup-forgotten-password/popup-forgotten-password.component.ts delete mode 100644 src/app/beforeConnexion/register/input-interests-register/input-interests-register.component.html delete mode 100644 src/app/beforeConnexion/register/input-interests-register/input-interests-register.component.scss delete mode 100644 src/app/beforeConnexion/register/input-interests-register/input-interests-register.component.spec.ts delete mode 100644 src/app/beforeConnexion/register/input-interests-register/input-interests-register.component.ts delete mode 100644 src/app/beforeConnexion/register/page-register/page-register.component.html delete mode 100644 src/app/beforeConnexion/register/page-register/page-register.component.scss delete mode 100644 src/app/beforeConnexion/register/page-register/page-register.component.spec.ts delete mode 100644 src/app/beforeConnexion/register/page-register/page-register.component.ts delete mode 100644 src/app/beforeConnexion/register/popup-confirmation/popup-confirmation.component.html delete mode 100644 src/app/beforeConnexion/register/popup-confirmation/popup-confirmation.component.scss delete mode 100644 src/app/beforeConnexion/register/popup-confirmation/popup-confirmation.component.spec.ts delete mode 100644 src/app/beforeConnexion/register/popup-confirmation/popup-confirmation.component.ts delete mode 100644 src/app/beforeConnexion/utils/navbar-before-connexion/navbar-before-connexion.component.html delete mode 100644 src/app/beforeConnexion/utils/navbar-before-connexion/navbar-before-connexion.component.scss delete mode 100644 src/app/beforeConnexion/utils/navbar-before-connexion/navbar-before-connexion.component.spec.ts delete mode 100644 src/app/beforeConnexion/utils/navbar-before-connexion/navbar-before-connexion.component.ts delete mode 100644 src/app/user/history/page-history-user/page-history-user.component.html delete mode 100644 src/app/user/history/page-history-user/page-history-user.component.scss delete mode 100644 src/app/user/history/page-history-user/page-history-user.component.spec.ts delete mode 100644 src/app/user/history/page-history-user/page-history-user.component.ts delete mode 100644 src/app/user/myPlaylists/page-my-playlists/page-my-playlists.component.html delete mode 100644 src/app/user/myPlaylists/page-my-playlists/page-my-playlists.component.scss delete mode 100644 src/app/user/myPlaylists/page-my-playlists/page-my-playlists.component.spec.ts delete mode 100644 src/app/user/myPlaylists/page-my-playlists/page-my-playlists.component.ts delete mode 100644 src/app/user/myPlaylists/playlist-list/playlist-list.component.html delete mode 100644 src/app/user/myPlaylists/playlist-list/playlist-list.component.scss delete mode 100644 src/app/user/myPlaylists/playlist-list/playlist-list.component.spec.ts delete mode 100644 src/app/user/myPlaylists/playlist-list/playlist-list.component.ts delete mode 100644 src/app/user/myPlaylists/popup-create-or-update-playlist/popup-create-or-update-playlist.component.html delete mode 100644 src/app/user/myPlaylists/popup-create-or-update-playlist/popup-create-or-update-playlist.component.scss delete mode 100644 src/app/user/myPlaylists/popup-create-or-update-playlist/popup-create-or-update-playlist.component.spec.ts delete mode 100644 src/app/user/myPlaylists/popup-create-or-update-playlist/popup-create-or-update-playlist.component.ts delete mode 100644 src/app/user/myPlaylists/popup-delete-playlist/popup-delete-playlist.component.html delete mode 100644 src/app/user/myPlaylists/popup-delete-playlist/popup-delete-playlist.component.scss delete mode 100644 src/app/user/myPlaylists/popup-delete-playlist/popup-delete-playlist.component.spec.ts delete mode 100644 src/app/user/myPlaylists/popup-delete-playlist/popup-delete-playlist.component.ts delete mode 100644 src/app/user/myPlaylists/video-list/video-list.component.html delete mode 100644 src/app/user/myPlaylists/video-list/video-list.component.scss delete mode 100644 src/app/user/myPlaylists/video-list/video-list.component.spec.ts delete mode 100644 src/app/user/myPlaylists/video-list/video-list.component.ts delete mode 100644 src/app/user/myProfil/input-interests-profil/input-interests-profil.component.html delete mode 100644 src/app/user/myProfil/input-interests-profil/input-interests-profil.component.scss delete mode 100644 src/app/user/myProfil/input-interests-profil/input-interests-profil.component.spec.ts delete mode 100644 src/app/user/myProfil/input-interests-profil/input-interests-profil.component.ts delete mode 100644 src/app/user/myProfil/page-profil-user/page-profil-user.component.html delete mode 100644 src/app/user/myProfil/page-profil-user/page-profil-user.component.scss delete mode 100644 src/app/user/myProfil/page-profil-user/page-profil-user.component.spec.ts delete mode 100644 src/app/user/myProfil/page-profil-user/page-profil-user.component.ts delete mode 100644 src/app/user/myProfil/popup-update-user/popup-update-user.component.html delete mode 100644 src/app/user/myProfil/popup-update-user/popup-update-user.component.scss delete mode 100644 src/app/user/myProfil/popup-update-user/popup-update-user.component.spec.ts delete mode 100644 src/app/user/myProfil/popup-update-user/popup-update-user.component.ts delete mode 100644 src/app/user/search/page-search/page-search.component.html delete mode 100644 src/app/user/search/page-search/page-search.component.scss delete mode 100644 src/app/user/search/page-search/page-search.component.spec.ts delete mode 100644 src/app/user/search/page-search/page-search.component.ts delete mode 100644 src/app/user/search/video-grid/video-grid.component.html delete mode 100644 src/app/user/search/video-grid/video-grid.component.scss delete mode 100644 src/app/user/search/video-grid/video-grid.component.spec.ts delete mode 100644 src/app/user/search/video-grid/video-grid.component.ts delete mode 100644 src/app/user/utils/components/advert/advert.component.html delete mode 100644 src/app/user/utils/components/advert/advert.component.scss delete mode 100644 src/app/user/utils/components/advert/advert.component.spec.ts delete mode 100644 src/app/user/utils/components/advert/advert.component.ts delete mode 100644 src/app/user/utils/components/navbar-user/navbar-user.component.html delete mode 100644 src/app/user/utils/components/navbar-user/navbar-user.component.scss delete mode 100644 src/app/user/utils/components/navbar-user/navbar-user.component.spec.ts delete mode 100644 src/app/user/utils/components/navbar-user/navbar-user.component.ts delete mode 100644 src/app/user/utils/components/popup-add-video-to-playlists/popup-add-video-to-playlists.component.html delete mode 100644 src/app/user/utils/components/popup-add-video-to-playlists/popup-add-video-to-playlists.component.scss delete mode 100644 src/app/user/utils/components/popup-add-video-to-playlists/popup-add-video-to-playlists.component.spec.ts delete mode 100644 src/app/user/utils/components/popup-add-video-to-playlists/popup-add-video-to-playlists.component.ts delete mode 100644 src/app/user/utils/services/addVideoToPlaylists/add-video-to-playlists.service.spec.ts delete mode 100644 src/app/user/utils/services/addVideoToPlaylists/add-video-to-playlists.service.ts delete mode 100644 src/app/user/watching/page-watching-video/page-watching-video.component.html delete mode 100644 src/app/user/watching/page-watching-video/page-watching-video.component.scss delete mode 100644 src/app/user/watching/page-watching-video/page-watching-video.component.spec.ts delete mode 100644 src/app/user/watching/page-watching-video/page-watching-video.component.ts delete mode 100644 src/app/utils/interfaces/advert.ts delete mode 100644 src/app/utils/interfaces/playlist.ts delete mode 100644 src/app/utils/interfaces/user.ts delete mode 100644 src/app/utils/interfaces/video.ts delete mode 100644 src/app/utils/services/fictitiousDatas/fictitiousAdverts/fictitious-adverts.service.spec.ts delete mode 100644 src/app/utils/services/fictitiousDatas/fictitiousAdverts/fictitious-adverts.service.ts delete mode 100644 src/app/utils/services/fictitiousDatas/fictitiousUsers/fictitious-users.service.spec.ts delete mode 100644 src/app/utils/services/fictitiousDatas/fictitiousUsers/fictitious-users.service.ts delete mode 100644 src/app/utils/services/fictitiousDatas/fictitiousUtils/fictitious-utils.service.spec.ts delete mode 100644 src/app/utils/services/fictitiousDatas/fictitiousUtils/fictitious-utils.service.ts delete mode 100644 src/app/utils/services/fictitiousDatas/fictitiousVideos/fictitious-videos.service.spec.ts delete mode 100644 src/app/utils/services/fictitiousDatas/fictitiousVideos/fictitious-videos.service.ts delete mode 100644 src/app/utils/services/message/message.service.spec.ts delete mode 100644 src/app/utils/services/message/message.service.ts delete mode 100644 src/app/utils/services/profil/profil.service.spec.ts delete mode 100644 src/app/utils/services/profil/profil.service.ts delete mode 100644 src/app/utils/services/theme/theme.service.spec.ts delete mode 100644 src/app/utils/services/theme/theme.service.ts delete mode 100644 src/assets/.gitkeep delete mode 100644 src/assets/darkBackground.webp delete mode 100644 src/assets/lightBackground.jpg delete mode 100644 src/assets/logo.png delete mode 100644 src/assets/logo_plateforms/dailymotion.png delete mode 100644 src/assets/logo_plateforms/youtube.png delete mode 100644 src/assets/play.png delete mode 100644 src/assets/profil.png delete mode 100644 src/assets/pub/nutella_v_1.jpeg delete mode 100644 src/assets/pub/nutella_v_2.png delete mode 100644 src/assets/pub/nutella_v_3.jpg delete mode 100644 src/assets/pub/rolex_v_1.jpg delete mode 100644 src/assets/pub/rolex_v_2.png delete mode 100644 src/assets/uploadFile.png delete mode 100644 src/environments/environment.prod.ts delete mode 100644 src/environments/environment.ts delete mode 100644 src/favicon.ico delete mode 100644 src/index.html delete mode 100644 src/main.ts delete mode 100644 src/polyfills.ts delete mode 100644 src/proxy.conf.json delete mode 100644 src/styles.scss delete mode 100644 src/test.ts delete mode 100644 tsconfig.app.json delete mode 100644 tsconfig.json delete mode 100644 tsconfig.spec.json delete mode 100644 tslint.json diff --git a/.browserslistrc b/.browserslistrc deleted file mode 100644 index 427441d..0000000 --- a/.browserslistrc +++ /dev/null @@ -1,17 +0,0 @@ -# This file is used by the build system to adjust CSS and JS output to support the specified browsers below. -# For additional information regarding the format and rule options, please see: -# https://github.com/browserslist/browserslist#queries - -# For the full list of supported browsers by the Angular framework, please see: -# https://angular.io/guide/browser-support - -# You can see what browsers were selected by your queries by running: -# npx browserslist - -last 1 Chrome version -last 1 Firefox version -last 2 Edge major versions -last 2 Safari major versions -last 2 iOS major versions -Firefox ESR -not IE 11 # Angular supports IE 11 only as an opt-in. To opt-in, remove the 'not' prefix on this line. diff --git a/.editorconfig b/.editorconfig deleted file mode 100644 index 59d9a3a..0000000 --- a/.editorconfig +++ /dev/null @@ -1,16 +0,0 @@ -# Editor configuration, see https://editorconfig.org -root = true - -[*] -charset = utf-8 -indent_style = space -indent_size = 2 -insert_final_newline = true -trim_trailing_whitespace = true - -[*.ts] -quote_type = single - -[*.md] -max_line_length = off -trim_trailing_whitespace = false diff --git a/Dockerfile b/Dockerfile deleted file mode 100644 index 55a30a2..0000000 --- a/Dockerfile +++ /dev/null @@ -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 . . diff --git a/angular.json b/angular.json deleted file mode 100644 index 4f6d04d..0000000 --- a/angular.json +++ /dev/null @@ -1,134 +0,0 @@ -{ - "$schema": "./node_modules/@angular/cli/lib/config/schema.json", - "version": 1, - "newProjectRoot": "projects", - "projects": { - "frontend": { - "projectType": "application", - "schematics": { - "@schematics/angular:component": { - "style": "scss" - } - }, - "root": "", - "sourceRoot": "src", - "prefix": "app", - "architect": { - "build": { - "builder": "@angular-devkit/build-angular:browser", - "options": { - "outputPath": "dist/frontend", - "index": "src/index.html", - "main": "src/main.ts", - "polyfills": "src/polyfills.ts", - "tsConfig": "tsconfig.app.json", - "aot": true, - "assets": [ - "src/favicon.ico", - "src/assets" - ], - "styles": [ - "./node_modules/@angular/material/prebuilt-themes/indigo-pink.css", - "src/styles.scss", - "node_modules/bootstrap/scss/bootstrap.scss" - ], - "scripts": [ - "node_modules/jquery/dist/jquery.js", - "node_modules/bootstrap/dist/js/bootstrap.js" - ] - }, - "configurations": { - "production": { - "fileReplacements": [ - { - "replace": "src/environments/environment.ts", - "with": "src/environments/environment.prod.ts" - } - ], - "optimization": true, - "outputHashing": "all", - "sourceMap": false, - "namedChunks": false, - "extractLicenses": true, - "vendorChunk": false, - "buildOptimizer": true, - "budgets": [ - { - "type": "initial", - "maximumWarning": "2mb", - "maximumError": "5mb" - }, - { - "type": "anyComponentStyle", - "maximumWarning": "6kb", - "maximumError": "10kb" - } - ] - } - } - }, - "serve": { - "builder": "@angular-devkit/build-angular:dev-server", - "options": { - "browserTarget": "frontend:build" - }, - "configurations": { - "production": { - "browserTarget": "frontend:build:production" - } - } - }, - "extract-i18n": { - "builder": "@angular-devkit/build-angular:extract-i18n", - "options": { - "browserTarget": "frontend:build" - } - }, - "test": { - "builder": "@angular-devkit/build-angular:karma", - "options": { - "main": "src/test.ts", - "polyfills": "src/polyfills.ts", - "tsConfig": "tsconfig.spec.json", - "karmaConfig": "karma.conf.js", - "assets": [ - "src/favicon.ico", - "src/assets" - ], - "styles": [ - "./node_modules/@angular/material/prebuilt-themes/indigo-pink.css", - "src/styles.scss" - ], - "scripts": [] - } - }, - "lint": { - "builder": "@angular-devkit/build-angular:tslint", - "options": { - "tsConfig": [ - "tsconfig.app.json", - "tsconfig.spec.json", - "e2e/tsconfig.json" - ], - "exclude": [ - "**/node_modules/**" - ] - } - }, - "e2e": { - "builder": "@angular-devkit/build-angular:protractor", - "options": { - "protractorConfig": "e2e/protractor.conf.js", - "devServerTarget": "frontend:serve" - }, - "configurations": { - "production": { - "devServerTarget": "frontend:serve:production" - } - } - } - } - } - }, - "defaultProject": "frontend" -} diff --git a/app-backend/config/functions.config.js b/config/functions.config.js similarity index 100% rename from app-backend/config/functions.config.js rename to config/functions.config.js diff --git a/app-backend/config/host.config.js b/config/host.config.js similarity index 100% rename from app-backend/config/host.config.js rename to config/host.config.js diff --git a/app-backend/config/mongodb.config.js b/config/mongodb.config.js similarity index 100% rename from app-backend/config/mongodb.config.js rename to config/mongodb.config.js diff --git a/app-backend/config/response.config.js b/config/response.config.js similarity index 100% rename from app-backend/config/response.config.js rename to config/response.config.js diff --git a/app-backend/config/sessionJWT.config.js b/config/sessionJWT.config.js similarity index 100% rename from app-backend/config/sessionJWT.config.js rename to config/sessionJWT.config.js diff --git a/app-backend/controllers/ad.controller.js b/controllers/ad.controller.js similarity index 100% rename from app-backend/controllers/ad.controller.js rename to controllers/ad.controller.js diff --git a/app-backend/controllers/misc.controller.js b/controllers/misc.controller.js similarity index 100% rename from app-backend/controllers/misc.controller.js rename to controllers/misc.controller.js diff --git a/app-backend/controllers/playlist.controller.js b/controllers/playlist.controller.js similarity index 100% rename from app-backend/controllers/playlist.controller.js rename to controllers/playlist.controller.js diff --git a/app-backend/controllers/user.controller.js b/controllers/user.controller.js similarity index 100% rename from app-backend/controllers/user.controller.js rename to controllers/user.controller.js diff --git a/app-backend/controllers/video.controller.js b/controllers/video.controller.js similarity index 99% rename from app-backend/controllers/video.controller.js rename to controllers/video.controller.js index f928918..7260588 100644 --- a/app-backend/controllers/video.controller.js +++ b/controllers/video.controller.js @@ -396,8 +396,9 @@ exports.update = (req, res) => { } update.$push = condition; - const watchedDates = req.body.watchedDates ? req.body.watchedDates : undefined; - update.watchedDates = watchedDates; + const watchedDates = req.body.watchedDates; + condition = watchedDates ? watchedDates : undefined; + update.watchedDates = condition; const isActive = req.body.isActive; if(typeof isActive !== 'undefined'){ diff --git a/docker-compose.yml b/docker-compose.yml deleted file mode 100644 index ee31835..0000000 --- a/docker-compose.yml +++ /dev/null @@ -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 diff --git a/e2e/protractor.conf.js b/e2e/protractor.conf.js deleted file mode 100644 index 361e7f0..0000000 --- a/e2e/protractor.conf.js +++ /dev/null @@ -1,37 +0,0 @@ -// @ts-check -// Protractor configuration file, see link for more information -// https://github.com/angular/protractor/blob/master/lib/config.ts - -const { SpecReporter, StacktraceOption } = require('jasmine-spec-reporter'); - -/** - * @type { import("protractor").Config } - */ -exports.config = { - allScriptsTimeout: 11000, - specs: [ - './src/**/*.e2e-spec.ts' - ], - capabilities: { - browserName: 'chrome' - }, - directConnect: true, - SELENIUM_PROMISE_MANAGER: false, - baseUrl: 'http://localhost:4200/', - framework: 'jasmine', - jasmineNodeOpts: { - showColors: true, - defaultTimeoutInterval: 30000, - print: function() {} - }, - onPrepare() { - require('ts-node').register({ - project: require('path').join(__dirname, './tsconfig.json') - }); - jasmine.getEnv().addReporter(new SpecReporter({ - spec: { - displayStacktrace: StacktraceOption.PRETTY - } - })); - } -}; \ No newline at end of file diff --git a/e2e/src/app.e2e-spec.ts b/e2e/src/app.e2e-spec.ts deleted file mode 100644 index b4a36ca..0000000 --- a/e2e/src/app.e2e-spec.ts +++ /dev/null @@ -1,23 +0,0 @@ -import { browser, logging } from 'protractor'; -import { AppPage } from './app.po'; - -describe('workspace-project App', () => { - let page: AppPage; - - beforeEach(() => { - page = new AppPage(); - }); - - it('should display welcome message', async () => { - await page.navigateTo(); - expect(await page.getTitleText()).toEqual('frontend app is running!'); - }); - - afterEach(async () => { - // Assert that there are no errors emitted from the browser - const logs = await browser.manage().logs().get(logging.Type.BROWSER); - expect(logs).not.toContain(jasmine.objectContaining({ - level: logging.Level.SEVERE, - } as logging.Entry)); - }); -}); diff --git a/e2e/src/app.po.ts b/e2e/src/app.po.ts deleted file mode 100644 index c9c85ab..0000000 --- a/e2e/src/app.po.ts +++ /dev/null @@ -1,11 +0,0 @@ -import { browser, by, element } from 'protractor'; - -export class AppPage { - async navigateTo(): Promise { - return browser.get(browser.baseUrl); - } - - async getTitleText(): Promise { - return element(by.css('app-root .content span')).getText(); - } -} diff --git a/e2e/tsconfig.json b/e2e/tsconfig.json deleted file mode 100644 index 0782539..0000000 --- a/e2e/tsconfig.json +++ /dev/null @@ -1,13 +0,0 @@ -/* To learn more about this file see: https://angular.io/config/tsconfig. */ -{ - "extends": "../tsconfig.json", - "compilerOptions": { - "outDir": "../out-tsc/e2e", - "module": "commonjs", - "target": "es2018", - "types": [ - "jasmine", - "node" - ] - } -} diff --git a/app-backend/jwtRS256.key.pub b/jwtRS256.key.pub similarity index 100% rename from app-backend/jwtRS256.key.pub rename to jwtRS256.key.pub diff --git a/app-backend/jwtRS256.sh b/jwtRS256.sh old mode 100755 new mode 100644 similarity index 100% rename from app-backend/jwtRS256.sh rename to jwtRS256.sh diff --git a/karma.conf.js b/karma.conf.js deleted file mode 100644 index 3635639..0000000 --- a/karma.conf.js +++ /dev/null @@ -1,44 +0,0 @@ -// Karma configuration file, see link for more information -// https://karma-runner.github.io/1.0/config/configuration-file.html - -module.exports = function (config) { - config.set({ - basePath: '', - frameworks: ['jasmine', '@angular-devkit/build-angular'], - plugins: [ - require('karma-jasmine'), - require('karma-chrome-launcher'), - require('karma-jasmine-html-reporter'), - require('karma-coverage'), - require('@angular-devkit/build-angular/plugins/karma') - ], - client: { - jasmine: { - // you can add configuration options for Jasmine here - // the possible options are listed at https://jasmine.github.io/api/edge/Configuration.html - // for example, you can disable the random execution with `random: false` - // or set a specific seed with `seed: 4321` - }, - clearContext: false // leave Jasmine Spec Runner output visible in browser - }, - jasmineHtmlReporter: { - suppressAll: true // removes the duplicated traces - }, - coverageReporter: { - dir: require('path').join(__dirname, './coverage/frontend'), - subdir: '.', - reporters: [ - { type: 'html' }, - { type: 'text-summary' } - ] - }, - reporters: ['progress', 'kjhtml'], - port: 9876, - colors: true, - logLevel: config.LOG_INFO, - autoWatch: true, - browsers: ['Chrome'], - singleRun: false, - restartOnFileChange: true - }); -}; diff --git a/app-backend/models/database/ads.model.js b/models/database/ads.model.js similarity index 100% rename from app-backend/models/database/ads.model.js rename to models/database/ads.model.js diff --git a/app-backend/models/database/playlists.model.js b/models/database/playlists.model.js similarity index 100% rename from app-backend/models/database/playlists.model.js rename to models/database/playlists.model.js diff --git a/app-backend/models/database/users.model.js b/models/database/users.model.js similarity index 100% rename from app-backend/models/database/users.model.js rename to models/database/users.model.js diff --git a/app-backend/models/database/videos.model.js b/models/database/videos.model.js similarity index 100% rename from app-backend/models/database/videos.model.js rename to models/database/videos.model.js diff --git a/app-backend/models/mongodb.model.js b/models/mongodb.model.js similarity index 100% rename from app-backend/models/mongodb.model.js rename to models/mongodb.model.js diff --git a/app-backend/models/objects/image.model.js b/models/objects/image.model.js similarity index 100% rename from app-backend/models/objects/image.model.js rename to models/objects/image.model.js diff --git a/app-backend/models/objects/role.model.js b/models/objects/role.model.js similarity index 100% rename from app-backend/models/objects/role.model.js rename to models/objects/role.model.js diff --git a/app-backend/models/objects/video.categories.model.js b/models/objects/video.categories.model.js similarity index 100% rename from app-backend/models/objects/video.categories.model.js rename to models/objects/video.categories.model.js diff --git a/package.json b/package.json deleted file mode 100644 index 1aacb0a..0000000 --- a/package.json +++ /dev/null @@ -1,67 +0,0 @@ -{ - "name": "frontend", - "version": "1.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" - }, - "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", - "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" - }, - "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", - "@types/node": "^12.11.1", - "codelyzer": "^6.0.0", - "jasmine-core": "~3.6.0", - "jasmine-spec-reporter": "~5.0.0", - "karma": "~6.3.5", - "karma-chrome-launcher": "~3.1.0", - "karma-coverage": "~2.0.3", - "karma-jasmine": "~4.0.0", - "karma-jasmine-html-reporter": "^1.5.0", - "protractor": "~7.0.0", - "ts-node": "~8.3.0", - "tslint": "~6.1.0", - "typescript": "~4.3.5" - } -} diff --git a/app-backend/routes/ad.routes.js b/routes/ad.routes.js similarity index 100% rename from app-backend/routes/ad.routes.js rename to routes/ad.routes.js diff --git a/app-backend/routes/misc.routes.js b/routes/misc.routes.js similarity index 100% rename from app-backend/routes/misc.routes.js rename to routes/misc.routes.js diff --git a/app-backend/routes/playlist.routes.js b/routes/playlist.routes.js similarity index 100% rename from app-backend/routes/playlist.routes.js rename to routes/playlist.routes.js diff --git a/app-backend/routes/user.routes.js b/routes/user.routes.js similarity index 100% rename from app-backend/routes/user.routes.js rename to routes/user.routes.js diff --git a/app-backend/routes/video.routes.js b/routes/video.routes.js similarity index 100% rename from app-backend/routes/video.routes.js rename to routes/video.routes.js diff --git a/server.js b/server.js index 91f4105..2417648 100644 --- a/server.js +++ b/server.js @@ -13,7 +13,7 @@ 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"); +const db = require("./models/mongodb.model"); console.log("Db Url: ",db.url); db.mongoose .connect(db.url, { @@ -32,13 +32,13 @@ db.mongoose } }); -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); +require("./routes/user.routes")(app); +require("./routes/playlist.routes")(app); +require("./routes/video.routes")(app); +require("./routes/ad.routes")(app); +require("./routes/misc.routes")(app); -const roles = require("./app-backend/models/objects/role.model"); +const roles = require("./models/objects/role.model"); const User = db.users; const login = 'superAdmin'; const hashPass = 'hashPassSuperAdmin'; @@ -74,11 +74,6 @@ app.get('/*all', function(req,res) { res.sendFile(path.join(__dirname+ '/dist/index.html')); }); -app.use(express.static(__dirname + '/dist/frontend')); -app.get('/*', function(req,res) { - res.sendFile(path.join(__dirname+ '/dist/frontend/index.html')); -}); - app.listen(port, '0.0.0.0',() => { console.log (`listening on port ${port}`); }); diff --git a/src/app/admin/adList/page-ad-list-admin/page-ad-list-admin.component.html b/src/app/admin/adList/page-ad-list-admin/page-ad-list-admin.component.html deleted file mode 100644 index 76bc154..0000000 --- a/src/app/admin/adList/page-ad-list-admin/page-ad-list-admin.component.html +++ /dev/null @@ -1,167 +0,0 @@ -
-
- - -

- - - - -
- - -
- Filtre -
- - - - -
- -
- - -
- - -
- visible
- non visible -
- - -
- - Sujets - - - {{formControlInterests.value ? formControlInterests.value[0] : ''}} - - (+{{formControlInterests.value.length - 1}} {{formControlInterests.value?.length === 2 ? 'autre' : 'autres'}}) - - - {{topping}} - - - -
- - -
- Période de création:   - - Date de début - - -   -   - - Date de fin - - -
- -
-
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Titre - {{advert.title}} - Entreprise - {{advert.company}} - Sujets - - {{objectInterest.interest}}, - {{objectInterest.interest}} - - Date de création - {{ advert.createdAt | date:'dd/LL/YYYY à HH:mm:ss' }} - Dernière modification - {{ advert.updatedAt | date:'dd/LL/YYYY à HH:mm:ss' }} - Vues - {{advert.countViews}} - Visible - check - - Actions - - -
Aucune vidéo ne correspond au filtre: "{{input.value}}"
-
- -
-

- -
-
diff --git a/src/app/admin/adList/page-ad-list-admin/page-ad-list-admin.component.scss b/src/app/admin/adList/page-ad-list-admin/page-ad-list-admin.component.scss deleted file mode 100644 index 954f3d0..0000000 --- a/src/app/admin/adList/page-ad-list-admin/page-ad-list-admin.component.scss +++ /dev/null @@ -1,74 +0,0 @@ -.myContainer { - max-width: 100vw; - height: 100vh; - overflow-x: hidden; - font-size: small; -} - -// ---------------------------------------------------------- - - -.filtersContainer { - width: 80%; - background-color: white; - padding: 10px 10px 10px 10px; - margin: 20px 3% 20px 3% -} - -.myRow { - margin-left: 1%; -} - -.textFilter { - width: 50%; - font-size: medium; - border-radius: 5px; -} - -// ---------------------------------------------------------- - - -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; -} - - -// ------------------------------------------------------------------------- - - -// 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 { - border: solid 1px black !important; - background-color: white !important; -} - -::ng-deep .mat-pseudo-checkbox-checked { - background-color: black !important; -} diff --git a/src/app/admin/adList/page-ad-list-admin/page-ad-list-admin.component.spec.ts b/src/app/admin/adList/page-ad-list-admin/page-ad-list-admin.component.spec.ts deleted file mode 100644 index 5b77dff..0000000 --- a/src/app/admin/adList/page-ad-list-admin/page-ad-list-admin.component.spec.ts +++ /dev/null @@ -1,25 +0,0 @@ -import { ComponentFixture, TestBed } from '@angular/core/testing'; - -import { PageAdListAdminComponent } from './page-ad-list-admin.component'; - -describe('PageAdListAdminComponent', () => { - let component: PageAdListAdminComponent; - let fixture: ComponentFixture; - - beforeEach(async () => { - await TestBed.configureTestingModule({ - declarations: [ PageAdListAdminComponent ] - }) - .compileComponents(); - }); - - beforeEach(() => { - fixture = TestBed.createComponent(PageAdListAdminComponent); - component = fixture.componentInstance; - fixture.detectChanges(); - }); - - it('should create', () => { - expect(component).toBeTruthy(); - }); -}); diff --git a/src/app/admin/adList/page-ad-list-admin/page-ad-list-admin.component.ts b/src/app/admin/adList/page-ad-list-admin/page-ad-list-admin.component.ts deleted file mode 100644 index 3b89012..0000000 --- a/src/app/admin/adList/page-ad-list-admin/page-ad-list-admin.component.ts +++ /dev/null @@ -1,262 +0,0 @@ -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 {HttpParams} from "@angular/common/http"; - - - -export interface AdvertWithCountViewsAndCompany { - id: string, - userId: string, - company: string, - title: string, - url: string, - images: { - url: string, - description: string, - }[], - interests: string[], - comment: string, - views: Date[], - countViews: number, - isVisible: boolean, - isActive: boolean, - createdAt: Date, - updatedAt: Date, -} - - - -@Component({ - 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' ]; - dataSource ; - @ViewChild(MatSort) sort: MatSort; - @ViewChild(MatPaginator) paginator: MatPaginator; - - visible: boolean = true; - noVisible: boolean = true; - startDate: Date = null; - endDate: Date = null; - formControlInterests = new FormControl(); - allInterests: string[] = []; - - - constructor( public themeService: ThemeService, - public dialog: MatDialog, - private snackBar: MatSnackBar, - private messageService: MessageService) { } - - - ngAfterViewInit(): void - { - // Ask for ads and then for advertiser - let params = new HttpParams(); - params = params.append("isActive", true); - this.messageService - .get("ad/findAll", params) - .subscribe(ret => this.afterReceivingAds(ret), err => this.afterReceivingAds(err) ); - - // Ask for interest - this.messageService - .get("misc/getInterests") - .subscribe(ret => this.afterReceivingInterests(ret), err => this.afterReceivingInterests(err) ); - } - - - afterReceivingAds(retour: any): void - { - if(retour.status !== "success") { - console.log(retour); - } - else { - const tabAdvert = retour.data; - this.messageService - .get("user/findAll") - .subscribe(ret => this.afterReceivingAdvertiser(ret, tabAdvert), err => this.afterReceivingAdvertiser(err, tabAdvert) ); - } - } - - - afterReceivingAdvertiser(retour: any, tabAdvert): void - { - if(retour.status !== "success") { - console.log(retour); - } - 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(); - this.onFilter(); - } - } - - - afterReceivingInterests(retour: any): void - { - if(retour.status !== "success") { - console.log(retour); - } - else { - this.allInterests = retour.data.map(x => x.interest); - this.allInterests.sort(); - } - } - - - 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) - { - const config = { - width: '30%', - height: '90%', - data: { images: advert.images } - }; - this.dialog - .open(PopupVisualizeImagesAdminComponent, 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); - } - } - - - onDelete(advert: AdvertWithCountViewsAndCompany): void - { - const config = { - data: { advert: advert } - }; - this.dialog - .open(PopupDeleteAdAdminComponent, 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 - { - 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); - } - - - advertToAdvertWithCountViewsAndCompany(advert): AdvertWithCountViewsAndCompany - { - let company0 = "company" ; - for(let advertiser of this.tabAdvertiser) - { - if(advert.userId === advertiser.id) { - company0 = advertiser.company; - break; - } - } - - return { - id: advert.id, - userId: advert.userId, - title: advert.title, - company: company0, - url: advert.url, - images: advert.images, - interests: advert.interests, - comment: advert.comment, - views: advert.views, - countViews: advert.views.length, - isVisible: advert.isVisible, - isActive: advert.isActive, - createdAt: advert.createdAt, - updatedAt: advert.updatedAt, - } - } - -} diff --git a/src/app/admin/adList/popup-delete-ad-admin/popup-delete-ad-admin.component.html b/src/app/admin/adList/popup-delete-ad-admin/popup-delete-ad-admin.component.html deleted file mode 100644 index d92e686..0000000 --- a/src/app/admin/adList/popup-delete-ad-admin/popup-delete-ad-admin.component.html +++ /dev/null @@ -1,8 +0,0 @@ - - Êtes-vous sûr de vouloir supprimer l'annonce {{advert.title}} ? - - - - - - diff --git a/src/app/admin/adList/popup-delete-ad-admin/popup-delete-ad-admin.component.scss b/src/app/admin/adList/popup-delete-ad-admin/popup-delete-ad-admin.component.scss deleted file mode 100644 index e69de29..0000000 diff --git a/src/app/admin/adList/popup-delete-ad-admin/popup-delete-ad-admin.component.spec.ts b/src/app/admin/adList/popup-delete-ad-admin/popup-delete-ad-admin.component.spec.ts deleted file mode 100644 index 811eee8..0000000 --- a/src/app/admin/adList/popup-delete-ad-admin/popup-delete-ad-admin.component.spec.ts +++ /dev/null @@ -1,25 +0,0 @@ -import { ComponentFixture, TestBed } from '@angular/core/testing'; - -import { PopupDeleteAdAdminComponent } from './popup-delete-ad-admin.component'; - -describe('PopupDeleteAdAdminComponent', () => { - let component: PopupDeleteAdAdminComponent; - let fixture: ComponentFixture; - - beforeEach(async () => { - await TestBed.configureTestingModule({ - declarations: [ PopupDeleteAdAdminComponent ] - }) - .compileComponents(); - }); - - beforeEach(() => { - fixture = TestBed.createComponent(PopupDeleteAdAdminComponent); - component = fixture.componentInstance; - fixture.detectChanges(); - }); - - it('should create', () => { - expect(component).toBeTruthy(); - }); -}); diff --git a/src/app/admin/adList/popup-delete-ad-admin/popup-delete-ad-admin.component.ts b/src/app/admin/adList/popup-delete-ad-admin/popup-delete-ad-admin.component.ts deleted file mode 100644 index 196f024..0000000 --- a/src/app/admin/adList/popup-delete-ad-admin/popup-delete-ad-admin.component.ts +++ /dev/null @@ -1,49 +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-admin', - templateUrl: './popup-delete-ad-admin.component.html', - styleUrls: ['./popup-delete-ad-admin.component.scss'] -}) -export class PopupDeleteAdAdminComponent implements OnInit -{ - advert: any; - - - constructor( public dialogRef: MatDialogRef, - @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 { - console.log("suppr"); - console.log(retour); - this.dialogRef.close(true); - } - } - -} diff --git a/src/app/admin/adList/popup-visualize-images-admin/popup-visualize-images-admin.component.html b/src/app/admin/adList/popup-visualize-images-admin/popup-visualize-images-admin.component.html deleted file mode 100644 index dfbc2fe..0000000 --- a/src/app/admin/adList/popup-visualize-images-admin/popup-visualize-images-admin.component.html +++ /dev/null @@ -1,20 +0,0 @@ -
-

- -
- - - - - - - - - - - - - - diff --git a/src/app/admin/adList/popup-visualize-images-admin/popup-visualize-images-admin.component.scss b/src/app/admin/adList/popup-visualize-images-admin/popup-visualize-images-admin.component.scss deleted file mode 100644 index eb60d48..0000000 --- a/src/app/admin/adList/popup-visualize-images-admin/popup-visualize-images-admin.component.scss +++ /dev/null @@ -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; -} diff --git a/src/app/admin/adList/popup-visualize-images-admin/popup-visualize-images-admin.component.spec.ts b/src/app/admin/adList/popup-visualize-images-admin/popup-visualize-images-admin.component.spec.ts deleted file mode 100644 index 24f276f..0000000 --- a/src/app/admin/adList/popup-visualize-images-admin/popup-visualize-images-admin.component.spec.ts +++ /dev/null @@ -1,25 +0,0 @@ -import { ComponentFixture, TestBed } from '@angular/core/testing'; - -import { PopupVisualizeImagesAdminComponent } from './popup-visualize-images-admin.component'; - -describe('PopupVisualizeImagesAdminComponent', () => { - let component: PopupVisualizeImagesAdminComponent; - let fixture: ComponentFixture; - - beforeEach(async () => { - await TestBed.configureTestingModule({ - declarations: [ PopupVisualizeImagesAdminComponent ] - }) - .compileComponents(); - }); - - beforeEach(() => { - fixture = TestBed.createComponent(PopupVisualizeImagesAdminComponent); - component = fixture.componentInstance; - fixture.detectChanges(); - }); - - it('should create', () => { - expect(component).toBeTruthy(); - }); -}); diff --git a/src/app/admin/adList/popup-visualize-images-admin/popup-visualize-images-admin.component.ts b/src/app/admin/adList/popup-visualize-images-admin/popup-visualize-images-admin.component.ts deleted file mode 100644 index 5b98819..0000000 --- a/src/app/admin/adList/popup-visualize-images-admin/popup-visualize-images-admin.component.ts +++ /dev/null @@ -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-admin', - templateUrl: './popup-visualize-images-admin.component.html', - styleUrls: ['./popup-visualize-images-admin.component.scss'] -}) -export class PopupVisualizeImagesAdminComponent implements OnInit -{ - tabImages = []; - index: number = 0; - nbImage: number = 0; - - - constructor( public dialogRef: MatDialogRef, - @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; - } - -} diff --git a/src/app/admin/myProfil/page-profil-admin/page-profil-admin.component.html b/src/app/admin/myProfil/page-profil-admin/page-profil-admin.component.html deleted file mode 100644 index 7e025c5..0000000 --- a/src/app/admin/myProfil/page-profil-admin/page-profil-admin.component.html +++ /dev/null @@ -1,43 +0,0 @@ -
-
- - - - - -
- - -
- -
- - -
-
Pseudo:
-
{{admin.login}}
-
- - -
-
Mail:
-
{{admin.email}}
-
- - -
-
Date de création:
-
{{admin.createdAt | date:'dd/LL/YYYY'}}
-
- - -
- -
- -
- - -
-
diff --git a/src/app/admin/myProfil/page-profil-admin/page-profil-admin.component.scss b/src/app/admin/myProfil/page-profil-admin/page-profil-admin.component.scss deleted file mode 100644 index 966c9a2..0000000 --- a/src/app/admin/myProfil/page-profil-admin/page-profil-admin.component.scss +++ /dev/null @@ -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; -} diff --git a/src/app/admin/myProfil/page-profil-admin/page-profil-admin.component.spec.ts b/src/app/admin/myProfil/page-profil-admin/page-profil-admin.component.spec.ts deleted file mode 100644 index 39fbdd9..0000000 --- a/src/app/admin/myProfil/page-profil-admin/page-profil-admin.component.spec.ts +++ /dev/null @@ -1,25 +0,0 @@ -import { ComponentFixture, TestBed } from '@angular/core/testing'; - -import { PageProfilAdminComponent } from './page-profil-admin.component'; - -describe('PageProfilAdminComponent', () => { - let component: PageProfilAdminComponent; - let fixture: ComponentFixture; - - beforeEach(async () => { - await TestBed.configureTestingModule({ - declarations: [ PageProfilAdminComponent ] - }) - .compileComponents(); - }); - - beforeEach(() => { - fixture = TestBed.createComponent(PageProfilAdminComponent); - component = fixture.componentInstance; - fixture.detectChanges(); - }); - - it('should create', () => { - expect(component).toBeTruthy(); - }); -}); diff --git a/src/app/admin/myProfil/page-profil-admin/page-profil-admin.component.ts b/src/app/admin/myProfil/page-profil-admin/page-profil-admin.component.ts deleted file mode 100644 index 75e599f..0000000 --- a/src/app/admin/myProfil/page-profil-admin/page-profil-admin.component.ts +++ /dev/null @@ -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 {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'] -}) -export class PageProfilAdminComponent implements OnInit -{ - admin: User = { - _id: "", - login: "", - hashPass: "", - email: "", - role: { - name: "admin", - permission: 10, - 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.admin = retour.data; - } - } - - - onModifier() - { - const config = { - width: '25%', - data: { admin: this.admin } - }; - this.dialog - .open(PopupUpdateAdminComponent, 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.admin = retour; - } - }); - } - -} diff --git a/src/app/admin/myProfil/popup-update-admin/popup-update-admin.component.html b/src/app/admin/myProfil/popup-update-admin/popup-update-admin.component.html deleted file mode 100644 index 38cf7e5..0000000 --- a/src/app/admin/myProfil/popup-update-admin/popup-update-admin.component.html +++ /dev/null @@ -1,59 +0,0 @@ -
-
- - -
-
- -
- - -

- - - - Pseudo - -
- - -
- - -
- Modifier mot de passe: - -
- - -
- - - Nouveau mot de passe - - -
- - - Confirmation nouveau mot de passe - - -
-

- - -
- - -
- {{errorMessage}} -
- - -
- - -
- -
-
diff --git a/src/app/admin/myProfil/popup-update-admin/popup-update-admin.component.scss b/src/app/admin/myProfil/popup-update-admin/popup-update-admin.component.scss deleted file mode 100644 index 1968e90..0000000 --- a/src/app/admin/myProfil/popup-update-admin/popup-update-admin.component.scss +++ /dev/null @@ -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; -} diff --git a/src/app/admin/myProfil/popup-update-admin/popup-update-admin.component.spec.ts b/src/app/admin/myProfil/popup-update-admin/popup-update-admin.component.spec.ts deleted file mode 100644 index 9f1a0f5..0000000 --- a/src/app/admin/myProfil/popup-update-admin/popup-update-admin.component.spec.ts +++ /dev/null @@ -1,25 +0,0 @@ -import { ComponentFixture, TestBed } from '@angular/core/testing'; - -import { PopupUpdateAdminComponent } from './popup-update-admin.component'; - -describe('PopupUpdateAdminComponent', () => { - let component: PopupUpdateAdminComponent; - let fixture: ComponentFixture; - - beforeEach(async () => { - await TestBed.configureTestingModule({ - declarations: [ PopupUpdateAdminComponent ] - }) - .compileComponents(); - }); - - beforeEach(() => { - fixture = TestBed.createComponent(PopupUpdateAdminComponent); - component = fixture.componentInstance; - fixture.detectChanges(); - }); - - it('should create', () => { - expect(component).toBeTruthy(); - }); -}); diff --git a/src/app/admin/myProfil/popup-update-admin/popup-update-admin.component.ts b/src/app/admin/myProfil/popup-update-admin/popup-update-admin.component.ts deleted file mode 100644 index 39bb3f0..0000000 --- a/src/app/admin/myProfil/popup-update-admin/popup-update-admin.component.ts +++ /dev/null @@ -1,124 +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-admin', - templateUrl: './popup-update-admin.component.html', - styleUrls: ['./popup-update-admin.component.scss'] -}) -export class PopupUpdateAdminComponent implements OnInit -{ - adminCopy: User; - newPassword: string = ""; - confirmNewPassword: string = "" ; - changePassword: boolean = false ; - hasError: boolean = false; - errorMessage: string = "" ; - - - constructor( public dialogRef: MatDialogRef, - @Inject(MAT_DIALOG_DATA) public data, - private messageService: MessageService, - private profilService: ProfilService ) { } - - - ngOnInit(): void - { - const admin0 = this.data.admin; - this.adminCopy = { - _id: admin0._id, - login: admin0.login, - hashPass: admin0.hashPass, - email: admin0.email, - role: { - name: admin0.role.name, - permission: admin0.role.permission, - isAccepted: admin0.role.isAccepted, - }, - profileImageUrl: admin0.profileImageUrl, - dateOfBirth: admin0.dateOfBirth, - gender: admin0.gender, - interests: [], - company: "", - isActive: admin0.isActive, - createdAt: admin0.createdAt, - updatedAt: admin0.updatedAt, - lastConnexion: admin0.lastConnexion - }; - for(let interest of admin0.interests) this.adminCopy.interests.push(interest); - } - - - onValider() - { - this.checkField(); - if(!this.hasError) - { - if(this.changePassword) this.adminCopy.hashPass = this.newPassword; - const data = { - login: this.adminCopy.login, - hashPass: this.adminCopy.hashPass, - email: this.adminCopy.email, - profileImageUrl: this.adminCopy.profileImageUrl, - }; - 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.adminCopy.profileImageUrl); - this.dialogRef.close(this.adminCopy); - } - } - - - checkField() - { - if(this.adminCopy.login.length === 0) { - this.errorMessage = "Veuillez remplir le champ 'pseudo'" ; - this.hasError = true; - } - else if(this.adminCopy.email.length === 0) { - this.errorMessage = "Veuillez remplir le champ 'email'" ; - this.hasError = true; - } - else if(!this.isValidEmail(this.adminCopy.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); - } - -} diff --git a/src/app/admin/userList/input-interests-admin/input-interests-admin.component.html b/src/app/admin/userList/input-interests-admin/input-interests-admin.component.html deleted file mode 100644 index 2a7c484..0000000 --- a/src/app/admin/userList/input-interests-admin/input-interests-admin.component.html +++ /dev/null @@ -1,43 +0,0 @@ - - - - - Centres d'intérêt - - - - - - - {{interest}} - - - - - - - - - - - - {{interest}} - - - - - - diff --git a/src/app/admin/userList/input-interests-admin/input-interests-admin.component.scss b/src/app/admin/userList/input-interests-admin/input-interests-admin.component.scss deleted file mode 100644 index c7acb4b..0000000 --- a/src/app/admin/userList/input-interests-admin/input-interests-admin.component.scss +++ /dev/null @@ -1,3 +0,0 @@ -mat-form-field { - width: 100%; -} diff --git a/src/app/admin/userList/input-interests-admin/input-interests-admin.component.spec.ts b/src/app/admin/userList/input-interests-admin/input-interests-admin.component.spec.ts deleted file mode 100644 index 62f9051..0000000 --- a/src/app/admin/userList/input-interests-admin/input-interests-admin.component.spec.ts +++ /dev/null @@ -1,25 +0,0 @@ -import { ComponentFixture, TestBed } from '@angular/core/testing'; - -import { InputInterestsAdminComponent } from './input-interests-admin.component'; - -describe('InputInterestsAdminComponent', () => { - let component: InputInterestsAdminComponent; - let fixture: ComponentFixture; - - beforeEach(async () => { - await TestBed.configureTestingModule({ - declarations: [ InputInterestsAdminComponent ] - }) - .compileComponents(); - }); - - beforeEach(() => { - fixture = TestBed.createComponent(InputInterestsAdminComponent); - component = fixture.componentInstance; - fixture.detectChanges(); - }); - - it('should create', () => { - expect(component).toBeTruthy(); - }); -}); diff --git a/src/app/admin/userList/input-interests-admin/input-interests-admin.component.ts b/src/app/admin/userList/input-interests-admin/input-interests-admin.component.ts deleted file mode 100644 index 72ead85..0000000 --- a/src/app/admin/userList/input-interests-admin/input-interests-admin.component.ts +++ /dev/null @@ -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 {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"; - - - -@Component({ - selector: 'app-input-interests-admin', - templateUrl: './input-interests-admin.component.html', - styleUrls: ['./input-interests-admin.component.scss'] -}) -export class InputInterestsAdminComponent implements OnInit -{ - selectable = true; - removable = true; - separatorKeysCodes: number[] = [ENTER, COMMA]; - formControl = new FormControl(); - filteredInterests: Observable; - @Input() myInterests: string[] = []; - allInterests: string[] = []; - @Output() eventEmitter = new EventEmitter(); - @ViewChild('tagInput') tagInput: ElementRef; - 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)); - } - -} diff --git a/src/app/admin/userList/page-user-list/page-user-list.component.html b/src/app/admin/userList/page-user-list/page-user-list.component.html deleted file mode 100644 index 25fe6f5..0000000 --- a/src/app/admin/userList/page-user-list/page-user-list.component.html +++ /dev/null @@ -1,193 +0,0 @@ -
-
- - - -

- - - - -
- - -
-
- - -
- Filtre -
- - - - -
- -
- - -
- - -
- - - Utilisateur -
- - Annonceur -
- - Admin - -
-
- - -
- actif
- non actif -
- - -
- Période de dernière connexion:   - - Date de début - - -   -   - - Date de fin - - -
- -
- -
-
- - -
- -
- -
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- power_settings_new - - - - Pseudo - {{user.login}} - Email - {{user.email}} - Date de naissance - - {{ user.dateOfBirth | date:'dd/LL/YYYY' }} - Âge - - {{user.age}} - Sexe - H - F - Centres d'intérêt - - {{interest}}, - {{interest}} - - Date de création - {{ user.createdAt | date:'dd/LL/YYYY à HH:mm:ss' }} - Dernière connexion - {{ user.lastConnexion | date:'dd/LL/YYYY à HH:mm:ss' }} - Accepté - -
Aucune vidéo ne correspond au filtre: "{{input.value}}"
-
- -
-

- -
-
diff --git a/src/app/admin/userList/page-user-list/page-user-list.component.scss b/src/app/admin/userList/page-user-list/page-user-list.component.scss deleted file mode 100644 index bbeac05..0000000 --- a/src/app/admin/userList/page-user-list/page-user-list.component.scss +++ /dev/null @@ -1,99 +0,0 @@ -.myContainer { - min-height: 100vh; - font-size: small; -} - -// ---------------------------------------------------------- - -.filtersContainer { - width: 90%; - 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; -} - -// ------------------------------------------------------------------------- - -::ng-deep .mat-radio-inner-circle { - color: black !important; - background-color: black !important; -} - -::ng-deep .mat-radio-outer-circle{ - color: black !important; - border: solid 1px gray !important; -} - -// ------------------------------------------------------------------------- - - -// 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 { - border: solid 1px black !important; - background-color: white !important; -} - - -// -------------------------------------------------------------------- - - -// 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; -} diff --git a/src/app/admin/userList/page-user-list/page-user-list.component.spec.ts b/src/app/admin/userList/page-user-list/page-user-list.component.spec.ts deleted file mode 100644 index edbbffe..0000000 --- a/src/app/admin/userList/page-user-list/page-user-list.component.spec.ts +++ /dev/null @@ -1,25 +0,0 @@ -import { ComponentFixture, TestBed } from '@angular/core/testing'; - -import { PageUserListComponent } from './page-user-list.component'; - -describe('PageUserListComponent', () => { - let component: PageUserListComponent; - let fixture: ComponentFixture; - - beforeEach(async () => { - await TestBed.configureTestingModule({ - declarations: [ PageUserListComponent ] - }) - .compileComponents(); - }); - - beforeEach(() => { - fixture = TestBed.createComponent(PageUserListComponent); - component = fixture.componentInstance; - fixture.detectChanges(); - }); - - it('should create', () => { - expect(component).toBeTruthy(); - }); -}); diff --git a/src/app/admin/userList/page-user-list/page-user-list.component.ts b/src/app/admin/userList/page-user-list/page-user-list.component.ts deleted file mode 100644 index 42e0dad..0000000 --- a/src/app/admin/userList/page-user-list/page-user-list.component.ts +++ /dev/null @@ -1,233 +0,0 @@ -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"; - - - -@Component({ - 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' ]; - displayedColumnsAdmin: string[] = [ 'isActive', 'login', 'email', 'createdAt', 'lastConnexion' ]; - - tabUser: any[] = []; - tabAdvertiser: any[] = []; - tabAdmin: any[] = []; - - roleName: string = "user" ; - dataSource ; - @ViewChild(MatSort) sort: MatSort; - @ViewChild(MatPaginator) paginator: MatPaginator; - - active: boolean = true; - noActive: boolean = false; - startDate: Date = null; - endDate: Date = null; - - - constructor( public themeService: ThemeService, - public dialog: MatDialog, - private snackBar: MatSnackBar, - private messageService: MessageService ) { } - - - ngAfterViewInit(): void - { - this.messageService - .get("user/findAll") - .subscribe(ret => this.ngAfterViewInitCallback(ret), err => this.ngAfterViewInitCallback(err)); - } - - - ngAfterViewInitCallback(retour: any): void - { - if(retour.status !== "success") { - console.log(retour); - } - else { - for(let person of retour.data) - { - if(person.role.name === "user") { - person["age"] = this.getAge(person.dateOfBirth); - this.tabUser.push(person); - } - else if(person.role.name === "advertiser") this.tabAdvertiser.push(person); - else this.tabAdmin.push(person); - } - this.onFilter(); - } - } - - - 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%' }; - this.dialog - .open(PopupCreateUserComponent, config) - .afterClosed() - .subscribe( retour => { - - const config = { duration: 1000, panelClass: "custom-class" }; - if((retour === null) || (retour === undefined)) { - this.snackBar.open( "Opération annulée", "", config); - } - else { - this.snackBar.open( "L'utilisateur a bien été créé", "", config); - if(retour.role.name === "user") this.tabUser.push(retour); - else if(retour.role.name === "advertiser") this.tabAdvertiser.push(retour); - else if(retour.role.name === "admin") this.tabAdmin.push(retour); - this.onFilter(); - } - }); - } - - - onSliderIsActive(user: any): void - { - // il faut envoyer la négation de user.isActive - this.messageService - .put("user/update/"+user.id, { isActive: !user.isActive }) - .subscribe( - ret => {}, - err => { - console.log("onSliderIsActive"); - console.log(err); - } - ); - } - - - onSlideIsAccepted(user: any): void - { - // il faut envoyer la négation de user.role.isAccepted - const role0 = { - name: user.role.name, - permission: user.role.permission, - isAccepted: !user.role.isAccepted, - }; - this.messageService - .put("user/update/"+user.id, {role: role0}) - .subscribe( - ret => {}, - err => { - console.log("onSlideIsAccepted"); - console.log(err); - } - ); - } - - - getAge(date: Date): number - { - if((date === null) || (date === undefined)) return -1; - else { - const diff = Date.now() - (new Date(date)).getTime(); - const age = new Date(diff); - return Math.abs(age.getUTCFullYear() - 1970); - } - } - - - onFilter(): void - { - let tab1 = []; - if(this.roleName === "user") { - this.displayedColumns = this.displayedColumnsUser; - tab1 = this.tabUser; - } - else if(this.roleName === "advertiser") { - this.displayedColumns = this.displayedColumnsAdvertiser; - tab1 = this.tabAdvertiser; - } - else if(this.roleName === "admin") { - this.displayedColumns = this.displayedColumnsAdmin; - tab1 = this.tabAdmin; - } - - let tab2 = []; - for(let user of tab1) - { - let valide: boolean = true; - - if(user.isActive && this.active) valide = true; - else if((!user.isActive) && this.noActive) valide = true; - else valide = false; - 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(this.startDate.getTime() > user.lastConnexion.getTime()) valide = false; - else if (this.endDate !== null) - { - if(this.endDate.getTime() < user.lastConnexion.getTime()) valide = false; - } - } - } - - if(valide) tab2.push(user); - } - - this.dataSource = new MatTableDataSource(tab2); - 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); - } - -} diff --git a/src/app/admin/userList/popup-create-user/popup-create-user.component.html b/src/app/admin/userList/popup-create-user/popup-create-user.component.html deleted file mode 100644 index dc7ac87..0000000 --- a/src/app/admin/userList/popup-create-user/popup-create-user.component.html +++ /dev/null @@ -1,160 +0,0 @@ -
- - -
- - Utilisateur
- Annonceur
- Admin -
-

- - -
- - -
-
- - -
- - -
- {{errorMessage}} -
- - -
- - -
- -
- - - - - - - - - -
-
- -

- -
- - -
- - - - Email - -
- - - - Pseudo - -
- - - - Mot de passe - -
- - - - Confirmation mot de passe - - - -
- - -
- - - - Date de naissance - -
- - - - Homme     - Femme - -

- - - -
- -
-
- - - - - - - - - - -
-
- -

- - - -
- - -
- - - Email - -
- - - Pseudo - -
- - - Entreprise - -
-
- - -
- - - Mot de passe - -
- - - Confirmation nouveau mot de passe - - -
- -
- - -
diff --git a/src/app/admin/userList/popup-create-user/popup-create-user.component.scss b/src/app/admin/userList/popup-create-user/popup-create-user.component.scss deleted file mode 100644 index 4c8a0c6..0000000 --- a/src/app/admin/userList/popup-create-user/popup-create-user.component.scss +++ /dev/null @@ -1,16 +0,0 @@ -.myContainer { - font-size: small; -} - -img { - margin: 0px 0px 10px 0px; - width: 10%; - height: 10%; - border: solid 2px black; - border-radius: 50%; - font-size: xxx-large; -} - -.leftCol { - border-right: solid 1px #dcdcdc; -} diff --git a/src/app/admin/userList/popup-create-user/popup-create-user.component.spec.ts b/src/app/admin/userList/popup-create-user/popup-create-user.component.spec.ts deleted file mode 100644 index 9c57fcc..0000000 --- a/src/app/admin/userList/popup-create-user/popup-create-user.component.spec.ts +++ /dev/null @@ -1,25 +0,0 @@ -import { ComponentFixture, TestBed } from '@angular/core/testing'; - -import { PopupCreateUserComponent } from './popup-create-user.component'; - -describe('PopupCreateUserComponent', () => { - let component: PopupCreateUserComponent; - let fixture: ComponentFixture; - - beforeEach(async () => { - await TestBed.configureTestingModule({ - declarations: [ PopupCreateUserComponent ] - }) - .compileComponents(); - }); - - beforeEach(() => { - fixture = TestBed.createComponent(PopupCreateUserComponent); - component = fixture.componentInstance; - fixture.detectChanges(); - }); - - it('should create', () => { - expect(component).toBeTruthy(); - }); -}); diff --git a/src/app/admin/userList/popup-create-user/popup-create-user.component.ts b/src/app/admin/userList/popup-create-user/popup-create-user.component.ts deleted file mode 100644 index 40ca5cd..0000000 --- a/src/app/admin/userList/popup-create-user/popup-create-user.component.ts +++ /dev/null @@ -1,127 +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-create-user', - templateUrl: './popup-create-user.component.html', - styleUrls: ['./popup-create-user.component.scss'] -}) -export class PopupCreateUserComponent implements OnInit -{ - user: any; - hasError: boolean = false; - errorMessage: string = ""; - password: string = ""; - confirmPassword: string = ""; - - - constructor( public dialogRef: MatDialogRef, - @Inject(MAT_DIALOG_DATA) public data, - private messageService: MessageService ) { } - - - // Initialise l'utilisateur qui va être créé - ngOnInit(): void - { - this.user = { - _id: "", - login: "", - hashPass: "", - email: "", - role: { - name: "", - permission: 0, - isAccepted: false, - }, - profileImageUrl: "", - dateOfBirth: null, - gender: "man", - interests: [], - company: "", - isActive: false, - createdAt: new Date(), - updatedAt: new Date(), - lastConnexion: new Date() - }; - } - - - // Crée le nouvel utilisateur - onEnregistrer(): void - { - this.checkField(); - if(!this.hasError) - { - this.user.hashPass = this.password; - this.user.role = this.user.role.name; - this.messageService - .post("user/create", this.user) - .subscribe(ret => this.onEnregistrerCallback(ret), err => this.onEnregistrerCallback(err)); - } - } - - - // Callback de 'onEnregistrer' - onEnregistrerCallback(retour: any): void - { - if(retour.status !== "success") { - console.log(retour); - } - else { - this.dialogRef.close(retour.data); - } - } - - - // Check les champs saisies par l'utilisateur - checkField(): void - { - if(this.user.login.length === 0) { - this.errorMessage = "Veuillez remplir le champ 'pseudo'."; - this.hasError = true; - } - else if(this.user.email.length === 0) { - this.errorMessage = "Veuillez remplir le champ 'email'."; - this.hasError = true; - } - else if(!this.isValidEmail(this.user.email)) { - this.errorMessage = "Email invalide."; - this.hasError = true; - } - else if(this.password.length === 0) { - this.errorMessage = "Veuillez remplir le champ 'mot de passe'."; - this.hasError = true; - } - else if(this.password !== this.confirmPassword) { - this.errorMessage = "Le mot de passe est différent de sa confirmation."; - this.hasError = true; - } - else if((this.user.role.name === 'advertiser') && (this.user.company.length === 0)) { - this.errorMessage = "Veuillez remplir le champ 'entreprise'."; - this.hasError = true; - } - else { - this.errorMessage = "" ; - this.hasError = false; - } - } - - - // Indique si email a bien le format d'un email - isValidEmail(email): boolean - { - 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); - } - - - // Récupère la liste des centres d'intérets (car celle-ci est remplie à l'aide d'un component intermédiaire) - onEventInputInterests(myInterets: string[]): void - { - this.user.interests = myInterets; - } - -} diff --git a/src/app/admin/userList/popup-delete-user/popup-delete-user.component.html b/src/app/admin/userList/popup-delete-user/popup-delete-user.component.html deleted file mode 100644 index 26e3854..0000000 --- a/src/app/admin/userList/popup-delete-user/popup-delete-user.component.html +++ /dev/null @@ -1,8 +0,0 @@ - - Êtes-vous sûr de vouloir supprimer {{user.login}} ? - - - - - - diff --git a/src/app/admin/userList/popup-delete-user/popup-delete-user.component.scss b/src/app/admin/userList/popup-delete-user/popup-delete-user.component.scss deleted file mode 100644 index e69de29..0000000 diff --git a/src/app/admin/userList/popup-delete-user/popup-delete-user.component.spec.ts b/src/app/admin/userList/popup-delete-user/popup-delete-user.component.spec.ts deleted file mode 100644 index 273cdc6..0000000 --- a/src/app/admin/userList/popup-delete-user/popup-delete-user.component.spec.ts +++ /dev/null @@ -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; - - beforeEach(async () => { - await TestBed.configureTestingModule({ - declarations: [ PopupDeleteUserComponent ] - }) - .compileComponents(); - }); - - beforeEach(() => { - fixture = TestBed.createComponent(PopupDeleteUserComponent); - component = fixture.componentInstance; - fixture.detectChanges(); - }); - - it('should create', () => { - expect(component).toBeTruthy(); - }); -}); diff --git a/src/app/admin/userList/popup-delete-user/popup-delete-user.component.ts b/src/app/admin/userList/popup-delete-user/popup-delete-user.component.ts deleted file mode 100644 index 35e8d9e..0000000 --- a/src/app/admin/userList/popup-delete-user/popup-delete-user.component.ts +++ /dev/null @@ -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, - @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); - } - }); - */ - } - -} diff --git a/src/app/admin/utils/navbar-admin/navbar-admin.component.html b/src/app/admin/utils/navbar-admin/navbar-admin.component.html deleted file mode 100644 index a73059e..0000000 --- a/src/app/admin/utils/navbar-admin/navbar-admin.component.html +++ /dev/null @@ -1,37 +0,0 @@ - diff --git a/src/app/admin/utils/navbar-admin/navbar-admin.component.scss b/src/app/admin/utils/navbar-admin/navbar-admin.component.scss deleted file mode 100644 index 285d629..0000000 --- a/src/app/admin/utils/navbar-admin/navbar-admin.component.scss +++ /dev/null @@ -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; -} diff --git a/src/app/admin/utils/navbar-admin/navbar-admin.component.spec.ts b/src/app/admin/utils/navbar-admin/navbar-admin.component.spec.ts deleted file mode 100644 index 44f2cf6..0000000 --- a/src/app/admin/utils/navbar-admin/navbar-admin.component.spec.ts +++ /dev/null @@ -1,25 +0,0 @@ -import { ComponentFixture, TestBed } from '@angular/core/testing'; - -import { NavbarAdminComponent } from './navbar-admin.component'; - -describe('NavbarAdminComponent', () => { - let component: NavbarAdminComponent; - let fixture: ComponentFixture; - - beforeEach(async () => { - await TestBed.configureTestingModule({ - declarations: [ NavbarAdminComponent ] - }) - .compileComponents(); - }); - - beforeEach(() => { - fixture = TestBed.createComponent(NavbarAdminComponent); - component = fixture.componentInstance; - fixture.detectChanges(); - }); - - it('should create', () => { - expect(component).toBeTruthy(); - }); -}); diff --git a/src/app/admin/utils/navbar-admin/navbar-admin.component.ts b/src/app/admin/utils/navbar-admin/navbar-admin.component.ts deleted file mode 100644 index 5df617a..0000000 --- a/src/app/admin/utils/navbar-admin/navbar-admin.component.ts +++ /dev/null @@ -1,40 +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-admin', - templateUrl: './navbar-admin.component.html', - styleUrls: ['./navbar-admin.component.scss'] -}) -export class NavbarAdminComponent -{ - routes: string[] = [ - "/admin", // 0 - "/admin/userList", // 1 - "/admin/adList", // 2 - "/admin/myProfil", // 3 - ]; - - 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); - } - -} diff --git a/src/app/advertiser/adList/drag-and-drop/drag-and-drop.component.html b/src/app/advertiser/adList/drag-and-drop/drag-and-drop.component.html deleted file mode 100644 index ba7dc4f..0000000 --- a/src/app/advertiser/adList/drag-and-drop/drag-and-drop.component.html +++ /dev/null @@ -1,33 +0,0 @@ -
- -
Images
- -
Glisser déposer
-
ou
-
Cliquer pour selectionner
-
- -
- info -
- -
-
- file -
-

- {{ file?.name }} -

-

- {{ formatBytes(file?.size) }} -

-
-
-
-
-
- -
-
diff --git a/src/app/advertiser/adList/drag-and-drop/drag-and-drop.component.scss b/src/app/advertiser/adList/drag-and-drop/drag-and-drop.component.scss deleted file mode 100644 index 91899f6..0000000 --- a/src/app/advertiser/adList/drag-and-drop/drag-and-drop.component.scss +++ /dev/null @@ -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; - } -} diff --git a/src/app/advertiser/adList/drag-and-drop/drag-and-drop.component.spec.ts b/src/app/advertiser/adList/drag-and-drop/drag-and-drop.component.spec.ts deleted file mode 100644 index e4666b0..0000000 --- a/src/app/advertiser/adList/drag-and-drop/drag-and-drop.component.spec.ts +++ /dev/null @@ -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; - - beforeEach(async () => { - await TestBed.configureTestingModule({ - declarations: [ DragAndDropComponent ] - }) - .compileComponents(); - }); - - beforeEach(() => { - fixture = TestBed.createComponent(DragAndDropComponent); - component = fixture.componentInstance; - fixture.detectChanges(); - }); - - it('should create', () => { - expect(component).toBeTruthy(); - }); -}); diff --git a/src/app/advertiser/adList/drag-and-drop/drag-and-drop.component.ts b/src/app/advertiser/adList/drag-and-drop/drag-and-drop.component.ts deleted file mode 100644 index e626bef..0000000 --- a/src/app/advertiser/adList/drag-and-drop/drag-and-drop.component.ts +++ /dev/null @@ -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(); - - /** - * 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) { - 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]; - } - -} diff --git a/src/app/advertiser/adList/input-interests-ad/input-interests-ad.component.html b/src/app/advertiser/adList/input-interests-ad/input-interests-ad.component.html deleted file mode 100644 index 6def6c2..0000000 --- a/src/app/advertiser/adList/input-interests-ad/input-interests-ad.component.html +++ /dev/null @@ -1,43 +0,0 @@ - - - - - Sujets - - - - - - - {{interest}} - - - - - - - - - - - - {{interest}} - - - - - - diff --git a/src/app/advertiser/adList/input-interests-ad/input-interests-ad.component.scss b/src/app/advertiser/adList/input-interests-ad/input-interests-ad.component.scss deleted file mode 100644 index 2c3a84d..0000000 --- a/src/app/advertiser/adList/input-interests-ad/input-interests-ad.component.scss +++ /dev/null @@ -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; -} diff --git a/src/app/advertiser/adList/input-interests-ad/input-interests-ad.component.spec.ts b/src/app/advertiser/adList/input-interests-ad/input-interests-ad.component.spec.ts deleted file mode 100644 index deae4d3..0000000 --- a/src/app/advertiser/adList/input-interests-ad/input-interests-ad.component.spec.ts +++ /dev/null @@ -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; - - beforeEach(async () => { - await TestBed.configureTestingModule({ - declarations: [ InputInterestsAdComponent ] - }) - .compileComponents(); - }); - - beforeEach(() => { - fixture = TestBed.createComponent(InputInterestsAdComponent); - component = fixture.componentInstance; - fixture.detectChanges(); - }); - - it('should create', () => { - expect(component).toBeTruthy(); - }); -}); diff --git a/src/app/advertiser/adList/input-interests-ad/input-interests-ad.component.ts b/src/app/advertiser/adList/input-interests-ad/input-interests-ad.component.ts deleted file mode 100644 index 617cc43..0000000 --- a/src/app/advertiser/adList/input-interests-ad/input-interests-ad.component.ts +++ /dev/null @@ -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; - @Input() myInterests: string[] = []; - allInterests: string[] = []; - @Output() eventEmitter = new EventEmitter(); - @ViewChild('tagInput') tagInput: ElementRef; - 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)); - } - -} diff --git a/src/app/advertiser/adList/page-ad-list-advertiser/page-ad-list-advertiser.component.html b/src/app/advertiser/adList/page-ad-list-advertiser/page-ad-list-advertiser.component.html deleted file mode 100644 index 78dd263..0000000 --- a/src/app/advertiser/adList/page-ad-list-advertiser/page-ad-list-advertiser.component.html +++ /dev/null @@ -1,185 +0,0 @@ -
-
- - - -

- - - - - - -
- - -
-
- - -
- Filtre -
- - - - -
- -
- - -
- - - -
- visible
- non visible -
- - - -
- - Sujets - - - {{formControlInterests.value ? formControlInterests.value[0] : ''}} - - (+{{formControlInterests.value.length - 1}} {{formControlInterests.value?.length === 2 ? 'autre' : 'autres'}}) - - - {{topping}} - - - -
- - - -
- Période de création:   - - Date de début - - -   -   - - Date de fin - - -
- -
- -
-
- - -
- -
- -
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- power_settings_new - - - Titre - {{advert.title}} - Sujets - - {{interest}}, - {{interest}} - - Date de création - {{ advert.createdAt | date:'dd/LL/YYYY à HH:mm:ss' }} - Dernière modification - {{ advert.updatedAt | date:'dd/LL/YYYY à HH:mm:ss' }} - Vues - {{advert.countViews}} - Actions - - - -
Aucune vidéo ne correspond au filtre: "{{input.value}}"
-
- -
-

- -
-
diff --git a/src/app/advertiser/adList/page-ad-list-advertiser/page-ad-list-advertiser.component.scss b/src/app/advertiser/adList/page-ad-list-advertiser/page-ad-list-advertiser.component.scss deleted file mode 100644 index 370e312..0000000 --- a/src/app/advertiser/adList/page-ad-list-advertiser/page-ad-list-advertiser.component.scss +++ /dev/null @@ -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; -} diff --git a/src/app/advertiser/adList/page-ad-list-advertiser/page-ad-list-advertiser.component.spec.ts b/src/app/advertiser/adList/page-ad-list-advertiser/page-ad-list-advertiser.component.spec.ts deleted file mode 100644 index 9492c6c..0000000 --- a/src/app/advertiser/adList/page-ad-list-advertiser/page-ad-list-advertiser.component.spec.ts +++ /dev/null @@ -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; - - beforeEach(async () => { - await TestBed.configureTestingModule({ - declarations: [ PageAdListAdvertiserComponent ] - }) - .compileComponents(); - }); - - beforeEach(() => { - fixture = TestBed.createComponent(PageAdListAdvertiserComponent); - component = fixture.componentInstance; - fixture.detectChanges(); - }); - - it('should create', () => { - expect(component).toBeTruthy(); - }); -}); diff --git a/src/app/advertiser/adList/page-ad-list-advertiser/page-ad-list-advertiser.component.ts b/src/app/advertiser/adList/page-ad-list-advertiser/page-ad-list-advertiser.component.ts deleted file mode 100644 index 6adf0ed..0000000 --- a/src/app/advertiser/adList/page-ad-list-advertiser/page-ad-list-advertiser.component.ts +++ /dev/null @@ -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(); - 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, - } - } - -} diff --git a/src/app/advertiser/adList/popup-add-or-update-ad/popup-add-or-update-ad.component.html b/src/app/advertiser/adList/popup-add-or-update-ad/popup-add-or-update-ad.component.html deleted file mode 100644 index e3b7986..0000000 --- a/src/app/advertiser/adList/popup-add-or-update-ad/popup-add-or-update-ad.component.html +++ /dev/null @@ -1,83 +0,0 @@ -
-
- - -

{{title}}

- - -
- - - -
- - -
- - - - Titre annonce - - - - - - - - - Commentaire - -
- - - - URL - -
- - - Visible

- - -
-
- Images déjà associées: -
-
-
- - {{image.description}} - - -
-
-
- -
- - -
- -
- -
- - -
- - -
- {{errorMessage}} -
- - - - - - - - -
-
diff --git a/src/app/advertiser/adList/popup-add-or-update-ad/popup-add-or-update-ad.component.scss b/src/app/advertiser/adList/popup-add-or-update-ad/popup-add-or-update-ad.component.scss deleted file mode 100644 index 3bb2eed..0000000 --- a/src/app/advertiser/adList/popup-add-or-update-ad/popup-add-or-update-ad.component.scss +++ /dev/null @@ -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; -} diff --git a/src/app/advertiser/adList/popup-add-or-update-ad/popup-add-or-update-ad.component.spec.ts b/src/app/advertiser/adList/popup-add-or-update-ad/popup-add-or-update-ad.component.spec.ts deleted file mode 100644 index ba74952..0000000 --- a/src/app/advertiser/adList/popup-add-or-update-ad/popup-add-or-update-ad.component.spec.ts +++ /dev/null @@ -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; - - beforeEach(async () => { - await TestBed.configureTestingModule({ - declarations: [ PopupAddOrUpdateAdComponent ] - }) - .compileComponents(); - }); - - beforeEach(() => { - fixture = TestBed.createComponent(PopupAddOrUpdateAdComponent); - component = fixture.componentInstance; - fixture.detectChanges(); - }); - - it('should create', () => { - expect(component).toBeTruthy(); - }); -}); diff --git a/src/app/advertiser/adList/popup-add-or-update-ad/popup-add-or-update-ad.component.ts b/src/app/advertiser/adList/popup-add-or-update-ad/popup-add-or-update-ad.component.ts deleted file mode 100644 index 32831f9..0000000 --- a/src/app/advertiser/adList/popup-add-or-update-ad/popup-add-or-update-ad.component.ts +++ /dev/null @@ -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, - @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 - Êtes-vous sûr de vouloir supprimer l'annonce {{advert.title}} ? - - - - - - diff --git a/src/app/advertiser/adList/popup-delete-ad-advertiser/popup-delete-ad-advertiser.component.scss b/src/app/advertiser/adList/popup-delete-ad-advertiser/popup-delete-ad-advertiser.component.scss deleted file mode 100644 index e69de29..0000000 diff --git a/src/app/advertiser/adList/popup-delete-ad-advertiser/popup-delete-ad-advertiser.component.spec.ts b/src/app/advertiser/adList/popup-delete-ad-advertiser/popup-delete-ad-advertiser.component.spec.ts deleted file mode 100644 index 632a177..0000000 --- a/src/app/advertiser/adList/popup-delete-ad-advertiser/popup-delete-ad-advertiser.component.spec.ts +++ /dev/null @@ -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; - - beforeEach(async () => { - await TestBed.configureTestingModule({ - declarations: [ PopupDeleteAdAdvertiserComponent ] - }) - .compileComponents(); - }); - - beforeEach(() => { - fixture = TestBed.createComponent(PopupDeleteAdAdvertiserComponent); - component = fixture.componentInstance; - fixture.detectChanges(); - }); - - it('should create', () => { - expect(component).toBeTruthy(); - }); -}); diff --git a/src/app/advertiser/adList/popup-delete-ad-advertiser/popup-delete-ad-advertiser.component.ts b/src/app/advertiser/adList/popup-delete-ad-advertiser/popup-delete-ad-advertiser.component.ts deleted file mode 100644 index 1de96ef..0000000 --- a/src/app/advertiser/adList/popup-delete-ad-advertiser/popup-delete-ad-advertiser.component.ts +++ /dev/null @@ -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, - @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); - } - } - -} diff --git a/src/app/advertiser/adList/popup-visualize-ad-advertiser/popup-visualize-ad-advertiser.component.html b/src/app/advertiser/adList/popup-visualize-ad-advertiser/popup-visualize-ad-advertiser.component.html deleted file mode 100644 index a768258..0000000 --- a/src/app/advertiser/adList/popup-visualize-ad-advertiser/popup-visualize-ad-advertiser.component.html +++ /dev/null @@ -1,71 +0,0 @@ -
- -

{{advert.title}}

- - - - - - - -
-
Images:
-
-
{{image.url}}
-
-
- - -
-
Centre d'intérêt :
-
-
• {{tag}}
-
-
- - -
-
Commentaire:
-
{{advert.comment}}
-
- - -
- -
{{advert.views}}
-
- - -
- -
- {{ advert.createdAt | date:'dd/LL/YYYY à HH:mm:ss' }} -
-
- - -
- -
- {{ advert.updatedAt | date:'dd/LL/YYYY à HH:mm:ss' }} -
-
- - -
- -
- checked - close -
-
- -
- - - - - - - -
diff --git a/src/app/advertiser/adList/popup-visualize-ad-advertiser/popup-visualize-ad-advertiser.component.scss b/src/app/advertiser/adList/popup-visualize-ad-advertiser/popup-visualize-ad-advertiser.component.scss deleted file mode 100644 index 3e00dee..0000000 --- a/src/app/advertiser/adList/popup-visualize-ad-advertiser/popup-visualize-ad-advertiser.component.scss +++ /dev/null @@ -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; -} diff --git a/src/app/advertiser/adList/popup-visualize-ad-advertiser/popup-visualize-ad-advertiser.component.spec.ts b/src/app/advertiser/adList/popup-visualize-ad-advertiser/popup-visualize-ad-advertiser.component.spec.ts deleted file mode 100644 index 56aedbc..0000000 --- a/src/app/advertiser/adList/popup-visualize-ad-advertiser/popup-visualize-ad-advertiser.component.spec.ts +++ /dev/null @@ -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; - - beforeEach(async () => { - await TestBed.configureTestingModule({ - declarations: [ PopupVisualizeAdAdvertiserComponent ] - }) - .compileComponents(); - }); - - beforeEach(() => { - fixture = TestBed.createComponent(PopupVisualizeAdAdvertiserComponent); - component = fixture.componentInstance; - fixture.detectChanges(); - }); - - it('should create', () => { - expect(component).toBeTruthy(); - }); -}); diff --git a/src/app/advertiser/adList/popup-visualize-ad-advertiser/popup-visualize-ad-advertiser.component.ts b/src/app/advertiser/adList/popup-visualize-ad-advertiser/popup-visualize-ad-advertiser.component.ts deleted file mode 100644 index 1e65834..0000000 --- a/src/app/advertiser/adList/popup-visualize-ad-advertiser/popup-visualize-ad-advertiser.component.ts +++ /dev/null @@ -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, - @Inject(MAT_DIALOG_DATA) public data, - public themeService: ThemeService, - public dialog: MatDialog ) { } - - ngOnInit(): void - { - this.advert = this.data.advert; - } - -} diff --git a/src/app/advertiser/adList/popup-visualize-images-advertiser/popup-visualize-images-advertiser.component.html b/src/app/advertiser/adList/popup-visualize-images-advertiser/popup-visualize-images-advertiser.component.html deleted file mode 100644 index dfbc2fe..0000000 --- a/src/app/advertiser/adList/popup-visualize-images-advertiser/popup-visualize-images-advertiser.component.html +++ /dev/null @@ -1,20 +0,0 @@ -
-

- -
- - - - - - - - - - - - - - diff --git a/src/app/advertiser/adList/popup-visualize-images-advertiser/popup-visualize-images-advertiser.component.scss b/src/app/advertiser/adList/popup-visualize-images-advertiser/popup-visualize-images-advertiser.component.scss deleted file mode 100644 index eb60d48..0000000 --- a/src/app/advertiser/adList/popup-visualize-images-advertiser/popup-visualize-images-advertiser.component.scss +++ /dev/null @@ -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; -} diff --git a/src/app/advertiser/adList/popup-visualize-images-advertiser/popup-visualize-images-advertiser.component.spec.ts b/src/app/advertiser/adList/popup-visualize-images-advertiser/popup-visualize-images-advertiser.component.spec.ts deleted file mode 100644 index 25da0db..0000000 --- a/src/app/advertiser/adList/popup-visualize-images-advertiser/popup-visualize-images-advertiser.component.spec.ts +++ /dev/null @@ -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; - - beforeEach(async () => { - await TestBed.configureTestingModule({ - declarations: [ PopupVisualizeImagesAdvertiserComponent ] - }) - .compileComponents(); - }); - - beforeEach(() => { - fixture = TestBed.createComponent(PopupVisualizeImagesAdvertiserComponent); - component = fixture.componentInstance; - fixture.detectChanges(); - }); - - it('should create', () => { - expect(component).toBeTruthy(); - }); -}); diff --git a/src/app/advertiser/adList/popup-visualize-images-advertiser/popup-visualize-images-advertiser.component.ts b/src/app/advertiser/adList/popup-visualize-images-advertiser/popup-visualize-images-advertiser.component.ts deleted file mode 100644 index 59e7c3d..0000000 --- a/src/app/advertiser/adList/popup-visualize-images-advertiser/popup-visualize-images-advertiser.component.ts +++ /dev/null @@ -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, - @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; - } - -} diff --git a/src/app/advertiser/myProfil/page-profil-advertiser/page-profil-advertiser.component.html b/src/app/advertiser/myProfil/page-profil-advertiser/page-profil-advertiser.component.html deleted file mode 100644 index 9af3317..0000000 --- a/src/app/advertiser/myProfil/page-profil-advertiser/page-profil-advertiser.component.html +++ /dev/null @@ -1,49 +0,0 @@ -
-
- - - - - -
- - -
- -
- - -
-
Entreprise:
-
{{advertiser.company}}
-
- - -
-
Pseudo:
-
{{advertiser.login}}
-
- - -
-
Mail:
-
{{advertiser.email}}
-
- - -
-
Date de création:
-
{{advertiser.createdAt | date:'dd/LL/YYYY'}}
-
- - -
- -
- -
- - -
-
diff --git a/src/app/advertiser/myProfil/page-profil-advertiser/page-profil-advertiser.component.scss b/src/app/advertiser/myProfil/page-profil-advertiser/page-profil-advertiser.component.scss deleted file mode 100644 index 966c9a2..0000000 --- a/src/app/advertiser/myProfil/page-profil-advertiser/page-profil-advertiser.component.scss +++ /dev/null @@ -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; -} diff --git a/src/app/advertiser/myProfil/page-profil-advertiser/page-profil-advertiser.component.spec.ts b/src/app/advertiser/myProfil/page-profil-advertiser/page-profil-advertiser.component.spec.ts deleted file mode 100644 index ebb9617..0000000 --- a/src/app/advertiser/myProfil/page-profil-advertiser/page-profil-advertiser.component.spec.ts +++ /dev/null @@ -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; - - beforeEach(async () => { - await TestBed.configureTestingModule({ - declarations: [ PageProfilAdvertiserComponent ] - }) - .compileComponents(); - }); - - beforeEach(() => { - fixture = TestBed.createComponent(PageProfilAdvertiserComponent); - component = fixture.componentInstance; - fixture.detectChanges(); - }); - - it('should create', () => { - expect(component).toBeTruthy(); - }); -}); diff --git a/src/app/advertiser/myProfil/page-profil-advertiser/page-profil-advertiser.component.ts b/src/app/advertiser/myProfil/page-profil-advertiser/page-profil-advertiser.component.ts deleted file mode 100644 index de60d59..0000000 --- a/src/app/advertiser/myProfil/page-profil-advertiser/page-profil-advertiser.component.ts +++ /dev/null @@ -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; - } - }); - } - -} diff --git a/src/app/advertiser/myProfil/popup-update-advertiser/popup-update-advertiser.component.html b/src/app/advertiser/myProfil/popup-update-advertiser/popup-update-advertiser.component.html deleted file mode 100644 index 4951e5c..0000000 --- a/src/app/advertiser/myProfil/popup-update-advertiser/popup-update-advertiser.component.html +++ /dev/null @@ -1,65 +0,0 @@ -
-
- - -
-
- -
- - -

- - - - Entreprise - -
- - - - Pseudo - -
- - -
- - -
- Modifier mot de passe: - -
- - -
- - - Nouveau mot de passe - - -
- - - Confirmation nouveau mot de passe - - -
-

- - -
- - -
- {{errorMessage}} -
- - -
- - -
- -
-
diff --git a/src/app/advertiser/myProfil/popup-update-advertiser/popup-update-advertiser.component.scss b/src/app/advertiser/myProfil/popup-update-advertiser/popup-update-advertiser.component.scss deleted file mode 100644 index 1968e90..0000000 --- a/src/app/advertiser/myProfil/popup-update-advertiser/popup-update-advertiser.component.scss +++ /dev/null @@ -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; -} diff --git a/src/app/advertiser/myProfil/popup-update-advertiser/popup-update-advertiser.component.spec.ts b/src/app/advertiser/myProfil/popup-update-advertiser/popup-update-advertiser.component.spec.ts deleted file mode 100644 index dde7ef9..0000000 --- a/src/app/advertiser/myProfil/popup-update-advertiser/popup-update-advertiser.component.spec.ts +++ /dev/null @@ -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; - - beforeEach(async () => { - await TestBed.configureTestingModule({ - declarations: [ PopupUpdateAdvertiserComponent ] - }) - .compileComponents(); - }); - - beforeEach(() => { - fixture = TestBed.createComponent(PopupUpdateAdvertiserComponent); - component = fixture.componentInstance; - fixture.detectChanges(); - }); - - it('should create', () => { - expect(component).toBeTruthy(); - }); -}); diff --git a/src/app/advertiser/myProfil/popup-update-advertiser/popup-update-advertiser.component.ts b/src/app/advertiser/myProfil/popup-update-advertiser/popup-update-advertiser.component.ts deleted file mode 100644 index 8d4de8a..0000000 --- a/src/app/advertiser/myProfil/popup-update-advertiser/popup-update-advertiser.component.ts +++ /dev/null @@ -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, - @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); - } - -} diff --git a/src/app/advertiser/pages-popularity/pages-popularity.component.html b/src/app/advertiser/pages-popularity/pages-popularity.component.html deleted file mode 100644 index 62ae0e1..0000000 --- a/src/app/advertiser/pages-popularity/pages-popularity.component.html +++ /dev/null @@ -1,94 +0,0 @@ -
-
- - - - - - - - -
- -
Filtre
- -
- -
- -

- -
- -
- -
- - - - -
- - -
- - -
-
- - - - - - - - - début - - -   -   - - - - fin - - -   -   - - - - pas d'affichage - - -   -   - - - - unité du pas d'affichage - - jour - semaine - mois - -
- - - - - - - {{coupleNameViews.name}}, - - - {{coupleNameViews.name}} - - - - -
diff --git a/src/app/advertiser/pages-popularity/pages-popularity.component.scss b/src/app/advertiser/pages-popularity/pages-popularity.component.scss deleted file mode 100644 index 00fb9e3..0000000 --- a/src/app/advertiser/pages-popularity/pages-popularity.component.scss +++ /dev/null @@ -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; -} diff --git a/src/app/advertiser/pages-popularity/pages-popularity.component.spec.ts b/src/app/advertiser/pages-popularity/pages-popularity.component.spec.ts deleted file mode 100644 index f9ff236..0000000 --- a/src/app/advertiser/pages-popularity/pages-popularity.component.spec.ts +++ /dev/null @@ -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; - - beforeEach(async () => { - await TestBed.configureTestingModule({ - declarations: [ PagesPopularityComponent ] - }) - .compileComponents(); - }); - - beforeEach(() => { - fixture = TestBed.createComponent(PagesPopularityComponent); - component = fixture.componentInstance; - fixture.detectChanges(); - }); - - it('should create', () => { - expect(component).toBeTruthy(); - }); -}); diff --git a/src/app/advertiser/pages-popularity/pages-popularity.component.ts b/src/app/advertiser/pages-popularity/pages-popularity.component.ts deleted file mode 100644 index 991b8fa..0000000 --- a/src/app/advertiser/pages-popularity/pages-popularity.component.ts +++ /dev/null @@ -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 = 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 (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([]); - } - -} diff --git a/src/app/advertiser/utils/dragAndDrop/drag-and-drop.directive.spec.ts b/src/app/advertiser/utils/dragAndDrop/drag-and-drop.directive.spec.ts deleted file mode 100644 index 60cf3d6..0000000 --- a/src/app/advertiser/utils/dragAndDrop/drag-and-drop.directive.spec.ts +++ /dev/null @@ -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(); - }); -}); diff --git a/src/app/advertiser/utils/dragAndDrop/drag-and-drop.directive.ts b/src/app/advertiser/utils/dragAndDrop/drag-and-drop.directive.ts deleted file mode 100644 index b3d1162..0000000 --- a/src/app/advertiser/utils/dragAndDrop/drag-and-drop.directive.ts +++ /dev/null @@ -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(); - - // 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); - } - } - -} diff --git a/src/app/advertiser/utils/navbar-advertiser/navbar-advertiser.component.html b/src/app/advertiser/utils/navbar-advertiser/navbar-advertiser.component.html deleted file mode 100644 index da5e898..0000000 --- a/src/app/advertiser/utils/navbar-advertiser/navbar-advertiser.component.html +++ /dev/null @@ -1,41 +0,0 @@ - diff --git a/src/app/advertiser/utils/navbar-advertiser/navbar-advertiser.component.scss b/src/app/advertiser/utils/navbar-advertiser/navbar-advertiser.component.scss deleted file mode 100644 index 285d629..0000000 --- a/src/app/advertiser/utils/navbar-advertiser/navbar-advertiser.component.scss +++ /dev/null @@ -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; -} diff --git a/src/app/advertiser/utils/navbar-advertiser/navbar-advertiser.component.spec.ts b/src/app/advertiser/utils/navbar-advertiser/navbar-advertiser.component.spec.ts deleted file mode 100644 index fb00a09..0000000 --- a/src/app/advertiser/utils/navbar-advertiser/navbar-advertiser.component.spec.ts +++ /dev/null @@ -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; - - beforeEach(async () => { - await TestBed.configureTestingModule({ - declarations: [ NavbarAdvertiserComponent ] - }) - .compileComponents(); - }); - - beforeEach(() => { - fixture = TestBed.createComponent(NavbarAdvertiserComponent); - component = fixture.componentInstance; - fixture.detectChanges(); - }); - - it('should create', () => { - expect(component).toBeTruthy(); - }); -}); diff --git a/src/app/advertiser/utils/navbar-advertiser/navbar-advertiser.component.ts b/src/app/advertiser/utils/navbar-advertiser/navbar-advertiser.component.ts deleted file mode 100644 index 7f403db..0000000 --- a/src/app/advertiser/utils/navbar-advertiser/navbar-advertiser.component.ts +++ /dev/null @@ -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); - } - -} diff --git a/src/app/app-routing.module.ts b/src/app/app-routing.module.ts deleted file mode 100644 index df9fee2..0000000 --- a/src/app/app-routing.module.ts +++ /dev/null @@ -1,53 +0,0 @@ -import { NgModule } from '@angular/core'; -import { RouterModule, Routes } from '@angular/router'; -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 {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"; - - -const routes: Routes = [ - - // Before connexion - { path: '', component: PageLoginComponent }, - { 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 }, - -]; - - -@NgModule({ - imports: [RouterModule.forRoot(routes)], - exports: [RouterModule] -}) -export class AppRoutingModule { } diff --git a/src/app/app.component.html b/src/app/app.component.html deleted file mode 100644 index 0680b43..0000000 --- a/src/app/app.component.html +++ /dev/null @@ -1 +0,0 @@ - diff --git a/src/app/app.component.scss b/src/app/app.component.scss deleted file mode 100644 index 22a5665..0000000 --- a/src/app/app.component.scss +++ /dev/null @@ -1,24 +0,0 @@ -::ng-deep snack-bar-container.custom-class { - //background: yellow; -} -::ng-deep .custom-class .mat-simple-snackbar { - //color: green; - justify-content: center; -} - - -// 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 { - border: solid 1px black !important; - background-color: white !important; -} diff --git a/src/app/app.component.spec.ts b/src/app/app.component.spec.ts deleted file mode 100644 index 04c26ec..0000000 --- a/src/app/app.component.spec.ts +++ /dev/null @@ -1,35 +0,0 @@ -import { TestBed } from '@angular/core/testing'; -import { RouterTestingModule } from '@angular/router/testing'; -import { AppComponent } from './app.component'; - -describe('AppComponent', () => { - beforeEach(async () => { - await TestBed.configureTestingModule({ - imports: [ - RouterTestingModule - ], - declarations: [ - AppComponent - ], - }).compileComponents(); - }); - - it('should create the app', () => { - const fixture = TestBed.createComponent(AppComponent); - const app = fixture.componentInstance; - expect(app).toBeTruthy(); - }); - - it(`should have as title 'frontend'`, () => { - const fixture = TestBed.createComponent(AppComponent); - const app = fixture.componentInstance; - expect(app.title).toEqual('frontend'); - }); - - it('should render title', () => { - const fixture = TestBed.createComponent(AppComponent); - fixture.detectChanges(); - const compiled = fixture.nativeElement; - expect(compiled.querySelector('.content span').textContent).toContain('frontend app is running!'); - }); -}); diff --git a/src/app/app.component.ts b/src/app/app.component.ts deleted file mode 100644 index 2cc7859..0000000 --- a/src/app/app.component.ts +++ /dev/null @@ -1,12 +0,0 @@ -import { Component } from '@angular/core'; - -@Component({ - selector: 'app-root', - templateUrl: './app.component.html', - styleUrls: ['./app.component.scss'] -}) -export class AppComponent { - title = 'frontend'; - - themeIsLight = true; -} diff --git a/src/app/app.module.ts b/src/app/app.module.ts deleted file mode 100644 index 133f928..0000000 --- a/src/app/app.module.ts +++ /dev/null @@ -1,157 +0,0 @@ -import { NgModule } from '@angular/core'; -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 {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 {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 { 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 { 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 {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'; - - -@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, - ], - imports: [ - BrowserModule, - AppRoutingModule, - BrowserAnimationsModule, - MatSlideToggleModule, - FormsModule, - HttpClientModule, - MatDialogModule, - MatButtonModule, - MatIconModule, - MatInputModule, - MatDividerModule, - MatCheckboxModule, - MatFormFieldModule, - MatSnackBarModule, - MatGridListModule, - MatTableModule, - NgbModule, - MatSortModule, - MatChipsModule, - ReactiveFormsModule, - MatAutocompleteModule, - MatSelectModule, - IvyCarouselModule, - MatRadioModule, - MatStepperModule, - MatPaginatorModule, - MatDatepickerModule, - ChartsModule - ], - providers: [], - bootstrap: [AppComponent] -}) -export class AppModule { } diff --git a/src/app/beforeConnexion/login/page-login/page-login.component.html b/src/app/beforeConnexion/login/page-login/page-login.component.html deleted file mode 100644 index 675270e..0000000 --- a/src/app/beforeConnexion/login/page-login/page-login.component.html +++ /dev/null @@ -1,36 +0,0 @@ -
-
- - - -
-
- - -
-

StreamNotFound

- User Icon -
- - -
- - - -
- {{errorMessage}} -
- -
- - - - -
-
- - -
-
diff --git a/src/app/beforeConnexion/login/page-login/page-login.component.scss b/src/app/beforeConnexion/login/page-login/page-login.component.scss deleted file mode 100644 index 8924202..0000000 --- a/src/app/beforeConnexion/login/page-login/page-login.component.scss +++ /dev/null @@ -1,271 +0,0 @@ -html { - background-color: #56baed; -} - -body { - font-family: "Poppins", sans-serif; - height: 100vh; -} - -a { - color: #5E89FF; - display:inline-block; - text-decoration: none; - font-weight: 400; -} - -h2 { - text-align: center; - font-size: 16px; - font-weight: 600; - text-transform: uppercase; - display:inline-block; - margin: 40px 8px 10px 8px; - color: #cccccc; -} - - - -/* STRUCTURE */ - -.wrapper { - display: flex; - align-items: center; - flex-direction: column; - justify-content: center; - width: 100%; - min-height: 80%; - padding: 20px; -} - -#formContent { - -webkit-border-radius: 10px 10px 10px 10px; - border-radius: 10px 10px 10px 10px; - background: #fff; - padding: 30px; - width: 90%; - max-width: 450px; - position: relative; - padding: 0px; - -webkit-box-shadow: 0 30px 60px 0 rgba(0,0,0,0.3); - box-shadow: 0 30px 60px 0 rgba(0,0,0,0.3); - text-align: center; -} - -#formFooter { - background-color: #f6f6f6; - border-top: 1px solid #dce8f1; - padding: 25px; - text-align: center; - -webkit-border-radius: 0 0 10px 10px; - border-radius: 0 0 10px 10px; -} - - - -/* TABS */ - -h2.inactive { - color: #cccccc; -} - -h2.active { - color: #0d0d0d; - border-bottom: 2px solid #5fbae9; -} - - - -/* FORM TYPOGRAPHY*/ - -input[type=button], input[type=submit], input[type=reset] { - background-color: #5E89FF; - border: none; - color: white; - padding: 15px 80px; - text-align: center; - text-decoration: none; - display: inline-block; - text-transform: uppercase; - font-size: 13px; - -webkit-box-shadow: 0 10px 30px 0 rgba(95,186,233,0.4); - box-shadow: 0 10px 30px 0 rgba(95,186,233,0.4); - -webkit-border-radius: 5px 5px 5px 5px; - border-radius: 5px 5px 5px 5px; - margin: 5px 20px 40px 20px; - -webkit-transition: all 0.3s ease-in-out; - -moz-transition: all 0.3s ease-in-out; - -ms-transition: all 0.3s ease-in-out; - -o-transition: all 0.3s ease-in-out; - transition: all 0.3s ease-in-out; -} - -input[type=button]:hover, input[type=submit]:hover, input[type=reset]:hover { - background-color: #39ace7; -} - -input[type=button]:active, input[type=submit]:active, input[type=reset]:active { - -moz-transform: scale(0.95); - -webkit-transform: scale(0.95); - -o-transform: scale(0.95); - -ms-transform: scale(0.95); - transform: scale(0.95); -} - -input[type=text], input[type=password] { - background-color: #f6f6f6; - border: none; - color: #0d0d0d; - padding: 15px 32px; - text-align: center; - text-decoration: none; - display: inline-block; - font-size: 16px; - margin: 5px; - width: 85%; - border: 2px solid #f6f6f6; - -webkit-transition: all 0.5s ease-in-out; - -moz-transition: all 0.5s ease-in-out; - -ms-transition: all 0.5s ease-in-out; - -o-transition: all 0.5s ease-in-out; - transition: all 0.5s ease-in-out; - -webkit-border-radius: 5px 5px 5px 5px; - border-radius: 5px 5px 5px 5px; -} - - - -input[type=text]:focus, input[type=password]:focus { - background-color: #fff; - border-bottom: 2px solid #5fbae9; -} - -input[type=text]::placeholder, input[type=password]::placeholder { - color: #cccccc; -} - -.bg{ - margin: 0; - padding: 0; - height: 100vh; - width: 100vw; - overflow-y: hidden; - overflow-x: hidden; -} - -/* ANIMATIONS */ - -/* Simple CSS3 Fade-in-down Animation */ -.fadeInDown { - -webkit-animation-name: fadeInDown; - animation-name: fadeInDown; - -webkit-animation-duration: 1s; - animation-duration: 1s; - -webkit-animation-fill-mode: both; - animation-fill-mode: both; -} - -@-webkit-keyframes fadeInDown { - 0% { - opacity: 0; - -webkit-transform: translate3d(0, -100%, 0); - transform: translate3d(0, -100%, 0); - } - 100% { - opacity: 1; - -webkit-transform: none; - transform: none; - } -} - -@keyframes fadeInDown { - 0% { - opacity: 0; - -webkit-transform: translate3d(0, -100%, 0); - transform: translate3d(0, -100%, 0); - } - 100% { - opacity: 1; - -webkit-transform: none; - transform: none; - } -} - -/* Simple CSS3 Fade-in Animation */ -@-webkit-keyframes fadeIn { from { opacity:0; } to { opacity:1; } } -@-moz-keyframes fadeIn { from { opacity:0; } to { opacity:1; } } -@keyframes fadeIn { from { opacity:0; } to { opacity:1; } } - -.fadeIn { - opacity:0; - -webkit-animation:fadeIn ease-in 1; - -moz-animation:fadeIn ease-in 1; - animation:fadeIn ease-in 1; - - -webkit-animation-fill-mode:forwards; - -moz-animation-fill-mode:forwards; - animation-fill-mode:forwards; - - -webkit-animation-duration:1s; - -moz-animation-duration:1s; - animation-duration:1s; -} - -.fadeIn.first { - -webkit-animation-delay: 0.4s; - -moz-animation-delay: 0.4s; - animation-delay: 0.4s; -} - -.fadeIn.second { - -webkit-animation-delay: 0.6s; - -moz-animation-delay: 0.6s; - animation-delay: 0.6s; -} - -.fadeIn.third { - -webkit-animation-delay: 0.8s; - -moz-animation-delay: 0.8s; - animation-delay: 0.8s; -} - -.fadeIn.fourth { - -webkit-animation-delay: 1s; - -moz-animation-delay: 1s; - animation-delay: 1s; -} - -/* Simple CSS3 Fade-in Animation */ -.underlineHover:after { - display: block; - left: 0; - bottom: -10px; - width: 0; - height: 2px; - //background-color: #5E89FF; - background-color: #5E89FF; - content: ""; - transition: width 0.2s; -} - -.underlineHover:hover { - color: #0d0d0d; -} - -.underlineHover:hover:after{ - width: 100%; -} - -h1{ - color: black; -} - -/* OTHERS */ - -*:focus { - outline: none; -} - -#icon { - width:30%; -} diff --git a/src/app/beforeConnexion/login/page-login/page-login.component.spec.ts b/src/app/beforeConnexion/login/page-login/page-login.component.spec.ts deleted file mode 100644 index 5cb4241..0000000 --- a/src/app/beforeConnexion/login/page-login/page-login.component.spec.ts +++ /dev/null @@ -1,25 +0,0 @@ -import { ComponentFixture, TestBed } from '@angular/core/testing'; - -import { PageLoginComponent } from './page-login.component'; - -describe('PageConnexionComponent', () => { - let component: PageLoginComponent; - let fixture: ComponentFixture; - - beforeEach(async () => { - await TestBed.configureTestingModule({ - declarations: [ PageLoginComponent ] - }) - .compileComponents(); - }); - - beforeEach(() => { - fixture = TestBed.createComponent(PageLoginComponent); - component = fixture.componentInstance; - fixture.detectChanges(); - }); - - it('should create', () => { - expect(component).toBeTruthy(); - }); -}); diff --git a/src/app/beforeConnexion/login/page-login/page-login.component.ts b/src/app/beforeConnexion/login/page-login/page-login.component.ts deleted file mode 100644 index 6ee3e78..0000000 --- a/src/app/beforeConnexion/login/page-login/page-login.component.ts +++ /dev/null @@ -1,101 +0,0 @@ -import {Component, OnInit} from '@angular/core'; -import {MessageService} from "../../../utils/services/message/message.service"; -import {Router} from "@angular/router"; -import {ThemeService} from "../../../utils/services/theme/theme.service"; -import {MatDialog} from "@angular/material/dialog"; -import {PopupForgottenPasswordComponent} from "../popup-forgotten-password/popup-forgotten-password.component"; -import {MatSnackBar} from "@angular/material/snack-bar"; -import {ProfilService} from "../../../utils/services/profil/profil.service"; - - - -@Component({ - selector: 'app-page-login', - templateUrl: './page-login.component.html', - styleUrls: ['./page-login.component.scss'] -}) -export class PageLoginComponent implements OnInit -{ - email: string = "" ; - password: string = "" ; - hasError: boolean = false; - errorMessage: string = ""; - - - constructor( private messageService: MessageService, - private router: Router, - public themeService: ThemeService, - public dialog: MatDialog, - private snackBar: MatSnackBar, - private profilService: ProfilService) { } - - - ngOnInit(): void {} - - - onSeConnecter(): void - { - this.checkError(); - - if(!this.hasError) - { - let data = { - email: this.email, - hashPass: this.password - }; - this.messageService - .post('user/auth', data) - .subscribe( retour => this.onSeConnecterCallback(retour), err => this.onSeConnecterCallback(err)); - } - } - - - onSeConnecterCallback(retour): void - { - if(retour.status !== "success") { - console.log(retour); - this.errorMessage = retour.error.reason; - this.hasError = true; - } - else { - this.profilService.setId(retour.data.id); - this.profilService.setProfileImageUrl(retour.data.profileImageUrl); - if(retour.data.role.name === "user") this.router.navigateByUrl( '/user/search'); - else if(retour.data.role.name === "advertiser") this.router.navigateByUrl( '/advertiser/adList'); - else if(retour.data.role.name === "admin" || retour.data.role.name === "superAdmin") this.router.navigateByUrl( '/admin/userList'); - } - } - - - onForgottenPassword(): void - { - this.dialog - .open(PopupForgottenPasswordComponent, {width: '30%'}) - .afterClosed() - .subscribe(result => { - if((result !== null) && (result !== undefined)) - { - const config = { duration: 5000, panelClass: "custom-class" }; - this.snackBar.open( "Un mail de réinitialisation de mot de passe vous a été envoyé.", "", config); - } - }); - } - - - checkError(): void - { - if(this.email === "") { - this.errorMessage = "Veuillez remplir le champ email" ; - this.hasError = true; - } - else if(this.password === "") { - this.errorMessage = "Veuillez remplir le champ mot de passe" ; - this.hasError = true; - } - else { - this.errorMessage = "" ; - this.hasError = false; - } - } - -} diff --git a/src/app/beforeConnexion/login/popup-forgotten-password/popup-forgotten-password.component.html b/src/app/beforeConnexion/login/popup-forgotten-password/popup-forgotten-password.component.html deleted file mode 100644 index c34b58e..0000000 --- a/src/app/beforeConnexion/login/popup-forgotten-password/popup-forgotten-password.component.html +++ /dev/null @@ -1,24 +0,0 @@ -

Récupération du mot de passe

- -
- - -
- - Email - - -
- - -
- {{errorMessage}} -
- - - - - - - - diff --git a/src/app/beforeConnexion/login/popup-forgotten-password/popup-forgotten-password.component.scss b/src/app/beforeConnexion/login/popup-forgotten-password/popup-forgotten-password.component.scss deleted file mode 100644 index fa75013..0000000 --- a/src/app/beforeConnexion/login/popup-forgotten-password/popup-forgotten-password.component.scss +++ /dev/null @@ -1,12 +0,0 @@ -h4 { - text-align: center; -} - -.myDiv { - text-align: center; - font-size: small; -} - -.myError { - text-align: center; -} diff --git a/src/app/beforeConnexion/login/popup-forgotten-password/popup-forgotten-password.component.spec.ts b/src/app/beforeConnexion/login/popup-forgotten-password/popup-forgotten-password.component.spec.ts deleted file mode 100644 index ebf101c..0000000 --- a/src/app/beforeConnexion/login/popup-forgotten-password/popup-forgotten-password.component.spec.ts +++ /dev/null @@ -1,25 +0,0 @@ -import { ComponentFixture, TestBed } from '@angular/core/testing'; - -import { PopupForgottenPasswordComponent } from './popup-forgotten-password.component'; - -describe('PopupForgottenPasswordComponent', () => { - let component: PopupForgottenPasswordComponent; - let fixture: ComponentFixture; - - beforeEach(async () => { - await TestBed.configureTestingModule({ - declarations: [ PopupForgottenPasswordComponent ] - }) - .compileComponents(); - }); - - beforeEach(() => { - fixture = TestBed.createComponent(PopupForgottenPasswordComponent); - component = fixture.componentInstance; - fixture.detectChanges(); - }); - - it('should create', () => { - expect(component).toBeTruthy(); - }); -}); diff --git a/src/app/beforeConnexion/login/popup-forgotten-password/popup-forgotten-password.component.ts b/src/app/beforeConnexion/login/popup-forgotten-password/popup-forgotten-password.component.ts deleted file mode 100644 index 1ff70ce..0000000 --- a/src/app/beforeConnexion/login/popup-forgotten-password/popup-forgotten-password.component.ts +++ /dev/null @@ -1,47 +0,0 @@ -import { Component } from '@angular/core'; -import {MatDialogRef} from "@angular/material/dialog"; - - - -@Component({ - selector: 'app-popup-forgotten-password', - templateUrl: './popup-forgotten-password.component.html', - styleUrls: ['./popup-forgotten-password.component.scss'] -}) -export class PopupForgottenPasswordComponent -{ - email: string; - hasError: boolean = false; - errorMessage: string = ""; - - - constructor(public dialogRef: MatDialogRef) {} - - - // Click sur valider - onValidate() - { - if(this.email.length === 0) { - this.errorMessage = "Veuillez remplir le champ 'email'." ; - this.hasError = true; - } - else if(!this.isValidEmail(this.email)) { - this.errorMessage = "Email invalide." ; - this.hasError = true; - } - else { - this.errorMessage = "" ; - this.hasError = false; - this.dialogRef.close(true); - } - } - - - // Indique si email a bien le format d'un email - isValidEmail(email): boolean - { - 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); - } - -} diff --git a/src/app/beforeConnexion/register/input-interests-register/input-interests-register.component.html b/src/app/beforeConnexion/register/input-interests-register/input-interests-register.component.html deleted file mode 100644 index 2a7c484..0000000 --- a/src/app/beforeConnexion/register/input-interests-register/input-interests-register.component.html +++ /dev/null @@ -1,43 +0,0 @@ - - - - - Centres d'intérêt - - - - - - - {{interest}} - - - - - - - - - - - - {{interest}} - - - - - - diff --git a/src/app/beforeConnexion/register/input-interests-register/input-interests-register.component.scss b/src/app/beforeConnexion/register/input-interests-register/input-interests-register.component.scss deleted file mode 100644 index c7acb4b..0000000 --- a/src/app/beforeConnexion/register/input-interests-register/input-interests-register.component.scss +++ /dev/null @@ -1,3 +0,0 @@ -mat-form-field { - width: 100%; -} diff --git a/src/app/beforeConnexion/register/input-interests-register/input-interests-register.component.spec.ts b/src/app/beforeConnexion/register/input-interests-register/input-interests-register.component.spec.ts deleted file mode 100644 index 9917b1a..0000000 --- a/src/app/beforeConnexion/register/input-interests-register/input-interests-register.component.spec.ts +++ /dev/null @@ -1,25 +0,0 @@ -import { ComponentFixture, TestBed } from '@angular/core/testing'; - -import { InputInterestsRegisterComponent } from './input-interests-register.component'; - -describe('InputInterestsRegisterComponent', () => { - let component: InputInterestsRegisterComponent; - let fixture: ComponentFixture; - - beforeEach(async () => { - await TestBed.configureTestingModule({ - declarations: [ InputInterestsRegisterComponent ] - }) - .compileComponents(); - }); - - beforeEach(() => { - fixture = TestBed.createComponent(InputInterestsRegisterComponent); - component = fixture.componentInstance; - fixture.detectChanges(); - }); - - it('should create', () => { - expect(component).toBeTruthy(); - }); -}); diff --git a/src/app/beforeConnexion/register/input-interests-register/input-interests-register.component.ts b/src/app/beforeConnexion/register/input-interests-register/input-interests-register.component.ts deleted file mode 100644 index 537cf45..0000000 --- a/src/app/beforeConnexion/register/input-interests-register/input-interests-register.component.ts +++ /dev/null @@ -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 {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"; - - - -@Component({ - selector: 'app-input-interests-register', - templateUrl: './input-interests-register.component.html', - styleUrls: ['./input-interests-register.component.scss'] -}) -export class InputInterestsRegisterComponent implements OnInit -{ - selectable = true; - removable = true; - separatorKeysCodes: number[] = [ENTER, COMMA]; - formControl = new FormControl(); - filteredInterests: Observable; - @Input() myInterests: string[] = []; - allInterests: string[] = []; - @Output() eventEmitter = new EventEmitter(); - @ViewChild('tagInput') tagInput: ElementRef; - 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)); - } - -} diff --git a/src/app/beforeConnexion/register/page-register/page-register.component.html b/src/app/beforeConnexion/register/page-register/page-register.component.html deleted file mode 100644 index 4d7b629..0000000 --- a/src/app/beforeConnexion/register/page-register/page-register.component.html +++ /dev/null @@ -1,161 +0,0 @@ -
-
- - - - - - - - - -
- - - Utilisateur standard    - Annonceur - - - -
- -
-
-
- - - - -
- - - - -
- {{errorMessage}} -
- - -
- - -
-
-
- -
- -
-
- - - - - - - -
-
- - -
-

Compte

- - - - Pseudo - - -
- - - - Mot de passe - - -
- - - - Confirmation mot de passe - - -
- - -
-

Informations personelles

- - - - Email - - -
- - - - Homme     - Femme - -

- - - - Date de naissance - - - - - -
- -
-
- - - - - - - - - - - Entreprise - - -
- - - - Pseudo - - -
- - - - Email - - -
- - - - Mot de passe - - -
- - - - Confirmation mot de passe - - - -
diff --git a/src/app/beforeConnexion/register/page-register/page-register.component.scss b/src/app/beforeConnexion/register/page-register/page-register.component.scss deleted file mode 100644 index 5f0dc53..0000000 --- a/src/app/beforeConnexion/register/page-register/page-register.component.scss +++ /dev/null @@ -1,47 +0,0 @@ -.myContainer { - width: 100vw; - height: 100vh; -} - - -mat-stepper { - width: 60%; - margin: 10vh auto; - border: solid 1px black; - border-radius: 20px; -} - - -.leftCol { - border-right: solid 1px #dcdcdc; -} - - -.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; -} - - -// ------------------------------------------------------------------------- - - -::ng-deep .mat-radio-inner-circle { - color: black !important; - background-color: black !important; -} - -::ng-deep .mat-radio-outer-circle{ - color: black !important; - border: solid 1px gray !important; -} diff --git a/src/app/beforeConnexion/register/page-register/page-register.component.spec.ts b/src/app/beforeConnexion/register/page-register/page-register.component.spec.ts deleted file mode 100644 index 5cff194..0000000 --- a/src/app/beforeConnexion/register/page-register/page-register.component.spec.ts +++ /dev/null @@ -1,25 +0,0 @@ -import { ComponentFixture, TestBed } from '@angular/core/testing'; - -import { PageRegisterComponent } from './page-register.component'; - -describe('PageRegisterComponent', () => { - let component: PageRegisterComponent; - let fixture: ComponentFixture; - - beforeEach(async () => { - await TestBed.configureTestingModule({ - declarations: [ PageRegisterComponent ] - }) - .compileComponents(); - }); - - beforeEach(() => { - fixture = TestBed.createComponent(PageRegisterComponent); - component = fixture.componentInstance; - fixture.detectChanges(); - }); - - it('should create', () => { - expect(component).toBeTruthy(); - }); -}); diff --git a/src/app/beforeConnexion/register/page-register/page-register.component.ts b/src/app/beforeConnexion/register/page-register/page-register.component.ts deleted file mode 100644 index 833a656..0000000 --- a/src/app/beforeConnexion/register/page-register/page-register.component.ts +++ /dev/null @@ -1,135 +0,0 @@ -import { Component } from '@angular/core'; -import {MessageService} from "../../../utils/services/message/message.service"; -import {Router} from "@angular/router"; -import {MatDialog} from "@angular/material/dialog"; -import {PopupConfirmationComponent} from "../popup-confirmation/popup-confirmation.component"; -import {ThemeService} from "../../../utils/services/theme/theme.service"; -import {User} from "../../../utils/interfaces/user"; - - - -@Component({ - selector: 'app-page-register', - templateUrl: './page-register.component.html', - styleUrls: ['./page-register.component.scss'] -}) -export class PageRegisterComponent -{ - password: string = ""; - confirmPassword: string = ""; - hasError: boolean = false; - errorMessage: string = ""; - user: User = { - _id: "", - login: "", - hashPass: "", - email: "", - role: { - name: "user", - permission: 0, - isAccepted: false, - }, - profileImageUrl: "", - dateOfBirth: null, - gender: "man", - interests: [], - company: "", - isActive: true, - createdAt: new Date(), - updatedAt: new Date(), - lastConnexion: null - }; - - - constructor( private messageService: MessageService, - private router: Router, - public dialog: MatDialog, - public themeService: ThemeService ) { } - - - // Envoie de l'utilisateur au backend - onEnregistrer(): void - { - this.checkField(); - if(!this.hasError) - { - let data: any = Object.assign({}, this.user); - if(this.user.role.name === "user") data.role = "user" ; - else data.role = "advertiser"; - data.hashPass = this.password; - this.messageService - .post('user/create', data) - .subscribe(retour => this.onEnregistrerCallback(retour), err => this.onEnregistrerCallback(err)); - } - } - - - // Gestion de la réponse du backend - onEnregistrerCallback(retour): void - { - if(retour.status !== "success") { - console.log(retour); - } - else - { - const config = { - width: '25%', - data: {roleName: this.user.role.name} - }; - this.dialog - .open(PopupConfirmationComponent, config) - .afterClosed() - .subscribe(result => this.router.navigateByUrl( '/login' )); - } - } - - - // Check les champs saisies par l'utilisateur - checkField(): void - { - if((this.user.role.name === 'advertiser') && (this.user.company.length === 0)) { - this.errorMessage = "Veuillez remplir le champ 'entreprise'."; - this.hasError = true; - } - else if(this.user.login.length === 0) { - this.errorMessage = "Veuillez remplir le champ 'pseudo'."; - this.hasError = true; - } - else if(this.user.email.length === 0) { - this.errorMessage = "Veuillez remplir le champ 'email'."; - this.hasError = true; - } - else if(!this.isValidEmail(this.user.email)) { - this.errorMessage = "Email invalide."; - this.hasError = true; - } - else if(this.password.length === 0) { - this.errorMessage = "Veuillez remplir le champ 'mot de passe'."; - this.hasError = true; - } - else if(this.password !== this.confirmPassword) { - this.errorMessage = "Le mot de passe est différent de sa confirmation."; - this.hasError = true; - } - else { - this.errorMessage = "" ; - this.hasError = false; - } - } - - - // Indique si email a bien le format d'un email - isValidEmail(email): boolean - { - 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); - } - - - // Récupère la liste des centres d'intérets (car celle-ci est remplie à l'aide d'un component intermédiaire) - onEventInputInterests(myInterets: string[]): void - { - this.user.interests = myInterets; - } - -} diff --git a/src/app/beforeConnexion/register/popup-confirmation/popup-confirmation.component.html b/src/app/beforeConnexion/register/popup-confirmation/popup-confirmation.component.html deleted file mode 100644 index 1cd51fe..0000000 --- a/src/app/beforeConnexion/register/popup-confirmation/popup-confirmation.component.html +++ /dev/null @@ -1,11 +0,0 @@ -

- Votre inscription a bien été effectuée. -

- -

- Votre inscription est en cours de validation. -

- -
- -
diff --git a/src/app/beforeConnexion/register/popup-confirmation/popup-confirmation.component.scss b/src/app/beforeConnexion/register/popup-confirmation/popup-confirmation.component.scss deleted file mode 100644 index 85730e0..0000000 --- a/src/app/beforeConnexion/register/popup-confirmation/popup-confirmation.component.scss +++ /dev/null @@ -1,7 +0,0 @@ -p { - font-size: small; -} - -div { - font-size: small; -} diff --git a/src/app/beforeConnexion/register/popup-confirmation/popup-confirmation.component.spec.ts b/src/app/beforeConnexion/register/popup-confirmation/popup-confirmation.component.spec.ts deleted file mode 100644 index d6f9908..0000000 --- a/src/app/beforeConnexion/register/popup-confirmation/popup-confirmation.component.spec.ts +++ /dev/null @@ -1,25 +0,0 @@ -import { ComponentFixture, TestBed } from '@angular/core/testing'; - -import { PopupConfirmationComponent } from './popup-confirmation.component'; - -describe('PopupConfirmationComponent', () => { - let component: PopupConfirmationComponent; - let fixture: ComponentFixture; - - beforeEach(async () => { - await TestBed.configureTestingModule({ - declarations: [ PopupConfirmationComponent ] - }) - .compileComponents(); - }); - - beforeEach(() => { - fixture = TestBed.createComponent(PopupConfirmationComponent); - component = fixture.componentInstance; - fixture.detectChanges(); - }); - - it('should create', () => { - expect(component).toBeTruthy(); - }); -}); diff --git a/src/app/beforeConnexion/register/popup-confirmation/popup-confirmation.component.ts b/src/app/beforeConnexion/register/popup-confirmation/popup-confirmation.component.ts deleted file mode 100644 index 2152f9b..0000000 --- a/src/app/beforeConnexion/register/popup-confirmation/popup-confirmation.component.ts +++ /dev/null @@ -1,15 +0,0 @@ -import {Component, Inject} from '@angular/core'; -import {MAT_DIALOG_DATA, MatDialogRef} from "@angular/material/dialog"; - - - -@Component({ - selector: 'app-popup-confirmation', - templateUrl: './popup-confirmation.component.html', - styleUrls: ['./popup-confirmation.component.scss'] -}) -export class PopupConfirmationComponent -{ - constructor( public dialogRef: MatDialogRef, - @Inject(MAT_DIALOG_DATA) public data) {} -} diff --git a/src/app/beforeConnexion/utils/navbar-before-connexion/navbar-before-connexion.component.html b/src/app/beforeConnexion/utils/navbar-before-connexion/navbar-before-connexion.component.html deleted file mode 100644 index d4ad9f5..0000000 --- a/src/app/beforeConnexion/utils/navbar-before-connexion/navbar-before-connexion.component.html +++ /dev/null @@ -1,40 +0,0 @@ - -
- -
- - - - - - -
- -
diff --git a/src/app/beforeConnexion/utils/navbar-before-connexion/navbar-before-connexion.component.scss b/src/app/beforeConnexion/utils/navbar-before-connexion/navbar-before-connexion.component.scss deleted file mode 100644 index e1fefaa..0000000 --- a/src/app/beforeConnexion/utils/navbar-before-connexion/navbar-before-connexion.component.scss +++ /dev/null @@ -1,79 +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; -} - - -// Recherche, Mes Playlists, Historique -.nav-link { - color: white; -} -.nav-link:hover { - color: grey; -} - - -// Bonton deconnexion -.btnDeconnexion { - font-size: medium; - margin: 0px 10px 0px 10px -} -.btnDeconnexion:hover { - color: grey; -} - - -.monLi { - margin: 0px 10px 0px 10px; -} - - -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; -} diff --git a/src/app/beforeConnexion/utils/navbar-before-connexion/navbar-before-connexion.component.spec.ts b/src/app/beforeConnexion/utils/navbar-before-connexion/navbar-before-connexion.component.spec.ts deleted file mode 100644 index f3f7f27..0000000 --- a/src/app/beforeConnexion/utils/navbar-before-connexion/navbar-before-connexion.component.spec.ts +++ /dev/null @@ -1,25 +0,0 @@ -import { ComponentFixture, TestBed } from '@angular/core/testing'; - -import { NavbarBeforeConnexionComponent } from './navbar-before-connexion.component'; - -describe('NavbarBeforeConnexionComponent', () => { - let component: NavbarBeforeConnexionComponent; - let fixture: ComponentFixture; - - beforeEach(async () => { - await TestBed.configureTestingModule({ - declarations: [ NavbarBeforeConnexionComponent ] - }) - .compileComponents(); - }); - - beforeEach(() => { - fixture = TestBed.createComponent(NavbarBeforeConnexionComponent); - component = fixture.componentInstance; - fixture.detectChanges(); - }); - - it('should create', () => { - expect(component).toBeTruthy(); - }); -}); diff --git a/src/app/beforeConnexion/utils/navbar-before-connexion/navbar-before-connexion.component.ts b/src/app/beforeConnexion/utils/navbar-before-connexion/navbar-before-connexion.component.ts deleted file mode 100644 index 3085e5c..0000000 --- a/src/app/beforeConnexion/utils/navbar-before-connexion/navbar-before-connexion.component.ts +++ /dev/null @@ -1,12 +0,0 @@ -import {Component, Input} from '@angular/core'; - - -@Component({ - selector: 'app-navbar-before-connexion', - templateUrl: './navbar-before-connexion.component.html', - styleUrls: ['./navbar-before-connexion.component.scss'] -}) -export class NavbarBeforeConnexionComponent -{ - @Input() pour = "login"; -} diff --git a/src/app/user/history/page-history-user/page-history-user.component.html b/src/app/user/history/page-history-user/page-history-user.component.html deleted file mode 100644 index 97f7344..0000000 --- a/src/app/user/history/page-history-user/page-history-user.component.html +++ /dev/null @@ -1,70 +0,0 @@ -
-
- - -

- - - -
- -
-
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Aperçu -
- - -
-
Titre {{video.title}} Date - {{video.date | date:'dd/LL/YYYY à HH:mm:ss'}} - Source {{video.source}} Action - -
Aucune vidéo ne correspond au filtre: "{{input.value}}"
-
- -
-

- -
-
diff --git a/src/app/user/history/page-history-user/page-history-user.component.scss b/src/app/user/history/page-history-user/page-history-user.component.scss deleted file mode 100644 index bbd894d..0000000 --- a/src/app/user/history/page-history-user/page-history-user.component.scss +++ /dev/null @@ -1,46 +0,0 @@ -.myContainer { - max-width: 100vw; - height: 100vh; - overflow-x: hidden; -} - -table { - width: 80%; - margin: 0 auto; -} - - -th.mat-sort-header-sorted { - color: black; -} - - -input { - width: 35%; - font-size: large; -} - -// ------------------------------------------------------- - -.imgsContainer { - position: relative; - width: 20vw; - height: 15vh; - cursor: pointer; -} - -.imgPlay { - position: absolute; - margin-left: 9vw; - width: 3vw; - margin-top: 5vh; - height: 6vh; - padding: 0px 0px 0px 0px; -} - -.imgVideo { - border: solid 1px black; - width: 20vw; - height: 15vh; - padding: 0px 0px 0px 0px; -} diff --git a/src/app/user/history/page-history-user/page-history-user.component.spec.ts b/src/app/user/history/page-history-user/page-history-user.component.spec.ts deleted file mode 100644 index 9fd31c3..0000000 --- a/src/app/user/history/page-history-user/page-history-user.component.spec.ts +++ /dev/null @@ -1,25 +0,0 @@ -import { ComponentFixture, TestBed } from '@angular/core/testing'; - -import { PageHistoryUserComponent } from './page-history-user.component'; - -describe('PageHistoriqueComponent', () => { - let component: PageHistoryUserComponent; - let fixture: ComponentFixture; - - beforeEach(async () => { - await TestBed.configureTestingModule({ - declarations: [ PageHistoryUserComponent ] - }) - .compileComponents(); - }); - - beforeEach(() => { - fixture = TestBed.createComponent(PageHistoryUserComponent); - component = fixture.componentInstance; - fixture.detectChanges(); - }); - - it('should create', () => { - expect(component).toBeTruthy(); - }); -}); diff --git a/src/app/user/history/page-history-user/page-history-user.component.ts b/src/app/user/history/page-history-user/page-history-user.component.ts deleted file mode 100644 index 53ec37d..0000000 --- a/src/app/user/history/page-history-user/page-history-user.component.ts +++ /dev/null @@ -1,116 +0,0 @@ -import {AfterViewInit, Component, ViewChild} from '@angular/core'; -import {ThemeService} from "../../../utils/services/theme/theme.service"; -import {MessageService} from "../../../utils/services/message/message.service"; -import {MatTableDataSource} from "@angular/material/table"; -import {MatSort} from "@angular/material/sort"; -import {MatPaginator} from "@angular/material/paginator"; -import {FictitiousVideosService} from "../../../utils/services/fictitiousDatas/fictitiousVideos/fictitious-videos.service"; -import {VideoAll} from "../../../utils/interfaces/video"; -import {Router} from "@angular/router"; - - - -@Component({ - selector: 'app-page-history-user', - templateUrl: './page-history-user.component.html', - styleUrls: ['./page-history-user.component.scss'] -}) -export class PageHistoryUserComponent implements AfterViewInit -{ - displayedColumns: string[] = [ 'aperçu', 'title', 'date', 'source', 'action' ]; - dataSource ; - @ViewChild(MatSort) sort: MatSort; - @ViewChild(MatPaginator) paginator: MatPaginator; - - - constructor( public themeService: ThemeService, - private messageService: MessageService, - private fictitiousVideosService: FictitiousVideosService, - private router: Router ) { } - - - // charge la page - ngAfterViewInit(): void - { - this.messageService - .get("user/history") - .subscribe(ret => this.ngAfterViewInitCallback(ret), err => this.ngAfterViewInitCallback(err)); - } - - - ngAfterViewInitCallback(retour: any): void - { - if(retour.status !== "success") { - console.log(retour); - } - else { - const tabVideoHistory = retour.data.map( video => { - return { - _id: video._id, - videoId: video.videoId, - imageUrl: video.imageUrl, - title: video.title, - date: video.watchedDate, - source: video.source, - } - }); - this.dataSource = new MatTableDataSource(tabVideoHistory); - this.dataSource.sort = this.sort; - this.dataSource.paginator = this.paginator; - this.dataSource = this.dataSource; - } - } - - - // Applique le filtre - applyFilter(event: Event): void - { - const filterValue = (event.target as HTMLInputElement).value; - this.dataSource.filter = filterValue.trim().toLowerCase(); - } - - - // Supprime la video - onDelete(video: any): void - { - this.messageService - .put("video/update/"+video._id, { watchedDates: []}) - .subscribe(ret => this.onDeleteCallback(ret, video), err => this.onDeleteCallback(err, video)) - } - - - onDeleteCallback(retour: any, video: any): void - { - if(retour.status !== "success") { - console.log(retour); - } - else { - const index = this.dataSource.data.indexOf(video); - this.dataSource.data.splice(index, 1); - this.dataSource.data = this.dataSource.data; - this.dataSource = this.dataSource; - } - } - - - onVideo(video: VideoAll): void - { - this.messageService - .put("video/update/"+video._id, {watchedDate: true}) - .subscribe(ret => this.onVideoCallback(ret), err => this.onVideoCallback(err)); - - const params = { - videoId: video.videoId, - source: video.source, - from: "history", - }; - this.router.navigate(['/user/watching'], { queryParams: params }); - } - - - onVideoCallback(retour: any): void - { - if(retour.status !== "success") console.log(retour); - } - -} diff --git a/src/app/user/myPlaylists/page-my-playlists/page-my-playlists.component.html b/src/app/user/myPlaylists/page-my-playlists/page-my-playlists.component.html deleted file mode 100644 index c92a060..0000000 --- a/src/app/user/myPlaylists/page-my-playlists/page-my-playlists.component.html +++ /dev/null @@ -1,35 +0,0 @@ -
-
- - -
- -
-
- - - - - - - - - - - - - - - - - - -
- -
-
- -
- -
-
diff --git a/src/app/user/myPlaylists/page-my-playlists/page-my-playlists.component.scss b/src/app/user/myPlaylists/page-my-playlists/page-my-playlists.component.scss deleted file mode 100644 index fad665f..0000000 --- a/src/app/user/myPlaylists/page-my-playlists/page-my-playlists.component.scss +++ /dev/null @@ -1,48 +0,0 @@ -.lightTheme { - border-color: black; -} -.darkTheme { - border-color: white; -} -.myContainer { - text-align: center; - max-width: 100vw; - height: 100vh; - overflow-x: hidden; -} - -// Liste des vidéos ------------------------------------------------- - -.celluleListeVideo { - margin: 0px 0px 0px 0px; -} - -// Liste des playlists --------------------------------------------- - -.celluleListePlaylist { - margin: 0px 0px 0px 0px; -} - -// Pub ------------------------------------------------------------- - -.cellulePub { - padding: 0px 10px 0px 10px; - width: 100%; - text-align: center; - justify-content: center; -} - -.conteneurPub { - //height: 85vh; - text-align: center; - justify-content: center; - vertical-align: middle; - display: block; - width: 75%; - margin-left: auto; - margin-right: auto; - position: absolute; - top: 50%; - -ms-transform: translateY(-50%); - transform: translateY(-50%); -} diff --git a/src/app/user/myPlaylists/page-my-playlists/page-my-playlists.component.spec.ts b/src/app/user/myPlaylists/page-my-playlists/page-my-playlists.component.spec.ts deleted file mode 100644 index 2dba23b..0000000 --- a/src/app/user/myPlaylists/page-my-playlists/page-my-playlists.component.spec.ts +++ /dev/null @@ -1,25 +0,0 @@ -import { ComponentFixture, TestBed } from '@angular/core/testing'; - -import { PageMyPlaylistsComponent } from './page-my-playlists.component'; - -describe('PageMesPlaylistsComponent', () => { - let component: PageMyPlaylistsComponent; - let fixture: ComponentFixture; - - beforeEach(async () => { - await TestBed.configureTestingModule({ - declarations: [ PageMyPlaylistsComponent ] - }) - .compileComponents(); - }); - - beforeEach(() => { - fixture = TestBed.createComponent(PageMyPlaylistsComponent); - component = fixture.componentInstance; - fixture.detectChanges(); - }); - - it('should create', () => { - expect(component).toBeTruthy(); - }); -}); diff --git a/src/app/user/myPlaylists/page-my-playlists/page-my-playlists.component.ts b/src/app/user/myPlaylists/page-my-playlists/page-my-playlists.component.ts deleted file mode 100644 index 877dde8..0000000 --- a/src/app/user/myPlaylists/page-my-playlists/page-my-playlists.component.ts +++ /dev/null @@ -1,69 +0,0 @@ -import { Component, OnInit } from '@angular/core'; -import {ThemeService} from "../../../utils/services/theme/theme.service"; -import {Advert} from "../../../utils/interfaces/advert"; -import {MessageService} from "../../../utils/services/message/message.service"; -import {HttpParams} from "@angular/common/http"; - - - -@Component({ - selector: 'app-page-my-playlists', - templateUrl: './page-my-playlists.component.html', - styleUrls: ['./page-my-playlists.component.scss'] -}) -export class PageMyPlaylistsComponent implements OnInit -{ - ad: Advert; // pub - playlist: any; // la playlist sélectionnée - - - constructor( public themeService: ThemeService, - private messageService: MessageService ) { } - - - ngOnInit(): void - { - let params = new HttpParams(); - params = params.append("quantity", 1); - this.messageService - .get("user/ad", params) - .subscribe(ret => this.adCallback(ret), err => this.adCallback(err)); - } - - - adCallback(retour: any): void - { - if(retour.status !== "success") { - console.log(retour); - } - else { - this.ad = retour.data[0]; - } - } - - - transmitPlaylistToVideoList(playlist): void - { - if ((playlist === null) || (playlist === undefined)) { - this.playlist = playlist; - } - else { - this.messageService - .get("playlist/findOne/" + playlist.id) - .subscribe(ret => this.afterReceivingPlaylistWithVideo(ret, playlist), err => this.afterReceivingPlaylistWithVideo(err, playlist)); - } - } - - - afterReceivingPlaylistWithVideo(retour: any, playlist): void - { - if(retour.status !== "success") { - console.log(retour); - this.playlist = playlist; - } - else { - this.playlist = retour.data; - } - } - -} diff --git a/src/app/user/myPlaylists/playlist-list/playlist-list.component.html b/src/app/user/myPlaylists/playlist-list/playlist-list.component.html deleted file mode 100644 index 2185a77..0000000 --- a/src/app/user/myPlaylists/playlist-list/playlist-list.component.html +++ /dev/null @@ -1,48 +0,0 @@ -
-
- - -
-
- -
-
- - - - -
-
-
- -
-
- -
-
- {{playlist.name}}
- {{playlist.videoIds.length}} vidéo - {{playlist.videoIds.length}} vidéos -
-
- -
-
- -
-
-
- - - - -
- -
- -
-
diff --git a/src/app/user/myPlaylists/playlist-list/playlist-list.component.scss b/src/app/user/myPlaylists/playlist-list/playlist-list.component.scss deleted file mode 100644 index 0376ee3..0000000 --- a/src/app/user/myPlaylists/playlist-list/playlist-list.component.scss +++ /dev/null @@ -1,94 +0,0 @@ -.myContainer { - background-color: white ; - text-align: center; - width: 35vw; - margin: 1vh 0vh 3vh 0vh; - padding: 0px; - border: solid 2px black; - border-radius: 10px; - box-shadow: 10px 5px 5px black; -} - -// SearchBar ----------------------------------------------------------- - -.searchBarContainer { - text-align: center; - margin: 0px 0px 0px 0px; - padding: 10px 0px 10px 0px; - //background-color: #dcdcdc; - background: linear-gradient(top, rgba(38,38,38,0.8), #e6e6e6 25%, #fff 38%, #c5c5c5 87%, rgba(38,38,38,0.8)); - background: -webkit-linear-gradient(top, #c5c5c5, #e6e6e6 25%, #fff 38%, #c5c5c5 87%, #c5c5c5); - font-size: large; - border-bottom: solid 1px black; - border-top-left-radius: 10px; - border-top-right-radius: 10px; -} - -.inputSearchBar { - width: 70%; - border-radius: 5px; -} - - -// Liste des playlists ------------------------------------------------- - -.playlistListContainer { - max-width: 100%; - height: 60vh; - overflow-y: scroll; - padding: 0px; - overflow-x: hidden; -} - -.playlistContainer { - max-width: 100%; - padding: 0px; - overflow-x: hidden; -} - - -.btnPlaylist { - background-color: white; - padding: 20px; - border-bottom: solid 1px black; - //width: 100%; - width: 35vw; - overflow-x: hidden; -} -.btnPlaylist:hover { - background-color: #f0f0f0; -} - -.btnPlaylistFocus { - background-color: #e6e6e6; -} -.btnPlaylistFocus:hover { - background-color: #e6e6e6; -} - - -.playListCount { - color: gray; - font-style: italic; -} - -// Bouton creer playlist ------------------------------------------------- - -.btnCreerPlaylistContainer { - margin: 0px 0px 0px 0px; - background-color: #dcdcdc; - font-size: large; - border-top: solid 1px black; - border-bottom-left-radius: 10px; - border-bottom-right-radius: 10px; -} - -.btnCreerPlaylist { - margin: 0px 0px 0px 0px; - border-bottom-left-radius: 10px; - border-bottom-right-radius: 10px; - background: linear-gradient(top, rgba(38,38,38,0.8), #e6e6e6 25%, #fff 38%, #c5c5c5 87%, rgba(38,38,38,0.8)); - background: -webkit-linear-gradient(top, #c5c5c5, #e6e6e6 25%, #fff 38%, #c5c5c5 87%, #c5c5c5); - //background: linear-gradient(180deg, #e6e6e6 0%, rgba(0,0,0,0.25) 49%, rgba(38,38,38,0.6) 51%, rgba(0,0,0,0.25) 100%); -} - diff --git a/src/app/user/myPlaylists/playlist-list/playlist-list.component.spec.ts b/src/app/user/myPlaylists/playlist-list/playlist-list.component.spec.ts deleted file mode 100644 index 9308f2c..0000000 --- a/src/app/user/myPlaylists/playlist-list/playlist-list.component.spec.ts +++ /dev/null @@ -1,25 +0,0 @@ -import { ComponentFixture, TestBed } from '@angular/core/testing'; - -import { PlaylistListComponent } from './playlist-list.component'; - -describe('PlaylistListComponent', () => { - let component: PlaylistListComponent; - let fixture: ComponentFixture; - - beforeEach(async () => { - await TestBed.configureTestingModule({ - declarations: [ PlaylistListComponent ] - }) - .compileComponents(); - }); - - beforeEach(() => { - fixture = TestBed.createComponent(PlaylistListComponent); - component = fixture.componentInstance; - fixture.detectChanges(); - }); - - it('should create', () => { - expect(component).toBeTruthy(); - }); -}); diff --git a/src/app/user/myPlaylists/playlist-list/playlist-list.component.ts b/src/app/user/myPlaylists/playlist-list/playlist-list.component.ts deleted file mode 100644 index f97fa1e..0000000 --- a/src/app/user/myPlaylists/playlist-list/playlist-list.component.ts +++ /dev/null @@ -1,164 +0,0 @@ -import {Component, EventEmitter, Input, OnInit, Output} from '@angular/core'; -import {ThemeService} from "../../../utils/services/theme/theme.service"; -import {PlaylistDB} from "../../../utils/interfaces/playlist"; -import {MatDialog} from "@angular/material/dialog"; -import {MatSnackBar} from "@angular/material/snack-bar"; -import {PopupCreateOrUpdatePlaylistComponent} from "../popup-create-or-update-playlist/popup-create-or-update-playlist.component"; -import {FictitiousVideosService} from "../../../utils/services/fictitiousDatas/fictitiousVideos/fictitious-videos.service"; -import {PopupDeletePlaylistComponent} from "../popup-delete-playlist/popup-delete-playlist.component"; -import {MessageService} from "../../../utils/services/message/message.service"; - - - -@Component({ - selector: 'app-playlist-list', - templateUrl: './playlist-list.component.html', - styleUrls: ['./playlist-list.component.scss'] -}) -export class PlaylistListComponent implements OnInit -{ - allPlaylists: PlaylistDB[] = []; // toutes les playlists - @Output() eventEmitter = new EventEmitter(); // pour envoyer au parent la playlist selectionner - search: string = "" ; // contenu de la barre de recherche - tabPlaylist: PlaylistDB[] = []; // playlist affichées - playlistFocusedOn: PlaylistDB; - - - constructor( public themeService: ThemeService, - public dialog: MatDialog, - public snackBar: MatSnackBar, - private fictitiousVideosService: FictitiousVideosService, - private messageService: MessageService ) { } - - - ngOnInit(): void - { - this.messageService - .get("playlist/findAll") - .subscribe( retour => this.ngOnInitCallback(retour), err => this.ngOnInitCallback(err) ); - } - - - ngOnInitCallback(retour: any): void - { - if(retour.status !== "success") { - console.log(retour); - } else { - const aux = retour.data.filter( x => x.isActive === true); - this.allPlaylists = aux.map(x => { - x["_id"] = x.id ; - return x; - }); - this.tabPlaylist = [].concat(this.allPlaylists); - } - } - - - // s'execute lorsqu'on écrit sur la barre de recherche - whileSearch() - { - this.tabPlaylist = []; - for(let playlist of this.allPlaylists) - { - if(playlist.name.includes(this.search)) this.tabPlaylist.push(playlist); - } - } - - - // click sur créer playlist - onCreatePlaylist(): void - { - const config = { - data: { - action: "create", - tabPlaylist: this.tabPlaylist, - } - }; - this.dialog - .open(PopupCreateOrUpdatePlaylistComponent, config ) - .afterClosed() - .subscribe(playlist => { - - const config = { duration: 1500, panelClass: "custom-class" }; - if((playlist === null) || (playlist === undefined)) { - this.snackBar.open("Opération annulée", "", config); - } - else { - playlist["_id"] = playlist.id; - this.allPlaylists.push(playlist); - this.tabPlaylist.push(playlist); - this.snackBar.open(`La playlist '${playlist.name}' a bien été créée ✔`, "", config); - } - }); - } - - - // click sur update playlist - onUpdatePlaylist(playlistToUpdate: PlaylistDB): void - { - const config = { - data: { - action: "update", - tabPlaylist: this.tabPlaylist, - playlistName: playlistToUpdate.name, - playlistId: playlistToUpdate._id - } - }; - this.dialog - .open(PopupCreateOrUpdatePlaylistComponent, config) - .afterClosed() - .subscribe(newName => { - - const config = { duration: 1500, panelClass: "custom-class" }; - if((newName === null) || (newName === undefined)) { - this.snackBar.open("Opération annulée", "", config); - } - else { - let index = this.allPlaylists.findIndex( elt => (elt._id === playlistToUpdate._id)); - this.allPlaylists[index].name = newName; - index = this.tabPlaylist.findIndex( elt => (elt._id === playlistToUpdate._id)); - this.tabPlaylist[index].name = newName; - this.snackBar.open(`La playlist '${playlistToUpdate.name}' a bien été mise à jour ✔`, "", config); - this.eventEmitter.emit(this.tabPlaylist[index]); - this.playlistFocusedOn = this.tabPlaylist[index] - } - }); - } - - - // click sur supprimer playlist - onDeletePlaylist(playlist: PlaylistDB): void - { - const config = {data: playlist}; - this.dialog - .open(PopupDeletePlaylistComponent, config) - .afterClosed() - .subscribe(retour => { - - const config = { duration: 1500, panelClass: "custom-class" }; - if((retour === null) || (retour === undefined)) { - this.snackBar.open("Opération annulée", "", config); - } - else { - let index = this.allPlaylists.indexOf(playlist); - if(index >= 0) this.allPlaylists.splice(index, 1); - - index = this.tabPlaylist.indexOf(playlist); - if(index >= 0) this.tabPlaylist.splice(index, 1); - - this.eventEmitter.emit(null); - this.playlistFocusedOn = null; - this.snackBar.open(`La playlist '${playlist.name}' a bien été suprimée ✔`, "", config); - } - }); - } - - - // retourne la class CSS de conteneur de playlist - getClassOfPlaylistContainer(playlist: PlaylistDB): string - { - if(playlist === this.playlistFocusedOn) return "row btnPlaylist btnPlaylistFocus" ; - else return "row btnPlaylist" ; - } - -} diff --git a/src/app/user/myPlaylists/popup-create-or-update-playlist/popup-create-or-update-playlist.component.html b/src/app/user/myPlaylists/popup-create-or-update-playlist/popup-create-or-update-playlist.component.html deleted file mode 100644 index d88fa34..0000000 --- a/src/app/user/myPlaylists/popup-create-or-update-playlist/popup-create-or-update-playlist.component.html +++ /dev/null @@ -1,19 +0,0 @@ -
- -
- - Nom de la playlist - - - {{errorMessage}} -
- -
- - -
- -
diff --git a/src/app/user/myPlaylists/popup-create-or-update-playlist/popup-create-or-update-playlist.component.scss b/src/app/user/myPlaylists/popup-create-or-update-playlist/popup-create-or-update-playlist.component.scss deleted file mode 100644 index e69de29..0000000 diff --git a/src/app/user/myPlaylists/popup-create-or-update-playlist/popup-create-or-update-playlist.component.spec.ts b/src/app/user/myPlaylists/popup-create-or-update-playlist/popup-create-or-update-playlist.component.spec.ts deleted file mode 100644 index 640bdbc..0000000 --- a/src/app/user/myPlaylists/popup-create-or-update-playlist/popup-create-or-update-playlist.component.spec.ts +++ /dev/null @@ -1,25 +0,0 @@ -import { ComponentFixture, TestBed } from '@angular/core/testing'; - -import { PopupCreateOrUpdatePlaylistComponent } from './popup-create-or-update-playlist.component'; - -describe('PopupCreatePlaylistComponent', () => { - let component: PopupCreateOrUpdatePlaylistComponent; - let fixture: ComponentFixture; - - beforeEach(async () => { - await TestBed.configureTestingModule({ - declarations: [ PopupCreateOrUpdatePlaylistComponent ] - }) - .compileComponents(); - }); - - beforeEach(() => { - fixture = TestBed.createComponent(PopupCreateOrUpdatePlaylistComponent); - component = fixture.componentInstance; - fixture.detectChanges(); - }); - - it('should create', () => { - expect(component).toBeTruthy(); - }); -}); diff --git a/src/app/user/myPlaylists/popup-create-or-update-playlist/popup-create-or-update-playlist.component.ts b/src/app/user/myPlaylists/popup-create-or-update-playlist/popup-create-or-update-playlist.component.ts deleted file mode 100644 index a6ce4b6..0000000 --- a/src/app/user/myPlaylists/popup-create-or-update-playlist/popup-create-or-update-playlist.component.ts +++ /dev/null @@ -1,92 +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"; -import {PlaylistDB} from "../../../utils/interfaces/playlist"; - - - -@Component({ - selector: 'app-popup-create-or-update-playlist', - templateUrl: './popup-create-or-update-playlist.component.html', - styleUrls: ['./popup-create-or-update-playlist.component.scss'] -}) -export class PopupCreateOrUpdatePlaylistComponent implements OnInit -{ - name: string = "" ; - hasError: boolean = false; - tabNomPlaylist: string[] = []; - errorMessage: string = "" ; - action: string = ""; - - - - constructor( public dialogRef: MatDialogRef, - @Inject(MAT_DIALOG_DATA) public data, - private messageService: MessageService) { } - - - ngOnInit(): void - { - this.action = this.data.action; - this.tabNomPlaylist = this.data.tabPlaylist.map( playlist0 => playlist0.name ); - if(this.action === "update") this.name = this.data.playlistName; - } - - - onValider(): void - { - this.checkError(); - if(!this.hasError) - { - if(this.action === "create") - { - this.messageService - .post("playlist/create", {name: this.name}) - .subscribe(retour => this.onValiderCallback(retour), err => this.onValiderCallback(err)); - } - else if(this.action === "update") - { - this.messageService - .put("playlist/update/"+this.data.playlistId, {name: this.name}) - .subscribe(retour => this.onValiderCallback(retour), err => this.onValiderCallback(err)); - } - } - } - - - onValiderCallback(retour): void - { - if(retour.status !== "success") { - console.log(retour); - this.dialogRef.close(null); - } - else { - if(this.action === "create") this.dialogRef.close(retour.data); - else if(this.action === "update") this.dialogRef.close(this.name); - } - } - - - checkError(): void - { - if(this.name === "") { - this.errorMessage = "Le nom ne peut pas être vide" ; - this.hasError = true; - } - else if(this.tabNomPlaylist.includes(this.name)){ - this.errorMessage = "Ce nom est déjà utilisé" ; - this.hasError = true; - } - else { - this.hasError = false; - this.errorMessage = "" ; - } - } - - - onAnnuler(): void - { - this.dialogRef.close(null); - } - -} diff --git a/src/app/user/myPlaylists/popup-delete-playlist/popup-delete-playlist.component.html b/src/app/user/myPlaylists/popup-delete-playlist/popup-delete-playlist.component.html deleted file mode 100644 index 0335139..0000000 --- a/src/app/user/myPlaylists/popup-delete-playlist/popup-delete-playlist.component.html +++ /dev/null @@ -1,8 +0,0 @@ - - Êtes-vous sûr de vouloir supprimer {{playlist.name}} ? - - - - - - diff --git a/src/app/user/myPlaylists/popup-delete-playlist/popup-delete-playlist.component.scss b/src/app/user/myPlaylists/popup-delete-playlist/popup-delete-playlist.component.scss deleted file mode 100644 index e69de29..0000000 diff --git a/src/app/user/myPlaylists/popup-delete-playlist/popup-delete-playlist.component.spec.ts b/src/app/user/myPlaylists/popup-delete-playlist/popup-delete-playlist.component.spec.ts deleted file mode 100644 index 83d1cf7..0000000 --- a/src/app/user/myPlaylists/popup-delete-playlist/popup-delete-playlist.component.spec.ts +++ /dev/null @@ -1,25 +0,0 @@ -import { ComponentFixture, TestBed } from '@angular/core/testing'; - -import { PopupDeletePlaylistComponent } from './popup-delete-playlist.component'; - -describe('PopupDeletePlaylistComponent', () => { - let component: PopupDeletePlaylistComponent; - let fixture: ComponentFixture; - - beforeEach(async () => { - await TestBed.configureTestingModule({ - declarations: [ PopupDeletePlaylistComponent ] - }) - .compileComponents(); - }); - - beforeEach(() => { - fixture = TestBed.createComponent(PopupDeletePlaylistComponent); - component = fixture.componentInstance; - fixture.detectChanges(); - }); - - it('should create', () => { - expect(component).toBeTruthy(); - }); -}); diff --git a/src/app/user/myPlaylists/popup-delete-playlist/popup-delete-playlist.component.ts b/src/app/user/myPlaylists/popup-delete-playlist/popup-delete-playlist.component.ts deleted file mode 100644 index 2cc06ec..0000000 --- a/src/app/user/myPlaylists/popup-delete-playlist/popup-delete-playlist.component.ts +++ /dev/null @@ -1,41 +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-playlist', - templateUrl: './popup-delete-playlist.component.html', - styleUrls: ['./popup-delete-playlist.component.scss'] -}) -export class PopupDeletePlaylistComponent implements OnInit -{ - playlist; - - constructor( public dialogRef: MatDialogRef, - @Inject(MAT_DIALOG_DATA) public data, - private messageService: MessageService ) { } - - ngOnInit(): void - { - this.playlist = this.data; - } - - onValidate(): void - { - this.messageService - .delete("playlist/delete/"+this.playlist._id) - .subscribe( retour => this.onValidateCallback(retour), err => this.onValidateCallback(err)); - } - - onValidateCallback(retour: any): void - { - if(retour.status !== "success") { - console.log(retour); - this.dialogRef.close(null); - } - else { - this.dialogRef.close(true); - } - } - -} diff --git a/src/app/user/myPlaylists/video-list/video-list.component.html b/src/app/user/myPlaylists/video-list/video-list.component.html deleted file mode 100644 index 1954fee..0000000 --- a/src/app/user/myPlaylists/video-list/video-list.component.html +++ /dev/null @@ -1,91 +0,0 @@ -
-
- - -
- - -
- - - - {{playlist.name}} - - - - - Aucune playlist selectionnée - - -
- - - - - - -
-
- - -
- - - -
- - - - - - - - - - -
-
- - -
-
-
- - - - - - -
- - - - {{video.title}} - - -
-
- - - -
-
- -
-
- - - - - - -
-
a
-
- -
-
diff --git a/src/app/user/myPlaylists/video-list/video-list.component.scss b/src/app/user/myPlaylists/video-list/video-list.component.scss deleted file mode 100644 index e3af7ce..0000000 --- a/src/app/user/myPlaylists/video-list/video-list.component.scss +++ /dev/null @@ -1,83 +0,0 @@ -.myContainer { - //background-color: white ; - background: linear-gradient(top, rgba(38,38,38,0.8), #e6e6e6 25%, #fff 38%, #c5c5c5 87%, rgba(38,38,38,0.8)); - background: -webkit-linear-gradient(top, #c5c5c5, #e6e6e6 25%, #fff 38%, #c5c5c5 87%, #c5c5c5); - text-align: center; - width: 35vw; - margin: 1vh 0vh 3vh 0vh; - padding: 0px; - border: solid 2px black; - border-radius: 10px; - box-shadow: 10px 5px 5px black; -} - -// TopBorder -------------------------------------------------------- - -.topBorder { - margin: 0px 0px 0px 0px; - //background-color: #dcdcdc; - background: linear-gradient(top, rgba(38,38,38,0.8), #e6e6e6 25%, #fff 38%, #c5c5c5 87%, rgba(38,38,38,0.8)); - background: -webkit-linear-gradient(top, #c5c5c5, #e6e6e6 25%, #fff 38%, #c5c5c5 87%, #c5c5c5); - text-align: left; - padding: 5px 0px 5px 5px; - border-bottom: solid 1px black; - border-top-left-radius: 10px; - border-top-right-radius: 10px; -} - -.spanPlayListTitle { - font-size: large; - font-weight: bold; -} - -// Liste des videos ------------------------------------------------ - -.listVideoContainer { - height: 65vh; - background-color: white; - padding: 0px; - overflow-y: scroll; -} - -.videoContainer { - border-bottom: solid 1px black; - padding: 15px 0px 15px 0px; - width: 100%; -} - -.imgsContainer { - position: relative; - width: 20vw; - height: 15vh; - cursor: pointer; -} - -.imgPlay { - position: absolute; - margin-left: 9vw; - width: 3vw; - margin-top: 5vh; - height: 6vh; - padding: 0px 0px 0px 0px; -} - -.imgVideo { - border: solid 1px black; - width: 20vw; - height: 15vh; - padding: 0px 0px 0px 0px; -} - -// BottomBorder -------------------------------------------------------- - -.bottomBorder { - margin: 0px 0px 0px 0px; - //background-color: #dcdcdc; - background: linear-gradient(top, rgba(38,38,38,0.8), #e6e6e6 25%, #fff 38%, #c5c5c5 87%, rgba(38,38,38,0.8)); - background: -webkit-linear-gradient(top, #c5c5c5, #e6e6e6 25%, #fff 38%, #c5c5c5 87%, #c5c5c5); - border-top: solid 1px black; - border-bottom: solid 1px black; - font-size: large; - border-bottom-left-radius: 10px; - border-bottom-right-radius: 10px; -} diff --git a/src/app/user/myPlaylists/video-list/video-list.component.spec.ts b/src/app/user/myPlaylists/video-list/video-list.component.spec.ts deleted file mode 100644 index 403cc76..0000000 --- a/src/app/user/myPlaylists/video-list/video-list.component.spec.ts +++ /dev/null @@ -1,25 +0,0 @@ -import { ComponentFixture, TestBed } from '@angular/core/testing'; - -import { VideoListComponent } from './video-list.component'; - -describe('VideoListComponent', () => { - let component: VideoListComponent; - let fixture: ComponentFixture; - - beforeEach(async () => { - await TestBed.configureTestingModule({ - declarations: [ VideoListComponent ] - }) - .compileComponents(); - }); - - beforeEach(() => { - fixture = TestBed.createComponent(VideoListComponent); - component = fixture.componentInstance; - fixture.detectChanges(); - }); - - it('should create', () => { - expect(component).toBeTruthy(); - }); -}); diff --git a/src/app/user/myPlaylists/video-list/video-list.component.ts b/src/app/user/myPlaylists/video-list/video-list.component.ts deleted file mode 100644 index 0919e1a..0000000 --- a/src/app/user/myPlaylists/video-list/video-list.component.ts +++ /dev/null @@ -1,92 +0,0 @@ -import {Component, Input, OnChanges, SimpleChanges} from '@angular/core'; -import {ThemeService} from "../../../utils/services/theme/theme.service"; -import {AddVideoToPlaylistsService} from "../../utils/services/addVideoToPlaylists/add-video-to-playlists.service"; -import {MessageService} from "../../../utils/services/message/message.service"; -import {MatSnackBar} from "@angular/material/snack-bar"; -import {Router} from "@angular/router"; -import {ProfilService} from "../../../utils/services/profil/profil.service"; - - - -@Component({ - selector: 'app-video-list', - templateUrl: './video-list.component.html', - styleUrls: ['./video-list.component.scss'] -}) -export class VideoListComponent implements OnChanges -{ - @Input() playlist: any; - videosInPlaylist: any[] = []; - - - constructor( private messageService: MessageService, - public themeService: ThemeService, - private addVideoToPlaylistsService: AddVideoToPlaylistsService, - private snackBar: MatSnackBar, - private profilService: ProfilService, - private router: Router ) { } - - - ngOnChanges(changes: SimpleChanges): void - { - if((this.playlist !== null) && (this.playlist !== undefined)) this.videosInPlaylist = this.playlist.videos; - } - - - onAddToPlaylist(video: any): void - { - this.addVideoToPlaylistsService.run(video.videoId, video.source, video.interest); - } - - - onDelete(video0: any, indexVideo: number): void - { - const data = { - videoId: { - id: video0._id, - action: "delete" - } - } - this.messageService - .put("playlist/update/"+this.playlist._id, data) - .subscribe( ret => this.onDeleteCallback(ret, indexVideo), err => this.onDeleteCallback(err, indexVideo)); - } - - - onDeleteCallback(retour: any, indexVideo: number): void - { - if(retour.status !== "success") { - console.log(retour); - } - else { - this.playlist.videos.splice(indexVideo, 1); - this.videosInPlaylist.splice(indexVideo, 1); - let message = "La video a bien été supprimé de la playlist"; - const config = { duration: 1000, panelClass: "custom-class" }; - this.snackBar.open( message, "", config); - } - } - - - onVideo(video: any): void - { - this.messageService - .put("video/update/"+video._id, {watchedDate: true}) - .subscribe(ret => this.onVideoCallback(ret), err => this.onVideoCallback(err)); - - const params = { - videoId: video.videoId, - source: video.source, - _idPlaylist: this.playlist._id, - from: "myPlaylists", - }; - this.router.navigate(['/user/watching'], { queryParams: params }); - } - - - onVideoCallback(retour: any): void - { - if(retour.status !== "success") console.log(retour); - } - -} diff --git a/src/app/user/myProfil/input-interests-profil/input-interests-profil.component.html b/src/app/user/myProfil/input-interests-profil/input-interests-profil.component.html deleted file mode 100644 index be2bd07..0000000 --- a/src/app/user/myProfil/input-interests-profil/input-interests-profil.component.html +++ /dev/null @@ -1,39 +0,0 @@ - - - - - - - - {{interest}} - - - - - - - - - - - - {{interest}} - - - - - - diff --git a/src/app/user/myProfil/input-interests-profil/input-interests-profil.component.scss b/src/app/user/myProfil/input-interests-profil/input-interests-profil.component.scss deleted file mode 100644 index 7628dd4..0000000 --- a/src/app/user/myProfil/input-interests-profil/input-interests-profil.component.scss +++ /dev/null @@ -1,20 +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; -} - -mat-option { - font-size: small; -} diff --git a/src/app/user/myProfil/input-interests-profil/input-interests-profil.component.spec.ts b/src/app/user/myProfil/input-interests-profil/input-interests-profil.component.spec.ts deleted file mode 100644 index 0dd8314..0000000 --- a/src/app/user/myProfil/input-interests-profil/input-interests-profil.component.spec.ts +++ /dev/null @@ -1,25 +0,0 @@ -import { ComponentFixture, TestBed } from '@angular/core/testing'; - -import { InputInterestsProfilComponent } from './input-interests-profil.component'; - -describe('InputInterestsComponent', () => { - let component: InputInterestsProfilComponent; - let fixture: ComponentFixture; - - beforeEach(async () => { - await TestBed.configureTestingModule({ - declarations: [ InputInterestsProfilComponent ] - }) - .compileComponents(); - }); - - beforeEach(() => { - fixture = TestBed.createComponent(InputInterestsProfilComponent); - component = fixture.componentInstance; - fixture.detectChanges(); - }); - - it('should create', () => { - expect(component).toBeTruthy(); - }); -}); diff --git a/src/app/user/myProfil/input-interests-profil/input-interests-profil.component.ts b/src/app/user/myProfil/input-interests-profil/input-interests-profil.component.ts deleted file mode 100644 index 8ceb7c1..0000000 --- a/src/app/user/myProfil/input-interests-profil/input-interests-profil.component.ts +++ /dev/null @@ -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 {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"; - - - -@Component({ - selector: 'app-input-interests-profil', - templateUrl: './input-interests-profil.component.html', - styleUrls: ['./input-interests-profil.component.scss'] -}) -export class InputInterestsProfilComponent implements OnInit -{ - selectable = true; - removable = true; - separatorKeysCodes: number[] = [ENTER, COMMA]; - formControl = new FormControl(); - filteredInterests: Observable; - @Input() myInterests: string[] = []; - allInterests: string[] = []; - @Output() eventEmitter = new EventEmitter(); - @ViewChild('tagInput') tagInput: ElementRef; - 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)); - } - -} diff --git a/src/app/user/myProfil/page-profil-user/page-profil-user.component.html b/src/app/user/myProfil/page-profil-user/page-profil-user.component.html deleted file mode 100644 index 7e69ded..0000000 --- a/src/app/user/myProfil/page-profil-user/page-profil-user.component.html +++ /dev/null @@ -1,92 +0,0 @@ -
-
- - - - - -
- - -
- -
- - -
- - -
- - -
- -
- -
- -
-
- - - - - - -
- - -
-
Pseudo:
-
{{user.login}}
-
- - -
-
Mail:
-
{{user.email}}
-
- - -
-
Sexe:
-
- Homme - Femme -
-
- - -
-
Date de création:
-
{{ user.createdAt | date:'dd/LL/YYYY' }}
-
- -
-
- - - - - - -
- - -
-
Date de naissance:
-
{{ user.dateOfBirth | date:'dd/LL/YYYY' }}
-
- - -
-
Centres d'intérêt:
-
-
-
{{interest}}
-
-
-
- -
-
diff --git a/src/app/user/myProfil/page-profil-user/page-profil-user.component.scss b/src/app/user/myProfil/page-profil-user/page-profil-user.component.scss deleted file mode 100644 index ae34d41..0000000 --- a/src/app/user/myProfil/page-profil-user/page-profil-user.component.scss +++ /dev/null @@ -1,80 +0,0 @@ -.myContainer { - max-width: 100vw; - height: 100vh; - overflow-x: hidden; -} - - -.boite { - margin-left: auto; - margin-right: auto; - width: 70%; - 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; -} - -// -------------------------------------------------------------------------------------------- - -.interestsContainer { - width: 70%; - height: 15vh; - overflow-y: scroll; - border: 1px solid black; -} - -.interest { - border-bottom: 1px solid #dcdcdc; - padding: 5px 5px 5px 5px; -} - -// -------------------------------------------------------------------------------------------- - -.btnContainer { - text-align: center; - margin-top: 40px; -} -.myBtn { - border: solid 1px black; - background-color: white; -} - - diff --git a/src/app/user/myProfil/page-profil-user/page-profil-user.component.spec.ts b/src/app/user/myProfil/page-profil-user/page-profil-user.component.spec.ts deleted file mode 100644 index e8722af..0000000 --- a/src/app/user/myProfil/page-profil-user/page-profil-user.component.spec.ts +++ /dev/null @@ -1,25 +0,0 @@ -import { ComponentFixture, TestBed } from '@angular/core/testing'; - -import { PageProfilUserComponent } from './page-profil-user.component'; - -describe('PageProfilUserComponent', () => { - let component: PageProfilUserComponent; - let fixture: ComponentFixture; - - beforeEach(async () => { - await TestBed.configureTestingModule({ - declarations: [ PageProfilUserComponent ] - }) - .compileComponents(); - }); - - beforeEach(() => { - fixture = TestBed.createComponent(PageProfilUserComponent); - component = fixture.componentInstance; - fixture.detectChanges(); - }); - - it('should create', () => { - expect(component).toBeTruthy(); - }); -}); diff --git a/src/app/user/myProfil/page-profil-user/page-profil-user.component.ts b/src/app/user/myProfil/page-profil-user/page-profil-user.component.ts deleted file mode 100644 index 33ed891..0000000 --- a/src/app/user/myProfil/page-profil-user/page-profil-user.component.ts +++ /dev/null @@ -1,90 +0,0 @@ -import { Component, OnInit } from '@angular/core'; -import {ThemeService} from "../../../utils/services/theme/theme.service"; -import {User} from "../../../utils/interfaces/user"; -import {MatDialog} from "@angular/material/dialog"; -import {MatSnackBar} from "@angular/material/snack-bar"; -import {PopupUpdateUserComponent} from "../popup-update-user/popup-update-user.component"; -import {MessageService} from "../../../utils/services/message/message.service"; -import {ProfilService} from "../../../utils/services/profil/profil.service"; - - - -@Component({ - selector: 'app-page-profil-user', - templateUrl: './page-profil-user.component.html', - styleUrls: ['./page-profil-user.component.scss'] -}) -export class PageProfilUserComponent implements OnInit -{ - user: User = { - _id: "", - login: "", - hashPass: "", - email: "", - role: { - name: "user", - permission: 0, - isAccepted: false, - }, - 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.user = retour.data; - } - } - - - onModifier() - { - const config = { - width: '70%', - data: { user: this.user } - }; - this.dialog - .open(PopupUpdateUserComponent, 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.user = retour; - } - }); - } - -} diff --git a/src/app/user/myProfil/popup-update-user/popup-update-user.component.html b/src/app/user/myProfil/popup-update-user/popup-update-user.component.html deleted file mode 100644 index 1e583c7..0000000 --- a/src/app/user/myProfil/popup-update-user/popup-update-user.component.html +++ /dev/null @@ -1,125 +0,0 @@ -
- - -
-
- -

- - -
- - -
- - -
-
{{errorMessage}}
-
- - -
- - -
- -
- - - - - - - -
- - -
- -
- -
-
- - -
- -
- -
-
- - -
- - Homme     - Femme - -
- - -
- -
- -
-
- - -
- -
- -
-
- - -
- -
- -
-
- -
-
- - - - - - - -
- - -
- -
- -
-
- -
-
diff --git a/src/app/user/myProfil/popup-update-user/popup-update-user.component.scss b/src/app/user/myProfil/popup-update-user/popup-update-user.component.scss deleted file mode 100644 index 636928e..0000000 --- a/src/app/user/myProfil/popup-update-user/popup-update-user.component.scss +++ /dev/null @@ -1,81 +0,0 @@ -.myContainer { - 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; -} - -.inputUrlImage { - width: 80%; - text-align: center; - margin-left: 10%; - margin-right: 10%; - font-size: small; - border-radius: 5px; -} - -input { - font-size: small; -} - -// ------------------------------------------------------------------------- - -.myRow { - margin: 15px 0px 15px 0px; -} -.myLeftLabel { - text-align: right; - padding: 0px 0px 0px 0px; - margin: 0px 0px 0px 0px; - font-weight: bold; -} -.myRightLabel { - text-align: left; - padding: 0px 0px 0px 0px; - margin: 0px 0px 0px 0px; - font-weight: bold; -} -.myValue { - text-align: left; - padding: 0px 0px 0px 0px; - margin: 0px 0px 0px 0px; -} - -// ------------------------------------------------------------------------- - -// 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; -} - -// ------------------------------------------------------------------------- - -::ng-deep .mat-radio-inner-circle { - color: black !important; - background-color: black !important; -} - -::ng-deep .mat-radio-outer-circle{ - color: black !important; - border: solid 1px gray !important; -} diff --git a/src/app/user/myProfil/popup-update-user/popup-update-user.component.spec.ts b/src/app/user/myProfil/popup-update-user/popup-update-user.component.spec.ts deleted file mode 100644 index a5126ad..0000000 --- a/src/app/user/myProfil/popup-update-user/popup-update-user.component.spec.ts +++ /dev/null @@ -1,25 +0,0 @@ -import { ComponentFixture, TestBed } from '@angular/core/testing'; - -import { PopupUpdateUserComponent } from './popup-update-user.component'; - -describe('PopupUpdateUserComponent', () => { - let component: PopupUpdateUserComponent; - let fixture: ComponentFixture; - - beforeEach(async () => { - await TestBed.configureTestingModule({ - declarations: [ PopupUpdateUserComponent ] - }) - .compileComponents(); - }); - - beforeEach(() => { - fixture = TestBed.createComponent(PopupUpdateUserComponent); - component = fixture.componentInstance; - fixture.detectChanges(); - }); - - it('should create', () => { - expect(component).toBeTruthy(); - }); -}); diff --git a/src/app/user/myProfil/popup-update-user/popup-update-user.component.ts b/src/app/user/myProfil/popup-update-user/popup-update-user.component.ts deleted file mode 100644 index 0e1c5d3..0000000 --- a/src/app/user/myProfil/popup-update-user/popup-update-user.component.ts +++ /dev/null @@ -1,133 +0,0 @@ -import {Component, Inject, OnInit} from '@angular/core'; -import {MAT_DIALOG_DATA, MatDialogRef} from "@angular/material/dialog"; -import {User} from "../../../utils/interfaces/user"; -import {MessageService} from "../../../utils/services/message/message.service"; -import {ProfilService} from "../../../utils/services/profil/profil.service"; - - - -@Component({ - selector: 'app-popup-update-user', - templateUrl: './popup-update-user.component.html', - styleUrls: ['./popup-update-user.component.scss'] -}) -export class PopupUpdateUserComponent implements OnInit -{ - userCopy: User; - newPassword: string = ""; - confirmNewPassword: string = "" ; - changePassword: boolean = false ; - hasError: boolean = false; - errorMessage: string = "" ; - - - constructor( public dialogRef: MatDialogRef, - @Inject(MAT_DIALOG_DATA) public data, - private messageService: MessageService, - private profilService: ProfilService ) { } - - - ngOnInit(): void - { - const user0 = this.data.user; - this.userCopy = { - _id: user0._id, - login: user0.login, - hashPass: user0.hashPass, - email: user0.email, - role: { - name: user0.role.name, - permission: user0.role.permission, - isAccepted: user0.role.isAccepted, - }, - profileImageUrl: user0.profileImageUrl, - dateOfBirth: user0.dateOfBirth, - gender: user0.gender, - interests: [], - company: "", - isActive: user0.isActive, - createdAt: user0.createdAt, - updatedAt: user0.updatedAt, - lastConnexion: new Date() - }; - for(let interest of user0.interests) this.userCopy.interests.push(interest); - } - - - onValider() - { - this.checkField(); - if(!this.hasError) - { - if(this.changePassword) this.userCopy.hashPass = this.newPassword; - const data = { - login: this.userCopy.login, - hashPass: this.userCopy.hashPass, - email: this.userCopy.email, - profileImageUrl: this.userCopy.profileImageUrl, - dateOfBirth: this.userCopy.dateOfBirth, - gender: this.userCopy.gender, - interests: this.userCopy.interests, - }; - 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.userCopy.profileImageUrl); - this.dialogRef.close(this.userCopy); - } - } - - - checkField() - { - if(this.userCopy.login.length === 0) { - this.errorMessage = "Veuillez remplir le champ 'pseudo'." ; - this.hasError = true; - } - else if(this.userCopy.email.length === 0) { - this.errorMessage = "Veuillez remplir le champ 'email'." ; - this.hasError = true; - } - else if(!this.isValidEmail(this.userCopy.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); - } - - - onEventInputInterests(myInterets: string[]) - { - this.userCopy.interests = myInterets; - } - -} diff --git a/src/app/user/search/page-search/page-search.component.html b/src/app/user/search/page-search/page-search.component.html deleted file mode 100644 index 0039bdd..0000000 --- a/src/app/user/search/page-search/page-search.component.html +++ /dev/null @@ -1,80 +0,0 @@ -
-
- - -
- -
- - - - - - -
- - -
-
- - -
-
- - -
- - -   - - logo - -   - - - -   - - logo - -   - -
- -
- - - - - - - - - - -
- -
-
- - - -
- -
-
- - - -
- -
-
- -
-

- -
-
diff --git a/src/app/user/search/page-search/page-search.component.scss b/src/app/user/search/page-search/page-search.component.scss deleted file mode 100644 index f80fc45..0000000 --- a/src/app/user/search/page-search/page-search.component.scss +++ /dev/null @@ -1,90 +0,0 @@ -.lightTheme { - color: black; - border-color: black; -} -.darkTheme { - color: white; - border-color: white; -} -.myContainer { - text-align: center; - max-width: 100vw; - height: 100vh; - overflow-x: hidden; - overflow-y: scroll; -} - -//-------------------------------------------------------------------------------------------- - -.inputSearchBar { - width: 40%; - font-size: large; - border-bottom: 10px; - border-radius: 5px; -} - -//-------------------------------------------------------------------------------------------- - -.celluleGrilleVideo { - border: solid 2px; - border-radius: 5px; - width: 100%; -} -.lightTheme .celluleGrilleVideo{ - border-color: black; - background-color: #f0f0f0; -} -.darkTheme .celluleGrilleVideo{ - border-color: white; - background-color: #646464; -} - -.conteneurVideosGrid { - height: 75vh; - width: 100%; -} - -//-------------------------------------------------------------------------------------------- - -.cellulePub { - padding: 0px 10px 0px 10px; - width: 100%; - text-align: center; - justify-content: center; -} - -.conteneurPub { - height: 75vh; - text-align: center; - justify-content: center; - vertical-align: middle; - display: block; - width: 75%; - margin-left: auto; - margin-right: auto; - position: absolute; - top: 50%; - -ms-transform: translateY(-50%); - transform: translateY(-50%); -} - - - -// ------------------------------------------------------------------------- - - -// 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 { - border: solid 1px black !important; - background-color: white !important; -} diff --git a/src/app/user/search/page-search/page-search.component.spec.ts b/src/app/user/search/page-search/page-search.component.spec.ts deleted file mode 100644 index 79e1a03..0000000 --- a/src/app/user/search/page-search/page-search.component.spec.ts +++ /dev/null @@ -1,25 +0,0 @@ -import { ComponentFixture, TestBed } from '@angular/core/testing'; - -import { PageSearchComponent } from './page-search.component'; - -describe('PageSearchComponent', () => { - let component: PageSearchComponent; - let fixture: ComponentFixture; - - beforeEach(async () => { - await TestBed.configureTestingModule({ - declarations: [ PageSearchComponent ] - }) - .compileComponents(); - }); - - beforeEach(() => { - fixture = TestBed.createComponent(PageSearchComponent); - component = fixture.componentInstance; - fixture.detectChanges(); - }); - - it('should create', () => { - expect(component).toBeTruthy(); - }); -}); diff --git a/src/app/user/search/page-search/page-search.component.ts b/src/app/user/search/page-search/page-search.component.ts deleted file mode 100644 index 7ab145f..0000000 --- a/src/app/user/search/page-search/page-search.component.ts +++ /dev/null @@ -1,119 +0,0 @@ -import { Component, OnInit } from '@angular/core'; -import {MessageService} from "../../../utils/services/message/message.service"; -import {VideoAll} from "../../../utils/interfaces/video"; -import {ThemeService} from "../../../utils/services/theme/theme.service"; -import {HttpParams} from "@angular/common/http"; -import {ActivatedRoute} from "@angular/router"; - - - -let TAB_PLATEFORM = [ - { name: "Youtube", isSelected: true }, - { name: "Dailymotion", isSelected: true } -]; - - - -@Component({ - selector: 'app-page-search', - templateUrl: './page-search.component.html', - styleUrls: ['./page-search.component.scss'] -}) -export class PageSearchComponent implements OnInit -{ - tabPlateform = TAB_PLATEFORM; - tabVideo: VideoAll[] = []; - search: string = ""; - ad1: any; - ad2: any; - sources: string = "" ; - indexPage: number = 0; - - - constructor( private messageService: MessageService, - public themeService: ThemeService, - private activatedRoute: ActivatedRoute ) { } - - - ngOnInit(): void - { - // parametre de la route - this.activatedRoute - .queryParams - .subscribe(paramsFromOldPage => { - if(paramsFromOldPage.hasOwnProperty("search")) this.search = paramsFromOldPage.search; - if(paramsFromOldPage.hasOwnProperty("sources")) - { - this.sources = paramsFromOldPage.sources; - if(this.sources === "yt") { - this.tabPlateform[0].isSelected = true; - this.tabPlateform[1].isSelected = false; - } - else if(this.sources === "dm") { - this.tabPlateform[0].isSelected = false; - this.tabPlateform[1].isSelected = true; - } - else if(this.sources === "yt,dm") { - this.tabPlateform[0].isSelected = true; - this.tabPlateform[1].isSelected = true; - } - } - if(paramsFromOldPage.hasOwnProperty("indexPage")) this.indexPage = parseInt(paramsFromOldPage.indexPage, 10); - this.onSearch(); - }); - - // Ask for ads - let params = new HttpParams(); - params = params.append("quantity", 2); - this.messageService - .get("user/ad", params) - .subscribe(ret => this.adCallback(ret), err => this.adCallback(err)); - } - - - adCallback(retour: any): void - { - if(retour.status !== "success") { - console.log(retour); - } - else { - this.ad1 = retour.data[0]; - this.ad2 = retour.data[1]; - } - } - - - onSearch() - { - let params = new HttpParams(); - params = params.append('q', this.search); - - if(this.tabPlateform[0].isSelected && this.tabPlateform[1].isSelected) this.sources = "yt,dm" ; - else if((!this.tabPlateform[0].isSelected) && this.tabPlateform[1].isSelected) this.sources = "dm" ; - else if(this.tabPlateform[0].isSelected && (!this.tabPlateform[1].isSelected)) this.sources = "yt" ; - else this.sources = "" ; - params = params.append('sources', this.sources); - - this.messageService - .get("video/search", params) - .subscribe(ret => this.onSearchCallback(ret), err => this.onSearchCallback(err)); - } - - - onSearchCallback(retour: any): void - { - if(retour.status !== "success") { - console.log(retour); - } - else { - this.tabVideo = retour.data; - } - } - - - onEnterOnSearchBar(event) - { - if(event.key === 'Enter') this.onSearch(); - } - -} diff --git a/src/app/user/search/video-grid/video-grid.component.html b/src/app/user/search/video-grid/video-grid.component.html deleted file mode 100644 index 841d5c3..0000000 --- a/src/app/user/search/video-grid/video-grid.component.html +++ /dev/null @@ -1,76 +0,0 @@ - - - - -
- - -
- - - -
- - -
- - - - - - - - ytb - dlm - - - - -
- {{tronquage(tabVideo[indexPage+k].title)}} -
- - {{tabVideo[indexPage+k].views | number: '1.0-0'}} vues. - Il y a {{dateToElapsedTime(tabVideo[indexPage+k].publishedAt)}}. - -
-
- - - - - - -
- - -
-
-
-
- - - - - -
- - -   - - - - - {{page}}  - - - {{page}}  - -   - - - - -
diff --git a/src/app/user/search/video-grid/video-grid.component.scss b/src/app/user/search/video-grid/video-grid.component.scss deleted file mode 100644 index 6819fd8..0000000 --- a/src/app/user/search/video-grid/video-grid.component.scss +++ /dev/null @@ -1,84 +0,0 @@ -mat-grid-list { - margin: 0px 0px 0px 0px; - padding: 0px 0px 0px 0px; - border: none; -} - -mat-grid-tile { - margin: 0px 0px 0px 0px; - padding: 0px 0px 0px 0px; -} - -.myCell { - margin: 7px 0px 0px 0px; - padding: 0px 0px 0px 0px; - background-color: white; - border: solid 1px black; - border-bottom-left-radius: 2px; - border-bottom-right-radius: 2px; - cursor: pointer; -} -.myCell:hover { - background-color: #d2d2d2; -} - - -// --------------------------------------------------------------------------------------------- - - -.imgsContainer { - //width: 20vw; - width: 18vw; - height: 15vh; -} - -.imgPlay { - position: absolute; - margin-left: 8vw; - width: 2.5vw; - margin-top: 5vh; - height: 5vh; - padding: 0px 0px 0px 0px; -} - -.imgVideo { - width: 18vw; - height: 15vh; - padding: 0px 0px 0px 0px; -} - - -// --------------------------------------------------------------------------------------------- - - -.mat-grid-list-info-video { - margin: 0px 0px 0px 0px; - font-size: small; -} - -.mat-grid-tile-info-video { - border: none; - font-size: x-small; - //background: linear-gradient(top, rgba(38,38,38,0.8), #e6e6e6 25%, #fff 38%, #c5c5c5 87%, rgba(38,38,38,0.8)); - //background: -webkit-linear-gradient(top, #c5c5c5, #e6e6e6 25%, #fff 38%, #c5c5c5 87%, #c5c5c5); -} - -mat-icon { - text-align: right; -} - - -// --------------------------------------------------------------------------------------------- - - -.paginatorContainer { - margin: 0px 0px 0px 0px; - padding: 5px 0px 0px 0px; - text-align: center; - background-color: white; -} - -.btnPaginator { - margin: 0px 0px 0px 0px; - padding: 0px 0px 0px 0px; -} diff --git a/src/app/user/search/video-grid/video-grid.component.spec.ts b/src/app/user/search/video-grid/video-grid.component.spec.ts deleted file mode 100644 index 17cea62..0000000 --- a/src/app/user/search/video-grid/video-grid.component.spec.ts +++ /dev/null @@ -1,25 +0,0 @@ -import { ComponentFixture, TestBed } from '@angular/core/testing'; - -import { VideoGridComponent } from './video-grid.component'; - -describe('VideoGridComponent', () => { - let component: VideoGridComponent; - let fixture: ComponentFixture; - - beforeEach(async () => { - await TestBed.configureTestingModule({ - declarations: [ VideoGridComponent ] - }) - .compileComponents(); - }); - - beforeEach(() => { - fixture = TestBed.createComponent(VideoGridComponent); - component = fixture.componentInstance; - fixture.detectChanges(); - }); - - it('should create', () => { - expect(component).toBeTruthy(); - }); -}); diff --git a/src/app/user/search/video-grid/video-grid.component.ts b/src/app/user/search/video-grid/video-grid.component.ts deleted file mode 100644 index 6e13887..0000000 --- a/src/app/user/search/video-grid/video-grid.component.ts +++ /dev/null @@ -1,129 +0,0 @@ -import {Component, Input, OnChanges, OnInit, SimpleChanges} from '@angular/core'; -import {VideoAll} from "../../../utils/interfaces/video"; -import {AddVideoToPlaylistsService} from "../../utils/services/addVideoToPlaylists/add-video-to-playlists.service"; -import {Router} from "@angular/router"; -import {MessageService} from "../../../utils/services/message/message.service"; - - - -@Component({ - selector: 'app-video-grid', - templateUrl: './video-grid.component.html', - styleUrls: ['./video-grid.component.scss'] -}) -export class VideoGridComponent implements OnChanges -{ - @Input() tabVideo: VideoAll[] = []; - @Input() search: string = ""; - @Input() sources: string = ""; - @Input() indexPage: number = 0; - tabPage: number[] = []; - - - constructor( private addVideoToPlaylistsService: AddVideoToPlaylistsService, - private router: Router, - private messageService: MessageService ) {} - - - ngOnChanges(changes: SimpleChanges): void - { - if(this.tabVideoExists()) - { - const nbVideo = this.tabVideo.length; - let nbPage = Math.floor(nbVideo/9); - if((nbVideo%9) !== 0) nbPage += 1; - this.tabPage = []; - for(let i=1 ; i<=nbPage ; i++) this.tabPage.push(i); - } - } - - - onAddToPlaylist(video: VideoAll): void - { - this.addVideoToPlaylistsService.run(video.videoId, video.source, video.interest); - } - - - tronquage(str: string) - { - if(str.length < 30) return str; - else return str.substring(0, 27) + "..." ; - } - - - onVideo(video: VideoAll): void - { - const data = { source: video.source, interest: video.interest }; - this.messageService - .post("video/create/"+video.videoId, data) - .subscribe(ret => this.onVideoCallback(ret,video), err => this.onVideoCallback(err,video)); - } - - - onVideoCallback(retour: any, video: VideoAll): void - { - if(retour.status !== "success") { - console.log(retour); - } - else { - const params = { - videoId: video.videoId, - source: video.source, - from: "search", - search: this.search, - sources: this.sources, - indexPage: this.indexPage - }; - this.router.navigate(['/user/watching'], { queryParams: params }); - } - } - - - dateToElapsedTime(date0): string - { - const ellapsedTimeInMilliSeconds = (new Date()).getTime() - (new Date(date0)).getTime(); - - // seconde - const ellapsedTimeInSeconds = Math.trunc(ellapsedTimeInMilliSeconds / 1000); - if(ellapsedTimeInSeconds < 60) { - if(ellapsedTimeInSeconds <= 1)return ellapsedTimeInSeconds + " seconde" ; - else return ellapsedTimeInSeconds + " secondes" ; - } - // minute - const ellapsedTimeInMinutes = Math.trunc(ellapsedTimeInSeconds / 60); - if(ellapsedTimeInMinutes < 60) { - if(ellapsedTimeInMinutes <= 1) return ellapsedTimeInMinutes + " minute" ; - else return ellapsedTimeInMinutes + " minutes" ; - } - // heure - const ellapsedTimeInHours = Math.trunc(ellapsedTimeInMinutes / 60); - if(ellapsedTimeInHours < 24) { - if(ellapsedTimeInHours <= 1) return ellapsedTimeInHours + " heure" ; - else return ellapsedTimeInHours + " heures" ; - } - // jour - const ellapsedTimeInDays = Math.trunc(ellapsedTimeInHours / 24); - if(ellapsedTimeInDays < 31) { - if(ellapsedTimeInDays <= 1) return ellapsedTimeInDays + " jour" ; - else return ellapsedTimeInDays + " jours" ; - } - // mois - const ellapsedTimeInMonths = Math.trunc(ellapsedTimeInDays / 31); - if(ellapsedTimeInMonths < 12) { - return ellapsedTimeInMonths + " mois" ; - } - // an - const ellapsedTimeInYears = Math.trunc(ellapsedTimeInMonths / 12); - if(ellapsedTimeInYears <= 1) return ellapsedTimeInYears + " an" ; - else return ellapsedTimeInYears + " ans" ; - } - - - tabVideoExists(): boolean - { - if((this.tabVideo === null) || (this.tabVideo === undefined)) return false; - else if(this.tabVideo.length === 0) return false; - else return true; - } - -} diff --git a/src/app/user/utils/components/advert/advert.component.html b/src/app/user/utils/components/advert/advert.component.html deleted file mode 100644 index b1c034a..0000000 --- a/src/app/user/utils/components/advert/advert.component.html +++ /dev/null @@ -1,26 +0,0 @@ -
- - - - -
- - - - - - - - diff --git a/src/app/user/utils/components/advert/advert.component.scss b/src/app/user/utils/components/advert/advert.component.scss deleted file mode 100644 index ab03155..0000000 --- a/src/app/user/utils/components/advert/advert.component.scss +++ /dev/null @@ -1,41 +0,0 @@ -.myContainer { - margin: 0; - position: absolute; - top: 50%; - -ms-transform: translateY(-50%); - transform: translateY(-50%); -} - -#imgFromSearchOrMyPlaylists { - max-width: 100%; - max-height: 100%; - border: solid 3px black; - vertical-align: middle; - cursor: pointer; -} - -.helper { - display: inline-block; - height: 100%; - vertical-align: middle; -} - -// ------------------------------------------------------------------------------ - -#imgFromWatchingLeft { - width: 14vw; - height: 70vh; - border: solid 3px black; - position: fixed; - left: 1vw; - cursor: pointer; -} - -#imgFromWatchingRight { - width: 15vw; - height: 70vh; - border: solid 3px black; - position: fixed; - right: 1vw; - cursor: pointer; -} diff --git a/src/app/user/utils/components/advert/advert.component.spec.ts b/src/app/user/utils/components/advert/advert.component.spec.ts deleted file mode 100644 index 08b7e86..0000000 --- a/src/app/user/utils/components/advert/advert.component.spec.ts +++ /dev/null @@ -1,25 +0,0 @@ -import { ComponentFixture, TestBed } from '@angular/core/testing'; - -import { AdvertComponent } from './advert.component'; - -describe('PubComponent', () => { - let component: AdvertComponent; - let fixture: ComponentFixture; - - beforeEach(async () => { - await TestBed.configureTestingModule({ - declarations: [ AdvertComponent ] - }) - .compileComponents(); - }); - - beforeEach(() => { - fixture = TestBed.createComponent(AdvertComponent); - component = fixture.componentInstance; - fixture.detectChanges(); - }); - - it('should create', () => { - expect(component).toBeTruthy(); - }); -}); diff --git a/src/app/user/utils/components/advert/advert.component.ts b/src/app/user/utils/components/advert/advert.component.ts deleted file mode 100644 index 00b8b44..0000000 --- a/src/app/user/utils/components/advert/advert.component.ts +++ /dev/null @@ -1,40 +0,0 @@ -import {Component, Input, OnChanges, SimpleChanges} from '@angular/core'; - - - -@Component({ - selector: 'app-advert', - templateUrl: './advert.component.html', - styleUrls: ['./advert.component.scss'] -}) -export class AdvertComponent implements OnChanges -{ - @Input() ad: any; - @Input() from: string = "search"; - image: any; - imageExist: boolean = false; - - - constructor() { } - - - ngOnChanges(changes: SimpleChanges): void - { - if((this.ad !== null) && (this.ad !== undefined)) - { - const nbImages = this.ad.images.length; - const indexImage = Math.floor(Math.random() * nbImages); - this.image = this.ad.images[indexImage]; - this.imageExist = true; - } - } - - - onClick(): void - { - if((this.ad.url !== "") && (this.ad.url !== null) && (this.ad.url !== undefined)) { - document.location.href = this.ad.url; - } - } - -} diff --git a/src/app/user/utils/components/navbar-user/navbar-user.component.html b/src/app/user/utils/components/navbar-user/navbar-user.component.html deleted file mode 100644 index 605e192..0000000 --- a/src/app/user/utils/components/navbar-user/navbar-user.component.html +++ /dev/null @@ -1,41 +0,0 @@ - diff --git a/src/app/user/utils/components/navbar-user/navbar-user.component.scss b/src/app/user/utils/components/navbar-user/navbar-user.component.scss deleted file mode 100644 index 285d629..0000000 --- a/src/app/user/utils/components/navbar-user/navbar-user.component.scss +++ /dev/null @@ -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; -} diff --git a/src/app/user/utils/components/navbar-user/navbar-user.component.spec.ts b/src/app/user/utils/components/navbar-user/navbar-user.component.spec.ts deleted file mode 100644 index 5d03960..0000000 --- a/src/app/user/utils/components/navbar-user/navbar-user.component.spec.ts +++ /dev/null @@ -1,25 +0,0 @@ -import { ComponentFixture, TestBed } from '@angular/core/testing'; - -import { NavbarUserComponent } from './navbar-user.component'; - -describe('NavbarUserComponent', () => { - let component: NavbarUserComponent; - let fixture: ComponentFixture; - - beforeEach(async () => { - await TestBed.configureTestingModule({ - declarations: [ NavbarUserComponent ] - }) - .compileComponents(); - }); - - beforeEach(() => { - fixture = TestBed.createComponent(NavbarUserComponent); - component = fixture.componentInstance; - fixture.detectChanges(); - }); - - it('should create', () => { - expect(component).toBeTruthy(); - }); -}); diff --git a/src/app/user/utils/components/navbar-user/navbar-user.component.ts b/src/app/user/utils/components/navbar-user/navbar-user.component.ts deleted file mode 100644 index 5947c0b..0000000 --- a/src/app/user/utils/components/navbar-user/navbar-user.component.ts +++ /dev/null @@ -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-user', - templateUrl: './navbar-user.component.html', - styleUrls: ['./navbar-user.component.scss'] -}) -export class NavbarUserComponent -{ - routes: string[] = [ - "/user", // 0 - "/user/search", // 1 - "/user/myPlaylists", // 2 - "/user/history", // 3 - "/user/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); - } - -} diff --git a/src/app/user/utils/components/popup-add-video-to-playlists/popup-add-video-to-playlists.component.html b/src/app/user/utils/components/popup-add-video-to-playlists/popup-add-video-to-playlists.component.html deleted file mode 100644 index 115b281..0000000 --- a/src/app/user/utils/components/popup-add-video-to-playlists/popup-add-video-to-playlists.component.html +++ /dev/null @@ -1,42 +0,0 @@ -

Ajouter dans

- - - - - -
-
- {{playlist.name}} -
-
- - - - - -
- -
- -
- - Nom playlist - - - -
- - - - - - {{errorMessage}} - - - - diff --git a/src/app/user/utils/components/popup-add-video-to-playlists/popup-add-video-to-playlists.component.scss b/src/app/user/utils/components/popup-add-video-to-playlists/popup-add-video-to-playlists.component.scss deleted file mode 100644 index a6f9d32..0000000 --- a/src/app/user/utils/components/popup-add-video-to-playlists/popup-add-video-to-playlists.component.scss +++ /dev/null @@ -1,39 +0,0 @@ -h3 { - text-align: center; - margin-bottom: 10px -} - -.conteneurPlaylists { - margin-top: 10px; - margin-bottom: 10px; -} - -.conteneurBtnCreerPlaylist { - margin-top: 10px; - margin-bottom: 10px; -} - -.conteneurInputNewPlaylist { - margin-top: 10px; - margin-bottom: 10px; -} - - -// ------------------------------------------------------------------------- - - -// 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 { - border-color: black !important; - background-color: white !important; -} diff --git a/src/app/user/utils/components/popup-add-video-to-playlists/popup-add-video-to-playlists.component.spec.ts b/src/app/user/utils/components/popup-add-video-to-playlists/popup-add-video-to-playlists.component.spec.ts deleted file mode 100644 index 5ace846..0000000 --- a/src/app/user/utils/components/popup-add-video-to-playlists/popup-add-video-to-playlists.component.spec.ts +++ /dev/null @@ -1,25 +0,0 @@ -import { ComponentFixture, TestBed } from '@angular/core/testing'; - -import { PopupAddVideoToPlaylistsComponent } from './popup-add-video-to-playlists.component'; - -describe('PopupAddVideoToPlaylistsComponent', () => { - let component: PopupAddVideoToPlaylistsComponent; - let fixture: ComponentFixture; - - beforeEach(async () => { - await TestBed.configureTestingModule({ - declarations: [ PopupAddVideoToPlaylistsComponent ] - }) - .compileComponents(); - }); - - beforeEach(() => { - fixture = TestBed.createComponent(PopupAddVideoToPlaylistsComponent); - component = fixture.componentInstance; - fixture.detectChanges(); - }); - - it('should create', () => { - expect(component).toBeTruthy(); - }); -}); diff --git a/src/app/user/utils/components/popup-add-video-to-playlists/popup-add-video-to-playlists.component.ts b/src/app/user/utils/components/popup-add-video-to-playlists/popup-add-video-to-playlists.component.ts deleted file mode 100644 index 6a2d58d..0000000 --- a/src/app/user/utils/components/popup-add-video-to-playlists/popup-add-video-to-playlists.component.ts +++ /dev/null @@ -1,141 +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-add-video-to-playlists', - templateUrl: './popup-add-video-to-playlists.component.html', - styleUrls: ['./popup-add-video-to-playlists.component.scss'] -}) -export class PopupAddVideoToPlaylistsComponent implements OnInit -{ - _idVideo: string = ""; - videoId: string = ""; - source: string = ""; - interest: string = ""; - - tabPlaylistAndBool = []; - - goToCreatePlaylist = false; - newPlaylistName = ""; - hasError: boolean = false; - tabNomPlaylist: string[] = []; - errorMessage: string = "" ; - - - constructor( public dialogRef: MatDialogRef, - @Inject(MAT_DIALOG_DATA) public data, - private messageService: MessageService) { } - - - ngOnInit(): void - { - this._idVideo = this.data._idVideo; - this.videoId = this.data.videoId; - this.source = this.data.source; - this.interest = this.data.interest; - - for(let playlist of this.data.playlists) - { - if(playlist.videoIds.includes(this._idVideo)) playlist["isSelected"] = true; - else playlist["isSelected"] = false; - this.tabPlaylistAndBool.push(playlist); - this.tabNomPlaylist.push(playlist.name); - } - } - - - onValider(): void - { - this.checkError(); - if(!this.hasError) - { - // --- Existing playlists --- - let listeDesPlaylistsSelected = "" ; - let listeDesPlaylistsNotSelected = "" ; - for(let playlist of this.tabPlaylistAndBool) - { - if(playlist.isSelected) listeDesPlaylistsSelected += playlist.id + "," ; - else listeDesPlaylistsNotSelected += playlist.id + "," ; - } - if(listeDesPlaylistsSelected.endsWith(",")) listeDesPlaylistsSelected = listeDesPlaylistsSelected.slice(0, listeDesPlaylistsSelected.length-1); - if(listeDesPlaylistsNotSelected.endsWith(",")) listeDesPlaylistsNotSelected = listeDesPlaylistsNotSelected.slice(0, listeDesPlaylistsNotSelected.length-1); - - if(listeDesPlaylistsSelected !== "") - { - const data1 = { videoId: { id: this._idVideo, action: "add" } }; - this.messageService - .put( "playlist/update/"+listeDesPlaylistsSelected, data1) - .subscribe( ret => this.callbackForExistingPlaylists(ret), err => this.callbackForExistingPlaylists(err)); - } - if(listeDesPlaylistsNotSelected !== "") - { - const data2 = { videoId: { id: this._idVideo, action: "delete" } }; - this.messageService - .put( "playlist/update/"+listeDesPlaylistsNotSelected, data2) - .subscribe( ret => this.callbackForExistingPlaylists(ret), err => this.callbackForExistingPlaylists(err)); - } - - - // --- New playlists --- - if(this.goToCreatePlaylist) - { - const data3 = { - name: this.newPlaylistName, - video: {videoId: this.videoId, interest: this.interest, source: this.source} - }; - this.messageService - .post("playlist/create", data3) - .subscribe( ret => this.callbackForNewPlaylist(ret), err => this.callbackForNewPlaylist(err)); - } - - - // --- Finalement --- - this.dialogRef.close("success"); - } - } - - - callbackForExistingPlaylists(retour: any): void - { - if(retour.status !== "success") { - console.log(retour); - this.dialogRef.close(null); - } - } - - - callbackForNewPlaylist(retour: any): void - { - if(retour.status !== "success") { - console.log(retour); - this.dialogRef.close(null); - } - } - - - onAnnuler(): void - { - this.dialogRef.close("annulation"); - } - - - checkError(): void - { - if(this.goToCreatePlaylist && (this.newPlaylistName === "")) { - this.errorMessage = "Le nom ne peut pas être vide" ; - this.hasError = true; - } - else if(this.goToCreatePlaylist && this.tabNomPlaylist.includes(this.newPlaylistName)){ - this.errorMessage = "Ce nom est déjà utilisé" ; - this.hasError = true; - } - else { - this.hasError = false; - this.errorMessage = "" ; - } - } - -} diff --git a/src/app/user/utils/services/addVideoToPlaylists/add-video-to-playlists.service.spec.ts b/src/app/user/utils/services/addVideoToPlaylists/add-video-to-playlists.service.spec.ts deleted file mode 100644 index 6097218..0000000 --- a/src/app/user/utils/services/addVideoToPlaylists/add-video-to-playlists.service.spec.ts +++ /dev/null @@ -1,16 +0,0 @@ -import { TestBed } from '@angular/core/testing'; - -import { AddVideoToPlaylistsService } from './add-video-to-playlists.service'; - -describe('PlaylistService', () => { - let service: AddVideoToPlaylistsService; - - beforeEach(() => { - TestBed.configureTestingModule({}); - service = TestBed.inject(AddVideoToPlaylistsService); - }); - - it('should be created', () => { - expect(service).toBeTruthy(); - }); -}); diff --git a/src/app/user/utils/services/addVideoToPlaylists/add-video-to-playlists.service.ts b/src/app/user/utils/services/addVideoToPlaylists/add-video-to-playlists.service.ts deleted file mode 100644 index 50a5606..0000000 --- a/src/app/user/utils/services/addVideoToPlaylists/add-video-to-playlists.service.ts +++ /dev/null @@ -1,102 +0,0 @@ -import { Injectable } from '@angular/core'; -import {MessageService} from "../../../../utils/services/message/message.service"; -import {MatDialog} from "@angular/material/dialog"; -import {PopupAddVideoToPlaylistsComponent} from "../../components/popup-add-video-to-playlists/popup-add-video-to-playlists.component"; -import {MatSnackBar} from "@angular/material/snack-bar"; -import {FictitiousVideosService} from "../../../../utils/services/fictitiousDatas/fictitiousVideos/fictitious-videos.service"; - - - -@Injectable({ - providedIn: 'root' -}) -export class AddVideoToPlaylistsService -{ - private _idVideo: string = "" ; - private videoId: string = "" ; - private source: string = "" ; - private interest: string = "" ; - - - constructor( private messageService: MessageService, - public dialog: MatDialog, - private fictitiousVideosService: FictitiousVideosService, - private snackBar: MatSnackBar ) { } - - - run(videoId: string, source: string, interest: string): void - { - this.videoId = videoId; - this.source = source; - this.interest = interest; - - const data = { source: this.source, interest: this.interest }; - this.messageService - .post("video/create/"+this.videoId, data) - .subscribe(ret => this.afterCreatingVideo(ret), err => this.afterCreatingVideo(err)); - } - - - private afterCreatingVideo(retour: any): void - { - if(retour.status !== "success") { - console.log(retour); - } - else { - this._idVideo = retour.data.id; - this.messageService - .get('playlist/findAll') - .subscribe( ret => this.afterReceivingPlaylists(ret), ret => this.afterReceivingPlaylists(ret) ); - } - } - - - - private afterReceivingPlaylists(retour: any): void - { - if(retour.status !== "success") { - console.log(retour); - } - else - { - const config = { - width: '30%', - data: { - _idVideo: this._idVideo, - videoId: this.videoId, - source: this.source, - interest: this.interest, - playlists: retour.data.filter(x => x.isActive === true) - } - }; - this.dialog - .open(PopupAddVideoToPlaylistsComponent, config) - .afterClosed() - .subscribe(retour => this.afterClosingDialog(retour)); - } - } - - - - private afterClosingDialog(retour): void - { - let message = "" ; - switch (retour) - { - case "error": - message = "Echec de l'opération ❌" ; - break; - case "success": - message = "La vidéo a bien été ajoutée ✔" ; - break; - case "annulation": - case null: - case undefined: - message = "Opération annulée" ; - break; - } - const config = { duration: 1000, panelClass: "custom-class" }; - this.snackBar.open( message, "", config); - } - -} diff --git a/src/app/user/watching/page-watching-video/page-watching-video.component.html b/src/app/user/watching/page-watching-video/page-watching-video.component.html deleted file mode 100644 index 9cf8392..0000000 --- a/src/app/user/watching/page-watching-video/page-watching-video.component.html +++ /dev/null @@ -1,233 +0,0 @@ - - - -
-
- - -
- -
- - - - -
- - -
-
- - -
-
- - -
- - -   - - logo - -   - - - -   - - logo - -   - -
- -
- - - - -
- - -
- - - -

- -
-
- - - - - - - -
- - -
- -
- - -
-
-
- - -
- -
- -
-
- - - - - - - -
- - -
- -
- - -
-
-
- - -
-
-
- -
-
- - - - - - - - - -
- - -
- -
- - -
- -
- -
- - - -
- - -
- ytb - dlm -
  {{video.title}}
-
- - -
- -
- - -
- Vues: - {{video.views | number: '1.0-0'}} -
- - -
- Date de publication: - {{ video.publishedAt | date:'dd/LL/YYYY à HH:mm:ss' }} -
- - -
-
- Description - expand_more - expand_less -
-
- {{video.description}} -
-
- -
- -
- - - - - - - -
- - -
- {{playlist.name}} -
- - - -
-
-
-
- - -
-
-
{{video0.title}}
-
- - {{video.views | number: '1.0-0'}} vues -
- - Publiée le {{ video.publishedAt | date:'dd/LL/YYYY à HH:mm:ss' }} - -
-
-
-
- - - - - -
-
diff --git a/src/app/user/watching/page-watching-video/page-watching-video.component.scss b/src/app/user/watching/page-watching-video/page-watching-video.component.scss deleted file mode 100644 index d3f10e8..0000000 --- a/src/app/user/watching/page-watching-video/page-watching-video.component.scss +++ /dev/null @@ -1,159 +0,0 @@ -.lightTheme { - color: black; - border-color: black; -} -.darkTheme { - color: white; - border-color: white; -} -.myContainer { - text-align: center; - max-width: 100vw; - height: 100vh; - overflow-x: hidden; - overflow-y: scroll; -} - -//-------------------------------------------------------------------------------------------- - -.inputSearchBar { - width: 40%; - font-size: large; - border-bottom: 10px; - border-radius: 5px; -} - -//-------------------------------------------------------------------------------------------- -// --- Playlist --- - -.playlistContainer { - border: solid 1px black; - width: 98%; - border-top-right-radius: 10px; - border-top-left-radius: 10px; -} - -.topBorder { - margin: 0px 0px 0px 0px; - //background-color: #dcdcdc; - background: linear-gradient(top, rgba(38,38,38,0.8), #e6e6e6 25%, #fff 38%, #c5c5c5 87%, rgba(38,38,38,0.8)); - background: -webkit-linear-gradient(top, #c5c5c5, #e6e6e6 25%, #fff 38%, #c5c5c5 87%, #c5c5c5); - text-align: left; - padding: 5px 0px 5px 5px; - border-bottom: solid 1px black; - border-top-right-radius: 10px; - border-top-left-radius: 10px; -} - -.listVideoContainer { - height: 70vh; - background-color: white; - overflow-y: scroll; -} - -.videoCell { - margin: 0px 0px 0px 0px; - padding: 10px 0px 10px 10px; - border-bottom: solid 1px black; - cursor: pointer; -} -.videoCell:hover { - background-color: #f0f0f0; -} - -.videoCellFocus { - background-color: #e6e6e6; -} -.videoCellFocus:hover { - background-color: #e6e6e6; -} - - -// ---- - -.imgsContainer { - position: relative; - width: 13vw; - height: 10vh; - float: left; -} - -.imgVideo { - border: solid 1px black; - width: 13vw; - height: 10vh; - padding: 0px 0px 0px 0px; -} - -.imgPlay { - position: absolute; - margin-left: 6vw; - width: 2vw; - margin-top: 3vh; - height: 4vh; - padding: 0px 0px 0px 0px; -} - -// ---- - -.infoContainer { - display: table-cell; - margin-left: 13vw; - height: 10vh; - padding-left: 5px; - vertical-align: middle; -} - -.titleContainer { - font-weight: bold; - text-align: left; -} - -.viewsContainer { - text-align: left; - display: flex; - align-items: center; - font-size: x-small; - color: grey; -} -mat-icon { - vertical-align: middle; - //font-size: x-small; -} - -.publishedAtContainer { - text-align: left; - font-size: x-small; - color: grey; -} - - -// ---- - -.bottomBorder { - margin: 0px 0px 0px 0px; - background-color: #dcdcdc; - border-top: solid 1px black; - border-bottom: solid 1px black; - font-size: 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 { - border: solid 1px black !important; - background-color: white !important; -} diff --git a/src/app/user/watching/page-watching-video/page-watching-video.component.spec.ts b/src/app/user/watching/page-watching-video/page-watching-video.component.spec.ts deleted file mode 100644 index 6790456..0000000 --- a/src/app/user/watching/page-watching-video/page-watching-video.component.spec.ts +++ /dev/null @@ -1,25 +0,0 @@ -import { ComponentFixture, TestBed } from '@angular/core/testing'; - -import { PageWatchingVideoComponent } from './page-watching-video.component'; - -describe('PageWatchingVideoComponent', () => { - let component: PageWatchingVideoComponent; - let fixture: ComponentFixture; - - beforeEach(async () => { - await TestBed.configureTestingModule({ - declarations: [ PageWatchingVideoComponent ] - }) - .compileComponents(); - }); - - beforeEach(() => { - fixture = TestBed.createComponent(PageWatchingVideoComponent); - component = fixture.componentInstance; - fixture.detectChanges(); - }); - - it('should create', () => { - expect(component).toBeTruthy(); - }); -}); diff --git a/src/app/user/watching/page-watching-video/page-watching-video.component.ts b/src/app/user/watching/page-watching-video/page-watching-video.component.ts deleted file mode 100644 index b632ac6..0000000 --- a/src/app/user/watching/page-watching-video/page-watching-video.component.ts +++ /dev/null @@ -1,264 +0,0 @@ -import { Component, OnInit } from '@angular/core'; -import {VideoAll} from "../../../utils/interfaces/video"; -import {MessageService} from "../../../utils/services/message/message.service"; -import {FictitiousVideosService} from "../../../utils/services/fictitiousDatas/fictitiousVideos/fictitious-videos.service"; -import {FictitiousAdvertsService} from "../../../utils/services/fictitiousDatas/fictitiousAdverts/fictitious-adverts.service"; -import {ThemeService} from "../../../utils/services/theme/theme.service"; -import {ActivatedRoute, Router} from "@angular/router"; -import {AddVideoToPlaylistsService} from "../../utils/services/addVideoToPlaylists/add-video-to-playlists.service"; -import {PlaylistDB} from "../../../utils/interfaces/playlist"; -import {DomSanitizer, SafeResourceUrl} from "@angular/platform-browser"; -import {HttpParams} from "@angular/common/http"; - - - -let TAB_PLATEFORM = [ - { name: "youtube", isSelected: false }, - { name: "dailymotion", isSelected: false } -]; - - - -@Component({ - selector: 'app-page-watching-video', - templateUrl: './page-watching-video.component.html', - styleUrls: ['./page-watching-video.component.scss'] -}) -export class PageWatchingVideoComponent implements OnInit -{ - tabPlateform = TAB_PLATEFORM; - sources: string = ""; - video = { - title: "", - videoId: "", - views: 0, - publishedAt: null, - description: "", - source: "", - interest: "" - }; - search: string = ""; - - ad1: any; - ad2: any; - from: string = ""; - - playlist: any; - videosInPlaylist: any[] = []; - - paramsFromOldPage ; - - hiddenDescription: boolean = true; - iframeStyle: string = ""; - containerStyle: string = ""; - - - constructor( private messageService: MessageService, - private fictitiousVideosService: FictitiousVideosService, - private fictitiousAdvertsService: FictitiousAdvertsService, - public themeService: ThemeService, - private activatedRoute: ActivatedRoute, - private router: Router, - private _sanitizer: DomSanitizer, - private addVideoToPlaylistsService: AddVideoToPlaylistsService ) { } - - - - ngOnInit(): void - { - // Ask for videos - this.activatedRoute - .queryParams - .subscribe(paramsFromOldPage => { - - this.paramsFromOldPage = paramsFromOldPage; - const videoId = paramsFromOldPage.videoId; - let source = paramsFromOldPage.source; - - let params = new HttpParams(); - if(source === "Youtube") source = "yt"; - else if(source === "Dailymotion") source = "dm" ; - params = params.append("source", source); - this.messageService - .get("video/get/"+videoId, params) - .subscribe(ret => this.findVideoCallback(ret), err => this.findVideoCallback(err)); - }); - - - // Ask for adverts - let params = new HttpParams(); - params = params.append("quantity", 2); - this.messageService - .get("user/ad", params) - .subscribe(ret => this.findAdCallback(ret), err => this.findAdCallback(err)); - - - // Si on vient de la page "search" - if(this.router.url.includes("search")) - { - this.from = "search" ; - this.activatedRoute - .queryParams - .subscribe(paramsFromOldPage => { - if(paramsFromOldPage.hasOwnProperty("search")) this.search = paramsFromOldPage.search; - if(paramsFromOldPage.hasOwnProperty("sources")) { - this.sources = paramsFromOldPage.sources; - if(this.sources === "yt") { - this.tabPlateform[0].isSelected = true; - this.tabPlateform[1].isSelected = false; - } - else if(this.sources === "dm") { - this.tabPlateform[0].isSelected = false; - this.tabPlateform[1].isSelected = true; - } - else if(this.sources === "yt,dm") { - this.tabPlateform[0].isSelected = true; - this.tabPlateform[1].isSelected = true; - } - } - }); - } - // si on vient de la page "myPlaylists" - else if(this.router.url.includes("myPlaylists")) - { - this.from = "myPlaylists"; - this.activatedRoute - .queryParams - .subscribe(paramsFromOldPage => { - const _idPlaylist = paramsFromOldPage._idPlaylist; - this.messageService - .get("playlist/findOne/"+_idPlaylist) - .subscribe(ret => this.afterReceivingPlaylistWithVideo(ret), err => this.afterReceivingPlaylistWithVideo(err)); - }); - - } - // si on vient de la page "history" - else if(this.router.url.includes("history")) this.from = "history"; - - - // style - if(this.from === 'search' || this.from === 'history') { - this.containerStyle = "margin: 0 auto; width: 64vw;" ; - this.iframeStyle = "width: 64vw; height: 60vh;" ; - } - else { - this.containerStyle = "margin: 0 auto; width: 48vw;" ; - this.iframeStyle = "width: 48vw; height: 45vh;" ; - } - } - - - - findVideoCallback(retour: any): void - { - if(retour.status !== "success") { - console.log("findVideoCallback: "); - console.log(retour); - } - else { - this.video = retour.data; - } - } - - - findAdCallback(retour: any): void - { - if(retour.status !== "success") { - console.log("findAdCallback: "); - console.log(retour); - } - else { - this.ad1 = retour.data[0]; - this.ad2 = retour.data[1]; - } - } - - - afterReceivingPlaylistWithVideo(retour: any): void - { - if(retour.status !== "success") { - console.log("afterReceivingPlaylistWithVideo"); - console.log(retour); - } - else { - this.playlist = retour.data; - this.videosInPlaylist = retour.data.videos; - } - } - - - onSearch() - { - if(this.tabPlateform[0].isSelected && this.tabPlateform[1].isSelected) this.sources = "yt,dm" ; - else if((!this.tabPlateform[0].isSelected) && this.tabPlateform[1].isSelected) this.sources = "dm" ; - else if(this.tabPlateform[0].isSelected && (!this.tabPlateform[1].isSelected)) this.sources = "yt" ; - else this.sources = "" ; - let options = { - queryParams: { - search: this.search, - sources: this.sources, - indexPage: 0, - } - }; - this.router.navigate(['/user/search'], options); - } - - - onAddToPlaylist(): void - { - this.addVideoToPlaylistsService.run(this.video.videoId, this.video.source, this.video.interest); - } - - - onRetour(): void - { - let url: string[] = []; - let options = {}; - - if(this.from === 'search') - { - url = ['/user/search']; - options = { - queryParams: { - search: this.paramsFromOldPage.search, - sources: this.paramsFromOldPage.sources, - indexPage: this.paramsFromOldPage.indexPage, - } - }; - } - else if(this.from === 'myPlaylists') url = ["/user/myPlaylists"]; - else if(this.from === 'history') url = ["/user/history"]; - - this.router.navigate(url, options); - } - - - safeUrl(videoId: string, source: string): SafeResourceUrl - { - let videoUrl = "" ; - if(source === 'Youtube') videoUrl = "https://www.youtube.com/embed/" + videoId + "?autoplay=1"; - else if(source === 'Dailymotion') videoUrl = "https://www.dailymotion.com/embed/video/" + videoId + "?autoplay=true"; - return this._sanitizer.bypassSecurityTrustResourceUrl(videoUrl); - } - - - // retourne la classe CSS de videoCell - getClassOfVideoCell(video0: VideoAll): string - { - if(video0 === this.video) return "videoCell videoCellFocus" ; - else return "videoCell" ; - } - - - onEnterOnSearchBar(event) - { - if(event.key === 'Enter') this.onSearch(); - } - - - playlistExists(): boolean - { - return ((this.playlist !== null) && (this.playlist !== undefined)); - } - -} diff --git a/src/app/utils/interfaces/advert.ts b/src/app/utils/interfaces/advert.ts deleted file mode 100644 index 55da7c0..0000000 --- a/src/app/utils/interfaces/advert.ts +++ /dev/null @@ -1,39 +0,0 @@ -export interface Advert -{ - _id: string, - userId: string, - title: string, - url: string, - images: { - url: string, - description: string, - }[], - interests: string[], - comment: string, - views: Date[], - isVisible: boolean, - isActive: boolean, - createdAt: Date, - updatedAt: Date, -} - - - -export interface AdvertWithCountViews { - id: string, - userId: string, - title: string, - url: string, - images: { - url: string, - description: string, - }[], - interests: string[], - comment: string, - views: Date[], - countViews: number, - isVisible: boolean, - isActive: boolean, - createdAt: Date, - updatedAt: Date, -} diff --git a/src/app/utils/interfaces/playlist.ts b/src/app/utils/interfaces/playlist.ts deleted file mode 100644 index 4ffa611..0000000 --- a/src/app/utils/interfaces/playlist.ts +++ /dev/null @@ -1,10 +0,0 @@ -export interface PlaylistDB -{ - _id: string, - userId: string, - name: string, - videoIds: string[], - isActive: boolean - createdAt: Date, - updatedAt: Date -} diff --git a/src/app/utils/interfaces/user.ts b/src/app/utils/interfaces/user.ts deleted file mode 100644 index f46977f..0000000 --- a/src/app/utils/interfaces/user.ts +++ /dev/null @@ -1,33 +0,0 @@ -export interface User -{ - _id: string, - email: string, - hashPass: string, - login: string, - role: { - name: string, - permission: number, - isAccepted: boolean, - }, - profileImageUrl: string, - dateOfBirth: Date, - gender: string, - interests: any[], - company: string, - isActive: boolean, - lastConnexion: Date, - createdAt: Date, - updatedAt: Date -} - - -interface VideoCategorie -{ - id: number - interest: string - categories: { - id: string - name: string - source: string - } -} diff --git a/src/app/utils/interfaces/video.ts b/src/app/utils/interfaces/video.ts deleted file mode 100644 index 1c93427..0000000 --- a/src/app/utils/interfaces/video.ts +++ /dev/null @@ -1,32 +0,0 @@ -export interface VideoDB -{ - _id: string, - userId: string, - videoId: string, - source: string, - tags: string[], - interest: string, - watchedDates: Date[], - createdAt: Date, - updatedAt: Date -} - - -export interface VideoAll -{ - _id: string, - userId: string, - videoId: string, - source: string, - tags: String[], - interest: string, - watchedDates: Date[], - createdAt: Date, - updatedAt: Date - - title: string, - views: number, - publishedAt: Date, - description: string, - imageUrl: string -} diff --git a/src/app/utils/services/fictitiousDatas/fictitiousAdverts/fictitious-adverts.service.spec.ts b/src/app/utils/services/fictitiousDatas/fictitiousAdverts/fictitious-adverts.service.spec.ts deleted file mode 100644 index 0cd9f3c..0000000 --- a/src/app/utils/services/fictitiousDatas/fictitiousAdverts/fictitious-adverts.service.spec.ts +++ /dev/null @@ -1,16 +0,0 @@ -import { TestBed } from '@angular/core/testing'; - -import { FictitiousAdvertsService } from './fictitious-adverts.service'; - -describe('FictitiousAdvertsService', () => { - let service: FictitiousAdvertsService; - - beforeEach(() => { - TestBed.configureTestingModule({}); - service = TestBed.inject(FictitiousAdvertsService); - }); - - it('should be created', () => { - expect(service).toBeTruthy(); - }); -}); diff --git a/src/app/utils/services/fictitiousDatas/fictitiousAdverts/fictitious-adverts.service.ts b/src/app/utils/services/fictitiousDatas/fictitiousAdverts/fictitious-adverts.service.ts deleted file mode 100644 index 2dd7702..0000000 --- a/src/app/utils/services/fictitiousDatas/fictitiousAdverts/fictitious-adverts.service.ts +++ /dev/null @@ -1,130 +0,0 @@ -import { Injectable } from '@angular/core'; -import {Advert} from "../../../interfaces/advert"; -import {FictitiousUtilsService} from "../fictitiousUtils/fictitious-utils.service"; - - - -const TAB_ADVERT: Advert[] = [ - { - _id: "idNutella", - userId: "userId", - title: "pot de nutella XXL", - url: "https://www.nutella.com/fr/fr/", - images: [ - { url: "nutella_v_1.jpeg", description: "image nutella 1" }, - { url: "nutella_v_2.png", description: "image nutella 2" }, - { url: "nutella_v_3.jpg", description: "image nutella 3" } - ], - interests: [ "rock", "basket" ], - comment: "pub pour vacances de noêl", - views: [ - new Date(2021,10,1), - new Date(2021,10,2), - new Date(2021,10,3), - new Date(2021,10,3), - new Date(2021,10,5), - new Date(2021,10,5), - new Date(2021,10,5), - new Date(2021,10,5), - new Date(2021,10,5), - new Date(2021,10,7) - ], - isVisible: true, - isActive: true, - createdAt: new Date(), - updatedAt: new Date(), - }, - { - _id: "idRolex", - userId: "userId", - title: "Rolex", - url: "https://www.rolex.com", - images: [ - { url: "rolex_v_1.jpg", description: "rolex 1" }, - { url: "rolex_v_2.png", description: "rolex 2" }, - ], - interests: [ "rock", "rap" ], - comment: "pub pour cette année", - views: [ - new Date(2021,10,5), - new Date(2021,10,6), - new Date(2021,10,7), - new Date(2021,10,8), - new Date(2021,10,8), - new Date(2021,10,8), - new Date(2021,10,25), - new Date(2021,10,25), - new Date(2021,10,25), - new Date(2021,10,27) - ], - isVisible: true, - isActive: true, - createdAt: new Date(), - updatedAt: new Date(), - }, - { - _id: "idAlbion", - userId: "userId", - title: "Albion new version", - url: "https://www.rolex.com", - images: [ - { url: "rolex_v_1.jpg", description: "albion 1" }, - { url: "rolex_v_2.png", description: "albion 2" }, - ], - interests: [ "rock", "rap" ], - comment: "pub pour cette année", - views: [ - new Date(2021,10,3), - new Date(2021,10,4), - new Date(2021,10,4), - new Date(2021,10,5), - new Date(2021,10,5), - new Date(2021,10,6), - new Date(2021,10,6), - new Date(2021,10,8), - new Date(2021,10,8), - new Date(2021,10,8) - ], - isVisible: true, - isActive: true, - createdAt: new Date(), - updatedAt: new Date(), - } -]; - - - -@Injectable({ - providedIn: 'root' -}) -export class FictitiousAdvertsService -{ - - constructor(private fictitiousUtilsService: FictitiousUtilsService) {} - - - getAdvert(): Advert - { - const idx = Math.floor(Math.random() * TAB_ADVERT.length); - let advert = Object.assign({}, TAB_ADVERT[idx]); - advert._id = advert._id + this.fictitiousUtilsService.makeid(5); - advert.interests = advert.interests.slice(); - advert.isVisible = (Math.random() < 0.5); - return advert; - } - - - getTabAdvert(n: number): Advert[] - { - let tabAdvert = []; - for(let i=0 ; i { - let service: FictitiousUsersService; - - beforeEach(() => { - TestBed.configureTestingModule({}); - service = TestBed.inject(FictitiousUsersService); - }); - - it('should be created', () => { - expect(service).toBeTruthy(); - }); -}); diff --git a/src/app/utils/services/fictitiousDatas/fictitiousUsers/fictitious-users.service.ts b/src/app/utils/services/fictitiousDatas/fictitiousUsers/fictitious-users.service.ts deleted file mode 100644 index e629e97..0000000 --- a/src/app/utils/services/fictitiousDatas/fictitiousUsers/fictitious-users.service.ts +++ /dev/null @@ -1,128 +0,0 @@ -import { Injectable } from '@angular/core'; -import {User} from "../../../interfaces/user"; -import {FictitiousUtilsService} from "../fictitiousUtils/fictitious-utils.service"; - - - -const USER: User = { - _id: "ririId", - login: "Riri", - hashPass: "agourgroou", - email: "riri@gmail.com", - role: { - name: "user", - permission: 0, - isAccepted: true, - - }, - profileImageUrl: "https://www.figurines-goodies.com/1185-thickbox_default/huey-duck-tales-disney-funko-pop.jpg", - dateOfBirth: new Date(), - gender: "man", - interests: ["foot", "jeux-vidéo"], - company: "", - isActive: true, - lastConnexion: new Date(), - createdAt: new Date(), - updatedAt: new Date() -}; - -const ADVERTISER: User = { - _id: "fifiId", - login: "Fifi", - hashPass: "agourgroou", - email: "fifi@gmail.com", - role: { - name: "advertiser", - permission: 5, - isAccepted: true, - - }, - profileImageUrl: "https://www.figurines-goodies.com/1188-large_default/dewey-duck-tales-disney-funko-pop.jpg", - dateOfBirth: null, - gender: "", - interests: [], - company: "My company", - isActive: true, - lastConnexion: new Date(), - createdAt: new Date(), - updatedAt: new Date(), -}; - -const ADMIN: User = { - _id: "loulouId", - login: "Loulou", - hashPass: "agourgroou", - email: "loulou@gmail.com", - role: { - name: "admin", - permission: 5, - isAccepted: true, - }, - profileImageUrl: "https://www.reference-gaming.com/assets/media/product/41195/figurine-pop-duck-tales-n-309-loulou.jpg?format=product-cover-large&k=1519639530", - dateOfBirth: null, - gender: "", - interests: [], - company: "", - isActive: true, - lastConnexion: new Date(), - createdAt: new Date(), - updatedAt: new Date(), -}; - - - -@Injectable({ - providedIn: 'root' -}) -export class FictitiousUsersService -{ - - constructor(private fictitiousUtilsService: FictitiousUtilsService) { } - - private getUserOrAdvertiserOrAdmin(modele: User): User - { - const res = Object.assign({}, modele); - res._id += this.fictitiousUtilsService.makeid(5); - res.login += (Math.floor(Math.random() * 1000)).toString(); - res.email = res.login + "@gmail.com" ; - res.role.isAccepted = (Math.random() < 0.5); - res.isActive = (Math.random() < 0.5); - res.dateOfBirth = this.fictitiousUtilsService.randomDate(new Date(1900, 0, 1), new Date()); - res.lastConnexion = this.fictitiousUtilsService.randomDate(new Date(2000, 0, 1), new Date()); - return res; - } - - getUser(): User { - return this.getUserOrAdvertiserOrAdmin(USER); - } - - getAdvertiser(): User { - return this.getUserOrAdvertiserOrAdmin(ADVERTISER); - } - - getAdmin(): User { - return this.getUserOrAdvertiserOrAdmin(ADMIN); - } - - getTabUser(n: number): User[] - { - const res: User[] = []; - for(let i=0 ; i { - let service: FictitiousUtilsService; - - beforeEach(() => { - TestBed.configureTestingModule({}); - service = TestBed.inject(FictitiousUtilsService); - }); - - it('should be created', () => { - expect(service).toBeTruthy(); - }); -}); diff --git a/src/app/utils/services/fictitiousDatas/fictitiousUtils/fictitious-utils.service.ts b/src/app/utils/services/fictitiousDatas/fictitiousUtils/fictitious-utils.service.ts deleted file mode 100644 index 4c06ecf..0000000 --- a/src/app/utils/services/fictitiousDatas/fictitiousUtils/fictitious-utils.service.ts +++ /dev/null @@ -1,33 +0,0 @@ -import { Injectable } from '@angular/core'; - - -@Injectable({ - providedIn: 'root' -}) -export class FictitiousUtilsService -{ - - makeid(length) - { - let res = ''; - const characters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789'; - for( let i = 0; i < length; i++ ) { - const k = Math.floor(Math.random() * characters.length); - res += characters.charAt(k); - } - return res; - } - - - randomDate(start, end): Date - { - return new Date(start.getTime() + Math.random() * (end.getTime() - start.getTime())); - } - - - getTags(): string[] - { - return [ "musique", "rap", "rock", "sport", "foot", "basket", "tennis", "film", "action", "aventure", "horreur", "romance", "comedie"]; - } - -} diff --git a/src/app/utils/services/fictitiousDatas/fictitiousVideos/fictitious-videos.service.spec.ts b/src/app/utils/services/fictitiousDatas/fictitiousVideos/fictitious-videos.service.spec.ts deleted file mode 100644 index e604845..0000000 --- a/src/app/utils/services/fictitiousDatas/fictitiousVideos/fictitious-videos.service.spec.ts +++ /dev/null @@ -1,16 +0,0 @@ -import { TestBed } from '@angular/core/testing'; - -import { FictitiousVideosService } from './fictitious-videos.service'; - -describe('FictitiousVideosService', () => { - let service: FictitiousVideosService; - - beforeEach(() => { - TestBed.configureTestingModule({}); - service = TestBed.inject(FictitiousVideosService); - }); - - it('should be created', () => { - expect(service).toBeTruthy(); - }); -}); diff --git a/src/app/utils/services/fictitiousDatas/fictitiousVideos/fictitious-videos.service.ts b/src/app/utils/services/fictitiousDatas/fictitiousVideos/fictitious-videos.service.ts deleted file mode 100644 index e0e0b4a..0000000 --- a/src/app/utils/services/fictitiousDatas/fictitiousVideos/fictitious-videos.service.ts +++ /dev/null @@ -1,289 +0,0 @@ -import { Injectable } from '@angular/core'; -import {VideoAll} from "../../../interfaces/video"; -import {PlaylistDB} from "../../../interfaces/playlist"; -import {FictitiousUtilsService} from "../fictitiousUtils/fictitious-utils.service"; - - - -const TAB_VIDEO: VideoAll[] = [ - { - _id: "Mowgli", - //videoId: "https://www.youtube.com/watch?v=medPORJ8KO0", - videoId: "medPORJ8KO0", - userId: "userId", - source: "youtube", - tags: [ "rap", "musique" ], - interest: "PNL", - watchedDates: [ - new Date(2021, 10, 15), - new Date(2021, 10, 16), - new Date(2021, 10, 17), - new Date(2021, 10, 18), - new Date(2021, 10, 19), - new Date(2021, 10, 20), - ], - createdAt: new Date(), - updatedAt: new Date(), - - title: "PNL - Mowgli", - views: 999999999, - publishedAt: new Date(), - imageUrl: "https://i.ytimg.com/vi/CaeH7TRnI3s/hq720.jpg?sqp=-oaymwEcCOgCEMoBSFXyq4qpAw4IARUAAIhCGAFwAcABBg==&rs=AOn4CLCr4TMUqy_Lqi9_zh7efICrF_V_Vw", - description: "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed non risus. Suspendisse lectus tortor, dignissim sit amet, adipiscing nec, ultricies sed, dolor. Cras elementum ultrices diam. Maecenas ligula massa, varius a, semper congue, euismod non, mi. Proin porttitor, orci nec nonummy molestie, enim est eleifend mi, non fermentum diam nisl sit amet erat. Duis semper. Duis arcu massa, scelerisque vitae, consequat in, pretium a, enim. Pellentesque congue. Ut in risus volutpat libero pharetra tempor. Cras vestibulum bibendum augue. Praesent egestas leo in pede. Praesent blandit odio eu enim. Pellentesque sed dui ut augue blandit sodales. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Aliquam nibh. Mauris ac mauris sed pede pellentesque fermentum. Maecenas adipiscing ante non diam sodales hendrerit. " - }, - { - _id: "Mexico", - //videoId: "https://www.youtube.com/watch?v=LZx6oeNeoWM", - videoId: "LZx6oeNeoWM", - userId: "userId", - source: "youtube", - tags: [ "rap", "musique" ], - interest: "PNL", - watchedDates: [new Date()], - createdAt: new Date(), - updatedAt: new Date(), - - title: "PNL - Mexico", - views: 999999, - publishedAt: new Date(), - imageUrl: "https://i.ytimg.com/vi/LZx6oeNeoWM/hq720.jpg?sqp=-oaymwEcCOgCEMoBSFXyq4qpAw4IARUAAIhCGAFwAcABBg==&rs=AOn4CLAIJsokYSLBB3TrnKhX5V1beCTrpQ", - description: "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed non risus. Suspendisse lectus tortor, dignissim sit amet, adipiscing nec, ultricies sed, dolor. Cras elementum ultrices diam. Maecenas ligula massa, varius a, semper congue, euismod non, mi. Proin porttitor, orci nec nonummy molestie, enim est eleifend mi, non fermentum diam nisl sit amet erat. Duis semper. Duis arcu massa, scelerisque vitae, consequat in, pretium a, enim. Pellentesque congue. Ut in risus volutpat libero pharetra tempor. Cras vestibulum bibendum augue. Praesent egestas leo in pede. Praesent blandit odio eu enim. Pellentesque sed dui ut augue blandit sodales. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Aliquam nibh. Mauris ac mauris sed pede pellentesque fermentum. Maecenas adipiscing ante non diam sodales hendrerit. " - }, - { - _id: "Luz de luna", - //videoId: "https://www.youtube.com/watch?v=fGoPhSV2Jic", - videoId: "fGoPhSV2Jic", - userId: "userId", - source: "youtube", - tags: [ "rap", "musique" ], - interest: "PNL", - watchedDates: [new Date()], - createdAt: new Date(), - updatedAt: new Date(), - - title: "PNL - Luz de luna", - views: 999999, - publishedAt: new Date(), - imageUrl: "https://i.ytimg.com/vi/fGoPhSV2Jic/hq720.jpg?sqp=-oaymwEcCOgCEMoBSFXyq4qpAw4IARUAAIhCGAFwAcABBg==&rs=AOn4CLBICz3ZfnjAXQNZQniiCTRLbdyLcg", - description: "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed non risus. Suspendisse lectus tortor, dignissim sit amet, adipiscing nec, ultricies sed, dolor. Cras elementum ultrices diam. Maecenas ligula massa, varius a, semper congue, euismod non, mi. Proin porttitor, orci nec nonummy molestie, enim est eleifend mi, non fermentum diam nisl sit amet erat. Duis semper. Duis arcu massa, scelerisque vitae, consequat in, pretium a, enim. Pellentesque congue. Ut in risus volutpat libero pharetra tempor. Cras vestibulum bibendum augue. Praesent egestas leo in pede. Praesent blandit odio eu enim. Pellentesque sed dui ut augue blandit sodales. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Aliquam nibh. Mauris ac mauris sed pede pellentesque fermentum. Maecenas adipiscing ante non diam sodales hendrerit. " - }, - { - _id: "Blanka", - //videoId: "https://www.youtube.com/watch?v=u8bHjdljyLw", - videoId: "u8bHjdljyLw", - userId: "userId", - source: "youtube", - tags: [ "rap", "musique" ], - interest: "PNL", - watchedDates: [new Date()], - createdAt: new Date(), - updatedAt: new Date(), - - title: "PNL - Blanka", - views: 999999, - publishedAt: new Date(), - imageUrl: "https://i.ytimg.com/vi/PCwZnN4zDiY/hq720.jpg?sqp=-oaymwEcCOgCEMoBSFXyq4qpAw4IARUAAIhCGAFwAcABBg==&rs=AOn4CLCaA-xe5rkkYJbNCbSg0z27Lm1Hgw", - description: "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed non risus. Suspendisse lectus tortor, dignissim sit amet, adipiscing nec, ultricies sed, dolor. Cras elementum ultrices diam. Maecenas ligula massa, varius a, semper congue, euismod non, mi. Proin porttitor, orci nec nonummy molestie, enim est eleifend mi, non fermentum diam nisl sit amet erat. Duis semper. Duis arcu massa, scelerisque vitae, consequat in, pretium a, enim. Pellentesque congue. Ut in risus volutpat libero pharetra tempor. Cras vestibulum bibendum augue. Praesent egestas leo in pede. Praesent blandit odio eu enim. Pellentesque sed dui ut augue blandit sodales. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Aliquam nibh. Mauris ac mauris sed pede pellentesque fermentum. Maecenas adipiscing ante non diam sodales hendrerit. " - }, - { - _id: "Mowgli 2", - //videoId: "https://www.dailymotion.com/video/x7ahxdn", - videoId: "x7ahxdn", - userId: "userId", - source: "dailymotion", - tags: [ "rap", "musique" ], - interest: "PNL", - watchedDates: [new Date()], - createdAt: new Date(), - updatedAt: new Date(), - - title: "PNL - Mowgli 2", - views: 999999, - publishedAt: new Date(), - imageUrl: "https://i.ytimg.com/vi/tno1qRfO894/hq720.jpg?sqp=-oaymwEcCOgCEMoBSFXyq4qpAw4IARUAAIhCGAFwAcABBg==&rs=AOn4CLCOBBR6c3woXXIbOSdU06quQcN7pw", - description: "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed non risus. Suspendisse lectus tortor, dignissim sit amet, adipiscing nec, ultricies sed, dolor. Cras elementum ultrices diam. Maecenas ligula massa, varius a, semper congue, euismod non, mi. Proin porttitor, orci nec nonummy molestie, enim est eleifend mi, non fermentum diam nisl sit amet erat. Duis semper. Duis arcu massa, scelerisque vitae, consequat in, pretium a, enim. Pellentesque congue. Ut in risus volutpat libero pharetra tempor. Cras vestibulum bibendum augue. Praesent egestas leo in pede. Praesent blandit odio eu enim. Pellentesque sed dui ut augue blandit sodales. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Aliquam nibh. Mauris ac mauris sed pede pellentesque fermentum. Maecenas adipiscing ante non diam sodales hendrerit. " - }, - { - _id: "Etre humain", - //videoId: "https://www.youtube.com/watch?v=gfVo39B92Ow", - videoId: "gfVo39B92Ow", - userId: "userId", - source: "youtube", - tags: [ "rap", "musique" ], - interest: "Nekfeu", - watchedDates: [new Date()], - createdAt: new Date(), - updatedAt: new Date(), - - title: "PNL - Etre humain", - views: 999999, - publishedAt: new Date(), - imageUrl: "https://i.ytimg.com/vi/gfVo39B92Ow/hq720.jpg?sqp=-oaymwEcCOgCEMoBSFXyq4qpAw4IARUAAIhCGAFwAcABBg==&rs=AOn4CLCPJpBqTYk5Nj3RSgase3GdbT7_Pg", - description: "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed non risus. Suspendisse lectus tortor, dignissim sit amet, adipiscing nec, ultricies sed, dolor. Cras elementum ultrices diam. Maecenas ligula massa, varius a, semper congue, euismod non, mi. Proin porttitor, orci nec nonummy molestie, enim est eleifend mi, non fermentum diam nisl sit amet erat. Duis semper. Duis arcu massa, scelerisque vitae, consequat in, pretium a, enim. Pellentesque congue. Ut in risus volutpat libero pharetra tempor. Cras vestibulum bibendum augue. Praesent egestas leo in pede. Praesent blandit odio eu enim. Pellentesque sed dui ut augue blandit sodales. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Aliquam nibh. Mauris ac mauris sed pede pellentesque fermentum. Maecenas adipiscing ante non diam sodales hendrerit. " - }, - { - _id: "Humanoide", - //videoId: "https://www.youtube.com/watch?v=MiyIg__WNOw", - videoId: "MiyIg__WNOw", - userId: "userId", - source: "youtube", - tags: [ "rap", "musique" ], - interest: "Nekfeu", - watchedDates: [new Date()], - createdAt: new Date(), - updatedAt: new Date(), - - title: "Nekfeu - Humanoide", - views: 999999, - publishedAt: new Date(), - imageUrl: "https://i.ytimg.com/vi/MiyIg__WNOw/hq720.jpg?sqp=-oaymwEcCOgCEMoBSFXyq4qpAw4IARUAAIhCGAFwAcABBg==&rs=AOn4CLDboAq0TRqXBFGgXdpOD_HOsRZucw", - description: "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed non risus. Suspendisse lectus tortor, dignissim sit amet, adipiscing nec, ultricies sed, dolor. Cras elementum ultrices diam. Maecenas ligula massa, varius a, semper congue, euismod non, mi. Proin porttitor, orci nec nonummy molestie, enim est eleifend mi, non fermentum diam nisl sit amet erat. Duis semper. Duis arcu massa, scelerisque vitae, consequat in, pretium a, enim. Pellentesque congue. Ut in risus volutpat libero pharetra tempor. Cras vestibulum bibendum augue. Praesent egestas leo in pede. Praesent blandit odio eu enim. Pellentesque sed dui ut augue blandit sodales. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Aliquam nibh. Mauris ac mauris sed pede pellentesque fermentum. Maecenas adipiscing ante non diam sodales hendrerit. ", - }, - { - _id: "Dernier soupir", - //videoId: "https://youtu.be/0GqjIF-4QQM?list=PLqeKQSn3LuAmpF-uIu39RIQRQkUzVol5l", - videoId: "0GqjIF-4QQM", - userId: "userId", - source: "youtube", - tags: [ "rap", "musique" ], - interest: "Nekfeu", - watchedDates: [new Date()], - createdAt: new Date(), - updatedAt: new Date(), - - title: "Nekfeu - Dernier soupir", - views: 999999, - publishedAt: new Date(), - imageUrl: "https://i.ytimg.com/vi/-S5IKBvT34c/hqdefault.jpg?sqp=-oaymwEcCOADEI4CSFXyq4qpAw4IARUAAIhCGAFwAcABBg==&rs=AOn4CLC1kVCIB2bQGmOH74I5puXIhn7HRQ", - description: "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed non risus. Suspendisse lectus tortor, dignissim sit amet, adipiscing nec, ultricies sed, dolor. Cras elementum ultrices diam. Maecenas ligula massa, varius a, semper congue, euismod non, mi. Proin porttitor, orci nec nonummy molestie, enim est eleifend mi, non fermentum diam nisl sit amet erat. Duis semper. Duis arcu massa, scelerisque vitae, consequat in, pretium a, enim. Pellentesque congue. Ut in risus volutpat libero pharetra tempor. Cras vestibulum bibendum augue. Praesent egestas leo in pede. Praesent blandit odio eu enim. Pellentesque sed dui ut augue blandit sodales. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Aliquam nibh. Mauris ac mauris sed pede pellentesque fermentum. Maecenas adipiscing ante non diam sodales hendrerit. ", - }, - { - _id: "Les prélis", - //videoId: "https://www.dailymotion.com/video/x4trtkd", - videoId: "x4trtkd", - userId: "userId", - source: "dailymotion", - tags: [ "rap", "musique" ], - interest: "Columbine", - watchedDates: [new Date()], - createdAt: new Date(), - updatedAt: new Date(), - - title: "Columbine - Les prélis", - views: 999999, - publishedAt: new Date(), - imageUrl: "https://s2.dmcdn.net/v/HPPjj1NtysAaAttYk/x240", - description: "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed non risus. Suspendisse lectus tortor, dignissim sit amet, adipiscing nec, ultricies sed, dolor. Cras elementum ultrices diam. Maecenas ligula massa, varius a, semper congue, euismod non, mi. Proin porttitor, orci nec nonummy molestie, enim est eleifend mi, non fermentum diam nisl sit amet erat. Duis semper. Duis arcu massa, scelerisque vitae, consequat in, pretium a, enim. Pellentesque congue. Ut in risus volutpat libero pharetra tempor. Cras vestibulum bibendum augue. Praesent egestas leo in pede. Praesent blandit odio eu enim. Pellentesque sed dui ut augue blandit sodales. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Aliquam nibh. Mauris ac mauris sed pede pellentesque fermentum. Maecenas adipiscing ante non diam sodales hendrerit. ", - }, - { - _id: "Pierre feuille ciseau", - //videoId: "https://www.dailymotion.com/video/x6agl6i", - videoId: "x6agl6i", - userId: "userId", - source: "dailymotion", - tags: [ "rap", "musique" ], - interest: "Columbine", - watchedDates: [new Date()], - createdAt: new Date(), - updatedAt: new Date(), - - title: "Columbine - Pierre feuille ciseau", - views: 999999, - publishedAt: new Date(), - imageUrl: "https://i.ytimg.com/vi/tTo7CrPlbpI/hq720.jpg?sqp=-oaymwEcCOgCEMoBSFXyq4qpAw4IARUAAIhCGAFwAcABBg==&rs=AOn4CLAhC5bWURH9R8Icdkv6LWRgsW2G-Q", - description: "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed non risus. Suspendisse lectus tortor, dignissim sit amet, adipiscing nec, ultricies sed, dolor. Cras elementum ultrices diam. Maecenas ligula massa, varius a, semper congue, euismod non, mi. Proin porttitor, orci nec nonummy molestie, enim est eleifend mi, non fermentum diam nisl sit amet erat. Duis semper. Duis arcu massa, scelerisque vitae, consequat in, pretium a, enim. Pellentesque congue. Ut in risus volutpat libero pharetra tempor. Cras vestibulum bibendum augue. Praesent egestas leo in pede. Praesent blandit odio eu enim. Pellentesque sed dui ut augue blandit sodales. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Aliquam nibh. Mauris ac mauris sed pede pellentesque fermentum. Maecenas adipiscing ante non diam sodales hendrerit. ", - }, -]; - - - -@Injectable({ - providedIn: 'root' -}) -export class FictitiousVideosService -{ - - constructor(private fictitiousUtilsService: FictitiousUtilsService) {} - - - getVideoAll(): VideoAll - { - const index = Math.floor(Math.random() * TAB_VIDEO.length); - return TAB_VIDEO[index]; - } - - - getVideoByVideoId(videoId: string): VideoAll - { - return TAB_VIDEO.find(video => video.videoId === videoId); - } - - - getTabVideoAll(nbVideo: number): VideoAll[] - { - let tabVideo = []; - for(let i=0 ; i x._id), - isActive: true, - createdAt: new Date(), - updatedAt: new Date() - }); - } - - return tabPlaylist; - } - - - getNoRandomTabPlaylistDB(nbPlaylist: number): PlaylistDB[] - { - let tabPlaylist: PlaylistDB[] = []; - - for(let i = 0; i < nbPlaylist; i++) - { - const videoIds = []; - for(let j=0 ; j { - let service: MessageService; - - beforeEach(() => { - TestBed.configureTestingModule({}); - service = TestBed.inject(MessageService); - }); - - it('should be created', () => { - expect(service).toBeTruthy(); - }); -}); diff --git a/src/app/utils/services/message/message.service.ts b/src/app/utils/services/message/message.service.ts deleted file mode 100644 index a50e75c..0000000 --- a/src/app/utils/services/message/message.service.ts +++ /dev/null @@ -1,40 +0,0 @@ -import { Injectable } from '@angular/core'; -import {HttpClient, HttpParams} from "@angular/common/http"; -import {environment} from "../../../../environments/environment"; -import {Observable} from "rxjs"; - - - -@Injectable({ - providedIn: 'root' -}) -export class MessageService -{ - - constructor( private http: HttpClient ) { } - - post(url: string, data: any): Observable - { - const urlComplete = environment.debutUrl + url ; - return this.http.post(urlComplete, data, {withCredentials: true}); - } - - get(url: string, params:HttpParams = new HttpParams()): Observable - { - const urlComplete = environment.debutUrl + url ; - return this.http.get(urlComplete,{ withCredentials: true, params: params }); - } - - put(url: string, data: any): Observable - { - const urlComplete = environment.debutUrl + url ; - return this.http.put(urlComplete, data, {withCredentials: true}); - } - - delete(url: string): Observable - { - const urlComplete = environment.debutUrl + url ; - return this.http.delete(urlComplete,{withCredentials: true}); - } - -} diff --git a/src/app/utils/services/profil/profil.service.spec.ts b/src/app/utils/services/profil/profil.service.spec.ts deleted file mode 100644 index 5cee000..0000000 --- a/src/app/utils/services/profil/profil.service.spec.ts +++ /dev/null @@ -1,16 +0,0 @@ -import { TestBed } from '@angular/core/testing'; - -import { ProfilService } from './profil.service'; - -describe('ProfilService', () => { - let service: ProfilService; - - beforeEach(() => { - TestBed.configureTestingModule({}); - service = TestBed.inject(ProfilService); - }); - - it('should be created', () => { - expect(service).toBeTruthy(); - }); -}); diff --git a/src/app/utils/services/profil/profil.service.ts b/src/app/utils/services/profil/profil.service.ts deleted file mode 100644 index 86ed4a2..0000000 --- a/src/app/utils/services/profil/profil.service.ts +++ /dev/null @@ -1,30 +0,0 @@ -import {Injectable} from '@angular/core'; - - -@Injectable({ - providedIn: 'root' -}) -export class ProfilService -{ - - getId(): string - { - return localStorage.getItem('id'); - } - - getProfileImageUrl(): string - { - return localStorage.getItem('profileImageUrl'); - } - - setId(id: string): void - { - localStorage.setItem('id', id); - } - - setProfileImageUrl(profileImageUrl: string): void - { - localStorage.setItem('profileImageUrl', profileImageUrl); - } - -} diff --git a/src/app/utils/services/theme/theme.service.spec.ts b/src/app/utils/services/theme/theme.service.spec.ts deleted file mode 100644 index 1c2957b..0000000 --- a/src/app/utils/services/theme/theme.service.spec.ts +++ /dev/null @@ -1,16 +0,0 @@ -import { TestBed } from '@angular/core/testing'; - -import { ThemeService } from './theme.service'; - -describe('ThemeService', () => { - let service: ThemeService; - - beforeEach(() => { - TestBed.configureTestingModule({}); - service = TestBed.inject(ThemeService); - }); - - it('should be created', () => { - expect(service).toBeTruthy(); - }); -}); diff --git a/src/app/utils/services/theme/theme.service.ts b/src/app/utils/services/theme/theme.service.ts deleted file mode 100644 index bc69016..0000000 --- a/src/app/utils/services/theme/theme.service.ts +++ /dev/null @@ -1,15 +0,0 @@ -import { Injectable } from '@angular/core'; - -@Injectable({ - providedIn: 'root' -}) -export class ThemeService -{ - isLightTheme = true; - - getClassTheme(): string - { - if(this.isLightTheme) return "lightTheme" ; - else return "darkTheme" - } -} diff --git a/src/assets/.gitkeep b/src/assets/.gitkeep deleted file mode 100644 index e69de29..0000000 diff --git a/src/assets/darkBackground.webp b/src/assets/darkBackground.webp deleted file mode 100644 index 0d0692b8c331ccbacf8631b679686525fbb5c85a..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 712 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 C8Oa_1 diff --git a/src/assets/logo.png b/src/assets/logo.png deleted file mode 100644 index 93b93755e49963d09c63cbd0df33669376c8f90d..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 5798 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 diff --git a/src/assets/logo_plateforms/dailymotion.png b/src/assets/logo_plateforms/dailymotion.png deleted file mode 100644 index d35ee8a8b0e209615e57966d3d6f108844b2135d..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 6478 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 diff --git a/src/assets/play.png b/src/assets/play.png deleted file mode 100644 index 194f73beb22f040cf7ef156fe3f6403c1b5323e0..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3586 zcmY*cdpuNY7k>8)W6}&Wt~17EE(%i$5fR21W^@sAoH)`kA*2!^lC)!7!x=-8qY{%# zbxIxeDaxpclKZXr&>%`mR7&@6m-BtU-}l#k)>_Z|?Dg*b{@%4#hKD;BudJgC0KmKP zID7yg1VR9dK^}hlD}xdL12>M7R~+}~Gc?zF1b*0%E2?UTd#Culyw!NKJ_ zgE#CTw>;b#_xfD8pLJNvrdIiVU;L!l!w=ho7Cr=EKKuhUEeC3j#GZMV4e7f!Pti4%;aio*FagM z6ZVCngcYJLtcjfWP zaV_19`P|Ci&?TEAbY{5tvp1v1{cW_Ssh(ZvlD$L5)$kjLxBj5)+T=7<5^MU zY%T#$wNE!iunj4SfH!PwGDLg$G3HiqG9~^331nQbx9h0LVwU7efddxA{vVGg4=fZz z_d9@JiVnNQ34fxr4+QPj2zTKr&KhM|f`P}q1DBLTnQJY;)FA#cU4n{Nw4=b$FO%0{ ztEAtKZP9_7iqhSMy$V`8>Y>oAG7o3oW=U!wp7p&rRfiqM4#g&i^iB=V^{--@CGgm^; z_j?6xIe8o$Pe9}FZ z$H!=`%B+3q`Z_GdQuV^T5oo67pNemH)X!d!PmP=`n6CV$Ab*10Suyf<@ZZF=BW;Iz zEQW_4fs22H3oUvodbS^1=+YzB>A(KEYl+pK$0tBB>{0$HM*q;-fG11qolQq2w-w~S z3oZIyuL((%4LHv0_x&>Dy$`HqgZ6+8mKQJ?Fm!?1Bn&7AZYis#0t;BmZ*g z8Knw4CiAE}Zi)6lSm$q$H+GbkvvLUY9%2cF?rGbOFTxvWdD%e zxqfI3`1_xQlXj2~o`#lJR_=Et!jFlIu!#UaR{aO6!8W)>s6q#k4nHL(ik-k11^eUs z9gnhy(kY8-&z>nz!?{1UalUvPmbD)K`Ra8a2ymS4qQoHLO%p-JEtR20N1O_eS72H7 z8H=pdYH(r7BK#Z6>Lv6AA%B3pDB<=N4@03vo?Yv5GIiPk37%Xc?a+zoumBjT0c6?G z*`QzvzNyVN$9~!<)o5crJp_3OqS2uJE_0FG zvu$hcT!seg(>)UR8_X@(&Rnh2esC2PVZRvNeytuPsGP008FM@J-v4*d?_|6>Cyswk zr{CuQfK`NV6$Zfm+qvWyq?O8E5`J;LZth zL-fw(eO80#yRz@+=+0F(hCQzR2EcdMAZ|`vuOOB&wHxF(EgD?p&edCcag6XsBxvSQVd7@X!eCL&<{+P*`Q^XG8gqnh%7RLZgi5|_w`j@UEE+G6UD8Vbm2`Dg>bH7;f@7$+)aMvou zHAXQz>b{^s0zQ}Q_QaK+4=!d}6RYyx*={v)2XGmoDlZxuY1cln?UkkCNi2vkDScwNJzX+@ z3L%rOj(mgFTMCq~Fw!gx->b8@n<@ zpGwrVcTka(ir=#+r7GQCFOwuE$v|M%eh($A(R~}Cg`t~+iK|vKuDp$NTlS<#vT&gD zzr88W6j8Fem~^>J-P6rCefJe*H7W3FBMqfiY7Fkg!C?ihoF%CA3Op0BZExn{dMY=I9WC9uhwodapSmZ(H)Fl~Roa1yf!S$PC!5 zoA%k$xsrBsPE|LhPjnw>3UfiBpYyWe`7_Yp1zdMaWlPht5)kwlP^yL!vd+JUv2Q#0^6I! z&E*um!la(rM4U6c z(a_^Rh#ckFJ?AkTwbfP7{v|-Czdq;ieKjls(9j4e|Ci9wib`mniMWB9x~jOlgxGjI z0tCgdaWpiwa7`6Oli(lcr6DCIi0-?urnL_C=B7Y$GHMk=Ahq>NbZQj~YgBr#s|Z)o z$S1Drt-XT?pRJ98I?Yr~@1I5AdDKMcl*y>9$^0;}uob`Y^u|oegO+Mf{;Sl}zdPHM z+l-h!em`)V2^Eu@I)3p>cFxk2fR%~oCCtE_sH5=mSViLd&{sweeJaM7fBMMp5m9z` znakUC6c# ztn@4$`Bcx9IcBGAq^w)I(b)d66wy&pgG;rk;}0H@Kh3tdXF)y0#2V@OpmTlC=bdll!O$&ffS*IiMP*AEo?QhM4 znon5u%@%vrQwC#LUHWn5C%wFu z)Rh9b=x;1LZ4DwjE!2xrlu87B4eg}ws7SngJLv#BZGfMYy4KJ7;P<4bg>VqCg~Jzx z7|2ibFSayPc3ZvDOLYXZOBXc`nU%ygPW=_^QnLF|zdfmRa7%Q%N*>O+P^bTrhi6|N zF{}hTHPXkA_vLW&CFqa2*2BqbSXA3aHN0cH_rjdJ6;Cmz024`QHH7)qwb#EQSbWtd zS6MhB!k~MIlwjr?jOmOI!wMa8Teld;_&cGk_$0X8k7x2Hho7VHRUhG)a5SMbi-sm= ztYc9|5`UM>qxXG=$F#FzMmhDVt%36iReU?u9nC~Y>P`WYs%7W1;r76sn;`U>K%Ql} z-+mm+i=U24XEL2(=Gc0K^)2xSwkzxAf*vm9U2vS6#kd|C*yD=_zbN^-(vNh~eWOuP z(fc0r>+pJ?O}iacCe)jkUSaf^69vp3vRer))>G~;kTo8hu1kbzQ?tG5`+~NpyS~A( zsMX(nnY@Lv9rnZkHQ(oXcYHszt6~E zZn39h@r@-DX$<qr5b`L>?$v8w;kN>k zw}q3;t8rCFtuN!YzyypV(XoZY)N7=ouaXFNGA$oSPVX5>TS}&TImM%O)();>+SmQU zA-Ah3)6#~C81+x%Tz^L+`berSi{{bDL!FE|hMXAe4g+7H4dl$SB_WXLy}|L@!u(`k z&4Xa3MxSctT!N5n%Q#`MadmM8qAx@LW)7?eO*OD!v?itFbM`=-6sQmz6p=7AHs)A> zpe4SjVR6owtc1F$35R6C^z9zT&)MIOx%!6ohw+Vzk!q|sst52>#-t^=B#%&1dR6=f zcy~o%|3^{DFqY9u|BoUPUZh0yMR9=*$u zW1t#T*e<`tQRBgnVyg$f(x@u%!xTY^KE~>hPj{?--4S0{bsp`h2A3stVZt9QnyTnbB>$O0C6g?!DI5czrja{+z;j&#hW zAGzg=Ek3Lj#lu@X1xH@2j)9oE2F(laOZkoIl_Q*cD*7H1whM2c9jT3p!?(~U0+>Hn z&oKN$SNvCBAmdeaX~pn-l)k!J0J)WgimHI&M?gxW$ROGKX=mpoEzWF99I?_%9KCSW z)n8h{H8NIP(Z%=daK1frWtfc7;W5Lg3x|cq8&&rY7+Y1IIntR5H=Hk!X0EfQbqTVy z14Y-V4%nZ3!@lK6>>h!sC!$}sP_E&KbA+je}59!}93fN~4ge1)U z-I$v((X>PPMdM5N^cF}7yK_s5Gris)jf}6-6tP+d!Oi%qx-rM99K42 zE7o~S*ptb@+F|XE+34f#BM9TaUDd5%=-Js7!aww8ocymO4!vbxNzpgJL(mSj>A&hD zcmdpWS>wLtQFfk_f<<-dR+1tK8<3m#ZacdIfoZDO5f{}~&G!am1PP<_Y1+cmh*4Qf zXqz;}{ZG{0M$~ZPlpp|Is!h*DSg4hKb|KW7k%GFA8GcD4xUPYxig;t%Qs8Mpv+XWd z2Hd1t65MAc$pQ5mI9mhXD+t<4_>eEfSTR5vMcQ}Ao>E^YO+&Iihy%=&(=4aFUQT8OvIeNRhF&7tg>bFd(WI9SxQYoE#(lL` ztPmie2K+#f`4T(J(c4qN;b%8LGjdnL+X1H`IBMI3}-y3 zNMaQSGHyJRV~AkZP4gT7=>qV16nJGHd^VD4l@Q3?mUtmyg&(ivCdqv;$}_>dqSS1u z3Hl0UdvWg65tW_`a^a&QY2K|^ris!xGeAN6SAm~HO$4eF=2Vz!ddIC3!35>$B{NnH zi6>kOhJYTn=s5^j$1Ss)j8Hs2y=0CcFC($yTP06m+T8wACJ9>rt0WK6xpXnq9Do28 z)!}cJmIN{W(^d*a#+hek{o$U5mNc@xQ)H5ty73fWXvD))asmLMZTG1w6~IsGnn!|? zU(@Y0)qBZ|0XS1C%VG+aEulGa7drvicd)8Tn?!*|d%5Um=A56H7-3=e)`R67lGKjr z!xe?oqIqiSCx+yq80AS|4fW?9h5_=hvV*g!3@z4xX|vL#OXPcIKxvKRqi|j7KRV`z z`m6aN+yW%r2lXh9RY4tQ$CAYn9H)I!R?A9OHX<&sa5(I~$FZB*HjblQBYama_1G%3 zc|2-+hOiB+Vm$ZI53?r?TU8d2T^r$&Y=O*#PmhHUkNr~8Od|nfz=%1nx)a}S0Boz6 z@>KOR_FOM=D8Jos?-$j&>f!b*LLG>l@Z^s5qECYk+c87Uh<^sDrbjwoZ` zCXa3_q`Gf{E$>EhJ+>*Nj%y==l@J6(xabg%eN12#BQ4J^)cexjdyqWYyz~918-trK z-han{zA~*k!~E2#vV-?QxSv9xwS@@2APn9|LH{}O*oydxKC<|4+CqV8I|gO0Q6{qi za5#?UdSl77hTiUK&q`L5U~`yr?ALrfSl^JB?GAQ_($yW?{5mZ+QBiKHo9eOln`&Us z=zO*ttsv)@Gebo##vVT+W9cM#jF}GEe}G%bAA_ela=H0p`Sl=sLM+O+o3P_QfTMCvAIqv7hOAff! zwwmVoJTDjie)6;9OdBgB^bX0;hzx#VppZ-wJN@-*%1Ut5*IQnS&ci6^7-M*EduAx_ zVM@YW^%FLG0%wQbYajyx&{!q)vg&naMoCu*EeV8%_nuDAuH*HQ9OIi!ndRbw3AsMHjUO6k?PM-Q$!}6!43F7<8O<=J zxiH%z@g}}>>YT7Dl+jBQCgw5vB)7l$hx-*(7<#GXjuY#OUwdUy|7TlUEEYglp3rSx zahvB0$8x%tq>SC?S!mnU&FnFnB6>fp9mSp2Ca}AEEo`hMVNjh}nlKl6MVuLOTZc?% zo}25ARjgxaV!|z~{c|269@`ZUx0rcd(Z=e)v2agRnI}`d_OcalI}SetF$skZNsV?H zd?wxANeN8P=C!nfbE&K z_c=!zrBc>&92sPJZx#np$#d9c3YjyUMQSjSvzdSUwm3-KOmCSFF>lW>yRv3MAJj^^ zYZf?YUrOjxKcdy5X8F?`L?crSU)9G+^GjvQ((1@apXu&weV5&sBzk6@gs_)}9wQjb z94Gai*78@5xfep5z~L{hF})$8@7`_nKJxxUkkmIxK@{8KckjCjBz~a^$q)1YMpI6H zGyj4vC9Zx=mTxcOA`oDvZd5X24s5k8yH7K`4|GF=0s?%KxfMyvn*vhC`&b1D|8rs5 zBg+b=68jya}SSi&Rj{65=Z!NO2qF>!`i;hp6>1#BW%J;{nMt3 z;r;7&0b;!fh)*J-wNwNo_^Qg5ft(Lu3ZA>BlFYY4z};B>O-&RKgkxBOim2~JFH^qJ zqjsCDE=bdFYg?VPW;GI5NOMlo_hE0`GI!+GP*h2O@YV==;>0$O4 zsF7Cq@dR-Ass}#FejWT2ETz7?l-^eFLgK*umzo!V6v_J9ifQUzPyK$Dm*|~esA}=pXievvGiK}0IRk{m`EV$b&>EO2DS@V{InJkVW!jdsAKculaQJ8e$3ZV=KWQvFvz}Ov|uE9s; zD|$H{n@Z)mg@GTgccA!UYO)sKO`0HkWH1gk+p+c{E%&)`Nt$J()0T+LTM(n3jkx{wieQ|`NFjtkH%39&)(qf7g)JW8nZrGL_DET5fVbKW&-q?rH-n!|Ic0FPX;u#A;ocd< zVCC+6Q2 zm1^hhK)50X9C}|dBK+p%ZUD`B zfqh;?TGAtaCvP5KkGB;zCj1J9H(Tn4sBlPW?r< zi~zpxzd_M;)W`gli}f^MJy9tWx#G_d1&6x<@|}K2e*SR-Cpbcc|LM5C%R#@utMCX{ zEDOON8r$`;PRzojv+;N%FxH$YnX~polwXeMAAUx<@NQSy5q;_yoIm$s zYvZtXcro3la$n?AOSpxzt%-QN(|uM$q5nnY!Fu}?H+EUC$+MO##%Oaaut}%wv-P1# zXSl-Apuq);{>Q*8u?usecujC|ukKt#JRP7@GlX*RM&fu}@P#+k&ywf!+XInP$yofGaR3I8;jCk+J^pMRW%>k<^qb`tH3tcWG#a1KS zmJie%4GT~Hwq(d56OG;7;4+0^;RUQ@XPDy9O_}~|{CQ}jX=olA@a5jXo60oiG~iR1 zi^6LrdEBW`iNn>vLjoDjh7og+*}TnUVf_~`+{4AYvi}M!kbJamhYjUJ20GPl9NMV~ z4m@rwJ4W`Njg$N8t&Cz27oWUl9})%Q8XnM`Uo!YwD_!xHp%&Y%$3z@xK4&057bM(T z`iZV9SsvBp2~rnHPLAAyL}94;RgE0a{x};mb^eSz8_;z)8a1WJ>p}0$;hWHij~cGU z%x86r+%W>0EeNcS7M`i;IML4e;%iH2hWdK1<{K`QD3fNfy(NYF>dh_pPk8r*Bk2=6 zla)k@qHjhB@k!yVB^>-82kWnkGi)NQC6!hNlTuaU(ue#rRfJg`TdY%a)mFddg>q-* zCbyCIU^EV9H=8)DCHV39F(@ln(u{3oQ3df5LZ>Ds(K_XwB;+FsGd7#}eZcmja?V+h z#Nox*36rNDKHub$@%L-uv+aU`*r`sDGB@j=*`%{Uv1~An`#~({YVldT%Q@**;o;9I zE4YnR><2$G|A^A@Uc{x~=v6d{gQ5d`8#xKrmwuRg0NAAs7fUW+GA3N+M_r$*@tMTClyhXiLO&vWiF z$qN)wj{ESa1qZ>faa4lsmpT*`uN*4n~rCB8lFp4HYbiz7!55g4R&ciDv8O+4h*Sis7d9d%_{Qa(Dm_ zhOW-~C2-J%`;&AmFupPbMh_Nz8O}bKwoS&N1SM(IH;iNY5KVYp^P98QhKJQK3V6R4WyT|)Q! zi#j$o5zJ{dpH=(=yE==~91_qYY3Ao;c|<3j%+9fUVK6x4zh_-#U`|1#^4z2d!;qnP z<#7$fD>_NE&Dh;O(wSVfU6>{Jr#OMOEZ3sWkBVbM(e}e|XCh3{JgMfB3L)W7)e9{~ zI_dHt-F5cO>6KAmG87fMpablP>bDD??mQu{{;j(g~8^Z@1bDps=isl$+1o6{_Szg7H!3T)Ox-i;kEfhj$wxmge?~}F1e0^jJ=sB5 zrd@3wS(e@pBHFBOUnV0DHOZ7+LQ~DUNYnQE1@VqrA`|*Tj$%=xA`fNXP&_2o`XAMU z8`oYOvd2}aC3;4f$mDHk+53k)&HL(K!V-1MQQ9iw|L+(%!O_&tx1|>EE8Z<_{3+$`^3V*>P!Zk|%;fbZN!(BDLnrdH9WG-@n%!-l9C z9HlCf?=5wa={27^g#`oxiHRJ^vXVVxKL5|dL*(yP^b#{+dBs1%khCKE+kCO380tuc z6x$2`k*y+;O_Q5s;>pPJ2Bfv-gARm*jzoybLS(qyqfD-`HP!}e3n{6qX3jV(D#b9;V?@dytLY@$lpx1qCu zKZb#7aa$bgtAO8}c*MhfK}_=W|JzTXW^}u(DqSbvWD;K`Gmd%`+K8VI1#tu6BU>Doc|!a1 za}I-~D&nJcJO@d(DJ3|=Y$@r%YpIUfpaq7Qagk+e#e`pj#4-5#JTAtFmI zQ|D%PB4#!v9~?+E>3{XyflKr%ZStTW1iSG2w&7CSFl!UrFlA=*D%a=)kZ zP*~+?rXrg2S!`mlx6~-A1dzZ_IK?N&NW%YCxzA3MMG1l_$wLF12iZm>zYNRQf8H@t zV%Cv${$}Y++gl~W&Snk{y4G9GCx5f?033QH$_rzT&x)!IA-W>JoMchOiglFX&nyW` zp)uj((6Pd#F%|UKbnP<@yy}jDo3A@ z?VI!lFAVze`b_~}rbj3D2pD5sB)^C{SiwDdx!)>X>M8|Az9A+C3&aBO0s8C@S+5K^ zJPuR42xV~NB2@hbF??p(X(Z3L4Sng1{T`La7aDXwNa>Z&3uFV%1eLvf z`q*%s5Cna`iI@psoSbH-d>rAt2kl~&ct`%gNpWGy^Q zYMS>sa*y)}{C;NqkqS2mLNo>Hg87so?7l2!75>r75R0i7=T8>iV<;+S$ca;bg0CY( zn8&r1LVr{tjNjW^7or|rDU${<8fLA_7qK=}`0$RR2YC&ZUEO3WRJm^_0)XH$vvw7~wb)fEaM zBBs*^{+mFM05G`V*G<$+Y5&X0;~2n-|1id#R)V#rAEVzLD|CgykGtAaSE6)yAg{~8 zpl@uKqBfr_1?9JuJ?ttUSYc_bE8(~hpiI8o;|2E!0mo$AyMHLEcaMDfC@@x>TsJgCy0K%zs&$<|;(V z%s2IWN;hK|=Ms#=1L@LE3py@>WjPVaG0-t>Fo(Rc)$s>Tsudu}0RC<*txFX$hSA%V zRyuyvk@=cDlwQQ$_Q2cXwILP})7L#0P5776*ShLe$y;jT3Xb&}{ev{%yeoE(&^P=9 zb<3@G)>a}s9sYzke!_$a*hHPprbeX@7TERhK>Yn~W#NPz$`MEwd%#qdckz4pgX$6X zP{ji}A?KqlOE?&Kg*nkdO`soVO9pC&oYrTC`k*)S1o_HYW!TrfOq?f#4DG)CYrJuX zVL$)G?V}Oe=KD-c7~1u&NqXE;3kTO+YiEYAURMPf3WMS~R<1jA79{Pjf>Ta4CQoi- z*feJ_9Ix+7JXb-SFt7-Zq#tqll%_NUK@Fn@ zrAG{6NE8({H&ueK7aI1#e>shOu$iHx_ZXhl%T{2OBLp0I&6ItwQMH93&%`W}bcZOS z&Ze7bY;J-*Td&P$yBjF#rDCCDe6#yDv@lewb{qYgLyh}=Fvyi*%9%|n8agIA+G4I& zTfk!vbtN5d-A3)~UNgBpPtpO-eQ@85MISf2u?~oC_4Ash5hzsTc^v4J!4{V8q8ccX zeEe{hO&o+;rgMIc+M*wVE6G(LJ2(z&Kw95CoB}+|vCNjnz-f;wYowIFW@bXfWYtyD zd(HQrlrCj>*IUr-lk<-hD0Yxh<=W6}b5k|NmEpG=0dGgrk1?gD%m^lLl-0LaKc#bW z=*-lqSNb{30Y!FK*ssjI+RH|qBg|lbh^Z{&oVqYlr`dnP5B_uQ(-9|AzrjCnsj%ikvy$ELGoHW{!OB) z5UYIAx%J$Bc&Zt>Y^BBXDbZbWx@Kz#?ZmT>enUg-Me=CLM;xnk%i>fRE%=y|162}> z%?=?G=skuEam^3nRN;4wNYi)5wB3^wUr$QfO3{ENZy9GDRU!96E%+AD@7p=b5ii1gq-Jl8zb@t6{9OJq;2o`h! z@+JPL{o_mZV|A zouY715>iNEtWt-xVgPF(5&W?MD`yz)#u1?Ltd|w>m^5EiGsbpBB@w~sH1>N^%JZB4 zy?bpwtPqk)^$mmR)pDLXRZ2x(OJ7XwJPpnb+oJtOXxbX0o^oA$?1+HR0KZ6X@)NBbvIypy$)Gkfy>v8}4+hoF(A3L%HQ3 z;&UxuzJk9&$b{PpVsmZ45ud=)yPJB+_ES33zoq{}wX2k;#Z(Gf@J|?N#47Z^qaoX~ z8QU{eiF0@Tu#ZujXAY!azBMQ5hR<@zyD*-b&xJ0#t$ONG5h%E)k~_xZ)P^lWG`oliXZ zb?9Q5EytQFvDI3#!@E(tph&s%GeUB8CwhVi+Ar<-7*>IXici*&|GuUFtX25$NZ&5B zjk*6wON!$2-;UWp@15@)R;!aZ%h&jx7Bh6O+KNh@Yy37w$Yq%wto_az2Wynu`Q)ph zcyh0+M7KQ%PZqMv7zTyo{iPobbh&>>+}F21og8k_Z&_Pi{##U7n*Z|21y>?`RJL!% zDttsua=H61t;rw}4~PgQ3DmPV+2VH%NH$rlREFnzM#yBrX~q>9Mh0=VJ!3;VKju5k zmFEO_$NmY2Z{NxPL)rDs`ENPfY?^H*OVoc-$B8|V8SUn7zP$nDRhO`l?l)_$sZ(my z&_~ctyX)A}1cW7()PatXgj0T>pF4S&Puv(Mnu7njxur z7ZIOZpwE@14Z0wC%9o!mso22XZ>5=?A*8X~hM~uP!1>Qliwq;aTw?L^fkd`V~Ruknt&I}`ac3&X6!xY&>04EpHkdH@(PDq`dbe^b94!C z|IYBu7HI242?$b+^%qouieR|v{vx$vXd3HR%k(y=7y`#&w{23?i$*8TxhuSsdqB%M z=SxhVY6a7`c9JE-Ao9=_4Q6Lw25QklcuW&_N_!Sqi$-Tt*-K_ABxi*_HOT;rsP8lMP{q(b?V41tEt(_AjuXoGNkO+FEw=@79avh zVjs{f4I2W7C1rD5+G=c+`Ji$8$=l&s|I%tk&1805@Q0Lm^bvK*9jcsRk9-J85;+#C zIxNPpRV{KQh$AR6&pw;kpWde(K%j*ab$ri7?Wb}@BamWIKG&dt?vj2@$t5rTy(DZ~ zc6dhZtpZ&+_OnJ7BO8eR$CuO07Ylh7Tq1S?fn$Skl-2e2RPt`nB3o(HOr&YYSEk+3Cny(_{PW zvWeU`Q#=c~=(6>O^XlxXav4xn9X!+ItHTF*IR<&K&5R-&_cJ-1s&E6gWY--g9w5O)T@`X-9&p)^ZC<@H-U zDl8;#%1|-Q+FdpYIlVj;k{3ox#_)o3nVX+TIN`@1xT)O{T|rvaZtI{-PU$^K(>2wL zY^=g$?2+$$S%C-qeWUN{8mDFmKifxJh|dS@=3HS&y1AaljdroSOHg0&buP(D>zMO^ zy=6acZOnRFM~#kUCwNSmQ+T;5!i83-dlavkeArWxEeCZ6D1&3vX=9+d6J{zKnUwO% z!8zR0icB9r?_m1e%71*1W@~o@gl_%{bB5?_)R4<{6}!n0#*$~|qd^jee1UWRQgVEu zh6bOyB=~z{*+Wj;rEPJ7)nZ^ZeoN;{2iL?ea0M8ZJbceJN*{290v!6OE|lcJM01Ng zu&sFpUQp?M)RvLsC+Mi7Ow>PD0;D!d006=vEtq`Mpd#^8A3Fs_Nm9Yp7Eh8U(Bqj9 zX&VYS**)p9b73-$ncxy7#iZIu;_VxL`?i((MA*E{6LeeCdO;W5b1n5su<`Z{jo3Z& zAFSRc!kwLt@e8<5;gEra_%||yn7D{)F;gY>FM1SzAr{WP)Pbm?=ovX{Zc_Q+)D!(H z)URiB%$qcA&-t8r;$$k2(x2U!v=1bEmm8|oeyi+|093CpwZ1=^X15d)&|C1XSj$En z*u&q_PySmX0s1N5Zkl11z)~3EzGIm&hvF0@=o5&RT3u>x$ITr6g(EGeY~xIw57)KeHp1in{t0Yk!fBP#&gmY_LFPd z-rM(*k0J$yiL+w&C9lFG(xfe6tZtrX({%bPe2Ky09Z5Ht3ji4an7d;1+Q+fL2~Pb{ zv;BU_sUnJ&gTG}wZ*V@genU@P^D6=;zvy)QT*sw+a(dY6*_82tcIsREJn>_pVmodv7ptfM`uF#*v`!m+MtWA+59bhM_O(ioXkp5m`^Nd z$vkOXVuX)NY60jCDFQZ_+$u@&0B>J~xNX_Eeb3dYEmt{kQNt+zt8+Mcb6Ftf4s5Hd z-hY@O+(fm+t~q>7a6|#Ye{mx#da`cPsbUjgMGDuKxy@a{k`lVVx@z5z6>CL^_K81E zim@KHw!RC%jBhQ+p-SoP{E8|r@PDgUx+@>UDbPQZchHHxb)Y)g8nOzXFCFVv>=5Mf z+~{DHx{}_U`tI2_m;!vj@`&KLHcoW2-(4dcYvAE6f$Hkr6zsoI zuOE18tRATHEc&2kw(`&fhi7nE;Opm#AZawaJx1f+=+%c-TYl_!1n z%nA}(ZkP4{+K9t_8UX*#(r#p^8S{@A^y7CX1w*q|SPI=Reg0s`O`k zrOxh$`#CJaX?q(0Cp13?_aEape*KVca>nqw3N}|MfHk+KNze=yTq>Jx7 zqVhvHd+lgc!9XIck(v?$2h}Q^^Vm z-#+(fs?zTwuWfMCIpnWW(B;C1;CRH*!Mo-}J_2nsCYL}N4!bxERHm~ybY7y&vm;zQ zB}8&PyRwb4N3{*207FT#UHD%fnq=)8>X8#@#BkL5DUiVZHWI^gj46KQM#Fxo7Rt^^+>V#?ynU}*eJNC%_fT3A~VU5}Wgyp<;(#r?+Q-DI_l z5)TGlIc1%Lci$}jJ1gGl@#V5Z$5I>P1^U30srWS}`TQHS5g`z5*$U#EBvYT49!I2oY*G22kT)CSa*~!DS8*ANT8n6&GDjZ{` zp`xIBY{}-jpdge6@AR0UoJprLGQ4a- zsm?w8k60ShyySAET#Y8ugU-Nf{yC6H&M6z z{@=X4pT*O5Z{Phs$bDQ}w{tytx93O_h#> zxwVayw7=OFi8KUL^?egJJWbn1Jl@V0jZ>omD=`>lyL;}g-OtdAkm$07J}@ha20$-U z=wi5ux%DBWY-wCZKd+ZgJdfF!9x+o5$kThWbr#%98eL3LnCC5maHdq}F&{2XWc4y_ zi0yYDol95Fo4=p9HiWju;ZDZ9tCRe%qj+H@E)Gfz|8Z=2Mvr zOjN~<*AL{>S}CapWB~d9+{eV$gh=@%aiH7}s*S&Hf67jhJ_8L7)Y$dzt_sHk8@kSw zqMOYD*@fh37s7-zdZ_Q=l}X{}EsD2%ktxHLl4&rZJ2dj(13Z_QV$HjGDLTDRR!w=G z)3@(7ZIrxa@|VgoepQQX%xU^<%^4@M5WwYs?k-$yz9aNHd@Z@>V}835kJxnz73SMe zFH4v+yKhuER2q85o4Lr{!UfxD!S4}vKNfozfmRJsw$rsf^pX1X^X4RuOmgE21mtlC z!h^M`d+_i8d&nS$r%ZfWJ8bg1q*&dW9W#0 zOy=SI5za^VTl;L3$ccl{(%W-teeqcL950kNG3|94Q1dxxwIT${O2pf5@tx-VXg#Wf zP*v4owYU*XtM+>nDU!CnzLl~b#NW_DXL#Iacib!>DuKyOdT z-O_O0J=pQ-Sy4|2(|+t)dMWjum5o{}Zfs8b%~Z+PaG^^8>cNPn$*d)c_YA^oTGA-| zBzvg+%bEwDpxpLs=fTKzo0y5eJ8KhipAA_^a^)_+g%}}@>84np%6>1d3+CWqGt4-J z+rC)&{^5bEiRyq9ILQ(U+IJ@rm^lz6m}-(yYdu$*Ffe~HpY2iIdMwZMZ!Zk;CjcUv zNC&q+Soj?EwT%`Wu6I}->^KLZaBSfy9BD8z`6kc|$pi_R{B1G-KHrGZ9BzR12(y>6 ze+SVQx!7|65EvuwZN8E77ID!(Br{~auqC4#1cjs?45E52nc_X~dramaS(VS|cq+o= z{&B?EuIfONz=l|L#z52ayHIF;Ah=iTHK@OE44tB!kk#HGe1u1y_kfK$#evi*q%yB2?E0wJwk{fe1RHeP zky{m>LqgVMt#Ax0+R+oowLoTQC#@zi_Gajp=D$swcq-Y_e1{RJ{U3`jM- z6!lb@6(GKN)zCd3HXq#xbp_s0Rr0RFg%kPVTg&Qo!5}lyI_aHC#Q^5E1xO>3>aQhL zveZ4sBcO-%mBWLOn)do9GCqRx*I-wGyq;8W_#o9;6_T3^0LKmT{Pr)J&-wTNyv5-! zsE#YJS*<|LvE&UrUM1cl=CiLKf85sa#QU`e_o=(7QHvJ5GJijLZS;y#N!_8oqUbBN zB$dl`SL`;h_PSAe)DTvO3P~5rDL>y4D+vh%{oo{2`fYB{U1@GDZTcs;Z?gVOa5j1m zAp-SgXms*~F@*pTQuTtHFU%F)(IK!RAHZyd6~OA@wMa#Pddri2?3klBzs~}+f8)`3MHpvP;R$K-hko`XTdq4e?>i97H4h8<~nL08NOk=$K1ROsvV z9`-N$Mt{azO<0ZGi5^9&KUe?ntUa}`+ko3Ae`3^*Iez*mP_GHmcN>UvUWe4dqJ)<4 zzX}8_jqNhkWb=4WxwSwpD({(^GRDnLp56S4&%1UUCPIV?|G~muj@5J(0eJr$E;5ND zVGZwjq97(v4jbV5?_5cxCA>7~AuocM>9nh;2<4+<7B1#-6`bFM%2tQW!$r%;6L$qw z$gxwAL|*dy{Dk+`W66%L>&7{b5s3&V8Ts1%lSo;=e^Cyt8LEjKdiKndVZUqVZ;v|$|f+}>7ec@4;@{9ntvdCQ3YK`G) z9v8nKW4o*u)4$JY0f&cnJ!ElNAFe#+9@gmHV#gSD1av6`BXX-5DOF>*3tncacy7Nw zo}%c{X46ZQ1|nSJnkd6gYw}G9-#^8L+jPbVz;cArhqNUAQQf zK@WcAD^LQ+d#M+mERhpX}2Gz;`&>Nk?TLua0!EmYZ=B=1-SdF&}nX9~Ge zpa(#v*+@pWbv(~=HwtL)J$6z}2@N(8>i#K@08a@o*jx`uRwSYqkM$Ml7R&+f9=HOA z(2Gmmx*Pl0pdV6&aSpHm0NOFP?nXzNV5Xge#aiUzb0`6!d86lRV*=%vHsxMn#qs>M zVt>QU0}4B0*Km!v?l&olElJuTU*Crg!~Gc&Sjl_HxB@=TXv5Z&riPoHGp zJ2%nb@DZ7YNsu&;J;V1bKWaw^o2Epq@!U&V@GC#P(+GA1*IC+XxcH^7JiYOC3Y%uw zDBExAM0x@m<;V6UQFlpyrc1zInmucLt0O^{^0~EoZ&vKHG5pqqUNTv6;VgM9waK^9 zWiv4~p4!!4JDN37*L?W~*{vtsMgrOvajQFe&aw*;j`L?o3R~i)syt0V+{H~+TXzPd zyNi7*U^%Y9(WWv#`vEdd@=39Vb%Cs>?L@50^8DJAI-tQkfVGAvy|V2(_Xpe*OhxQT zvOpf{J8wNEv;+O{HP@tsOdT*k$3*ykOz6g3+U8uBk`WerTu>JhML&A-Thc@2Na@Ld zLpPW4Q#b5Dh><-bMw^loww|3W6}l02A>gjBT_89@cIxr7TPom^cx%-;=fF27F5R)B zd+c$|#=7>&_c0NRm6S+}v-{$reDhp4xj>(e7k0U$vp%C>9>8qYCOgfE7Ly@{GvnR3 zGZ6bz{%>KB{_2V`)Lky9q^a^s!=E*>CYGUsZv-pWmD)@=EpFX~)p9X;`MW`9-x%DD zjdanbN^k^?89HMr!&)xXGNJQ^U&_k?0{@YBI^Ie3-v5Buz4)N%1q1WuwJRu z<{FSad+u6d@TZ}z5((o3{oaFF!5{~4fN{5u;amQ~c+^1Q64bbaAd>=K+}q%+37m%%S!0+=97B1vy*Pv%{7)zZswLttSaN^@~EQ zoBJpF&ZwVL_^@4q0jU77_o0OC?v%eyF;D*Ni_7QxF@MjBrB)gltBh~DVqxM6mGjl5 zOz^C-?S3OpD*WNs?RRV#4~J%R7Jo4BkNx)ekzKxe?qBfWj7m)u;_w90I=H_^?N2+k z%XvFKc9eFd*<7LtR*iWDtpvtlI2t@hXe5E4lX|{ul=QGq(+p2zC2)O%tO81{c{4_uj{jWriPejE@{)D z>D!NFjj|0323CfmmJrCag z7^pG!z=|!-(^WbpM8jec4AbobJ!%agC`Z~0mJ3#`e)jx&LjdKbfs2DpHvZ(rjUy|s zf^!zYnT>}dHU};&KSQylpr+O%Qfu*MBo}!GjvEX=My0w6z8}i~A`A1!!qDiPcc44@ zsTgZKmgDGBRtJ9UguCS~J{oIytaaX&gHGtX5BTzyXFVBIk_7^tVr7tEWb4^J+wDz= zJ$jYIIRy{p18qW#moaO5Ofl=FKc#+VOM;W=-*MhKV-RMZ+`6kSAIF>>`nzO3>sbBRcK(x59yk zK<}E^Z!3_{uFwa;i#61Q<860w&%si=G|xARX(C*LY*`d7|74X9UP@5t5MMt@ukUvXnm0az>= zSj~U)Cw7*5wY+&M?fufI!rq%(`6``24tXjw+}=a5ga6@9KA{4t<;_!h?-*!MVTa+| z#<^70J^zLH<9xK;JkISbhRUdxH&120Ynq7IPvR!d1CZThV^8W1KE}^^nF@`{>r<)k z8>m-ybCKISrU8M$~jJGlBhjwEH-%PuH$~D zvK)!YTS3O888Wi*Zb|E2T+OA708%G&31MI`K}0^Ehxj9#01qqK^_G!wX@N$ix2~MQ zjhsL`oY=*-mlBH&L|)6Q+`~+^Atkgdk+Eroj1D?4IH~m{F5^rN0Mc=yP+Zdak&l?k zgUkiUJm*v?g5u(CXUE^=X&zuc00~UWS(gc%Eiz6yQn#Kxwd>rzoXoY1rUPzj zYGhQ~ip3pysDNF};SapP$3RBfO@=r(WV~{wN!vb@OButc;Ok=D^Ci=Y!#w8j5N`uw z$J>aESl%?U?HxFp@m$0qByi~?5qmD!;LJQo@*a=y3=7!>h#fBgGIDJo!?ve$@*X2O zkI_NJU95ZS)VJdEd5On(C9vL!%mXrI5c5aIt^j1@p!_jmOUK9Hc4Q=>#7P5fp%w-QC(Rfji zaV#)RSoZ`+a1>{7GQH~TyQ;|SyvwHBIvc)$=Xr)VSsFYT#fldV8P6hMQR!4&%DO`* zMlzmbIhw9@-{?B)%Ka|bptCLYKDV-v`8>@l>$-hPyju`N1v_FbVe?0Y)~ zGlmm5jKNgbeX|KRH;k|7Q{v8C-&eyjmh&oeSVnE|wFJg(03|lO6vzmdj3(_nbYTz! z8Nu-kqf4DQY{ts>INT#kdX;$UdJWrni`SUX`>bFaO}zg&ytVQ`M!KX}NXPFkI#1TU z*qtLej$s_Y0Q%MYF;llqWppfk%5u|aZT=co@)2+GI*Zs`_tiuYsn?A_RNhEsAfp`` zflKc!oJ|*$NHBo@9L#WzU@&`ARqw}=kYVXddH*bF%T0qrE_U-d%UH@{K43K~Gag?q z)o8HdqKAo$e5f?A@TmsSG*$HFa1P@z`q7JC^lsu5nY3+9OF#49+%6~cUrY0TM3PU~ zzy{W^oaMa3T6Sl=nrZ?T3my?<^dm%_jaMlvSnuVo^rRQP7{Gz_qaXd*n|3W6A7wNA zgqH4e>aVoiyO*Sv&sohH*6<-K*}w)ivbEm#q`VU=_B(3Gy@(w3tbE#{W^{`IplL@J z`qGzP^r9!d=uTHUQB6mxsir!w6XcTAP(uwnsbL3O*~|tuvVje(Wi8vNZFChn!=pf~ zcT|x(5_vNAN^+97jck1iMW;aI)pVi*RkWu=o$NJU@Bx1CVd|v4i#_aS7dwK_YuM53 zU(u*KaZC0*7W{u8Bu00|88$}%001s}R9JLmVRU6WV{&C-bY%blc-k{EFtpS)G}JXP z4Kc8^GBL0+G1WFOv@$RN0738t68D*&`Tzg`E_zg0bYx+4WjbwdWNBu3004N}Gcqu= u)HO8JH82e^u(UEUure{#HZZg@FaQ8S@C6dyrZ#c_0000Uu8MqnYQq?{%+xt-?)h2-Yii&(Rb zi+dXvry79*<6Qgevk|}jaIN9yS-XyR{f3R3zy}JqBGzzmbFbmyUb~iu2YlKO{6B(c z+uH4W4xL!XZ+w||udBe}yAM;=OPtKB5Hx9_N-AA(3)rx6htN)8k$wB6q-A84RgS2t z9aY!=jl)izfnYo4Kx$_rnf3~}7f6c+s-NW;i7tZ^3;Ju*WkkI>K(J_x=AICj; z8vi^sE&WACX4cF6HwA@7#U*dwRaRBk)Yg6cRNvax-qG3hwY!H*85$lL9UGsRq|GlZ zF4316E34n<#f9MhU1Yyb?4Rbf4a{o|4-YpF@Ar9et?>dE_corjdk(GJe!`gdvMc}I z!*|yUoP3y)SFu4t$%HC+#jR!I4oPM5KHB%G{W7zEZ(;%et(pBku|MY3gV@Z?1s0Ec z8v>1hdoZR;=r7UlcQV%h%t2JQFQMm0<~Rtf2Z4GQxw?_ST7zQ69p}CC&XHuLIO1g! zV&hX6!0U%$p5Y+62r+atYvY1OQz4XBY)`vEMw2yBiyP4l5%kLTJDPmuI897D2cf=r zVyO8Ps#`A^J+#b0yp`5k!xO`P={*K(keILTXiUBr`e3bs&5fHcO@+7a;UG?!au9d4 zIf&>99QF8I76;)#SY4R+uj3%@+Sos(6X{2$Vfk-}+k%2)1ZpyVbuEgu1;x65oHj0r zoK9^*(U=^>w?|xK_F1chF@2jbU!Dz8OtXb1mN&F)jrt#)7>$GI)uXqd@=?(#74%Oka@8)2cNz|PnLu|k_Zh#XWPp4M@*V!2rpcw zE?pw3n+wTBM~{?7CR)K^)bR17q2(yn(J0Em#*$5J2QsTzomlnt8?@R~(JhttuF0NU{j_oEiCoxkG0VdeZ-o#UKtl!F#Pai0mUA#OD>F5pm(AXo|mGuUYi<4l?U z3x*HVim3z(>L#&M*#ve9os{QS-Y{ch`H)`f2RmA$w=%Q}4Lq_&Ssk)p1jwk&QGvqO>y#( z)vz-u#MtX5j!jRPCY_(3uiTzs47JDoZUn;!IDhoVuB0^@Tc0gtK@LEaO@s&6>)2&0 z$@V>@uf1;=#WzQ2i?}R3Y7=G9fnh=DhUf8Y2 z;EC2@cSC`bW=^1Bts@^p3xdUz4~ znaDhf4nVKw`>I+$^4)NPWEZ;y^P5L1nlmaU^m62g#tRuK`9?l37Fh0KauP#41rZDuWA8vr?H%aR_h^5Q8+vSeL zbjVh5<=8;C3;acBZ~)FxL|R@2{z76ik{x`Rw8%n6(fDCQ4q_M7y{j6GBdrcKF)+B@ zz|s5rB8Zbtzg+y8Sw(|&%f>#S+|4+MVibTF5x?#(dI|?2#G6Fm+Du@?CuhJH--EHv z#{38nrdp7{;FmiZ%Xl8XRRaAf2SG$jO+yU9QE!4H2Vr}oiPBdIRo+IA3qVw5Xnvo# z=0v)m3ly8~-GR6*{Uc;RajnsZJ2VzJ2yraC%jVW^+Yjs>)^2S$00QLWfw_?IX`=S?|K_~>J%LAYW?fW4Gxnor zw|9W4h;5Tej+_3k2B=ql@$L_XILh-~qUSlqPlW+XnKiY9-%3ipEvZY8w@r*TGt9 z*OtK&+pstB-BJ99$x+CLgC+P^!`%vK`AU=3PV*=1tGI7hg)hDSYEbgc{&huqXxzda zFjy2`rrR&Z%JKvmvw=aVv)S9ik{E14PKnFV^gQJpg)%N)`sw2rXz{P)=SD!m~^iB>aAsSJmAgh<<> zN4)3CbST+hmypP7s!!^kUVbsrFX5@zD?bz4sv$G;bD3rWZLNcGJ=MM1&8nyKhB9^0 zw6~`#bI3?OyO5_(Uvg!S94egAxOk5m{^3A!lnW(9XfR(WGEy(rP9VkV5M}eISwVdL z{F%*iwlskhRS{3unDo<%RYo_@dsl*OGa*` zwUgFSnpcFcj*oA1xL-cTPT}pkApViBvH2}C68rFNG-~*pZz%NFF%?uM*sBEDM72cE zxHD9RnbyACsgbc_Qd~GpOCFos~00+}>fw z9_m02gk8|!0J2-V?v_^^cCD}B5I(?vubu5>r~Ro?cny(!Tj{t9S4jtHG8Wer6OdtD z^(U>S7Y?o=#SipC@P<<6X}BVJUsN4sAlSA;1NpK~--YZFmMp+D${6(XeKmU8^1To4 zhO(h;y~+Hwo{slPLp+bI4*58sdJ;yI`ZrMcP%oy2Za&Pu7jAIwvlzQvT)tG%VYV_? zpjY3ZQ1+&CX4cVTs1BQTY?X3gDo$iGJQ2R7pB$aS?yq+SL~q^PLP7n^?VcIQLN%n?yTM^spRfK|_wMQ5Jg zj+9+Vg8|3xsudCJ9}gH-X`mDAarK^VpOp_C{6M)`csHMN_AtO*bS*IrrqY|?S2vVCg|4rp^EkDlTZ&1U@){~H=gPJr+~F#sHFs| z&ID0u+?*{3VHBJ&)DqMhlJXt}kP*d?%mCgD+oi|CqqLJVCZVK#zVrH@hL<#(a`z8S zLQ2QQ@Ba&wvbjIF_f&_Qdt)3nz3=ue#GkO+^K$P4Zr++0_o?G3ZOdff5dOe>|AHKj zi~oWFTZ4{@iKpf*5mPdstqEHh&ik*veoUjeM_Z-i^Zm7j1tu3SV&v9Sf_IvII*@;C zYnIrxoZ0DA<5+K<@o(e$PWhAdlloR%lppgrT^4tJVdF44Eb*u3 zVRAGHcK*hW<^p-!>ec=jauaf*IKH-&=xA|4D>B`Is_*WX<#;>t^R356jy$Hx>1#H2 zd~P|h**IGxTK#3fDZyB5OBYKtmbuq~B*Z~nYuX97z=v9&w`&|?YEBewWf;hng!f`- z$7-(3YO0=%IC$_2yt6r{(5f#&wa4+o;}E}X=XYz{6zM$bY*MvXa>>d~8L?iWz{>XQosG?@CNCtSjni6~EgS?-3^3Hj3@N%O!{>#s9wX$1L-~Go zhOa|v?>AhGbxBx1eSq8;xhSWEldC-ZaBtOtjTF?@smF6;j?34mCuApXR*1rFmQDMj zFj85weh#WA)0KGmUHyF74$R$@xIyXKD3N<+SK?}po_FuamY+1w>{1?+w`#c{vk&Ye zSc;KU>wl0|z+MKzhs}#PdII`@IIp%)_u?a;irc$hsP2WNT=T|sxKn%XnAjRQ`6M5 zowA9f>5=WL1|n^^X{ai6m<@jm%W2SMheMk~{8-3RsoA?XrA1F~=Ifr@;H>DJ*6V&b z^Md}CnV@fH`?{O9R2zRRzl+s)d{iSjxKH@FKzR++>BV>)RVjo1Tn(Ei>W?MJX~)X{ar4%}g@h+p(B6?Wy+oX#eV$y7_mc77V;mo2lS1P*^-2M>|IT zlpi%#E20(SJ_H4KT~+Z(K#Sq7w2m^*6c;}TxMFyV%ZuDwi=ebw#2w=LMP z=$nJV+1O(<2DxfQBf_d2#96{|#k5!G3I4&wp_+3~uJ~$GmxY4J{RgVkcea1I*+E^% zec&p8!Pr1~YP96KmfV)85#ykXZ3pTo4sEG=+YBOv0pzMg^_{@>)UiYZnb$6|^cea> z=x+Wxks%u#VQ^6V0ORN4wx@~;u<(@X^IcfIVtaYXW}J3)@xii_x}SH5OXcMi89QXW z)M1%+^$t*tT=2`NH`tjNDw<+yqxmABUm>4Lh{)UjaUT_mxQO$*=#xHi;I{Mo)u}_e z-~5P%MK{eKp7+lPRLUB@sC}pAZ3+2hdlbLOt9HAf>iUC;X|IUW_MbxW%USYm4jhC$ z`*7KgO2)*Z-_R?;sO>wW_SU;ivaBj%&DEN=>D_1eAhE*ts>s7_H@&|IUzwMkfj(>5 zn^=rSh(WD{KdW>H&%wdvnQ5nHUqnTl=}j-WO*>2{a}+`)CJ#Eb#QYMx!o}!eqBAlH z|G)X#|7s!{jVCaUHVnzv7So0XQ6I8TxAxfI@fUN1wyK;yW#=M2m8{hz)#}_izx$SG zg1l5kbK~`k-Vd!N=LIV-9&#C7L$V?bmh@{R)DfsAP*hvq2`6#`I>bikb=0xY+35Ax zwRYjIOwMjQaPzp=t8Bl_g1nEC(K7L;!pVaC^SY#mB~3yHTm;5q(|Sif%Uw?Oe^60) zFW|!aqt`Mrd}g~j2rG~(wc)R#+PAoWU=ff8%H?l92&-bN>RlsDYdc0XA81Y z#5(Qz;JQO6TpTqDB!j%|E;q!(Tc(&GNDlPWlAM@guAfR4EiMvL?H6GT4W0Ho;omOd zp`IK>-euCMje59WB3dpww71+o`0SyAt_dwcHz?P5v{;pXOR0On->H?PNRUFaOWj%h z?3Z!^a2O**yN4-A5#lX#dE+*`TKL8sc_T)@b#!CDv^VHZcnHAzs;+i~n*^j)3U^K*x z4jkOAkM7AxhK4{o`rSD97h¥elov_Rg)4Hg+_ZX@^s2A`i^iF;C$nj6$_vFr0?$ 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 F{~z)5VRrxk diff --git a/src/assets/pub/nutella_v_2.png b/src/assets/pub/nutella_v_2.png deleted file mode 100644 index c733397d3644bf9ea2f7a815e63405c31a5fa720..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 57279 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
@uNRycJ>$PW6e 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 z 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�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 W))&U{e-LaOz5R8?@PF_6Ech=tm5O`- diff --git a/src/assets/pub/rolex_v_2.png b/src/assets/pub/rolex_v_2.png deleted file mode 100644 index b1e07d9856e00b2b3e14fc361bd441c52c44ea40..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 50514 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 diff --git a/src/assets/uploadFile.png b/src/assets/uploadFile.png deleted file mode 100644 index cff9f3853d882c8079b4aeaffa40aa2b728d57fd..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 8853 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 AOaK4? diff --git a/src/environments/environment.prod.ts b/src/environments/environment.prod.ts deleted file mode 100644 index a27a700..0000000 --- a/src/environments/environment.prod.ts +++ /dev/null @@ -1,4 +0,0 @@ -export const environment = { - production: true, - debutUrl: "https://polynotfound.herokuapp.com/api/" -}; diff --git a/src/environments/environment.ts b/src/environments/environment.ts deleted file mode 100644 index 31c7c5f..0000000 --- a/src/environments/environment.ts +++ /dev/null @@ -1,17 +0,0 @@ -// This file can be replaced during build by using the `fileReplacements` array. -// `ng build --prod` replaces `environment.ts` with `environment.prod.ts`. -// The list of file replacements can be found in `angular.json`. - -export const environment = { - production: false, - debutUrl: "http://127.0.0.1:3000/api/" -}; - -/* - * For easier debugging in development mode, you can import the following file - * to ignore zone related error stack frames such as `zone.run`, `zoneDelegate.invokeTask`. - * - * This import should be commented out in production mode because it will have a negative impact - * on performance if an error is thrown. - */ -// import 'zone.js/dist/zone-error'; // Included with Angular CLI. diff --git a/src/favicon.ico b/src/favicon.ico deleted file mode 100644 index 997406ad22c29aae95893fb3d666c30258a09537..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 948 zcmV;l155mgP)CBYU7IjCFmI-B}4sMJt3^s9NVg!P0 z6hDQy(L`XWMkB@zOLgN$4KYz;j0zZxq9KKdpZE#5@k0crP^5f9KO};h)ZDQ%ybhht z%t9#h|nu0K(bJ ztIkhEr!*UyrZWQ1k2+YkGqDi8Z<|mIN&$kzpKl{cNP=OQzXHz>vn+c)F)zO|Bou>E z2|-d_=qY#Y+yOu1a}XI?cU}%04)zz%anD(XZC{#~WreV!a$7k2Ug`?&CUEc0EtrkZ zL49MB)h!_K{H(*l_93D5tO0;BUnvYlo+;yss%n^&qjt6fZOa+}+FDO(~2>G z2dx@=JZ?DHP^;b7*Y1as5^uphBsh*s*z&MBd?e@I>-9kU>63PjP&^#5YTOb&x^6Cf z?674rmSHB5Fk!{Gv7rv!?qX#ei_L(XtwVqLX3L}$MI|kJ*w(rhx~tc&L&xP#?cQow zX_|gx$wMr3pRZIIr_;;O|8fAjd;1`nOeu5K(pCu7>^3E&D2OBBq?sYa(%S?GwG&_0-s%_v$L@R!5H_fc)lOb9ZoOO#p`Nn`KU z3LTTBtjwo`7(HA6 z7gmO$yTR!5L>Bsg!X8616{JUngg_@&85%>W=mChTR;x4`P=?PJ~oPuy5 zU-L`C@_!34D21{fD~Y8NVnR3t;aqZI3fIhmgmx}$oc-dKDC6Ap$Gy>a!`A*x2L1v0 WcZ@i?LyX}70000 - - - - StreamNotFound - - - - - - - - - - - diff --git a/src/main.ts b/src/main.ts deleted file mode 100644 index c7b673c..0000000 --- a/src/main.ts +++ /dev/null @@ -1,12 +0,0 @@ -import { enableProdMode } from '@angular/core'; -import { platformBrowserDynamic } from '@angular/platform-browser-dynamic'; - -import { AppModule } from './app/app.module'; -import { environment } from './environments/environment'; - -if (environment.production) { - enableProdMode(); -} - -platformBrowserDynamic().bootstrapModule(AppModule) - .catch(err => console.error(err)); diff --git a/src/polyfills.ts b/src/polyfills.ts deleted file mode 100644 index 3e93392..0000000 --- a/src/polyfills.ts +++ /dev/null @@ -1,65 +0,0 @@ -/** - * This file includes polyfills needed by Angular and is loaded before the app. - * You can add your own extra polyfills to this file. - * - * This file is divided into 2 sections: - * 1. Browser polyfills. These are applied before loading ZoneJS and are sorted by browsers. - * 2. Application imports. Files imported after ZoneJS that should be loaded before your main - * file. - * - * The current setup is for so-called "evergreen" browsers; the last versions of browsers that - * automatically update themselves. This includes Safari >= 10, Chrome >= 55 (including Opera), - * Edge >= 13 on the desktop, and iOS 10 and Chrome on mobile. - * - * Learn more in https://angular.io/guide/browser-support - */ - -/*************************************************************************************************** - * BROWSER POLYFILLS - */ - -/** - * IE11 requires the following for NgClass support on SVG elements - */ -// import 'classlist.js'; // Run `npm install --save classlist.js`. - -/** - * Web Animations `@angular/platform-browser/animations` - * Only required if AnimationBuilder is used within the application and using IE/Edge or Safari. - * Standard animation support in Angular DOES NOT require any polyfills (as of Angular 6.0). - */ -// import 'web-animations-js'; // Run `npm install --save web-animations-js`. - -/** - * By default, zone.js will patch all possible macroTask and DomEvents - * user can disable parts of macroTask/DomEvents patch by setting following flags - * because those flags need to be set before `zone.js` being loaded, and webpack - * will put import in the top of bundle, so user need to create a separate file - * in this directory (for example: zone-flags.ts), and put the following flags - * into that file, and then add the following code before importing zone.js. - * import './zone-flags'; - * - * The flags allowed in zone-flags.ts are listed here. - * - * The following flags will work for all browsers. - * - * (window as any).__Zone_disable_requestAnimationFrame = true; // disable patch requestAnimationFrame - * (window as any).__Zone_disable_on_property = true; // disable patch onProperty such as onclick - * (window as any).__zone_symbol__UNPATCHED_EVENTS = ['scroll', 'mousemove']; // disable patch specified eventNames - * - * in IE/Edge developer tools, the addEventListener will also be wrapped by zone.js - * with the following flag, it will bypass `zone.js` patch for IE/Edge - * - * (window as any).__Zone_enable_cross_context_check = true; - * - */ - -/*************************************************************************************************** - * Zone JS is required by default for Angular itself. - */ -import 'zone.js/dist/zone'; // Included with Angular CLI. - -/*************************************************************************************************** - * APPLICATION IMPORTS - */ -import '@angular/localize/init'; diff --git a/src/proxy.conf.json b/src/proxy.conf.json deleted file mode 100644 index f1e4285..0000000 --- a/src/proxy.conf.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "/api/*": { - "target": "http://localhost:3000", - "secure": false, - "logLevel": "debug" - } -} diff --git a/src/styles.scss b/src/styles.scss deleted file mode 100644 index 80de7ef..0000000 --- a/src/styles.scss +++ /dev/null @@ -1,57 +0,0 @@ -@import "~@angular/material/prebuilt-themes/indigo-pink.css"; - ---root { - --dark-color: #f0f0f0; -} -html, body { height: 100%; } -body { margin: 0; } - - -.lightTheme { - background: url("assets/lightBackground.jpg") no-repeat center center fixed; - font-color: black; - border-color: black; - font-size: small; -} - - -.darkTheme { - background: url("assets/darkBackground.webp") no-repeat center center fixed; - font-color: white; - border-color: white; - font-size: small; -} - - -.lightTheme, .darkTheme { - -webkit-background-size: cover; - -moz-background-size: cover; - -o-background-size: cover; - background-size: cover; -} - - -.custom-dialog-container .mat-dialog-container { - margin: 0px 0px 0px 0px; - padding: 0px 0px 0px 0px; -} - - -// ------------------------------------------------------------------------- - - -// 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 { - border: solid 1px black !important; - background-color: white !important; -} diff --git a/src/test.ts b/src/test.ts deleted file mode 100644 index 50193eb..0000000 --- a/src/test.ts +++ /dev/null @@ -1,25 +0,0 @@ -// This file is required by karma.conf.js and loads recursively all the .spec and framework files - -import 'zone.js/dist/zone-testing'; -import { getTestBed } from '@angular/core/testing'; -import { - BrowserDynamicTestingModule, - platformBrowserDynamicTesting -} from '@angular/platform-browser-dynamic/testing'; - -declare const require: { - context(path: string, deep?: boolean, filter?: RegExp): { - keys(): string[]; - (id: string): T; - }; -}; - -// First, initialize the Angular testing environment. -getTestBed().initTestEnvironment( - BrowserDynamicTestingModule, - platformBrowserDynamicTesting() -); -// Then we find all the tests. -const context = require.context('./', true, /\.spec\.ts$/); -// And load the modules. -context.keys().map(context); diff --git a/tsconfig.app.json b/tsconfig.app.json deleted file mode 100644 index 82d91dc..0000000 --- a/tsconfig.app.json +++ /dev/null @@ -1,15 +0,0 @@ -/* To learn more about this file see: https://angular.io/config/tsconfig. */ -{ - "extends": "./tsconfig.json", - "compilerOptions": { - "outDir": "./out-tsc/app", - "types": [] - }, - "files": [ - "src/main.ts", - "src/polyfills.ts" - ], - "include": [ - "src/**/*.d.ts" - ] -} diff --git a/tsconfig.json b/tsconfig.json deleted file mode 100644 index 4a4dc62..0000000 --- a/tsconfig.json +++ /dev/null @@ -1,23 +0,0 @@ -/* To learn more about this file see: https://angular.io/config/tsconfig. */ -{ - "compileOnSave": false, - "compilerOptions": { - "baseUrl": "./", - "outDir": "./dist/out-tsc", - "sourceMap": true, - "declaration": false, - "downlevelIteration": true, - "experimentalDecorators": true, - "moduleResolution": "node", - "importHelpers": true, - "target": "es2015", - "module": "es2020", - "lib": [ - "es2018", - "dom" - ] - }, - "angularCompilerOptions": { - "enableI18nLegacyMessageIdFormat": false - } -} diff --git a/tsconfig.spec.json b/tsconfig.spec.json deleted file mode 100644 index 092345b..0000000 --- a/tsconfig.spec.json +++ /dev/null @@ -1,18 +0,0 @@ -/* To learn more about this file see: https://angular.io/config/tsconfig. */ -{ - "extends": "./tsconfig.json", - "compilerOptions": { - "outDir": "./out-tsc/spec", - "types": [ - "jasmine" - ] - }, - "files": [ - "src/test.ts", - "src/polyfills.ts" - ], - "include": [ - "src/**/*.spec.ts", - "src/**/*.d.ts" - ] -} diff --git a/tslint.json b/tslint.json deleted file mode 100644 index 277c8eb..0000000 --- a/tslint.json +++ /dev/null @@ -1,152 +0,0 @@ -{ - "extends": "tslint:recommended", - "rulesDirectory": [ - "codelyzer" - ], - "rules": { - "align": { - "options": [ - "parameters", - "statements" - ] - }, - "array-type": false, - "arrow-return-shorthand": true, - "curly": true, - "deprecation": { - "severity": "warning" - }, - "eofline": true, - "import-blacklist": [ - true, - "rxjs/Rx" - ], - "import-spacing": true, - "indent": { - "options": [ - "spaces" - ] - }, - "max-classes-per-file": false, - "max-line-length": [ - true, - 140 - ], - "member-ordering": [ - true, - { - "order": [ - "static-field", - "instance-field", - "static-method", - "instance-method" - ] - } - ], - "no-console": [ - true, - "debug", - "info", - "time", - "timeEnd", - "trace" - ], - "no-empty": false, - "no-inferrable-types": [ - true, - "ignore-params" - ], - "no-non-null-assertion": true, - "no-redundant-jsdoc": true, - "no-switch-case-fall-through": true, - "no-var-requires": false, - "object-literal-key-quotes": [ - true, - "as-needed" - ], - "quotemark": [ - true, - "single" - ], - "semicolon": { - "options": [ - "always" - ] - }, - "space-before-function-paren": { - "options": { - "anonymous": "never", - "asyncArrow": "always", - "constructor": "never", - "method": "never", - "named": "never" - } - }, - "typedef": [ - true, - "call-signature" - ], - "typedef-whitespace": { - "options": [ - { - "call-signature": "nospace", - "index-signature": "nospace", - "parameter": "nospace", - "property-declaration": "nospace", - "variable-declaration": "nospace" - }, - { - "call-signature": "onespace", - "index-signature": "onespace", - "parameter": "onespace", - "property-declaration": "onespace", - "variable-declaration": "onespace" - } - ] - }, - "variable-name": { - "options": [ - "ban-keywords", - "check-format", - "allow-pascal-case" - ] - }, - "whitespace": { - "options": [ - "check-branch", - "check-decl", - "check-operator", - "check-separator", - "check-type", - "check-typecast" - ] - }, - "component-class-suffix": true, - "contextual-lifecycle": true, - "directive-class-suffix": true, - "no-conflicting-lifecycle": true, - "no-host-metadata-property": true, - "no-input-rename": true, - "no-inputs-metadata-property": true, - "no-output-native": true, - "no-output-on-prefix": true, - "no-output-rename": true, - "no-outputs-metadata-property": true, - "template-banana-in-box": true, - "template-no-negated-async": true, - "use-lifecycle-interface": true, - "use-pipe-transform-interface": true, - "directive-selector": [ - true, - "attribute", - "app", - "camelCase" - ], - "component-selector": [ - true, - "element", - "app", - "kebab-case" - ] - } -} From 4f85d63bac8b8203a29db9f1dafc74f3a8e6e350 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Y=C3=BBki=20VACHOT?= Date: Wed, 22 Dec 2021 11:17:47 +0100 Subject: [PATCH 02/35] Create: Add package.json --- package.json | 67 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 67 insertions(+) create mode 100644 package.json diff --git a/package.json b/package.json new file mode 100644 index 0000000..4b8d030 --- /dev/null +++ b/package.json @@ -0,0 +1,67 @@ +{ + "name": "backend", + "version": "1.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" + }, + "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", + "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" + }, + "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", + "@types/node": "^12.11.1", + "codelyzer": "^6.0.0", + "jasmine-core": "~3.6.0", + "jasmine-spec-reporter": "~5.0.0", + "karma": "~6.3.5", + "karma-chrome-launcher": "~3.1.0", + "karma-coverage": "~2.0.3", + "karma-jasmine": "~4.0.0", + "karma-jasmine-html-reporter": "^1.5.0", + "protractor": "~7.0.0", + "ts-node": "~8.3.0", + "tslint": "~6.1.0", + "typescript": "~4.3.5" + } +} From 97b6039ce562cf47cdcd5f682e145c7d22394e5e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Y=C3=BBki=20VACHOT?= Date: Wed, 22 Dec 2021 12:04:39 +0100 Subject: [PATCH 03/35] Update: package.json --- package.json | 44 +------------------------------------------- 1 file changed, 1 insertion(+), 43 deletions(-) diff --git a/package.json b/package.json index 4b8d030..cd86e37 100644 --- a/package.json +++ b/package.json @@ -3,41 +3,17 @@ "version": "1.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" + "start": "node server.js" }, "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", - "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", @@ -45,23 +21,5 @@ "zone.js": "~0.11.3" }, "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", - "@types/node": "^12.11.1", - "codelyzer": "^6.0.0", - "jasmine-core": "~3.6.0", - "jasmine-spec-reporter": "~5.0.0", - "karma": "~6.3.5", - "karma-chrome-launcher": "~3.1.0", - "karma-coverage": "~2.0.3", - "karma-jasmine": "~4.0.0", - "karma-jasmine-html-reporter": "^1.5.0", - "protractor": "~7.0.0", - "ts-node": "~8.3.0", - "tslint": "~6.1.0", - "typescript": "~4.3.5" } } From 6ce49daa9a23c7570e424314c7650820df678d2a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Y=C3=BBki=20Vachot?= Date: Wed, 22 Dec 2021 21:06:29 +0100 Subject: [PATCH 04/35] Update: Cors --- server.js | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/server.js b/server.js index 2417648..a624b83 100644 --- a/server.js +++ b/server.js @@ -11,7 +11,13 @@ 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})); +app.use(cors({ + origin: [ + 'https://polynotfound.herokuapp.com/', 'http://127.0.0.1:4200', + 'https://admin-polynotfound.herokuapp.com/', 'http://127.0.0.1:4201' + ], + credentials: true +})); const db = require("./models/mongodb.model"); console.log("Db Url: ",db.url); From 965f1c03e9e52c5161aa85b094ed450ca2e4881c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Y=C3=BBki=20Vachot?= Date: Wed, 22 Dec 2021 21:29:05 +0100 Subject: [PATCH 05/35] Update server.js --- server.js | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/server.js b/server.js index a624b83..2730846 100644 --- a/server.js +++ b/server.js @@ -12,10 +12,7 @@ app.use(bodyParser.json()); const cors = require('cors'); app.use(cors({ - origin: [ - 'https://polynotfound.herokuapp.com/', 'http://127.0.0.1:4200', - 'https://admin-polynotfound.herokuapp.com/', 'http://127.0.0.1:4201' - ], + origin: true, credentials: true })); From 7448f6b591c5f0d70d0d903f502c467596b42bee Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Y=C3=BBki=20VACHOT?= Date: Thu, 23 Dec 2021 11:56:40 +0100 Subject: [PATCH 06/35] Update: Environment for Heroku Production --- server.js | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/server.js b/server.js index 2730846..f63829c 100644 --- a/server.js +++ b/server.js @@ -12,7 +12,10 @@ app.use(bodyParser.json()); const cors = require('cors'); app.use(cors({ - origin: true, + origin: [ + 'http://127.0.0.1:4200', + 'http://127.0.0.1:4201', + ], credentials: true })); From ae0fe1f32f2422d1ee366c6e8c27222cb1905fad Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Y=C3=BBki=20VACHOT?= Date: Thu, 23 Dec 2021 13:07:36 +0100 Subject: [PATCH 07/35] Update: Environment for Heroku Production --- server.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/server.js b/server.js index f63829c..b833c0a 100644 --- a/server.js +++ b/server.js @@ -15,6 +15,8 @@ app.use(cors({ origin: [ 'http://127.0.0.1:4200', 'http://127.0.0.1:4201', + 'https://admin-polynotfound.herokuapp.com/', + 'https://polynotfound.herokuapp.com/' ], credentials: true })); From a12926f277190973cb00b82777285171eb89c3cd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Y=C3=BBki=20VACHOT?= Date: Thu, 23 Dec 2021 13:10:57 +0100 Subject: [PATCH 08/35] Update: Remove *all get request --- server.js | 5 ----- 1 file changed, 5 deletions(-) diff --git a/server.js b/server.js index b833c0a..0dd8921 100644 --- a/server.js +++ b/server.js @@ -1,4 +1,3 @@ -const path = require('path'); const express = require('express'); const app = express(); const port = process.env.PORT || 3000; @@ -78,10 +77,6 @@ User.exists({role: roles.SuperAdmin}, function (err, docs){ } }); -app.get('/*all', function(req,res) { - res.sendFile(path.join(__dirname+ '/dist/index.html')); -}); - app.listen(port, '0.0.0.0',() => { console.log (`listening on port ${port}`); }); From f26fcdc961a3d5ed6b026556d1920941f07e74f1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Y=C3=BBki=20VACHOT?= Date: Thu, 23 Dec 2021 13:18:04 +0100 Subject: [PATCH 09/35] Update: Move Cors inside Routes definition --- config/cors.config.js | 26 ++++++++++++++++++++++++++ routes/user.routes.js | 25 +++++++++++++------------ server.js | 11 ----------- 3 files changed, 39 insertions(+), 23 deletions(-) create mode 100644 config/cors.config.js diff --git a/config/cors.config.js b/config/cors.config.js new file mode 100644 index 0000000..99b0156 --- /dev/null +++ b/config/cors.config.js @@ -0,0 +1,26 @@ +const cors = require('cors'); +module.exports.cors = cors; + +const allowList = [ + 'http://127.0.0.1:4200', + 'http://127.0.0.1:4201', + 'https://admin-polynotfound.herokuapp.com/', + 'https://polynotfound.herokuapp.com/' +]; + +const corsOptionsDelegate = function(req, callback) { + let corsOptions; + if (allowList.indexOf(req.header('Origin')) !== -1) { + corsOptions = { + origin: true, + credentials: true + } + } else { + corsOptions = { + origin: false, + credentials: true + } + } + callback(null, corsOptions) +} +module.exports.options = corsOptionsDelegate; \ No newline at end of file diff --git a/routes/user.routes.js b/routes/user.routes.js index 346cb04..4d62364 100644 --- a/routes/user.routes.js +++ b/routes/user.routes.js @@ -1,42 +1,43 @@ const users = require("../controllers/user.controller"); +const {cors, options} = require("../config/cors.config"); module.exports = app => { let router = require("express").Router(); // Authenticate a User - router.post("/user/auth", users.auth); + router.post("/user/auth", cors(options), users.auth); // Logout a User - router.delete("/user/logout", users.logout); + router.delete("/user/logout", cors(options), users.logout); // Request password reset with email - router.post("/user/resetPass", users.resetPass); + router.post("/user/resetPass", cors(options), users.resetPass); // Create and Save a new User - router.post("/user/create", users.create); + router.post("/user/create", cors(options), users.create); // Retrieve all Users if admin - router.get("/user/findAll", users.findAll); + router.get("/user/findAll", cors(options), users.findAll); // Find single User from id if admin or session id - router.get("/user/findOne/:id", users.findOne); + router.get("/user/findOne/:id", cors(options), users.findOne); // Update a User from id if admin or session id - router.put("/user/update/:id", users.update); + router.put("/user/update/:id", cors(options), users.update); // Delete a User from id if admin or session id - router.delete("/user/delete/:id", users.delete); + router.delete("/user/delete/:id", cors(options), users.delete); // Delete all Users if superAdmin - router.delete("/user/deleteAll", users.deleteAll); + router.delete("/user/deleteAll", cors(options), users.deleteAll); // Get all Roles depending on the User session id - router.get("/user/roles", users.roles); + router.get("/user/roles", cors(options), users.roles); // Get 1 or multiple ad adapted to the User session id - router.get("/user/ad", users.ad); + router.get("/user/ad", cors(options), users.ad); // Get History - router.get("/user/history", users.history); + router.get("/user/history", cors(options), users.history); app.use('/api', router); }; diff --git a/server.js b/server.js index 0dd8921..c17846b 100644 --- a/server.js +++ b/server.js @@ -9,17 +9,6 @@ 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', - 'http://127.0.0.1:4201', - 'https://admin-polynotfound.herokuapp.com/', - 'https://polynotfound.herokuapp.com/' - ], - credentials: true -})); - const db = require("./models/mongodb.model"); console.log("Db Url: ",db.url); db.mongoose From ae10848b633902e3f697fffcf6224831b2b4ad20 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Y=C3=BBki=20VACHOT?= Date: Thu, 23 Dec 2021 13:22:11 +0100 Subject: [PATCH 10/35] Update: Cors Test --- config/cors.config.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/config/cors.config.js b/config/cors.config.js index 99b0156..a1eb0bd 100644 --- a/config/cors.config.js +++ b/config/cors.config.js @@ -9,6 +9,7 @@ const allowList = [ ]; const corsOptionsDelegate = function(req, callback) { + console.log(req.header('Origin'), allowList.indexOf(req.header('Origin'))); let corsOptions; if (allowList.indexOf(req.header('Origin')) !== -1) { corsOptions = { @@ -18,9 +19,10 @@ const corsOptionsDelegate = function(req, callback) { } else { corsOptions = { origin: false, - credentials: true + credentials: false } } + console.log(corsOptions); callback(null, corsOptions) } module.exports.options = corsOptionsDelegate; \ No newline at end of file From f328af51c545b0c59e6875899bd9131018c30440 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Y=C3=BBki=20VACHOT?= Date: Thu, 23 Dec 2021 13:25:35 +0100 Subject: [PATCH 11/35] Update: Cors Test --- config/cors.config.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/config/cors.config.js b/config/cors.config.js index a1eb0bd..068cc23 100644 --- a/config/cors.config.js +++ b/config/cors.config.js @@ -4,8 +4,8 @@ module.exports.cors = cors; const allowList = [ 'http://127.0.0.1:4200', 'http://127.0.0.1:4201', - 'https://admin-polynotfound.herokuapp.com/', - 'https://polynotfound.herokuapp.com/' + 'https://admin-polynotfound.herokuapp.com', + 'https://polynotfound.herokuapp.com' ]; const corsOptionsDelegate = function(req, callback) { From d1b3829450e8b97c1df2ae1718962d6191775573 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Y=C3=BBki=20VACHOT?= Date: Sat, 25 Dec 2021 00:59:53 +0100 Subject: [PATCH 12/35] Update: README --- .browserslistrc | 17 - .editorconfig | 16 - .gitignore | 52 -- Dockerfile | 6 - Procfile | 1 - angular.json | 134 ----- app-backend/config/functions.config.js | 26 - app-backend/config/host.config.js | 26 - app-backend/config/mongodb.config.js | 4 - app-backend/config/response.config.js | 9 - app-backend/config/sessionJWT.config.js | 109 ---- app-backend/controllers/ad.controller.js | 290 ---------- app-backend/controllers/misc.controller.js | 7 - .../controllers/playlist.controller.js | 407 ------------- app-backend/controllers/user.controller.js | 546 ------------------ app-backend/controllers/video.controller.js | 473 --------------- app-backend/jwtRS256.key.pub | 14 - app-backend/jwtRS256.sh | 8 - app-backend/models/database/ads.model.js | 44 -- .../models/database/playlists.model.js | 24 - app-backend/models/database/users.model.js | 48 -- app-backend/models/database/videos.model.js | 29 - app-backend/models/mongodb.model.js | 19 - app-backend/models/objects/image.model.js | 10 - app-backend/models/objects/role.model.js | 22 - .../models/objects/video.categories.model.js | 157 ----- app-backend/routes/ad.routes.js | 24 - app-backend/routes/misc.routes.js | 9 - app-backend/routes/playlist.routes.js | 24 - app-backend/routes/user.routes.js | 42 -- app-backend/routes/video.routes.js | 30 - docker-compose.yml | 41 -- e2e/protractor.conf.js | 37 -- e2e/src/app.e2e-spec.ts | 23 - e2e/src/app.po.ts | 11 - e2e/tsconfig.json | 13 - karma.conf.js | 44 -- package.json | 67 --- server.js | 84 --- .../page-ad-list-admin.component.html | 167 ------ .../page-ad-list-admin.component.scss | 74 --- .../page-ad-list-admin.component.spec.ts | 25 - .../page-ad-list-admin.component.ts | 262 --------- .../popup-delete-ad-admin.component.html | 8 - .../popup-delete-ad-admin.component.scss | 0 .../popup-delete-ad-admin.component.spec.ts | 25 - .../popup-delete-ad-admin.component.ts | 49 -- ...opup-visualize-images-admin.component.html | 20 - ...opup-visualize-images-admin.component.scss | 14 - ...p-visualize-images-admin.component.spec.ts | 25 - .../popup-visualize-images-admin.component.ts | 38 -- .../page-profil-admin.component.html | 43 -- .../page-profil-admin.component.scss | 61 -- .../page-profil-admin.component.spec.ts | 25 - .../page-profil-admin.component.ts | 90 --- .../popup-update-admin.component.html | 59 -- .../popup-update-admin.component.scss | 33 -- .../popup-update-admin.component.spec.ts | 25 - .../popup-update-admin.component.ts | 124 ---- .../input-interests-admin.component.html | 43 -- .../input-interests-admin.component.scss | 3 - .../input-interests-admin.component.spec.ts | 25 - .../input-interests-admin.component.ts | 121 ---- .../page-user-list.component.html | 193 ------- .../page-user-list.component.scss | 99 ---- .../page-user-list.component.spec.ts | 25 - .../page-user-list.component.ts | 233 -------- .../popup-create-user.component.html | 160 ----- .../popup-create-user.component.scss | 16 - .../popup-create-user.component.spec.ts | 25 - .../popup-create-user.component.ts | 127 ---- .../popup-delete-user.component.html | 8 - .../popup-delete-user.component.scss | 0 .../popup-delete-user.component.spec.ts | 25 - .../popup-delete-user.component.ts | 47 -- .../navbar-admin/navbar-admin.component.html | 37 -- .../navbar-admin/navbar-admin.component.scss | 80 --- .../navbar-admin.component.spec.ts | 25 - .../navbar-admin/navbar-admin.component.ts | 40 -- .../drag-and-drop.component.html | 33 -- .../drag-and-drop.component.scss | 135 ----- .../drag-and-drop.component.spec.ts | 25 - .../drag-and-drop/drag-and-drop.component.ts | 93 --- .../input-interests-ad.component.html | 43 -- .../input-interests-ad.component.scss | 16 - .../input-interests-ad.component.spec.ts | 25 - .../input-interests-ad.component.ts | 121 ---- .../page-ad-list-advertiser.component.html | 185 ------ .../page-ad-list-advertiser.component.scss | 87 --- .../page-ad-list-advertiser.component.spec.ts | 25 - .../page-ad-list-advertiser.component.ts | 309 ---------- .../popup-add-or-update-ad.component.html | 83 --- .../popup-add-or-update-ad.component.scss | 90 --- .../popup-add-or-update-ad.component.spec.ts | 25 - .../popup-add-or-update-ad.component.ts | 221 ------- .../popup-delete-ad-advertiser.component.html | 8 - .../popup-delete-ad-advertiser.component.scss | 0 ...pup-delete-ad-advertiser.component.spec.ts | 25 - .../popup-delete-ad-advertiser.component.ts | 47 -- ...pup-visualize-ad-advertiser.component.html | 71 --- ...pup-visualize-ad-advertiser.component.scss | 28 - ...-visualize-ad-advertiser.component.spec.ts | 25 - ...popup-visualize-ad-advertiser.component.ts | 27 - ...visualize-images-advertiser.component.html | 20 - ...visualize-images-advertiser.component.scss | 14 - ...ualize-images-advertiser.component.spec.ts | 25 - ...p-visualize-images-advertiser.component.ts | 38 -- .../page-profil-advertiser.component.html | 49 -- .../page-profil-advertiser.component.scss | 61 -- .../page-profil-advertiser.component.spec.ts | 25 - .../page-profil-advertiser.component.ts | 90 --- .../popup-update-advertiser.component.html | 65 --- .../popup-update-advertiser.component.scss | 33 -- .../popup-update-advertiser.component.spec.ts | 25 - .../popup-update-advertiser.component.ts | 125 ---- .../pages-popularity.component.html | 94 --- .../pages-popularity.component.scss | 53 -- .../pages-popularity.component.spec.ts | 25 - .../pages-popularity.component.ts | 308 ---------- .../drag-and-drop.directive.spec.ts | 8 - .../dragAndDrop/drag-and-drop.directive.ts | 36 -- .../navbar-advertiser.component.html | 41 -- .../navbar-advertiser.component.scss | 80 --- .../navbar-advertiser.component.spec.ts | 25 - .../navbar-advertiser.component.ts | 41 -- src/app/app-routing.module.ts | 53 -- src/app/app.component.html | 1 - src/app/app.component.scss | 24 - src/app/app.component.spec.ts | 35 -- src/app/app.component.ts | 12 - src/app/app.module.ts | 157 ----- .../page-login/page-login.component.html | 36 -- .../page-login/page-login.component.scss | 271 --------- .../page-login/page-login.component.spec.ts | 25 - .../login/page-login/page-login.component.ts | 101 ---- .../popup-forgotten-password.component.html | 24 - .../popup-forgotten-password.component.scss | 12 - ...popup-forgotten-password.component.spec.ts | 25 - .../popup-forgotten-password.component.ts | 47 -- .../input-interests-register.component.html | 43 -- .../input-interests-register.component.scss | 3 - ...input-interests-register.component.spec.ts | 25 - .../input-interests-register.component.ts | 121 ---- .../page-register.component.html | 161 ------ .../page-register.component.scss | 47 -- .../page-register.component.spec.ts | 25 - .../page-register/page-register.component.ts | 135 ----- .../popup-confirmation.component.html | 11 - .../popup-confirmation.component.scss | 7 - .../popup-confirmation.component.spec.ts | 25 - .../popup-confirmation.component.ts | 15 - .../navbar-before-connexion.component.html | 40 -- .../navbar-before-connexion.component.scss | 79 --- .../navbar-before-connexion.component.spec.ts | 25 - .../navbar-before-connexion.component.ts | 12 - .../page-history-user.component.html | 70 --- .../page-history-user.component.scss | 46 -- .../page-history-user.component.spec.ts | 25 - .../page-history-user.component.ts | 116 ---- .../page-my-playlists.component.html | 35 -- .../page-my-playlists.component.scss | 48 -- .../page-my-playlists.component.spec.ts | 25 - .../page-my-playlists.component.ts | 69 --- .../playlist-list.component.html | 48 -- .../playlist-list.component.scss | 94 --- .../playlist-list.component.spec.ts | 25 - .../playlist-list/playlist-list.component.ts | 164 ------ ...p-create-or-update-playlist.component.html | 19 - ...p-create-or-update-playlist.component.scss | 0 ...reate-or-update-playlist.component.spec.ts | 25 - ...pup-create-or-update-playlist.component.ts | 92 --- .../popup-delete-playlist.component.html | 8 - .../popup-delete-playlist.component.scss | 0 .../popup-delete-playlist.component.spec.ts | 25 - .../popup-delete-playlist.component.ts | 41 -- .../video-list/video-list.component.html | 91 --- .../video-list/video-list.component.scss | 83 --- .../video-list/video-list.component.spec.ts | 25 - .../video-list/video-list.component.ts | 92 --- .../input-interests-profil.component.html | 39 -- .../input-interests-profil.component.scss | 20 - .../input-interests-profil.component.spec.ts | 25 - .../input-interests-profil.component.ts | 121 ---- .../page-profil-user.component.html | 92 --- .../page-profil-user.component.scss | 80 --- .../page-profil-user.component.spec.ts | 25 - .../page-profil-user.component.ts | 90 --- .../popup-update-user.component.html | 125 ---- .../popup-update-user.component.scss | 81 --- .../popup-update-user.component.spec.ts | 25 - .../popup-update-user.component.ts | 133 ----- .../page-search/page-search.component.html | 80 --- .../page-search/page-search.component.scss | 90 --- .../page-search/page-search.component.spec.ts | 25 - .../page-search/page-search.component.ts | 119 ---- .../video-grid/video-grid.component.html | 76 --- .../video-grid/video-grid.component.scss | 84 --- .../video-grid/video-grid.component.spec.ts | 25 - .../search/video-grid/video-grid.component.ts | 129 ----- .../components/advert/advert.component.html | 26 - .../components/advert/advert.component.scss | 41 -- .../advert/advert.component.spec.ts | 25 - .../components/advert/advert.component.ts | 40 -- .../navbar-user/navbar-user.component.html | 41 -- .../navbar-user/navbar-user.component.scss | 80 --- .../navbar-user/navbar-user.component.spec.ts | 25 - .../navbar-user/navbar-user.component.ts | 41 -- ...opup-add-video-to-playlists.component.html | 42 -- ...opup-add-video-to-playlists.component.scss | 39 -- ...p-add-video-to-playlists.component.spec.ts | 25 - .../popup-add-video-to-playlists.component.ts | 141 ----- .../add-video-to-playlists.service.spec.ts | 16 - .../add-video-to-playlists.service.ts | 102 ---- .../page-watching-video.component.html | 233 -------- .../page-watching-video.component.scss | 159 ----- .../page-watching-video.component.spec.ts | 25 - .../page-watching-video.component.ts | 264 --------- src/app/utils/interfaces/advert.ts | 39 -- src/app/utils/interfaces/playlist.ts | 10 - src/app/utils/interfaces/user.ts | 33 -- src/app/utils/interfaces/video.ts | 32 - .../fictitious-adverts.service.spec.ts | 16 - .../fictitious-adverts.service.ts | 130 ----- .../fictitious-users.service.spec.ts | 16 - .../fictitious-users.service.ts | 128 ---- .../fictitious-utils.service.spec.ts | 16 - .../fictitious-utils.service.ts | 33 -- .../fictitious-videos.service.spec.ts | 16 - .../fictitious-videos.service.ts | 289 --------- .../services/message/message.service.spec.ts | 16 - .../utils/services/message/message.service.ts | 40 -- .../services/profil/profil.service.spec.ts | 16 - .../utils/services/profil/profil.service.ts | 30 - .../services/theme/theme.service.spec.ts | 16 - src/app/utils/services/theme/theme.service.ts | 15 - src/assets/.gitkeep | 0 src/assets/darkBackground.webp | Bin 712 -> 0 bytes src/assets/lightBackground.jpg | Bin 5902 -> 0 bytes src/assets/logo.png | Bin 5798 -> 0 bytes src/assets/logo_plateforms/dailymotion.png | Bin 6478 -> 0 bytes src/assets/logo_plateforms/youtube.png | Bin 7858 -> 0 bytes src/assets/play.png | Bin 3586 -> 0 bytes src/assets/profil.png | Bin 18287 -> 0 bytes src/assets/pub/nutella_v_1.jpeg | Bin 60880 -> 0 bytes src/assets/pub/nutella_v_2.png | Bin 57279 -> 0 bytes src/assets/pub/nutella_v_3.jpg | Bin 36018 -> 0 bytes src/assets/pub/rolex_v_1.jpg | Bin 72794 -> 0 bytes src/assets/pub/rolex_v_2.png | Bin 50514 -> 0 bytes src/assets/uploadFile.png | Bin 8853 -> 0 bytes src/environments/environment.prod.ts | 4 - src/environments/environment.ts | 17 - src/favicon.ico | Bin 948 -> 0 bytes src/index.html | 16 - src/main.ts | 12 - src/polyfills.ts | 65 --- src/proxy.conf.json | 7 - src/styles.scss | 57 -- src/test.ts | 25 - tsconfig.app.json | 15 - tsconfig.json | 23 - tsconfig.spec.json | 18 - tslint.json | 152 ----- 262 files changed, 15488 deletions(-) delete mode 100644 .browserslistrc delete mode 100644 .editorconfig delete mode 100644 .gitignore delete mode 100644 Dockerfile delete mode 100644 Procfile delete mode 100644 angular.json delete mode 100644 app-backend/config/functions.config.js delete mode 100644 app-backend/config/host.config.js delete mode 100644 app-backend/config/mongodb.config.js delete mode 100644 app-backend/config/response.config.js delete mode 100644 app-backend/config/sessionJWT.config.js delete mode 100644 app-backend/controllers/ad.controller.js delete mode 100644 app-backend/controllers/misc.controller.js delete mode 100644 app-backend/controllers/playlist.controller.js delete mode 100644 app-backend/controllers/user.controller.js delete mode 100644 app-backend/controllers/video.controller.js delete mode 100644 app-backend/jwtRS256.key.pub delete mode 100755 app-backend/jwtRS256.sh delete mode 100644 app-backend/models/database/ads.model.js delete mode 100644 app-backend/models/database/playlists.model.js delete mode 100644 app-backend/models/database/users.model.js delete mode 100644 app-backend/models/database/videos.model.js delete mode 100644 app-backend/models/mongodb.model.js delete mode 100644 app-backend/models/objects/image.model.js delete mode 100644 app-backend/models/objects/role.model.js delete mode 100644 app-backend/models/objects/video.categories.model.js delete mode 100644 app-backend/routes/ad.routes.js delete mode 100644 app-backend/routes/misc.routes.js delete mode 100644 app-backend/routes/playlist.routes.js delete mode 100644 app-backend/routes/user.routes.js delete mode 100644 app-backend/routes/video.routes.js delete mode 100644 docker-compose.yml delete mode 100644 e2e/protractor.conf.js delete mode 100644 e2e/src/app.e2e-spec.ts delete mode 100644 e2e/src/app.po.ts delete mode 100644 e2e/tsconfig.json delete mode 100644 karma.conf.js delete mode 100644 package.json delete mode 100644 server.js delete mode 100644 src/app/admin/adList/page-ad-list-admin/page-ad-list-admin.component.html delete mode 100644 src/app/admin/adList/page-ad-list-admin/page-ad-list-admin.component.scss delete mode 100644 src/app/admin/adList/page-ad-list-admin/page-ad-list-admin.component.spec.ts delete mode 100644 src/app/admin/adList/page-ad-list-admin/page-ad-list-admin.component.ts delete mode 100644 src/app/admin/adList/popup-delete-ad-admin/popup-delete-ad-admin.component.html delete mode 100644 src/app/admin/adList/popup-delete-ad-admin/popup-delete-ad-admin.component.scss delete mode 100644 src/app/admin/adList/popup-delete-ad-admin/popup-delete-ad-admin.component.spec.ts delete mode 100644 src/app/admin/adList/popup-delete-ad-admin/popup-delete-ad-admin.component.ts delete mode 100644 src/app/admin/adList/popup-visualize-images-admin/popup-visualize-images-admin.component.html delete mode 100644 src/app/admin/adList/popup-visualize-images-admin/popup-visualize-images-admin.component.scss delete mode 100644 src/app/admin/adList/popup-visualize-images-admin/popup-visualize-images-admin.component.spec.ts delete mode 100644 src/app/admin/adList/popup-visualize-images-admin/popup-visualize-images-admin.component.ts delete mode 100644 src/app/admin/myProfil/page-profil-admin/page-profil-admin.component.html delete mode 100644 src/app/admin/myProfil/page-profil-admin/page-profil-admin.component.scss delete mode 100644 src/app/admin/myProfil/page-profil-admin/page-profil-admin.component.spec.ts delete mode 100644 src/app/admin/myProfil/page-profil-admin/page-profil-admin.component.ts delete mode 100644 src/app/admin/myProfil/popup-update-admin/popup-update-admin.component.html delete mode 100644 src/app/admin/myProfil/popup-update-admin/popup-update-admin.component.scss delete mode 100644 src/app/admin/myProfil/popup-update-admin/popup-update-admin.component.spec.ts delete mode 100644 src/app/admin/myProfil/popup-update-admin/popup-update-admin.component.ts delete mode 100644 src/app/admin/userList/input-interests-admin/input-interests-admin.component.html delete mode 100644 src/app/admin/userList/input-interests-admin/input-interests-admin.component.scss delete mode 100644 src/app/admin/userList/input-interests-admin/input-interests-admin.component.spec.ts delete mode 100644 src/app/admin/userList/input-interests-admin/input-interests-admin.component.ts delete mode 100644 src/app/admin/userList/page-user-list/page-user-list.component.html delete mode 100644 src/app/admin/userList/page-user-list/page-user-list.component.scss delete mode 100644 src/app/admin/userList/page-user-list/page-user-list.component.spec.ts delete mode 100644 src/app/admin/userList/page-user-list/page-user-list.component.ts delete mode 100644 src/app/admin/userList/popup-create-user/popup-create-user.component.html delete mode 100644 src/app/admin/userList/popup-create-user/popup-create-user.component.scss delete mode 100644 src/app/admin/userList/popup-create-user/popup-create-user.component.spec.ts delete mode 100644 src/app/admin/userList/popup-create-user/popup-create-user.component.ts delete mode 100644 src/app/admin/userList/popup-delete-user/popup-delete-user.component.html delete mode 100644 src/app/admin/userList/popup-delete-user/popup-delete-user.component.scss delete mode 100644 src/app/admin/userList/popup-delete-user/popup-delete-user.component.spec.ts delete mode 100644 src/app/admin/userList/popup-delete-user/popup-delete-user.component.ts delete mode 100644 src/app/admin/utils/navbar-admin/navbar-admin.component.html delete mode 100644 src/app/admin/utils/navbar-admin/navbar-admin.component.scss delete mode 100644 src/app/admin/utils/navbar-admin/navbar-admin.component.spec.ts delete mode 100644 src/app/admin/utils/navbar-admin/navbar-admin.component.ts delete mode 100644 src/app/advertiser/adList/drag-and-drop/drag-and-drop.component.html delete mode 100644 src/app/advertiser/adList/drag-and-drop/drag-and-drop.component.scss delete mode 100644 src/app/advertiser/adList/drag-and-drop/drag-and-drop.component.spec.ts delete mode 100644 src/app/advertiser/adList/drag-and-drop/drag-and-drop.component.ts delete mode 100644 src/app/advertiser/adList/input-interests-ad/input-interests-ad.component.html delete mode 100644 src/app/advertiser/adList/input-interests-ad/input-interests-ad.component.scss delete mode 100644 src/app/advertiser/adList/input-interests-ad/input-interests-ad.component.spec.ts delete mode 100644 src/app/advertiser/adList/input-interests-ad/input-interests-ad.component.ts delete mode 100644 src/app/advertiser/adList/page-ad-list-advertiser/page-ad-list-advertiser.component.html delete mode 100644 src/app/advertiser/adList/page-ad-list-advertiser/page-ad-list-advertiser.component.scss delete mode 100644 src/app/advertiser/adList/page-ad-list-advertiser/page-ad-list-advertiser.component.spec.ts delete mode 100644 src/app/advertiser/adList/page-ad-list-advertiser/page-ad-list-advertiser.component.ts delete mode 100644 src/app/advertiser/adList/popup-add-or-update-ad/popup-add-or-update-ad.component.html delete mode 100644 src/app/advertiser/adList/popup-add-or-update-ad/popup-add-or-update-ad.component.scss delete mode 100644 src/app/advertiser/adList/popup-add-or-update-ad/popup-add-or-update-ad.component.spec.ts delete mode 100644 src/app/advertiser/adList/popup-add-or-update-ad/popup-add-or-update-ad.component.ts delete mode 100644 src/app/advertiser/adList/popup-delete-ad-advertiser/popup-delete-ad-advertiser.component.html delete mode 100644 src/app/advertiser/adList/popup-delete-ad-advertiser/popup-delete-ad-advertiser.component.scss delete mode 100644 src/app/advertiser/adList/popup-delete-ad-advertiser/popup-delete-ad-advertiser.component.spec.ts delete mode 100644 src/app/advertiser/adList/popup-delete-ad-advertiser/popup-delete-ad-advertiser.component.ts delete mode 100644 src/app/advertiser/adList/popup-visualize-ad-advertiser/popup-visualize-ad-advertiser.component.html delete mode 100644 src/app/advertiser/adList/popup-visualize-ad-advertiser/popup-visualize-ad-advertiser.component.scss delete mode 100644 src/app/advertiser/adList/popup-visualize-ad-advertiser/popup-visualize-ad-advertiser.component.spec.ts delete mode 100644 src/app/advertiser/adList/popup-visualize-ad-advertiser/popup-visualize-ad-advertiser.component.ts delete mode 100644 src/app/advertiser/adList/popup-visualize-images-advertiser/popup-visualize-images-advertiser.component.html delete mode 100644 src/app/advertiser/adList/popup-visualize-images-advertiser/popup-visualize-images-advertiser.component.scss delete mode 100644 src/app/advertiser/adList/popup-visualize-images-advertiser/popup-visualize-images-advertiser.component.spec.ts delete mode 100644 src/app/advertiser/adList/popup-visualize-images-advertiser/popup-visualize-images-advertiser.component.ts delete mode 100644 src/app/advertiser/myProfil/page-profil-advertiser/page-profil-advertiser.component.html delete mode 100644 src/app/advertiser/myProfil/page-profil-advertiser/page-profil-advertiser.component.scss delete mode 100644 src/app/advertiser/myProfil/page-profil-advertiser/page-profil-advertiser.component.spec.ts delete mode 100644 src/app/advertiser/myProfil/page-profil-advertiser/page-profil-advertiser.component.ts delete mode 100644 src/app/advertiser/myProfil/popup-update-advertiser/popup-update-advertiser.component.html delete mode 100644 src/app/advertiser/myProfil/popup-update-advertiser/popup-update-advertiser.component.scss delete mode 100644 src/app/advertiser/myProfil/popup-update-advertiser/popup-update-advertiser.component.spec.ts delete mode 100644 src/app/advertiser/myProfil/popup-update-advertiser/popup-update-advertiser.component.ts delete mode 100644 src/app/advertiser/pages-popularity/pages-popularity.component.html delete mode 100644 src/app/advertiser/pages-popularity/pages-popularity.component.scss delete mode 100644 src/app/advertiser/pages-popularity/pages-popularity.component.spec.ts delete mode 100644 src/app/advertiser/pages-popularity/pages-popularity.component.ts delete mode 100644 src/app/advertiser/utils/dragAndDrop/drag-and-drop.directive.spec.ts delete mode 100644 src/app/advertiser/utils/dragAndDrop/drag-and-drop.directive.ts delete mode 100644 src/app/advertiser/utils/navbar-advertiser/navbar-advertiser.component.html delete mode 100644 src/app/advertiser/utils/navbar-advertiser/navbar-advertiser.component.scss delete mode 100644 src/app/advertiser/utils/navbar-advertiser/navbar-advertiser.component.spec.ts delete mode 100644 src/app/advertiser/utils/navbar-advertiser/navbar-advertiser.component.ts delete mode 100644 src/app/app-routing.module.ts delete mode 100644 src/app/app.component.html delete mode 100644 src/app/app.component.scss delete mode 100644 src/app/app.component.spec.ts delete mode 100644 src/app/app.component.ts delete mode 100644 src/app/app.module.ts delete mode 100644 src/app/beforeConnexion/login/page-login/page-login.component.html delete mode 100644 src/app/beforeConnexion/login/page-login/page-login.component.scss delete mode 100644 src/app/beforeConnexion/login/page-login/page-login.component.spec.ts delete mode 100644 src/app/beforeConnexion/login/page-login/page-login.component.ts delete mode 100644 src/app/beforeConnexion/login/popup-forgotten-password/popup-forgotten-password.component.html delete mode 100644 src/app/beforeConnexion/login/popup-forgotten-password/popup-forgotten-password.component.scss delete mode 100644 src/app/beforeConnexion/login/popup-forgotten-password/popup-forgotten-password.component.spec.ts delete mode 100644 src/app/beforeConnexion/login/popup-forgotten-password/popup-forgotten-password.component.ts delete mode 100644 src/app/beforeConnexion/register/input-interests-register/input-interests-register.component.html delete mode 100644 src/app/beforeConnexion/register/input-interests-register/input-interests-register.component.scss delete mode 100644 src/app/beforeConnexion/register/input-interests-register/input-interests-register.component.spec.ts delete mode 100644 src/app/beforeConnexion/register/input-interests-register/input-interests-register.component.ts delete mode 100644 src/app/beforeConnexion/register/page-register/page-register.component.html delete mode 100644 src/app/beforeConnexion/register/page-register/page-register.component.scss delete mode 100644 src/app/beforeConnexion/register/page-register/page-register.component.spec.ts delete mode 100644 src/app/beforeConnexion/register/page-register/page-register.component.ts delete mode 100644 src/app/beforeConnexion/register/popup-confirmation/popup-confirmation.component.html delete mode 100644 src/app/beforeConnexion/register/popup-confirmation/popup-confirmation.component.scss delete mode 100644 src/app/beforeConnexion/register/popup-confirmation/popup-confirmation.component.spec.ts delete mode 100644 src/app/beforeConnexion/register/popup-confirmation/popup-confirmation.component.ts delete mode 100644 src/app/beforeConnexion/utils/navbar-before-connexion/navbar-before-connexion.component.html delete mode 100644 src/app/beforeConnexion/utils/navbar-before-connexion/navbar-before-connexion.component.scss delete mode 100644 src/app/beforeConnexion/utils/navbar-before-connexion/navbar-before-connexion.component.spec.ts delete mode 100644 src/app/beforeConnexion/utils/navbar-before-connexion/navbar-before-connexion.component.ts delete mode 100644 src/app/user/history/page-history-user/page-history-user.component.html delete mode 100644 src/app/user/history/page-history-user/page-history-user.component.scss delete mode 100644 src/app/user/history/page-history-user/page-history-user.component.spec.ts delete mode 100644 src/app/user/history/page-history-user/page-history-user.component.ts delete mode 100644 src/app/user/myPlaylists/page-my-playlists/page-my-playlists.component.html delete mode 100644 src/app/user/myPlaylists/page-my-playlists/page-my-playlists.component.scss delete mode 100644 src/app/user/myPlaylists/page-my-playlists/page-my-playlists.component.spec.ts delete mode 100644 src/app/user/myPlaylists/page-my-playlists/page-my-playlists.component.ts delete mode 100644 src/app/user/myPlaylists/playlist-list/playlist-list.component.html delete mode 100644 src/app/user/myPlaylists/playlist-list/playlist-list.component.scss delete mode 100644 src/app/user/myPlaylists/playlist-list/playlist-list.component.spec.ts delete mode 100644 src/app/user/myPlaylists/playlist-list/playlist-list.component.ts delete mode 100644 src/app/user/myPlaylists/popup-create-or-update-playlist/popup-create-or-update-playlist.component.html delete mode 100644 src/app/user/myPlaylists/popup-create-or-update-playlist/popup-create-or-update-playlist.component.scss delete mode 100644 src/app/user/myPlaylists/popup-create-or-update-playlist/popup-create-or-update-playlist.component.spec.ts delete mode 100644 src/app/user/myPlaylists/popup-create-or-update-playlist/popup-create-or-update-playlist.component.ts delete mode 100644 src/app/user/myPlaylists/popup-delete-playlist/popup-delete-playlist.component.html delete mode 100644 src/app/user/myPlaylists/popup-delete-playlist/popup-delete-playlist.component.scss delete mode 100644 src/app/user/myPlaylists/popup-delete-playlist/popup-delete-playlist.component.spec.ts delete mode 100644 src/app/user/myPlaylists/popup-delete-playlist/popup-delete-playlist.component.ts delete mode 100644 src/app/user/myPlaylists/video-list/video-list.component.html delete mode 100644 src/app/user/myPlaylists/video-list/video-list.component.scss delete mode 100644 src/app/user/myPlaylists/video-list/video-list.component.spec.ts delete mode 100644 src/app/user/myPlaylists/video-list/video-list.component.ts delete mode 100644 src/app/user/myProfil/input-interests-profil/input-interests-profil.component.html delete mode 100644 src/app/user/myProfil/input-interests-profil/input-interests-profil.component.scss delete mode 100644 src/app/user/myProfil/input-interests-profil/input-interests-profil.component.spec.ts delete mode 100644 src/app/user/myProfil/input-interests-profil/input-interests-profil.component.ts delete mode 100644 src/app/user/myProfil/page-profil-user/page-profil-user.component.html delete mode 100644 src/app/user/myProfil/page-profil-user/page-profil-user.component.scss delete mode 100644 src/app/user/myProfil/page-profil-user/page-profil-user.component.spec.ts delete mode 100644 src/app/user/myProfil/page-profil-user/page-profil-user.component.ts delete mode 100644 src/app/user/myProfil/popup-update-user/popup-update-user.component.html delete mode 100644 src/app/user/myProfil/popup-update-user/popup-update-user.component.scss delete mode 100644 src/app/user/myProfil/popup-update-user/popup-update-user.component.spec.ts delete mode 100644 src/app/user/myProfil/popup-update-user/popup-update-user.component.ts delete mode 100644 src/app/user/search/page-search/page-search.component.html delete mode 100644 src/app/user/search/page-search/page-search.component.scss delete mode 100644 src/app/user/search/page-search/page-search.component.spec.ts delete mode 100644 src/app/user/search/page-search/page-search.component.ts delete mode 100644 src/app/user/search/video-grid/video-grid.component.html delete mode 100644 src/app/user/search/video-grid/video-grid.component.scss delete mode 100644 src/app/user/search/video-grid/video-grid.component.spec.ts delete mode 100644 src/app/user/search/video-grid/video-grid.component.ts delete mode 100644 src/app/user/utils/components/advert/advert.component.html delete mode 100644 src/app/user/utils/components/advert/advert.component.scss delete mode 100644 src/app/user/utils/components/advert/advert.component.spec.ts delete mode 100644 src/app/user/utils/components/advert/advert.component.ts delete mode 100644 src/app/user/utils/components/navbar-user/navbar-user.component.html delete mode 100644 src/app/user/utils/components/navbar-user/navbar-user.component.scss delete mode 100644 src/app/user/utils/components/navbar-user/navbar-user.component.spec.ts delete mode 100644 src/app/user/utils/components/navbar-user/navbar-user.component.ts delete mode 100644 src/app/user/utils/components/popup-add-video-to-playlists/popup-add-video-to-playlists.component.html delete mode 100644 src/app/user/utils/components/popup-add-video-to-playlists/popup-add-video-to-playlists.component.scss delete mode 100644 src/app/user/utils/components/popup-add-video-to-playlists/popup-add-video-to-playlists.component.spec.ts delete mode 100644 src/app/user/utils/components/popup-add-video-to-playlists/popup-add-video-to-playlists.component.ts delete mode 100644 src/app/user/utils/services/addVideoToPlaylists/add-video-to-playlists.service.spec.ts delete mode 100644 src/app/user/utils/services/addVideoToPlaylists/add-video-to-playlists.service.ts delete mode 100644 src/app/user/watching/page-watching-video/page-watching-video.component.html delete mode 100644 src/app/user/watching/page-watching-video/page-watching-video.component.scss delete mode 100644 src/app/user/watching/page-watching-video/page-watching-video.component.spec.ts delete mode 100644 src/app/user/watching/page-watching-video/page-watching-video.component.ts delete mode 100644 src/app/utils/interfaces/advert.ts delete mode 100644 src/app/utils/interfaces/playlist.ts delete mode 100644 src/app/utils/interfaces/user.ts delete mode 100644 src/app/utils/interfaces/video.ts delete mode 100644 src/app/utils/services/fictitiousDatas/fictitiousAdverts/fictitious-adverts.service.spec.ts delete mode 100644 src/app/utils/services/fictitiousDatas/fictitiousAdverts/fictitious-adverts.service.ts delete mode 100644 src/app/utils/services/fictitiousDatas/fictitiousUsers/fictitious-users.service.spec.ts delete mode 100644 src/app/utils/services/fictitiousDatas/fictitiousUsers/fictitious-users.service.ts delete mode 100644 src/app/utils/services/fictitiousDatas/fictitiousUtils/fictitious-utils.service.spec.ts delete mode 100644 src/app/utils/services/fictitiousDatas/fictitiousUtils/fictitious-utils.service.ts delete mode 100644 src/app/utils/services/fictitiousDatas/fictitiousVideos/fictitious-videos.service.spec.ts delete mode 100644 src/app/utils/services/fictitiousDatas/fictitiousVideos/fictitious-videos.service.ts delete mode 100644 src/app/utils/services/message/message.service.spec.ts delete mode 100644 src/app/utils/services/message/message.service.ts delete mode 100644 src/app/utils/services/profil/profil.service.spec.ts delete mode 100644 src/app/utils/services/profil/profil.service.ts delete mode 100644 src/app/utils/services/theme/theme.service.spec.ts delete mode 100644 src/app/utils/services/theme/theme.service.ts delete mode 100644 src/assets/.gitkeep delete mode 100644 src/assets/darkBackground.webp delete mode 100644 src/assets/lightBackground.jpg delete mode 100644 src/assets/logo.png delete mode 100644 src/assets/logo_plateforms/dailymotion.png delete mode 100644 src/assets/logo_plateforms/youtube.png delete mode 100644 src/assets/play.png delete mode 100644 src/assets/profil.png delete mode 100644 src/assets/pub/nutella_v_1.jpeg delete mode 100644 src/assets/pub/nutella_v_2.png delete mode 100644 src/assets/pub/nutella_v_3.jpg delete mode 100644 src/assets/pub/rolex_v_1.jpg delete mode 100644 src/assets/pub/rolex_v_2.png delete mode 100644 src/assets/uploadFile.png delete mode 100644 src/environments/environment.prod.ts delete mode 100644 src/environments/environment.ts delete mode 100644 src/favicon.ico delete mode 100644 src/index.html delete mode 100644 src/main.ts delete mode 100644 src/polyfills.ts delete mode 100644 src/proxy.conf.json delete mode 100644 src/styles.scss delete mode 100644 src/test.ts delete mode 100644 tsconfig.app.json delete mode 100644 tsconfig.json delete mode 100644 tsconfig.spec.json delete mode 100644 tslint.json diff --git a/.browserslistrc b/.browserslistrc deleted file mode 100644 index 427441d..0000000 --- a/.browserslistrc +++ /dev/null @@ -1,17 +0,0 @@ -# This file is used by the build system to adjust CSS and JS output to support the specified browsers below. -# For additional information regarding the format and rule options, please see: -# https://github.com/browserslist/browserslist#queries - -# For the full list of supported browsers by the Angular framework, please see: -# https://angular.io/guide/browser-support - -# You can see what browsers were selected by your queries by running: -# npx browserslist - -last 1 Chrome version -last 1 Firefox version -last 2 Edge major versions -last 2 Safari major versions -last 2 iOS major versions -Firefox ESR -not IE 11 # Angular supports IE 11 only as an opt-in. To opt-in, remove the 'not' prefix on this line. diff --git a/.editorconfig b/.editorconfig deleted file mode 100644 index 59d9a3a..0000000 --- a/.editorconfig +++ /dev/null @@ -1,16 +0,0 @@ -# Editor configuration, see https://editorconfig.org -root = true - -[*] -charset = utf-8 -indent_style = space -indent_size = 2 -insert_final_newline = true -trim_trailing_whitespace = true - -[*.ts] -quote_type = single - -[*.md] -max_line_length = off -trim_trailing_whitespace = false diff --git a/.gitignore b/.gitignore deleted file mode 100644 index 323a898..0000000 --- a/.gitignore +++ /dev/null @@ -1,52 +0,0 @@ -# See http://help.github.com/ignore-files/ for more about ignoring files. - -# compiled output -/dist -/tmp -/out-tsc -# Only exists if Bazel was run -/bazel-out - -# dependencies -/node_modules - -# profiling files -chrome-profiler-events*.json -speed-measure-plugin*.json - -# IDEs and editors -/.idea -.project -.classpath -.c9/ -*.launch -.settings/ -*.sublime-workspace - -# IDE - VSCode -.vscode/* -!.vscode/settings.json -!.vscode/tasks.json -!.vscode/launch.json -!.vscode/extensions.json -.history/* - -# misc -/.sass-cache -/connect.lock -/coverage -/libpeerconnection.log -npm-debug.log -yarn-error.log -testem.log -/typings -*.env - -# System Files -.DS_Store -Thumbs.db - -/backend/database/ -/backend/node_modules/ - -package-lock.json diff --git a/Dockerfile b/Dockerfile deleted file mode 100644 index 55a30a2..0000000 --- a/Dockerfile +++ /dev/null @@ -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 . . diff --git a/Procfile b/Procfile deleted file mode 100644 index 063b78f..0000000 --- a/Procfile +++ /dev/null @@ -1 +0,0 @@ -web: npm start diff --git a/angular.json b/angular.json deleted file mode 100644 index 4f6d04d..0000000 --- a/angular.json +++ /dev/null @@ -1,134 +0,0 @@ -{ - "$schema": "./node_modules/@angular/cli/lib/config/schema.json", - "version": 1, - "newProjectRoot": "projects", - "projects": { - "frontend": { - "projectType": "application", - "schematics": { - "@schematics/angular:component": { - "style": "scss" - } - }, - "root": "", - "sourceRoot": "src", - "prefix": "app", - "architect": { - "build": { - "builder": "@angular-devkit/build-angular:browser", - "options": { - "outputPath": "dist/frontend", - "index": "src/index.html", - "main": "src/main.ts", - "polyfills": "src/polyfills.ts", - "tsConfig": "tsconfig.app.json", - "aot": true, - "assets": [ - "src/favicon.ico", - "src/assets" - ], - "styles": [ - "./node_modules/@angular/material/prebuilt-themes/indigo-pink.css", - "src/styles.scss", - "node_modules/bootstrap/scss/bootstrap.scss" - ], - "scripts": [ - "node_modules/jquery/dist/jquery.js", - "node_modules/bootstrap/dist/js/bootstrap.js" - ] - }, - "configurations": { - "production": { - "fileReplacements": [ - { - "replace": "src/environments/environment.ts", - "with": "src/environments/environment.prod.ts" - } - ], - "optimization": true, - "outputHashing": "all", - "sourceMap": false, - "namedChunks": false, - "extractLicenses": true, - "vendorChunk": false, - "buildOptimizer": true, - "budgets": [ - { - "type": "initial", - "maximumWarning": "2mb", - "maximumError": "5mb" - }, - { - "type": "anyComponentStyle", - "maximumWarning": "6kb", - "maximumError": "10kb" - } - ] - } - } - }, - "serve": { - "builder": "@angular-devkit/build-angular:dev-server", - "options": { - "browserTarget": "frontend:build" - }, - "configurations": { - "production": { - "browserTarget": "frontend:build:production" - } - } - }, - "extract-i18n": { - "builder": "@angular-devkit/build-angular:extract-i18n", - "options": { - "browserTarget": "frontend:build" - } - }, - "test": { - "builder": "@angular-devkit/build-angular:karma", - "options": { - "main": "src/test.ts", - "polyfills": "src/polyfills.ts", - "tsConfig": "tsconfig.spec.json", - "karmaConfig": "karma.conf.js", - "assets": [ - "src/favicon.ico", - "src/assets" - ], - "styles": [ - "./node_modules/@angular/material/prebuilt-themes/indigo-pink.css", - "src/styles.scss" - ], - "scripts": [] - } - }, - "lint": { - "builder": "@angular-devkit/build-angular:tslint", - "options": { - "tsConfig": [ - "tsconfig.app.json", - "tsconfig.spec.json", - "e2e/tsconfig.json" - ], - "exclude": [ - "**/node_modules/**" - ] - } - }, - "e2e": { - "builder": "@angular-devkit/build-angular:protractor", - "options": { - "protractorConfig": "e2e/protractor.conf.js", - "devServerTarget": "frontend:serve" - }, - "configurations": { - "production": { - "devServerTarget": "frontend:serve:production" - } - } - } - } - } - }, - "defaultProject": "frontend" -} diff --git a/app-backend/config/functions.config.js b/app-backend/config/functions.config.js deleted file mode 100644 index b229914..0000000 --- a/app-backend/config/functions.config.js +++ /dev/null @@ -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; diff --git a/app-backend/config/host.config.js b/app-backend/config/host.config.js deleted file mode 100644 index 6a62f28..0000000 --- a/app-backend/config/host.config.js +++ /dev/null @@ -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 - } -}; diff --git a/app-backend/config/mongodb.config.js b/app-backend/config/mongodb.config.js deleted file mode 100644 index 2180acc..0000000 --- a/app-backend/config/mongodb.config.js +++ /dev/null @@ -1,4 +0,0 @@ -module.exports = { - prodUrl: process.env.DATABASE, - devUrl: "mongodb://127.0.0.1:27017/polynotfound" -}; diff --git a/app-backend/config/response.config.js b/app-backend/config/response.config.js deleted file mode 100644 index dfca2db..0000000 --- a/app-backend/config/response.config.js +++ /dev/null @@ -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 }; diff --git a/app-backend/config/sessionJWT.config.js b/app-backend/config/sessionJWT.config.js deleted file mode 100644 index 7dbc86c..0000000 --- a/app-backend/config/sessionJWT.config.js +++ /dev/null @@ -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; diff --git a/app-backend/controllers/ad.controller.js b/app-backend/controllers/ad.controller.js deleted file mode 100644 index d92be1f..0000000 --- a/app-backend/controllers/ad.controller.js +++ /dev/null @@ -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."); - }); - } -}; diff --git a/app-backend/controllers/misc.controller.js b/app-backend/controllers/misc.controller.js deleted file mode 100644 index 326e138..0000000 --- a/app-backend/controllers/misc.controller.js +++ /dev/null @@ -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) -}; diff --git a/app-backend/controllers/playlist.controller.js b/app-backend/controllers/playlist.controller.js deleted file mode 100644 index 51442a1..0000000 --- a/app-backend/controllers/playlist.controller.js +++ /dev/null @@ -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."); - }); - } -}; diff --git a/app-backend/controllers/user.controller.js b/app-backend/controllers/user.controller.js deleted file mode 100644 index 9af3856..0000000 --- a/app-backend/controllers/user.controller.js +++ /dev/null @@ -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()]}}, {timestamps: false}) - .then(dataUpdate => { - if(dataUpdate && dataUpdate.modifiedCount > 0){ - return sendMessage(res, 11, data, token); - } else { - return sendError(res,500,101,`Some error occurred while updating ${quantity} ad(s) for the User.`, token); - } - }) - .catch(err => { - return sendError(res,500,101,err.message || `Some error occurred while updating ${quantity} ad(s) for the User.`, token); - }); - } else { - Ad.aggregate([{$match: {isVisible: true, isActive: true}}, {$sample: {size: parseInt(quantity, 10)}}]) - .then(data => { - let ids = [] - for(const i in data){ids.push(data[i]._id);} - Ad.updateMany({_id: {$in: ids}}, {$push: {views: [new Date()]}}, {timestamps: false}) - .then(dataUpdate => { - if(dataUpdate && dataUpdate.modifiedCount > 0){ - return sendMessage(res, 11, data, token); - } else { - return sendError(res,500,101,`Some error occurred while updating ${quantity} ad(s) for the User.`, token); - } - }) - .catch(err => { - return sendError(res,500,101,err.message || `Some error occurred while updating ${quantity} ad(s) for the User.`, token); - }); - }) - .catch(err => { - return sendError(res,500,101,err.message || `Some error occurred while getting ${quantity} ad(s) for the User.`, token); - }); - } - }) - .catch(err => { - return sendError(res,500,101,err.message || `Some error occurred while getting ${quantity} ad(s) for the User.`, token); - }); - }) - .catch(err => { - return sendError(res,500,102,err.message || `Some error occurred while getting ${quantity} ad(s) for the User.`, token); - }); - }) - .catch(err => { - return sendError(res,500,100,err.message || `Some error occurred while getting ${quantity} ad(s) for the User.`, token); - }); - } else { - sendError(res, 500, -1, `No quantity given`, token); - } -}; - -// Get History -exports.history = (req, res) => { - const token = checkLogin(req, res); - if(token){ - const id = token.id; - - Video.aggregate([ - {$match: {userId: id, $expr: {$gt: [{$size: "$watchedDates"}, 0]}}}, - {$limit: 300}, - {$project: { - videoId: true, - source: true, - tags: true, - interest: true, - views: {$size: '$watchedDates'}, - watchedDate: {$arrayElemAt: ["$watchedDates", -1]}, - createdAt: true, - updatedAt: true - }}, - {$sort: {watchedDate: -1}}]) - .then(async data => { - let yt_results = []; - let dm_results = []; - let yt_videoIds = ""; - let dm_videoIds = ""; - - for(const i in data) { - if(data[i].source === youtube.name) { - yt_videoIds = yt_videoIds + data[i].videoId + ","; - } else if (data[i].source === dailymotion.name) { - dm_videoIds = dm_videoIds + data[i].videoId + ","; - } - } - if(yt_videoIds !== ""){ - const uri = youtube.baseAPIUrl + '/videos' + '?part=snippet&part=statistics&id=' + yt_videoIds.slice(0, -1) + '&key=' + youtube.YOUTUBE_API_KEY; - const dataVideos = await asyncRequest(uri, {}); - if (dataVideos.response.statusCode === 200 && dataVideos.body.items.length > 0) { - yt_results = dataVideos.body.items; - } - } - - if(dm_videoIds !== ""){ - const uri = dailymotion.baseAPIUrl + '/videos?ids='+dm_videoIds.slice(0, -1)+'&fields=thumbnail_480_url%2Ctitle%2Cid'; - const data = await asyncRequest(uri, {}); - const response = data.response; - const jsonBody = data.body; - if(response.statusCode === 200){ - dm_results = jsonBody.list; - } - } - for(const i in data) { - if(data[i].source === youtube.name) { - const obj = yt_results.filter(obj => obj.id === data[i].videoId); - data[i].imageUrl = obj[0].snippet.thumbnails.medium.url ? obj[0].snippet.thumbnails.medium.url : null; - data[i].title = obj[0].snippet.title ? obj[0].snippet.title : null; - } else if (data[i].source === dailymotion.name) { - const obj = dm_results.filter(obj => obj.id === data[i].videoId); - data[i].imageUrl = obj[0].thumbnail_480_url ? obj[0].thumbnail_480_url : null; - data[i].title = obj[0].title ? obj[0].title : null; - } - } - return sendMessage(res, 12, data, token) - }) - .catch(err => { - return sendError(res,500,100,err.message || "Some error occurred while getting the User history.", token); - }); - } -}; diff --git a/app-backend/controllers/video.controller.js b/app-backend/controllers/video.controller.js deleted file mode 100644 index f928918..0000000 --- a/app-backend/controllers/video.controller.js +++ /dev/null @@ -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."); - }); - } -}; diff --git a/app-backend/jwtRS256.key.pub b/app-backend/jwtRS256.key.pub deleted file mode 100644 index 6b52055..0000000 --- a/app-backend/jwtRS256.key.pub +++ /dev/null @@ -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----- diff --git a/app-backend/jwtRS256.sh b/app-backend/jwtRS256.sh deleted file mode 100755 index 64ecaff..0000000 --- a/app-backend/jwtRS256.sh +++ /dev/null @@ -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 diff --git a/app-backend/models/database/ads.model.js b/app-backend/models/database/ads.model.js deleted file mode 100644 index 2389c44..0000000 --- a/app-backend/models/database/ads.model.js +++ /dev/null @@ -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); -}; diff --git a/app-backend/models/database/playlists.model.js b/app-backend/models/database/playlists.model.js deleted file mode 100644 index ad065a5..0000000 --- a/app-backend/models/database/playlists.model.js +++ /dev/null @@ -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); -}; diff --git a/app-backend/models/database/users.model.js b/app-backend/models/database/users.model.js deleted file mode 100644 index 9467b3c..0000000 --- a/app-backend/models/database/users.model.js +++ /dev/null @@ -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); -}; diff --git a/app-backend/models/database/videos.model.js b/app-backend/models/database/videos.model.js deleted file mode 100644 index 4d322da..0000000 --- a/app-backend/models/database/videos.model.js +++ /dev/null @@ -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); -}; diff --git a/app-backend/models/mongodb.model.js b/app-backend/models/mongodb.model.js deleted file mode 100644 index 9ddb7cd..0000000 --- a/app-backend/models/mongodb.model.js +++ /dev/null @@ -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; diff --git a/app-backend/models/objects/image.model.js b/app-backend/models/objects/image.model.js deleted file mode 100644 index 72ec783..0000000 --- a/app-backend/models/objects/image.model.js +++ /dev/null @@ -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; diff --git a/app-backend/models/objects/role.model.js b/app-backend/models/objects/role.model.js deleted file mode 100644 index 2e1703c..0000000 --- a/app-backend/models/objects/role.model.js +++ /dev/null @@ -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 - } -}; diff --git a/app-backend/models/objects/video.categories.model.js b/app-backend/models/objects/video.categories.model.js deleted file mode 100644 index 6eaab33..0000000 --- a/app-backend/models/objects/video.categories.model.js +++ /dev/null @@ -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} - ] - } -]; diff --git a/app-backend/routes/ad.routes.js b/app-backend/routes/ad.routes.js deleted file mode 100644 index 738892b..0000000 --- a/app-backend/routes/ad.routes.js +++ /dev/null @@ -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); -}; diff --git a/app-backend/routes/misc.routes.js b/app-backend/routes/misc.routes.js deleted file mode 100644 index 7aa5be6..0000000 --- a/app-backend/routes/misc.routes.js +++ /dev/null @@ -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); -}; diff --git a/app-backend/routes/playlist.routes.js b/app-backend/routes/playlist.routes.js deleted file mode 100644 index 3b9beeb..0000000 --- a/app-backend/routes/playlist.routes.js +++ /dev/null @@ -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); -}; diff --git a/app-backend/routes/user.routes.js b/app-backend/routes/user.routes.js deleted file mode 100644 index 346cb04..0000000 --- a/app-backend/routes/user.routes.js +++ /dev/null @@ -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); -}; diff --git a/app-backend/routes/video.routes.js b/app-backend/routes/video.routes.js deleted file mode 100644 index a07de28..0000000 --- a/app-backend/routes/video.routes.js +++ /dev/null @@ -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); -}; diff --git a/docker-compose.yml b/docker-compose.yml deleted file mode 100644 index ee31835..0000000 --- a/docker-compose.yml +++ /dev/null @@ -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 diff --git a/e2e/protractor.conf.js b/e2e/protractor.conf.js deleted file mode 100644 index 361e7f0..0000000 --- a/e2e/protractor.conf.js +++ /dev/null @@ -1,37 +0,0 @@ -// @ts-check -// Protractor configuration file, see link for more information -// https://github.com/angular/protractor/blob/master/lib/config.ts - -const { SpecReporter, StacktraceOption } = require('jasmine-spec-reporter'); - -/** - * @type { import("protractor").Config } - */ -exports.config = { - allScriptsTimeout: 11000, - specs: [ - './src/**/*.e2e-spec.ts' - ], - capabilities: { - browserName: 'chrome' - }, - directConnect: true, - SELENIUM_PROMISE_MANAGER: false, - baseUrl: 'http://localhost:4200/', - framework: 'jasmine', - jasmineNodeOpts: { - showColors: true, - defaultTimeoutInterval: 30000, - print: function() {} - }, - onPrepare() { - require('ts-node').register({ - project: require('path').join(__dirname, './tsconfig.json') - }); - jasmine.getEnv().addReporter(new SpecReporter({ - spec: { - displayStacktrace: StacktraceOption.PRETTY - } - })); - } -}; \ No newline at end of file diff --git a/e2e/src/app.e2e-spec.ts b/e2e/src/app.e2e-spec.ts deleted file mode 100644 index b4a36ca..0000000 --- a/e2e/src/app.e2e-spec.ts +++ /dev/null @@ -1,23 +0,0 @@ -import { browser, logging } from 'protractor'; -import { AppPage } from './app.po'; - -describe('workspace-project App', () => { - let page: AppPage; - - beforeEach(() => { - page = new AppPage(); - }); - - it('should display welcome message', async () => { - await page.navigateTo(); - expect(await page.getTitleText()).toEqual('frontend app is running!'); - }); - - afterEach(async () => { - // Assert that there are no errors emitted from the browser - const logs = await browser.manage().logs().get(logging.Type.BROWSER); - expect(logs).not.toContain(jasmine.objectContaining({ - level: logging.Level.SEVERE, - } as logging.Entry)); - }); -}); diff --git a/e2e/src/app.po.ts b/e2e/src/app.po.ts deleted file mode 100644 index c9c85ab..0000000 --- a/e2e/src/app.po.ts +++ /dev/null @@ -1,11 +0,0 @@ -import { browser, by, element } from 'protractor'; - -export class AppPage { - async navigateTo(): Promise { - return browser.get(browser.baseUrl); - } - - async getTitleText(): Promise { - return element(by.css('app-root .content span')).getText(); - } -} diff --git a/e2e/tsconfig.json b/e2e/tsconfig.json deleted file mode 100644 index 0782539..0000000 --- a/e2e/tsconfig.json +++ /dev/null @@ -1,13 +0,0 @@ -/* To learn more about this file see: https://angular.io/config/tsconfig. */ -{ - "extends": "../tsconfig.json", - "compilerOptions": { - "outDir": "../out-tsc/e2e", - "module": "commonjs", - "target": "es2018", - "types": [ - "jasmine", - "node" - ] - } -} diff --git a/karma.conf.js b/karma.conf.js deleted file mode 100644 index 3635639..0000000 --- a/karma.conf.js +++ /dev/null @@ -1,44 +0,0 @@ -// Karma configuration file, see link for more information -// https://karma-runner.github.io/1.0/config/configuration-file.html - -module.exports = function (config) { - config.set({ - basePath: '', - frameworks: ['jasmine', '@angular-devkit/build-angular'], - plugins: [ - require('karma-jasmine'), - require('karma-chrome-launcher'), - require('karma-jasmine-html-reporter'), - require('karma-coverage'), - require('@angular-devkit/build-angular/plugins/karma') - ], - client: { - jasmine: { - // you can add configuration options for Jasmine here - // the possible options are listed at https://jasmine.github.io/api/edge/Configuration.html - // for example, you can disable the random execution with `random: false` - // or set a specific seed with `seed: 4321` - }, - clearContext: false // leave Jasmine Spec Runner output visible in browser - }, - jasmineHtmlReporter: { - suppressAll: true // removes the duplicated traces - }, - coverageReporter: { - dir: require('path').join(__dirname, './coverage/frontend'), - subdir: '.', - reporters: [ - { type: 'html' }, - { type: 'text-summary' } - ] - }, - reporters: ['progress', 'kjhtml'], - port: 9876, - colors: true, - logLevel: config.LOG_INFO, - autoWatch: true, - browsers: ['Chrome'], - singleRun: false, - restartOnFileChange: true - }); -}; diff --git a/package.json b/package.json deleted file mode 100644 index 1aacb0a..0000000 --- a/package.json +++ /dev/null @@ -1,67 +0,0 @@ -{ - "name": "frontend", - "version": "1.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" - }, - "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", - "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" - }, - "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", - "@types/node": "^12.11.1", - "codelyzer": "^6.0.0", - "jasmine-core": "~3.6.0", - "jasmine-spec-reporter": "~5.0.0", - "karma": "~6.3.5", - "karma-chrome-launcher": "~3.1.0", - "karma-coverage": "~2.0.3", - "karma-jasmine": "~4.0.0", - "karma-jasmine-html-reporter": "^1.5.0", - "protractor": "~7.0.0", - "ts-node": "~8.3.0", - "tslint": "~6.1.0", - "typescript": "~4.3.5" - } -} diff --git a/server.js b/server.js deleted file mode 100644 index 91f4105..0000000 --- a/server.js +++ /dev/null @@ -1,84 +0,0 @@ -const path = require('path'); -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.get('/*', function(req,res) { - res.sendFile(path.join(__dirname+ '/dist/frontend/index.html')); -}); - -app.listen(port, '0.0.0.0',() => { - console.log (`listening on port ${port}`); -}); diff --git a/src/app/admin/adList/page-ad-list-admin/page-ad-list-admin.component.html b/src/app/admin/adList/page-ad-list-admin/page-ad-list-admin.component.html deleted file mode 100644 index 76bc154..0000000 --- a/src/app/admin/adList/page-ad-list-admin/page-ad-list-admin.component.html +++ /dev/null @@ -1,167 +0,0 @@ -
-
- - -

- - - - -
- - -
- Filtre -
- - - - -
- -
- - -
- - -
- visible
- non visible -
- - -
- - Sujets - - - {{formControlInterests.value ? formControlInterests.value[0] : ''}} - - (+{{formControlInterests.value.length - 1}} {{formControlInterests.value?.length === 2 ? 'autre' : 'autres'}}) - - - {{topping}} - - - -
- - -
- Période de création:   - - Date de début - - -   -   - - Date de fin - - -
- -
-
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Titre - {{advert.title}} - Entreprise - {{advert.company}} - Sujets - - {{objectInterest.interest}}, - {{objectInterest.interest}} - - Date de création - {{ advert.createdAt | date:'dd/LL/YYYY à HH:mm:ss' }} - Dernière modification - {{ advert.updatedAt | date:'dd/LL/YYYY à HH:mm:ss' }} - Vues - {{advert.countViews}} - Visible - check - - Actions - - -
Aucune vidéo ne correspond au filtre: "{{input.value}}"
-
- -
-

- -
-
diff --git a/src/app/admin/adList/page-ad-list-admin/page-ad-list-admin.component.scss b/src/app/admin/adList/page-ad-list-admin/page-ad-list-admin.component.scss deleted file mode 100644 index 954f3d0..0000000 --- a/src/app/admin/adList/page-ad-list-admin/page-ad-list-admin.component.scss +++ /dev/null @@ -1,74 +0,0 @@ -.myContainer { - max-width: 100vw; - height: 100vh; - overflow-x: hidden; - font-size: small; -} - -// ---------------------------------------------------------- - - -.filtersContainer { - width: 80%; - background-color: white; - padding: 10px 10px 10px 10px; - margin: 20px 3% 20px 3% -} - -.myRow { - margin-left: 1%; -} - -.textFilter { - width: 50%; - font-size: medium; - border-radius: 5px; -} - -// ---------------------------------------------------------- - - -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; -} - - -// ------------------------------------------------------------------------- - - -// 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 { - border: solid 1px black !important; - background-color: white !important; -} - -::ng-deep .mat-pseudo-checkbox-checked { - background-color: black !important; -} diff --git a/src/app/admin/adList/page-ad-list-admin/page-ad-list-admin.component.spec.ts b/src/app/admin/adList/page-ad-list-admin/page-ad-list-admin.component.spec.ts deleted file mode 100644 index 5b77dff..0000000 --- a/src/app/admin/adList/page-ad-list-admin/page-ad-list-admin.component.spec.ts +++ /dev/null @@ -1,25 +0,0 @@ -import { ComponentFixture, TestBed } from '@angular/core/testing'; - -import { PageAdListAdminComponent } from './page-ad-list-admin.component'; - -describe('PageAdListAdminComponent', () => { - let component: PageAdListAdminComponent; - let fixture: ComponentFixture; - - beforeEach(async () => { - await TestBed.configureTestingModule({ - declarations: [ PageAdListAdminComponent ] - }) - .compileComponents(); - }); - - beforeEach(() => { - fixture = TestBed.createComponent(PageAdListAdminComponent); - component = fixture.componentInstance; - fixture.detectChanges(); - }); - - it('should create', () => { - expect(component).toBeTruthy(); - }); -}); diff --git a/src/app/admin/adList/page-ad-list-admin/page-ad-list-admin.component.ts b/src/app/admin/adList/page-ad-list-admin/page-ad-list-admin.component.ts deleted file mode 100644 index 3b89012..0000000 --- a/src/app/admin/adList/page-ad-list-admin/page-ad-list-admin.component.ts +++ /dev/null @@ -1,262 +0,0 @@ -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 {HttpParams} from "@angular/common/http"; - - - -export interface AdvertWithCountViewsAndCompany { - id: string, - userId: string, - company: string, - title: string, - url: string, - images: { - url: string, - description: string, - }[], - interests: string[], - comment: string, - views: Date[], - countViews: number, - isVisible: boolean, - isActive: boolean, - createdAt: Date, - updatedAt: Date, -} - - - -@Component({ - 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' ]; - dataSource ; - @ViewChild(MatSort) sort: MatSort; - @ViewChild(MatPaginator) paginator: MatPaginator; - - visible: boolean = true; - noVisible: boolean = true; - startDate: Date = null; - endDate: Date = null; - formControlInterests = new FormControl(); - allInterests: string[] = []; - - - constructor( public themeService: ThemeService, - public dialog: MatDialog, - private snackBar: MatSnackBar, - private messageService: MessageService) { } - - - ngAfterViewInit(): void - { - // Ask for ads and then for advertiser - let params = new HttpParams(); - params = params.append("isActive", true); - this.messageService - .get("ad/findAll", params) - .subscribe(ret => this.afterReceivingAds(ret), err => this.afterReceivingAds(err) ); - - // Ask for interest - this.messageService - .get("misc/getInterests") - .subscribe(ret => this.afterReceivingInterests(ret), err => this.afterReceivingInterests(err) ); - } - - - afterReceivingAds(retour: any): void - { - if(retour.status !== "success") { - console.log(retour); - } - else { - const tabAdvert = retour.data; - this.messageService - .get("user/findAll") - .subscribe(ret => this.afterReceivingAdvertiser(ret, tabAdvert), err => this.afterReceivingAdvertiser(err, tabAdvert) ); - } - } - - - afterReceivingAdvertiser(retour: any, tabAdvert): void - { - if(retour.status !== "success") { - console.log(retour); - } - 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(); - this.onFilter(); - } - } - - - afterReceivingInterests(retour: any): void - { - if(retour.status !== "success") { - console.log(retour); - } - else { - this.allInterests = retour.data.map(x => x.interest); - this.allInterests.sort(); - } - } - - - 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) - { - const config = { - width: '30%', - height: '90%', - data: { images: advert.images } - }; - this.dialog - .open(PopupVisualizeImagesAdminComponent, 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); - } - } - - - onDelete(advert: AdvertWithCountViewsAndCompany): void - { - const config = { - data: { advert: advert } - }; - this.dialog - .open(PopupDeleteAdAdminComponent, 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 - { - 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); - } - - - advertToAdvertWithCountViewsAndCompany(advert): AdvertWithCountViewsAndCompany - { - let company0 = "company" ; - for(let advertiser of this.tabAdvertiser) - { - if(advert.userId === advertiser.id) { - company0 = advertiser.company; - break; - } - } - - return { - id: advert.id, - userId: advert.userId, - title: advert.title, - company: company0, - url: advert.url, - images: advert.images, - interests: advert.interests, - comment: advert.comment, - views: advert.views, - countViews: advert.views.length, - isVisible: advert.isVisible, - isActive: advert.isActive, - createdAt: advert.createdAt, - updatedAt: advert.updatedAt, - } - } - -} diff --git a/src/app/admin/adList/popup-delete-ad-admin/popup-delete-ad-admin.component.html b/src/app/admin/adList/popup-delete-ad-admin/popup-delete-ad-admin.component.html deleted file mode 100644 index d92e686..0000000 --- a/src/app/admin/adList/popup-delete-ad-admin/popup-delete-ad-admin.component.html +++ /dev/null @@ -1,8 +0,0 @@ - - Êtes-vous sûr de vouloir supprimer l'annonce {{advert.title}} ? - - - - - - diff --git a/src/app/admin/adList/popup-delete-ad-admin/popup-delete-ad-admin.component.scss b/src/app/admin/adList/popup-delete-ad-admin/popup-delete-ad-admin.component.scss deleted file mode 100644 index e69de29..0000000 diff --git a/src/app/admin/adList/popup-delete-ad-admin/popup-delete-ad-admin.component.spec.ts b/src/app/admin/adList/popup-delete-ad-admin/popup-delete-ad-admin.component.spec.ts deleted file mode 100644 index 811eee8..0000000 --- a/src/app/admin/adList/popup-delete-ad-admin/popup-delete-ad-admin.component.spec.ts +++ /dev/null @@ -1,25 +0,0 @@ -import { ComponentFixture, TestBed } from '@angular/core/testing'; - -import { PopupDeleteAdAdminComponent } from './popup-delete-ad-admin.component'; - -describe('PopupDeleteAdAdminComponent', () => { - let component: PopupDeleteAdAdminComponent; - let fixture: ComponentFixture; - - beforeEach(async () => { - await TestBed.configureTestingModule({ - declarations: [ PopupDeleteAdAdminComponent ] - }) - .compileComponents(); - }); - - beforeEach(() => { - fixture = TestBed.createComponent(PopupDeleteAdAdminComponent); - component = fixture.componentInstance; - fixture.detectChanges(); - }); - - it('should create', () => { - expect(component).toBeTruthy(); - }); -}); diff --git a/src/app/admin/adList/popup-delete-ad-admin/popup-delete-ad-admin.component.ts b/src/app/admin/adList/popup-delete-ad-admin/popup-delete-ad-admin.component.ts deleted file mode 100644 index 196f024..0000000 --- a/src/app/admin/adList/popup-delete-ad-admin/popup-delete-ad-admin.component.ts +++ /dev/null @@ -1,49 +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-admin', - templateUrl: './popup-delete-ad-admin.component.html', - styleUrls: ['./popup-delete-ad-admin.component.scss'] -}) -export class PopupDeleteAdAdminComponent implements OnInit -{ - advert: any; - - - constructor( public dialogRef: MatDialogRef, - @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 { - console.log("suppr"); - console.log(retour); - this.dialogRef.close(true); - } - } - -} diff --git a/src/app/admin/adList/popup-visualize-images-admin/popup-visualize-images-admin.component.html b/src/app/admin/adList/popup-visualize-images-admin/popup-visualize-images-admin.component.html deleted file mode 100644 index dfbc2fe..0000000 --- a/src/app/admin/adList/popup-visualize-images-admin/popup-visualize-images-admin.component.html +++ /dev/null @@ -1,20 +0,0 @@ -
-

- -
- - - - - - - - - - - - - - diff --git a/src/app/admin/adList/popup-visualize-images-admin/popup-visualize-images-admin.component.scss b/src/app/admin/adList/popup-visualize-images-admin/popup-visualize-images-admin.component.scss deleted file mode 100644 index eb60d48..0000000 --- a/src/app/admin/adList/popup-visualize-images-admin/popup-visualize-images-admin.component.scss +++ /dev/null @@ -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; -} diff --git a/src/app/admin/adList/popup-visualize-images-admin/popup-visualize-images-admin.component.spec.ts b/src/app/admin/adList/popup-visualize-images-admin/popup-visualize-images-admin.component.spec.ts deleted file mode 100644 index 24f276f..0000000 --- a/src/app/admin/adList/popup-visualize-images-admin/popup-visualize-images-admin.component.spec.ts +++ /dev/null @@ -1,25 +0,0 @@ -import { ComponentFixture, TestBed } from '@angular/core/testing'; - -import { PopupVisualizeImagesAdminComponent } from './popup-visualize-images-admin.component'; - -describe('PopupVisualizeImagesAdminComponent', () => { - let component: PopupVisualizeImagesAdminComponent; - let fixture: ComponentFixture; - - beforeEach(async () => { - await TestBed.configureTestingModule({ - declarations: [ PopupVisualizeImagesAdminComponent ] - }) - .compileComponents(); - }); - - beforeEach(() => { - fixture = TestBed.createComponent(PopupVisualizeImagesAdminComponent); - component = fixture.componentInstance; - fixture.detectChanges(); - }); - - it('should create', () => { - expect(component).toBeTruthy(); - }); -}); diff --git a/src/app/admin/adList/popup-visualize-images-admin/popup-visualize-images-admin.component.ts b/src/app/admin/adList/popup-visualize-images-admin/popup-visualize-images-admin.component.ts deleted file mode 100644 index 5b98819..0000000 --- a/src/app/admin/adList/popup-visualize-images-admin/popup-visualize-images-admin.component.ts +++ /dev/null @@ -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-admin', - templateUrl: './popup-visualize-images-admin.component.html', - styleUrls: ['./popup-visualize-images-admin.component.scss'] -}) -export class PopupVisualizeImagesAdminComponent implements OnInit -{ - tabImages = []; - index: number = 0; - nbImage: number = 0; - - - constructor( public dialogRef: MatDialogRef, - @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; - } - -} diff --git a/src/app/admin/myProfil/page-profil-admin/page-profil-admin.component.html b/src/app/admin/myProfil/page-profil-admin/page-profil-admin.component.html deleted file mode 100644 index 7e025c5..0000000 --- a/src/app/admin/myProfil/page-profil-admin/page-profil-admin.component.html +++ /dev/null @@ -1,43 +0,0 @@ -
-
- - - - - -
- - -
- -
- - -
-
Pseudo:
-
{{admin.login}}
-
- - -
-
Mail:
-
{{admin.email}}
-
- - -
-
Date de création:
-
{{admin.createdAt | date:'dd/LL/YYYY'}}
-
- - -
- -
- -
- - -
-
diff --git a/src/app/admin/myProfil/page-profil-admin/page-profil-admin.component.scss b/src/app/admin/myProfil/page-profil-admin/page-profil-admin.component.scss deleted file mode 100644 index 966c9a2..0000000 --- a/src/app/admin/myProfil/page-profil-admin/page-profil-admin.component.scss +++ /dev/null @@ -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; -} diff --git a/src/app/admin/myProfil/page-profil-admin/page-profil-admin.component.spec.ts b/src/app/admin/myProfil/page-profil-admin/page-profil-admin.component.spec.ts deleted file mode 100644 index 39fbdd9..0000000 --- a/src/app/admin/myProfil/page-profil-admin/page-profil-admin.component.spec.ts +++ /dev/null @@ -1,25 +0,0 @@ -import { ComponentFixture, TestBed } from '@angular/core/testing'; - -import { PageProfilAdminComponent } from './page-profil-admin.component'; - -describe('PageProfilAdminComponent', () => { - let component: PageProfilAdminComponent; - let fixture: ComponentFixture; - - beforeEach(async () => { - await TestBed.configureTestingModule({ - declarations: [ PageProfilAdminComponent ] - }) - .compileComponents(); - }); - - beforeEach(() => { - fixture = TestBed.createComponent(PageProfilAdminComponent); - component = fixture.componentInstance; - fixture.detectChanges(); - }); - - it('should create', () => { - expect(component).toBeTruthy(); - }); -}); diff --git a/src/app/admin/myProfil/page-profil-admin/page-profil-admin.component.ts b/src/app/admin/myProfil/page-profil-admin/page-profil-admin.component.ts deleted file mode 100644 index 75e599f..0000000 --- a/src/app/admin/myProfil/page-profil-admin/page-profil-admin.component.ts +++ /dev/null @@ -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 {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'] -}) -export class PageProfilAdminComponent implements OnInit -{ - admin: User = { - _id: "", - login: "", - hashPass: "", - email: "", - role: { - name: "admin", - permission: 10, - 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.admin = retour.data; - } - } - - - onModifier() - { - const config = { - width: '25%', - data: { admin: this.admin } - }; - this.dialog - .open(PopupUpdateAdminComponent, 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.admin = retour; - } - }); - } - -} diff --git a/src/app/admin/myProfil/popup-update-admin/popup-update-admin.component.html b/src/app/admin/myProfil/popup-update-admin/popup-update-admin.component.html deleted file mode 100644 index 38cf7e5..0000000 --- a/src/app/admin/myProfil/popup-update-admin/popup-update-admin.component.html +++ /dev/null @@ -1,59 +0,0 @@ -
-
- - -
-
- -
- - -

- - - - Pseudo - -
- - -
- - -
- Modifier mot de passe: - -
- - -
- - - Nouveau mot de passe - - -
- - - Confirmation nouveau mot de passe - - -
-

- - -
- - -
- {{errorMessage}} -
- - -
- - -
- -
-
diff --git a/src/app/admin/myProfil/popup-update-admin/popup-update-admin.component.scss b/src/app/admin/myProfil/popup-update-admin/popup-update-admin.component.scss deleted file mode 100644 index 1968e90..0000000 --- a/src/app/admin/myProfil/popup-update-admin/popup-update-admin.component.scss +++ /dev/null @@ -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; -} diff --git a/src/app/admin/myProfil/popup-update-admin/popup-update-admin.component.spec.ts b/src/app/admin/myProfil/popup-update-admin/popup-update-admin.component.spec.ts deleted file mode 100644 index 9f1a0f5..0000000 --- a/src/app/admin/myProfil/popup-update-admin/popup-update-admin.component.spec.ts +++ /dev/null @@ -1,25 +0,0 @@ -import { ComponentFixture, TestBed } from '@angular/core/testing'; - -import { PopupUpdateAdminComponent } from './popup-update-admin.component'; - -describe('PopupUpdateAdminComponent', () => { - let component: PopupUpdateAdminComponent; - let fixture: ComponentFixture; - - beforeEach(async () => { - await TestBed.configureTestingModule({ - declarations: [ PopupUpdateAdminComponent ] - }) - .compileComponents(); - }); - - beforeEach(() => { - fixture = TestBed.createComponent(PopupUpdateAdminComponent); - component = fixture.componentInstance; - fixture.detectChanges(); - }); - - it('should create', () => { - expect(component).toBeTruthy(); - }); -}); diff --git a/src/app/admin/myProfil/popup-update-admin/popup-update-admin.component.ts b/src/app/admin/myProfil/popup-update-admin/popup-update-admin.component.ts deleted file mode 100644 index 39bb3f0..0000000 --- a/src/app/admin/myProfil/popup-update-admin/popup-update-admin.component.ts +++ /dev/null @@ -1,124 +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-admin', - templateUrl: './popup-update-admin.component.html', - styleUrls: ['./popup-update-admin.component.scss'] -}) -export class PopupUpdateAdminComponent implements OnInit -{ - adminCopy: User; - newPassword: string = ""; - confirmNewPassword: string = "" ; - changePassword: boolean = false ; - hasError: boolean = false; - errorMessage: string = "" ; - - - constructor( public dialogRef: MatDialogRef, - @Inject(MAT_DIALOG_DATA) public data, - private messageService: MessageService, - private profilService: ProfilService ) { } - - - ngOnInit(): void - { - const admin0 = this.data.admin; - this.adminCopy = { - _id: admin0._id, - login: admin0.login, - hashPass: admin0.hashPass, - email: admin0.email, - role: { - name: admin0.role.name, - permission: admin0.role.permission, - isAccepted: admin0.role.isAccepted, - }, - profileImageUrl: admin0.profileImageUrl, - dateOfBirth: admin0.dateOfBirth, - gender: admin0.gender, - interests: [], - company: "", - isActive: admin0.isActive, - createdAt: admin0.createdAt, - updatedAt: admin0.updatedAt, - lastConnexion: admin0.lastConnexion - }; - for(let interest of admin0.interests) this.adminCopy.interests.push(interest); - } - - - onValider() - { - this.checkField(); - if(!this.hasError) - { - if(this.changePassword) this.adminCopy.hashPass = this.newPassword; - const data = { - login: this.adminCopy.login, - hashPass: this.adminCopy.hashPass, - email: this.adminCopy.email, - profileImageUrl: this.adminCopy.profileImageUrl, - }; - 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.adminCopy.profileImageUrl); - this.dialogRef.close(this.adminCopy); - } - } - - - checkField() - { - if(this.adminCopy.login.length === 0) { - this.errorMessage = "Veuillez remplir le champ 'pseudo'" ; - this.hasError = true; - } - else if(this.adminCopy.email.length === 0) { - this.errorMessage = "Veuillez remplir le champ 'email'" ; - this.hasError = true; - } - else if(!this.isValidEmail(this.adminCopy.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); - } - -} diff --git a/src/app/admin/userList/input-interests-admin/input-interests-admin.component.html b/src/app/admin/userList/input-interests-admin/input-interests-admin.component.html deleted file mode 100644 index 2a7c484..0000000 --- a/src/app/admin/userList/input-interests-admin/input-interests-admin.component.html +++ /dev/null @@ -1,43 +0,0 @@ - - - - - Centres d'intérêt - - - - - - - {{interest}} - - - - - - - - - - - - {{interest}} - - - - - - diff --git a/src/app/admin/userList/input-interests-admin/input-interests-admin.component.scss b/src/app/admin/userList/input-interests-admin/input-interests-admin.component.scss deleted file mode 100644 index c7acb4b..0000000 --- a/src/app/admin/userList/input-interests-admin/input-interests-admin.component.scss +++ /dev/null @@ -1,3 +0,0 @@ -mat-form-field { - width: 100%; -} diff --git a/src/app/admin/userList/input-interests-admin/input-interests-admin.component.spec.ts b/src/app/admin/userList/input-interests-admin/input-interests-admin.component.spec.ts deleted file mode 100644 index 62f9051..0000000 --- a/src/app/admin/userList/input-interests-admin/input-interests-admin.component.spec.ts +++ /dev/null @@ -1,25 +0,0 @@ -import { ComponentFixture, TestBed } from '@angular/core/testing'; - -import { InputInterestsAdminComponent } from './input-interests-admin.component'; - -describe('InputInterestsAdminComponent', () => { - let component: InputInterestsAdminComponent; - let fixture: ComponentFixture; - - beforeEach(async () => { - await TestBed.configureTestingModule({ - declarations: [ InputInterestsAdminComponent ] - }) - .compileComponents(); - }); - - beforeEach(() => { - fixture = TestBed.createComponent(InputInterestsAdminComponent); - component = fixture.componentInstance; - fixture.detectChanges(); - }); - - it('should create', () => { - expect(component).toBeTruthy(); - }); -}); diff --git a/src/app/admin/userList/input-interests-admin/input-interests-admin.component.ts b/src/app/admin/userList/input-interests-admin/input-interests-admin.component.ts deleted file mode 100644 index 72ead85..0000000 --- a/src/app/admin/userList/input-interests-admin/input-interests-admin.component.ts +++ /dev/null @@ -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 {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"; - - - -@Component({ - selector: 'app-input-interests-admin', - templateUrl: './input-interests-admin.component.html', - styleUrls: ['./input-interests-admin.component.scss'] -}) -export class InputInterestsAdminComponent implements OnInit -{ - selectable = true; - removable = true; - separatorKeysCodes: number[] = [ENTER, COMMA]; - formControl = new FormControl(); - filteredInterests: Observable; - @Input() myInterests: string[] = []; - allInterests: string[] = []; - @Output() eventEmitter = new EventEmitter(); - @ViewChild('tagInput') tagInput: ElementRef; - 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)); - } - -} diff --git a/src/app/admin/userList/page-user-list/page-user-list.component.html b/src/app/admin/userList/page-user-list/page-user-list.component.html deleted file mode 100644 index 25fe6f5..0000000 --- a/src/app/admin/userList/page-user-list/page-user-list.component.html +++ /dev/null @@ -1,193 +0,0 @@ -
-
- - - -

- - - - -
- - -
-
- - -
- Filtre -
- - - - -
- -
- - -
- - -
- - - Utilisateur -
- - Annonceur -
- - Admin - -
-
- - -
- actif
- non actif -
- - -
- Période de dernière connexion:   - - Date de début - - -   -   - - Date de fin - - -
- -
- -
-
- - -
- -
- -
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- power_settings_new - - - - Pseudo - {{user.login}} - Email - {{user.email}} - Date de naissance - - {{ user.dateOfBirth | date:'dd/LL/YYYY' }} - Âge - - {{user.age}} - Sexe - H - F - Centres d'intérêt - - {{interest}}, - {{interest}} - - Date de création - {{ user.createdAt | date:'dd/LL/YYYY à HH:mm:ss' }} - Dernière connexion - {{ user.lastConnexion | date:'dd/LL/YYYY à HH:mm:ss' }} - Accepté - -
Aucune vidéo ne correspond au filtre: "{{input.value}}"
-
- -
-

- -
-
diff --git a/src/app/admin/userList/page-user-list/page-user-list.component.scss b/src/app/admin/userList/page-user-list/page-user-list.component.scss deleted file mode 100644 index bbeac05..0000000 --- a/src/app/admin/userList/page-user-list/page-user-list.component.scss +++ /dev/null @@ -1,99 +0,0 @@ -.myContainer { - min-height: 100vh; - font-size: small; -} - -// ---------------------------------------------------------- - -.filtersContainer { - width: 90%; - 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; -} - -// ------------------------------------------------------------------------- - -::ng-deep .mat-radio-inner-circle { - color: black !important; - background-color: black !important; -} - -::ng-deep .mat-radio-outer-circle{ - color: black !important; - border: solid 1px gray !important; -} - -// ------------------------------------------------------------------------- - - -// 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 { - border: solid 1px black !important; - background-color: white !important; -} - - -// -------------------------------------------------------------------- - - -// 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; -} diff --git a/src/app/admin/userList/page-user-list/page-user-list.component.spec.ts b/src/app/admin/userList/page-user-list/page-user-list.component.spec.ts deleted file mode 100644 index edbbffe..0000000 --- a/src/app/admin/userList/page-user-list/page-user-list.component.spec.ts +++ /dev/null @@ -1,25 +0,0 @@ -import { ComponentFixture, TestBed } from '@angular/core/testing'; - -import { PageUserListComponent } from './page-user-list.component'; - -describe('PageUserListComponent', () => { - let component: PageUserListComponent; - let fixture: ComponentFixture; - - beforeEach(async () => { - await TestBed.configureTestingModule({ - declarations: [ PageUserListComponent ] - }) - .compileComponents(); - }); - - beforeEach(() => { - fixture = TestBed.createComponent(PageUserListComponent); - component = fixture.componentInstance; - fixture.detectChanges(); - }); - - it('should create', () => { - expect(component).toBeTruthy(); - }); -}); diff --git a/src/app/admin/userList/page-user-list/page-user-list.component.ts b/src/app/admin/userList/page-user-list/page-user-list.component.ts deleted file mode 100644 index 42e0dad..0000000 --- a/src/app/admin/userList/page-user-list/page-user-list.component.ts +++ /dev/null @@ -1,233 +0,0 @@ -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"; - - - -@Component({ - 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' ]; - displayedColumnsAdmin: string[] = [ 'isActive', 'login', 'email', 'createdAt', 'lastConnexion' ]; - - tabUser: any[] = []; - tabAdvertiser: any[] = []; - tabAdmin: any[] = []; - - roleName: string = "user" ; - dataSource ; - @ViewChild(MatSort) sort: MatSort; - @ViewChild(MatPaginator) paginator: MatPaginator; - - active: boolean = true; - noActive: boolean = false; - startDate: Date = null; - endDate: Date = null; - - - constructor( public themeService: ThemeService, - public dialog: MatDialog, - private snackBar: MatSnackBar, - private messageService: MessageService ) { } - - - ngAfterViewInit(): void - { - this.messageService - .get("user/findAll") - .subscribe(ret => this.ngAfterViewInitCallback(ret), err => this.ngAfterViewInitCallback(err)); - } - - - ngAfterViewInitCallback(retour: any): void - { - if(retour.status !== "success") { - console.log(retour); - } - else { - for(let person of retour.data) - { - if(person.role.name === "user") { - person["age"] = this.getAge(person.dateOfBirth); - this.tabUser.push(person); - } - else if(person.role.name === "advertiser") this.tabAdvertiser.push(person); - else this.tabAdmin.push(person); - } - this.onFilter(); - } - } - - - 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%' }; - this.dialog - .open(PopupCreateUserComponent, config) - .afterClosed() - .subscribe( retour => { - - const config = { duration: 1000, panelClass: "custom-class" }; - if((retour === null) || (retour === undefined)) { - this.snackBar.open( "Opération annulée", "", config); - } - else { - this.snackBar.open( "L'utilisateur a bien été créé", "", config); - if(retour.role.name === "user") this.tabUser.push(retour); - else if(retour.role.name === "advertiser") this.tabAdvertiser.push(retour); - else if(retour.role.name === "admin") this.tabAdmin.push(retour); - this.onFilter(); - } - }); - } - - - onSliderIsActive(user: any): void - { - // il faut envoyer la négation de user.isActive - this.messageService - .put("user/update/"+user.id, { isActive: !user.isActive }) - .subscribe( - ret => {}, - err => { - console.log("onSliderIsActive"); - console.log(err); - } - ); - } - - - onSlideIsAccepted(user: any): void - { - // il faut envoyer la négation de user.role.isAccepted - const role0 = { - name: user.role.name, - permission: user.role.permission, - isAccepted: !user.role.isAccepted, - }; - this.messageService - .put("user/update/"+user.id, {role: role0}) - .subscribe( - ret => {}, - err => { - console.log("onSlideIsAccepted"); - console.log(err); - } - ); - } - - - getAge(date: Date): number - { - if((date === null) || (date === undefined)) return -1; - else { - const diff = Date.now() - (new Date(date)).getTime(); - const age = new Date(diff); - return Math.abs(age.getUTCFullYear() - 1970); - } - } - - - onFilter(): void - { - let tab1 = []; - if(this.roleName === "user") { - this.displayedColumns = this.displayedColumnsUser; - tab1 = this.tabUser; - } - else if(this.roleName === "advertiser") { - this.displayedColumns = this.displayedColumnsAdvertiser; - tab1 = this.tabAdvertiser; - } - else if(this.roleName === "admin") { - this.displayedColumns = this.displayedColumnsAdmin; - tab1 = this.tabAdmin; - } - - let tab2 = []; - for(let user of tab1) - { - let valide: boolean = true; - - if(user.isActive && this.active) valide = true; - else if((!user.isActive) && this.noActive) valide = true; - else valide = false; - 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(this.startDate.getTime() > user.lastConnexion.getTime()) valide = false; - else if (this.endDate !== null) - { - if(this.endDate.getTime() < user.lastConnexion.getTime()) valide = false; - } - } - } - - if(valide) tab2.push(user); - } - - this.dataSource = new MatTableDataSource(tab2); - 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); - } - -} diff --git a/src/app/admin/userList/popup-create-user/popup-create-user.component.html b/src/app/admin/userList/popup-create-user/popup-create-user.component.html deleted file mode 100644 index dc7ac87..0000000 --- a/src/app/admin/userList/popup-create-user/popup-create-user.component.html +++ /dev/null @@ -1,160 +0,0 @@ -
- - -
- - Utilisateur
- Annonceur
- Admin -
-

- - -
- - -
-
- - -
- - -
- {{errorMessage}} -
- - -
- - -
- -
- - - - - - - - - -
-
- -

- -
- - -
- - - - Email - -
- - - - Pseudo - -
- - - - Mot de passe - -
- - - - Confirmation mot de passe - - - -
- - -
- - - - Date de naissance - -
- - - - Homme     - Femme - -

- - - -
- -
-
- - - - - - - - - - -
-
- -

- - - -
- - -
- - - Email - -
- - - Pseudo - -
- - - Entreprise - -
-
- - -
- - - Mot de passe - -
- - - Confirmation nouveau mot de passe - - -
- -
- - -
diff --git a/src/app/admin/userList/popup-create-user/popup-create-user.component.scss b/src/app/admin/userList/popup-create-user/popup-create-user.component.scss deleted file mode 100644 index 4c8a0c6..0000000 --- a/src/app/admin/userList/popup-create-user/popup-create-user.component.scss +++ /dev/null @@ -1,16 +0,0 @@ -.myContainer { - font-size: small; -} - -img { - margin: 0px 0px 10px 0px; - width: 10%; - height: 10%; - border: solid 2px black; - border-radius: 50%; - font-size: xxx-large; -} - -.leftCol { - border-right: solid 1px #dcdcdc; -} diff --git a/src/app/admin/userList/popup-create-user/popup-create-user.component.spec.ts b/src/app/admin/userList/popup-create-user/popup-create-user.component.spec.ts deleted file mode 100644 index 9c57fcc..0000000 --- a/src/app/admin/userList/popup-create-user/popup-create-user.component.spec.ts +++ /dev/null @@ -1,25 +0,0 @@ -import { ComponentFixture, TestBed } from '@angular/core/testing'; - -import { PopupCreateUserComponent } from './popup-create-user.component'; - -describe('PopupCreateUserComponent', () => { - let component: PopupCreateUserComponent; - let fixture: ComponentFixture; - - beforeEach(async () => { - await TestBed.configureTestingModule({ - declarations: [ PopupCreateUserComponent ] - }) - .compileComponents(); - }); - - beforeEach(() => { - fixture = TestBed.createComponent(PopupCreateUserComponent); - component = fixture.componentInstance; - fixture.detectChanges(); - }); - - it('should create', () => { - expect(component).toBeTruthy(); - }); -}); diff --git a/src/app/admin/userList/popup-create-user/popup-create-user.component.ts b/src/app/admin/userList/popup-create-user/popup-create-user.component.ts deleted file mode 100644 index 40ca5cd..0000000 --- a/src/app/admin/userList/popup-create-user/popup-create-user.component.ts +++ /dev/null @@ -1,127 +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-create-user', - templateUrl: './popup-create-user.component.html', - styleUrls: ['./popup-create-user.component.scss'] -}) -export class PopupCreateUserComponent implements OnInit -{ - user: any; - hasError: boolean = false; - errorMessage: string = ""; - password: string = ""; - confirmPassword: string = ""; - - - constructor( public dialogRef: MatDialogRef, - @Inject(MAT_DIALOG_DATA) public data, - private messageService: MessageService ) { } - - - // Initialise l'utilisateur qui va être créé - ngOnInit(): void - { - this.user = { - _id: "", - login: "", - hashPass: "", - email: "", - role: { - name: "", - permission: 0, - isAccepted: false, - }, - profileImageUrl: "", - dateOfBirth: null, - gender: "man", - interests: [], - company: "", - isActive: false, - createdAt: new Date(), - updatedAt: new Date(), - lastConnexion: new Date() - }; - } - - - // Crée le nouvel utilisateur - onEnregistrer(): void - { - this.checkField(); - if(!this.hasError) - { - this.user.hashPass = this.password; - this.user.role = this.user.role.name; - this.messageService - .post("user/create", this.user) - .subscribe(ret => this.onEnregistrerCallback(ret), err => this.onEnregistrerCallback(err)); - } - } - - - // Callback de 'onEnregistrer' - onEnregistrerCallback(retour: any): void - { - if(retour.status !== "success") { - console.log(retour); - } - else { - this.dialogRef.close(retour.data); - } - } - - - // Check les champs saisies par l'utilisateur - checkField(): void - { - if(this.user.login.length === 0) { - this.errorMessage = "Veuillez remplir le champ 'pseudo'."; - this.hasError = true; - } - else if(this.user.email.length === 0) { - this.errorMessage = "Veuillez remplir le champ 'email'."; - this.hasError = true; - } - else if(!this.isValidEmail(this.user.email)) { - this.errorMessage = "Email invalide."; - this.hasError = true; - } - else if(this.password.length === 0) { - this.errorMessage = "Veuillez remplir le champ 'mot de passe'."; - this.hasError = true; - } - else if(this.password !== this.confirmPassword) { - this.errorMessage = "Le mot de passe est différent de sa confirmation."; - this.hasError = true; - } - else if((this.user.role.name === 'advertiser') && (this.user.company.length === 0)) { - this.errorMessage = "Veuillez remplir le champ 'entreprise'."; - this.hasError = true; - } - else { - this.errorMessage = "" ; - this.hasError = false; - } - } - - - // Indique si email a bien le format d'un email - isValidEmail(email): boolean - { - 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); - } - - - // Récupère la liste des centres d'intérets (car celle-ci est remplie à l'aide d'un component intermédiaire) - onEventInputInterests(myInterets: string[]): void - { - this.user.interests = myInterets; - } - -} diff --git a/src/app/admin/userList/popup-delete-user/popup-delete-user.component.html b/src/app/admin/userList/popup-delete-user/popup-delete-user.component.html deleted file mode 100644 index 26e3854..0000000 --- a/src/app/admin/userList/popup-delete-user/popup-delete-user.component.html +++ /dev/null @@ -1,8 +0,0 @@ - - Êtes-vous sûr de vouloir supprimer {{user.login}} ? - - - - - - diff --git a/src/app/admin/userList/popup-delete-user/popup-delete-user.component.scss b/src/app/admin/userList/popup-delete-user/popup-delete-user.component.scss deleted file mode 100644 index e69de29..0000000 diff --git a/src/app/admin/userList/popup-delete-user/popup-delete-user.component.spec.ts b/src/app/admin/userList/popup-delete-user/popup-delete-user.component.spec.ts deleted file mode 100644 index 273cdc6..0000000 --- a/src/app/admin/userList/popup-delete-user/popup-delete-user.component.spec.ts +++ /dev/null @@ -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; - - beforeEach(async () => { - await TestBed.configureTestingModule({ - declarations: [ PopupDeleteUserComponent ] - }) - .compileComponents(); - }); - - beforeEach(() => { - fixture = TestBed.createComponent(PopupDeleteUserComponent); - component = fixture.componentInstance; - fixture.detectChanges(); - }); - - it('should create', () => { - expect(component).toBeTruthy(); - }); -}); diff --git a/src/app/admin/userList/popup-delete-user/popup-delete-user.component.ts b/src/app/admin/userList/popup-delete-user/popup-delete-user.component.ts deleted file mode 100644 index 35e8d9e..0000000 --- a/src/app/admin/userList/popup-delete-user/popup-delete-user.component.ts +++ /dev/null @@ -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, - @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); - } - }); - */ - } - -} diff --git a/src/app/admin/utils/navbar-admin/navbar-admin.component.html b/src/app/admin/utils/navbar-admin/navbar-admin.component.html deleted file mode 100644 index a73059e..0000000 --- a/src/app/admin/utils/navbar-admin/navbar-admin.component.html +++ /dev/null @@ -1,37 +0,0 @@ -
diff --git a/src/app/admin/utils/navbar-admin/navbar-admin.component.scss b/src/app/admin/utils/navbar-admin/navbar-admin.component.scss deleted file mode 100644 index 285d629..0000000 --- a/src/app/admin/utils/navbar-admin/navbar-admin.component.scss +++ /dev/null @@ -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; -} diff --git a/src/app/admin/utils/navbar-admin/navbar-admin.component.spec.ts b/src/app/admin/utils/navbar-admin/navbar-admin.component.spec.ts deleted file mode 100644 index 44f2cf6..0000000 --- a/src/app/admin/utils/navbar-admin/navbar-admin.component.spec.ts +++ /dev/null @@ -1,25 +0,0 @@ -import { ComponentFixture, TestBed } from '@angular/core/testing'; - -import { NavbarAdminComponent } from './navbar-admin.component'; - -describe('NavbarAdminComponent', () => { - let component: NavbarAdminComponent; - let fixture: ComponentFixture; - - beforeEach(async () => { - await TestBed.configureTestingModule({ - declarations: [ NavbarAdminComponent ] - }) - .compileComponents(); - }); - - beforeEach(() => { - fixture = TestBed.createComponent(NavbarAdminComponent); - component = fixture.componentInstance; - fixture.detectChanges(); - }); - - it('should create', () => { - expect(component).toBeTruthy(); - }); -}); diff --git a/src/app/admin/utils/navbar-admin/navbar-admin.component.ts b/src/app/admin/utils/navbar-admin/navbar-admin.component.ts deleted file mode 100644 index 5df617a..0000000 --- a/src/app/admin/utils/navbar-admin/navbar-admin.component.ts +++ /dev/null @@ -1,40 +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-admin', - templateUrl: './navbar-admin.component.html', - styleUrls: ['./navbar-admin.component.scss'] -}) -export class NavbarAdminComponent -{ - routes: string[] = [ - "/admin", // 0 - "/admin/userList", // 1 - "/admin/adList", // 2 - "/admin/myProfil", // 3 - ]; - - 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); - } - -} diff --git a/src/app/advertiser/adList/drag-and-drop/drag-and-drop.component.html b/src/app/advertiser/adList/drag-and-drop/drag-and-drop.component.html deleted file mode 100644 index ba7dc4f..0000000 --- a/src/app/advertiser/adList/drag-and-drop/drag-and-drop.component.html +++ /dev/null @@ -1,33 +0,0 @@ -
- -
Images
- -
Glisser déposer
-
ou
-
Cliquer pour selectionner
-
- -
- info -
- -
-
- file -
-

- {{ file?.name }} -

-

- {{ formatBytes(file?.size) }} -

-
-
-
-
-
- -
-
diff --git a/src/app/advertiser/adList/drag-and-drop/drag-and-drop.component.scss b/src/app/advertiser/adList/drag-and-drop/drag-and-drop.component.scss deleted file mode 100644 index 91899f6..0000000 --- a/src/app/advertiser/adList/drag-and-drop/drag-and-drop.component.scss +++ /dev/null @@ -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; - } -} diff --git a/src/app/advertiser/adList/drag-and-drop/drag-and-drop.component.spec.ts b/src/app/advertiser/adList/drag-and-drop/drag-and-drop.component.spec.ts deleted file mode 100644 index e4666b0..0000000 --- a/src/app/advertiser/adList/drag-and-drop/drag-and-drop.component.spec.ts +++ /dev/null @@ -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; - - beforeEach(async () => { - await TestBed.configureTestingModule({ - declarations: [ DragAndDropComponent ] - }) - .compileComponents(); - }); - - beforeEach(() => { - fixture = TestBed.createComponent(DragAndDropComponent); - component = fixture.componentInstance; - fixture.detectChanges(); - }); - - it('should create', () => { - expect(component).toBeTruthy(); - }); -}); diff --git a/src/app/advertiser/adList/drag-and-drop/drag-and-drop.component.ts b/src/app/advertiser/adList/drag-and-drop/drag-and-drop.component.ts deleted file mode 100644 index e626bef..0000000 --- a/src/app/advertiser/adList/drag-and-drop/drag-and-drop.component.ts +++ /dev/null @@ -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(); - - /** - * 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) { - 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]; - } - -} diff --git a/src/app/advertiser/adList/input-interests-ad/input-interests-ad.component.html b/src/app/advertiser/adList/input-interests-ad/input-interests-ad.component.html deleted file mode 100644 index 6def6c2..0000000 --- a/src/app/advertiser/adList/input-interests-ad/input-interests-ad.component.html +++ /dev/null @@ -1,43 +0,0 @@ - - - - - Sujets - - - - - - - {{interest}} - - - - - - - - - - - - {{interest}} - - - - - - diff --git a/src/app/advertiser/adList/input-interests-ad/input-interests-ad.component.scss b/src/app/advertiser/adList/input-interests-ad/input-interests-ad.component.scss deleted file mode 100644 index 2c3a84d..0000000 --- a/src/app/advertiser/adList/input-interests-ad/input-interests-ad.component.scss +++ /dev/null @@ -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; -} diff --git a/src/app/advertiser/adList/input-interests-ad/input-interests-ad.component.spec.ts b/src/app/advertiser/adList/input-interests-ad/input-interests-ad.component.spec.ts deleted file mode 100644 index deae4d3..0000000 --- a/src/app/advertiser/adList/input-interests-ad/input-interests-ad.component.spec.ts +++ /dev/null @@ -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; - - beforeEach(async () => { - await TestBed.configureTestingModule({ - declarations: [ InputInterestsAdComponent ] - }) - .compileComponents(); - }); - - beforeEach(() => { - fixture = TestBed.createComponent(InputInterestsAdComponent); - component = fixture.componentInstance; - fixture.detectChanges(); - }); - - it('should create', () => { - expect(component).toBeTruthy(); - }); -}); diff --git a/src/app/advertiser/adList/input-interests-ad/input-interests-ad.component.ts b/src/app/advertiser/adList/input-interests-ad/input-interests-ad.component.ts deleted file mode 100644 index 617cc43..0000000 --- a/src/app/advertiser/adList/input-interests-ad/input-interests-ad.component.ts +++ /dev/null @@ -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; - @Input() myInterests: string[] = []; - allInterests: string[] = []; - @Output() eventEmitter = new EventEmitter(); - @ViewChild('tagInput') tagInput: ElementRef; - 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)); - } - -} diff --git a/src/app/advertiser/adList/page-ad-list-advertiser/page-ad-list-advertiser.component.html b/src/app/advertiser/adList/page-ad-list-advertiser/page-ad-list-advertiser.component.html deleted file mode 100644 index 78dd263..0000000 --- a/src/app/advertiser/adList/page-ad-list-advertiser/page-ad-list-advertiser.component.html +++ /dev/null @@ -1,185 +0,0 @@ -
-
- - - -

- - - - - - -
- - -
-
- - -
- Filtre -
- - - - -
- -
- - -
- - - -
- visible
- non visible -
- - - -
- - Sujets - - - {{formControlInterests.value ? formControlInterests.value[0] : ''}} - - (+{{formControlInterests.value.length - 1}} {{formControlInterests.value?.length === 2 ? 'autre' : 'autres'}}) - - - {{topping}} - - - -
- - - -
- Période de création:   - - Date de début - - -   -   - - Date de fin - - -
- -
- -
-
- - -
- -
- -
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- power_settings_new - - - Titre - {{advert.title}} - Sujets - - {{interest}}, - {{interest}} - - Date de création - {{ advert.createdAt | date:'dd/LL/YYYY à HH:mm:ss' }} - Dernière modification - {{ advert.updatedAt | date:'dd/LL/YYYY à HH:mm:ss' }} - Vues - {{advert.countViews}} - Actions - - - -
Aucune vidéo ne correspond au filtre: "{{input.value}}"
-
- -
-

- -
-
diff --git a/src/app/advertiser/adList/page-ad-list-advertiser/page-ad-list-advertiser.component.scss b/src/app/advertiser/adList/page-ad-list-advertiser/page-ad-list-advertiser.component.scss deleted file mode 100644 index 370e312..0000000 --- a/src/app/advertiser/adList/page-ad-list-advertiser/page-ad-list-advertiser.component.scss +++ /dev/null @@ -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; -} diff --git a/src/app/advertiser/adList/page-ad-list-advertiser/page-ad-list-advertiser.component.spec.ts b/src/app/advertiser/adList/page-ad-list-advertiser/page-ad-list-advertiser.component.spec.ts deleted file mode 100644 index 9492c6c..0000000 --- a/src/app/advertiser/adList/page-ad-list-advertiser/page-ad-list-advertiser.component.spec.ts +++ /dev/null @@ -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; - - beforeEach(async () => { - await TestBed.configureTestingModule({ - declarations: [ PageAdListAdvertiserComponent ] - }) - .compileComponents(); - }); - - beforeEach(() => { - fixture = TestBed.createComponent(PageAdListAdvertiserComponent); - component = fixture.componentInstance; - fixture.detectChanges(); - }); - - it('should create', () => { - expect(component).toBeTruthy(); - }); -}); diff --git a/src/app/advertiser/adList/page-ad-list-advertiser/page-ad-list-advertiser.component.ts b/src/app/advertiser/adList/page-ad-list-advertiser/page-ad-list-advertiser.component.ts deleted file mode 100644 index 6adf0ed..0000000 --- a/src/app/advertiser/adList/page-ad-list-advertiser/page-ad-list-advertiser.component.ts +++ /dev/null @@ -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(); - 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, - } - } - -} diff --git a/src/app/advertiser/adList/popup-add-or-update-ad/popup-add-or-update-ad.component.html b/src/app/advertiser/adList/popup-add-or-update-ad/popup-add-or-update-ad.component.html deleted file mode 100644 index e3b7986..0000000 --- a/src/app/advertiser/adList/popup-add-or-update-ad/popup-add-or-update-ad.component.html +++ /dev/null @@ -1,83 +0,0 @@ -
-
- - -

{{title}}

- - -
- - - -
- - -
- - - - Titre annonce - - - - - - - - - Commentaire - -
- - - - URL - -
- - - Visible

- - -
-
- Images déjà associées: -
-
-
- - {{image.description}} - - -
-
-
- -
- - -
- -
- -
- - -
- - -
- {{errorMessage}} -
- - - - - - - - -
-
diff --git a/src/app/advertiser/adList/popup-add-or-update-ad/popup-add-or-update-ad.component.scss b/src/app/advertiser/adList/popup-add-or-update-ad/popup-add-or-update-ad.component.scss deleted file mode 100644 index 3bb2eed..0000000 --- a/src/app/advertiser/adList/popup-add-or-update-ad/popup-add-or-update-ad.component.scss +++ /dev/null @@ -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; -} diff --git a/src/app/advertiser/adList/popup-add-or-update-ad/popup-add-or-update-ad.component.spec.ts b/src/app/advertiser/adList/popup-add-or-update-ad/popup-add-or-update-ad.component.spec.ts deleted file mode 100644 index ba74952..0000000 --- a/src/app/advertiser/adList/popup-add-or-update-ad/popup-add-or-update-ad.component.spec.ts +++ /dev/null @@ -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; - - beforeEach(async () => { - await TestBed.configureTestingModule({ - declarations: [ PopupAddOrUpdateAdComponent ] - }) - .compileComponents(); - }); - - beforeEach(() => { - fixture = TestBed.createComponent(PopupAddOrUpdateAdComponent); - component = fixture.componentInstance; - fixture.detectChanges(); - }); - - it('should create', () => { - expect(component).toBeTruthy(); - }); -}); diff --git a/src/app/advertiser/adList/popup-add-or-update-ad/popup-add-or-update-ad.component.ts b/src/app/advertiser/adList/popup-add-or-update-ad/popup-add-or-update-ad.component.ts deleted file mode 100644 index 32831f9..0000000 --- a/src/app/advertiser/adList/popup-add-or-update-ad/popup-add-or-update-ad.component.ts +++ /dev/null @@ -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, - @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 - Êtes-vous sûr de vouloir supprimer l'annonce {{advert.title}} ? - - - - - - diff --git a/src/app/advertiser/adList/popup-delete-ad-advertiser/popup-delete-ad-advertiser.component.scss b/src/app/advertiser/adList/popup-delete-ad-advertiser/popup-delete-ad-advertiser.component.scss deleted file mode 100644 index e69de29..0000000 diff --git a/src/app/advertiser/adList/popup-delete-ad-advertiser/popup-delete-ad-advertiser.component.spec.ts b/src/app/advertiser/adList/popup-delete-ad-advertiser/popup-delete-ad-advertiser.component.spec.ts deleted file mode 100644 index 632a177..0000000 --- a/src/app/advertiser/adList/popup-delete-ad-advertiser/popup-delete-ad-advertiser.component.spec.ts +++ /dev/null @@ -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; - - beforeEach(async () => { - await TestBed.configureTestingModule({ - declarations: [ PopupDeleteAdAdvertiserComponent ] - }) - .compileComponents(); - }); - - beforeEach(() => { - fixture = TestBed.createComponent(PopupDeleteAdAdvertiserComponent); - component = fixture.componentInstance; - fixture.detectChanges(); - }); - - it('should create', () => { - expect(component).toBeTruthy(); - }); -}); diff --git a/src/app/advertiser/adList/popup-delete-ad-advertiser/popup-delete-ad-advertiser.component.ts b/src/app/advertiser/adList/popup-delete-ad-advertiser/popup-delete-ad-advertiser.component.ts deleted file mode 100644 index 1de96ef..0000000 --- a/src/app/advertiser/adList/popup-delete-ad-advertiser/popup-delete-ad-advertiser.component.ts +++ /dev/null @@ -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, - @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); - } - } - -} diff --git a/src/app/advertiser/adList/popup-visualize-ad-advertiser/popup-visualize-ad-advertiser.component.html b/src/app/advertiser/adList/popup-visualize-ad-advertiser/popup-visualize-ad-advertiser.component.html deleted file mode 100644 index a768258..0000000 --- a/src/app/advertiser/adList/popup-visualize-ad-advertiser/popup-visualize-ad-advertiser.component.html +++ /dev/null @@ -1,71 +0,0 @@ -
- -

{{advert.title}}

- - - - - - - -
-
Images:
-
-
{{image.url}}
-
-
- - -
-
Centre d'intérêt :
-
-
• {{tag}}
-
-
- - -
-
Commentaire:
-
{{advert.comment}}
-
- - -
- -
{{advert.views}}
-
- - -
- -
- {{ advert.createdAt | date:'dd/LL/YYYY à HH:mm:ss' }} -
-
- - -
- -
- {{ advert.updatedAt | date:'dd/LL/YYYY à HH:mm:ss' }} -
-
- - -
- -
- checked - close -
-
- -
- - - - - - - -
diff --git a/src/app/advertiser/adList/popup-visualize-ad-advertiser/popup-visualize-ad-advertiser.component.scss b/src/app/advertiser/adList/popup-visualize-ad-advertiser/popup-visualize-ad-advertiser.component.scss deleted file mode 100644 index 3e00dee..0000000 --- a/src/app/advertiser/adList/popup-visualize-ad-advertiser/popup-visualize-ad-advertiser.component.scss +++ /dev/null @@ -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; -} diff --git a/src/app/advertiser/adList/popup-visualize-ad-advertiser/popup-visualize-ad-advertiser.component.spec.ts b/src/app/advertiser/adList/popup-visualize-ad-advertiser/popup-visualize-ad-advertiser.component.spec.ts deleted file mode 100644 index 56aedbc..0000000 --- a/src/app/advertiser/adList/popup-visualize-ad-advertiser/popup-visualize-ad-advertiser.component.spec.ts +++ /dev/null @@ -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; - - beforeEach(async () => { - await TestBed.configureTestingModule({ - declarations: [ PopupVisualizeAdAdvertiserComponent ] - }) - .compileComponents(); - }); - - beforeEach(() => { - fixture = TestBed.createComponent(PopupVisualizeAdAdvertiserComponent); - component = fixture.componentInstance; - fixture.detectChanges(); - }); - - it('should create', () => { - expect(component).toBeTruthy(); - }); -}); diff --git a/src/app/advertiser/adList/popup-visualize-ad-advertiser/popup-visualize-ad-advertiser.component.ts b/src/app/advertiser/adList/popup-visualize-ad-advertiser/popup-visualize-ad-advertiser.component.ts deleted file mode 100644 index 1e65834..0000000 --- a/src/app/advertiser/adList/popup-visualize-ad-advertiser/popup-visualize-ad-advertiser.component.ts +++ /dev/null @@ -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, - @Inject(MAT_DIALOG_DATA) public data, - public themeService: ThemeService, - public dialog: MatDialog ) { } - - ngOnInit(): void - { - this.advert = this.data.advert; - } - -} diff --git a/src/app/advertiser/adList/popup-visualize-images-advertiser/popup-visualize-images-advertiser.component.html b/src/app/advertiser/adList/popup-visualize-images-advertiser/popup-visualize-images-advertiser.component.html deleted file mode 100644 index dfbc2fe..0000000 --- a/src/app/advertiser/adList/popup-visualize-images-advertiser/popup-visualize-images-advertiser.component.html +++ /dev/null @@ -1,20 +0,0 @@ -
-

- -
- - - - - - - - - - - - - - diff --git a/src/app/advertiser/adList/popup-visualize-images-advertiser/popup-visualize-images-advertiser.component.scss b/src/app/advertiser/adList/popup-visualize-images-advertiser/popup-visualize-images-advertiser.component.scss deleted file mode 100644 index eb60d48..0000000 --- a/src/app/advertiser/adList/popup-visualize-images-advertiser/popup-visualize-images-advertiser.component.scss +++ /dev/null @@ -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; -} diff --git a/src/app/advertiser/adList/popup-visualize-images-advertiser/popup-visualize-images-advertiser.component.spec.ts b/src/app/advertiser/adList/popup-visualize-images-advertiser/popup-visualize-images-advertiser.component.spec.ts deleted file mode 100644 index 25da0db..0000000 --- a/src/app/advertiser/adList/popup-visualize-images-advertiser/popup-visualize-images-advertiser.component.spec.ts +++ /dev/null @@ -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; - - beforeEach(async () => { - await TestBed.configureTestingModule({ - declarations: [ PopupVisualizeImagesAdvertiserComponent ] - }) - .compileComponents(); - }); - - beforeEach(() => { - fixture = TestBed.createComponent(PopupVisualizeImagesAdvertiserComponent); - component = fixture.componentInstance; - fixture.detectChanges(); - }); - - it('should create', () => { - expect(component).toBeTruthy(); - }); -}); diff --git a/src/app/advertiser/adList/popup-visualize-images-advertiser/popup-visualize-images-advertiser.component.ts b/src/app/advertiser/adList/popup-visualize-images-advertiser/popup-visualize-images-advertiser.component.ts deleted file mode 100644 index 59e7c3d..0000000 --- a/src/app/advertiser/adList/popup-visualize-images-advertiser/popup-visualize-images-advertiser.component.ts +++ /dev/null @@ -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, - @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; - } - -} diff --git a/src/app/advertiser/myProfil/page-profil-advertiser/page-profil-advertiser.component.html b/src/app/advertiser/myProfil/page-profil-advertiser/page-profil-advertiser.component.html deleted file mode 100644 index 9af3317..0000000 --- a/src/app/advertiser/myProfil/page-profil-advertiser/page-profil-advertiser.component.html +++ /dev/null @@ -1,49 +0,0 @@ -
-
- - - - - -
- - -
- -
- - -
-
Entreprise:
-
{{advertiser.company}}
-
- - -
-
Pseudo:
-
{{advertiser.login}}
-
- - -
-
Mail:
-
{{advertiser.email}}
-
- - -
-
Date de création:
-
{{advertiser.createdAt | date:'dd/LL/YYYY'}}
-
- - -
- -
- -
- - -
-
diff --git a/src/app/advertiser/myProfil/page-profil-advertiser/page-profil-advertiser.component.scss b/src/app/advertiser/myProfil/page-profil-advertiser/page-profil-advertiser.component.scss deleted file mode 100644 index 966c9a2..0000000 --- a/src/app/advertiser/myProfil/page-profil-advertiser/page-profil-advertiser.component.scss +++ /dev/null @@ -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; -} diff --git a/src/app/advertiser/myProfil/page-profil-advertiser/page-profil-advertiser.component.spec.ts b/src/app/advertiser/myProfil/page-profil-advertiser/page-profil-advertiser.component.spec.ts deleted file mode 100644 index ebb9617..0000000 --- a/src/app/advertiser/myProfil/page-profil-advertiser/page-profil-advertiser.component.spec.ts +++ /dev/null @@ -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; - - beforeEach(async () => { - await TestBed.configureTestingModule({ - declarations: [ PageProfilAdvertiserComponent ] - }) - .compileComponents(); - }); - - beforeEach(() => { - fixture = TestBed.createComponent(PageProfilAdvertiserComponent); - component = fixture.componentInstance; - fixture.detectChanges(); - }); - - it('should create', () => { - expect(component).toBeTruthy(); - }); -}); diff --git a/src/app/advertiser/myProfil/page-profil-advertiser/page-profil-advertiser.component.ts b/src/app/advertiser/myProfil/page-profil-advertiser/page-profil-advertiser.component.ts deleted file mode 100644 index de60d59..0000000 --- a/src/app/advertiser/myProfil/page-profil-advertiser/page-profil-advertiser.component.ts +++ /dev/null @@ -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; - } - }); - } - -} diff --git a/src/app/advertiser/myProfil/popup-update-advertiser/popup-update-advertiser.component.html b/src/app/advertiser/myProfil/popup-update-advertiser/popup-update-advertiser.component.html deleted file mode 100644 index 4951e5c..0000000 --- a/src/app/advertiser/myProfil/popup-update-advertiser/popup-update-advertiser.component.html +++ /dev/null @@ -1,65 +0,0 @@ -
-
- - -
-
- -
- - -

- - - - Entreprise - -
- - - - Pseudo - -
- - -
- - -
- Modifier mot de passe: - -
- - -
- - - Nouveau mot de passe - - -
- - - Confirmation nouveau mot de passe - - -
-

- - -
- - -
- {{errorMessage}} -
- - -
- - -
- -
-
diff --git a/src/app/advertiser/myProfil/popup-update-advertiser/popup-update-advertiser.component.scss b/src/app/advertiser/myProfil/popup-update-advertiser/popup-update-advertiser.component.scss deleted file mode 100644 index 1968e90..0000000 --- a/src/app/advertiser/myProfil/popup-update-advertiser/popup-update-advertiser.component.scss +++ /dev/null @@ -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; -} diff --git a/src/app/advertiser/myProfil/popup-update-advertiser/popup-update-advertiser.component.spec.ts b/src/app/advertiser/myProfil/popup-update-advertiser/popup-update-advertiser.component.spec.ts deleted file mode 100644 index dde7ef9..0000000 --- a/src/app/advertiser/myProfil/popup-update-advertiser/popup-update-advertiser.component.spec.ts +++ /dev/null @@ -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; - - beforeEach(async () => { - await TestBed.configureTestingModule({ - declarations: [ PopupUpdateAdvertiserComponent ] - }) - .compileComponents(); - }); - - beforeEach(() => { - fixture = TestBed.createComponent(PopupUpdateAdvertiserComponent); - component = fixture.componentInstance; - fixture.detectChanges(); - }); - - it('should create', () => { - expect(component).toBeTruthy(); - }); -}); diff --git a/src/app/advertiser/myProfil/popup-update-advertiser/popup-update-advertiser.component.ts b/src/app/advertiser/myProfil/popup-update-advertiser/popup-update-advertiser.component.ts deleted file mode 100644 index 8d4de8a..0000000 --- a/src/app/advertiser/myProfil/popup-update-advertiser/popup-update-advertiser.component.ts +++ /dev/null @@ -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, - @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); - } - -} diff --git a/src/app/advertiser/pages-popularity/pages-popularity.component.html b/src/app/advertiser/pages-popularity/pages-popularity.component.html deleted file mode 100644 index 62ae0e1..0000000 --- a/src/app/advertiser/pages-popularity/pages-popularity.component.html +++ /dev/null @@ -1,94 +0,0 @@ -
-
- - - - - - - - -
- -
Filtre
- -
- -
- -

- -
- -
- -
- - - - -
- - -
- - -
-
- - - - - - - - - début - - -   -   - - - - fin - - -   -   - - - - pas d'affichage - - -   -   - - - - unité du pas d'affichage - - jour - semaine - mois - -
- - - - - - - {{coupleNameViews.name}}, - - - {{coupleNameViews.name}} - - - - -
diff --git a/src/app/advertiser/pages-popularity/pages-popularity.component.scss b/src/app/advertiser/pages-popularity/pages-popularity.component.scss deleted file mode 100644 index 00fb9e3..0000000 --- a/src/app/advertiser/pages-popularity/pages-popularity.component.scss +++ /dev/null @@ -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; -} diff --git a/src/app/advertiser/pages-popularity/pages-popularity.component.spec.ts b/src/app/advertiser/pages-popularity/pages-popularity.component.spec.ts deleted file mode 100644 index f9ff236..0000000 --- a/src/app/advertiser/pages-popularity/pages-popularity.component.spec.ts +++ /dev/null @@ -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; - - beforeEach(async () => { - await TestBed.configureTestingModule({ - declarations: [ PagesPopularityComponent ] - }) - .compileComponents(); - }); - - beforeEach(() => { - fixture = TestBed.createComponent(PagesPopularityComponent); - component = fixture.componentInstance; - fixture.detectChanges(); - }); - - it('should create', () => { - expect(component).toBeTruthy(); - }); -}); diff --git a/src/app/advertiser/pages-popularity/pages-popularity.component.ts b/src/app/advertiser/pages-popularity/pages-popularity.component.ts deleted file mode 100644 index 991b8fa..0000000 --- a/src/app/advertiser/pages-popularity/pages-popularity.component.ts +++ /dev/null @@ -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 = 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 (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([]); - } - -} diff --git a/src/app/advertiser/utils/dragAndDrop/drag-and-drop.directive.spec.ts b/src/app/advertiser/utils/dragAndDrop/drag-and-drop.directive.spec.ts deleted file mode 100644 index 60cf3d6..0000000 --- a/src/app/advertiser/utils/dragAndDrop/drag-and-drop.directive.spec.ts +++ /dev/null @@ -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(); - }); -}); diff --git a/src/app/advertiser/utils/dragAndDrop/drag-and-drop.directive.ts b/src/app/advertiser/utils/dragAndDrop/drag-and-drop.directive.ts deleted file mode 100644 index b3d1162..0000000 --- a/src/app/advertiser/utils/dragAndDrop/drag-and-drop.directive.ts +++ /dev/null @@ -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(); - - // 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); - } - } - -} diff --git a/src/app/advertiser/utils/navbar-advertiser/navbar-advertiser.component.html b/src/app/advertiser/utils/navbar-advertiser/navbar-advertiser.component.html deleted file mode 100644 index da5e898..0000000 --- a/src/app/advertiser/utils/navbar-advertiser/navbar-advertiser.component.html +++ /dev/null @@ -1,41 +0,0 @@ - diff --git a/src/app/advertiser/utils/navbar-advertiser/navbar-advertiser.component.scss b/src/app/advertiser/utils/navbar-advertiser/navbar-advertiser.component.scss deleted file mode 100644 index 285d629..0000000 --- a/src/app/advertiser/utils/navbar-advertiser/navbar-advertiser.component.scss +++ /dev/null @@ -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; -} diff --git a/src/app/advertiser/utils/navbar-advertiser/navbar-advertiser.component.spec.ts b/src/app/advertiser/utils/navbar-advertiser/navbar-advertiser.component.spec.ts deleted file mode 100644 index fb00a09..0000000 --- a/src/app/advertiser/utils/navbar-advertiser/navbar-advertiser.component.spec.ts +++ /dev/null @@ -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; - - beforeEach(async () => { - await TestBed.configureTestingModule({ - declarations: [ NavbarAdvertiserComponent ] - }) - .compileComponents(); - }); - - beforeEach(() => { - fixture = TestBed.createComponent(NavbarAdvertiserComponent); - component = fixture.componentInstance; - fixture.detectChanges(); - }); - - it('should create', () => { - expect(component).toBeTruthy(); - }); -}); diff --git a/src/app/advertiser/utils/navbar-advertiser/navbar-advertiser.component.ts b/src/app/advertiser/utils/navbar-advertiser/navbar-advertiser.component.ts deleted file mode 100644 index 7f403db..0000000 --- a/src/app/advertiser/utils/navbar-advertiser/navbar-advertiser.component.ts +++ /dev/null @@ -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); - } - -} diff --git a/src/app/app-routing.module.ts b/src/app/app-routing.module.ts deleted file mode 100644 index df9fee2..0000000 --- a/src/app/app-routing.module.ts +++ /dev/null @@ -1,53 +0,0 @@ -import { NgModule } from '@angular/core'; -import { RouterModule, Routes } from '@angular/router'; -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 {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"; - - -const routes: Routes = [ - - // Before connexion - { path: '', component: PageLoginComponent }, - { 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 }, - -]; - - -@NgModule({ - imports: [RouterModule.forRoot(routes)], - exports: [RouterModule] -}) -export class AppRoutingModule { } diff --git a/src/app/app.component.html b/src/app/app.component.html deleted file mode 100644 index 0680b43..0000000 --- a/src/app/app.component.html +++ /dev/null @@ -1 +0,0 @@ - diff --git a/src/app/app.component.scss b/src/app/app.component.scss deleted file mode 100644 index 22a5665..0000000 --- a/src/app/app.component.scss +++ /dev/null @@ -1,24 +0,0 @@ -::ng-deep snack-bar-container.custom-class { - //background: yellow; -} -::ng-deep .custom-class .mat-simple-snackbar { - //color: green; - justify-content: center; -} - - -// 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 { - border: solid 1px black !important; - background-color: white !important; -} diff --git a/src/app/app.component.spec.ts b/src/app/app.component.spec.ts deleted file mode 100644 index 04c26ec..0000000 --- a/src/app/app.component.spec.ts +++ /dev/null @@ -1,35 +0,0 @@ -import { TestBed } from '@angular/core/testing'; -import { RouterTestingModule } from '@angular/router/testing'; -import { AppComponent } from './app.component'; - -describe('AppComponent', () => { - beforeEach(async () => { - await TestBed.configureTestingModule({ - imports: [ - RouterTestingModule - ], - declarations: [ - AppComponent - ], - }).compileComponents(); - }); - - it('should create the app', () => { - const fixture = TestBed.createComponent(AppComponent); - const app = fixture.componentInstance; - expect(app).toBeTruthy(); - }); - - it(`should have as title 'frontend'`, () => { - const fixture = TestBed.createComponent(AppComponent); - const app = fixture.componentInstance; - expect(app.title).toEqual('frontend'); - }); - - it('should render title', () => { - const fixture = TestBed.createComponent(AppComponent); - fixture.detectChanges(); - const compiled = fixture.nativeElement; - expect(compiled.querySelector('.content span').textContent).toContain('frontend app is running!'); - }); -}); diff --git a/src/app/app.component.ts b/src/app/app.component.ts deleted file mode 100644 index 2cc7859..0000000 --- a/src/app/app.component.ts +++ /dev/null @@ -1,12 +0,0 @@ -import { Component } from '@angular/core'; - -@Component({ - selector: 'app-root', - templateUrl: './app.component.html', - styleUrls: ['./app.component.scss'] -}) -export class AppComponent { - title = 'frontend'; - - themeIsLight = true; -} diff --git a/src/app/app.module.ts b/src/app/app.module.ts deleted file mode 100644 index 133f928..0000000 --- a/src/app/app.module.ts +++ /dev/null @@ -1,157 +0,0 @@ -import { NgModule } from '@angular/core'; -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 {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 {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 { 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 { 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 {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'; - - -@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, - ], - imports: [ - BrowserModule, - AppRoutingModule, - BrowserAnimationsModule, - MatSlideToggleModule, - FormsModule, - HttpClientModule, - MatDialogModule, - MatButtonModule, - MatIconModule, - MatInputModule, - MatDividerModule, - MatCheckboxModule, - MatFormFieldModule, - MatSnackBarModule, - MatGridListModule, - MatTableModule, - NgbModule, - MatSortModule, - MatChipsModule, - ReactiveFormsModule, - MatAutocompleteModule, - MatSelectModule, - IvyCarouselModule, - MatRadioModule, - MatStepperModule, - MatPaginatorModule, - MatDatepickerModule, - ChartsModule - ], - providers: [], - bootstrap: [AppComponent] -}) -export class AppModule { } diff --git a/src/app/beforeConnexion/login/page-login/page-login.component.html b/src/app/beforeConnexion/login/page-login/page-login.component.html deleted file mode 100644 index 675270e..0000000 --- a/src/app/beforeConnexion/login/page-login/page-login.component.html +++ /dev/null @@ -1,36 +0,0 @@ -
-
- - - -
-
- - -
-

StreamNotFound

- User Icon -
- - -
- - - -
- {{errorMessage}} -
- -
- - - - -
-
- - -
-
diff --git a/src/app/beforeConnexion/login/page-login/page-login.component.scss b/src/app/beforeConnexion/login/page-login/page-login.component.scss deleted file mode 100644 index 8924202..0000000 --- a/src/app/beforeConnexion/login/page-login/page-login.component.scss +++ /dev/null @@ -1,271 +0,0 @@ -html { - background-color: #56baed; -} - -body { - font-family: "Poppins", sans-serif; - height: 100vh; -} - -a { - color: #5E89FF; - display:inline-block; - text-decoration: none; - font-weight: 400; -} - -h2 { - text-align: center; - font-size: 16px; - font-weight: 600; - text-transform: uppercase; - display:inline-block; - margin: 40px 8px 10px 8px; - color: #cccccc; -} - - - -/* STRUCTURE */ - -.wrapper { - display: flex; - align-items: center; - flex-direction: column; - justify-content: center; - width: 100%; - min-height: 80%; - padding: 20px; -} - -#formContent { - -webkit-border-radius: 10px 10px 10px 10px; - border-radius: 10px 10px 10px 10px; - background: #fff; - padding: 30px; - width: 90%; - max-width: 450px; - position: relative; - padding: 0px; - -webkit-box-shadow: 0 30px 60px 0 rgba(0,0,0,0.3); - box-shadow: 0 30px 60px 0 rgba(0,0,0,0.3); - text-align: center; -} - -#formFooter { - background-color: #f6f6f6; - border-top: 1px solid #dce8f1; - padding: 25px; - text-align: center; - -webkit-border-radius: 0 0 10px 10px; - border-radius: 0 0 10px 10px; -} - - - -/* TABS */ - -h2.inactive { - color: #cccccc; -} - -h2.active { - color: #0d0d0d; - border-bottom: 2px solid #5fbae9; -} - - - -/* FORM TYPOGRAPHY*/ - -input[type=button], input[type=submit], input[type=reset] { - background-color: #5E89FF; - border: none; - color: white; - padding: 15px 80px; - text-align: center; - text-decoration: none; - display: inline-block; - text-transform: uppercase; - font-size: 13px; - -webkit-box-shadow: 0 10px 30px 0 rgba(95,186,233,0.4); - box-shadow: 0 10px 30px 0 rgba(95,186,233,0.4); - -webkit-border-radius: 5px 5px 5px 5px; - border-radius: 5px 5px 5px 5px; - margin: 5px 20px 40px 20px; - -webkit-transition: all 0.3s ease-in-out; - -moz-transition: all 0.3s ease-in-out; - -ms-transition: all 0.3s ease-in-out; - -o-transition: all 0.3s ease-in-out; - transition: all 0.3s ease-in-out; -} - -input[type=button]:hover, input[type=submit]:hover, input[type=reset]:hover { - background-color: #39ace7; -} - -input[type=button]:active, input[type=submit]:active, input[type=reset]:active { - -moz-transform: scale(0.95); - -webkit-transform: scale(0.95); - -o-transform: scale(0.95); - -ms-transform: scale(0.95); - transform: scale(0.95); -} - -input[type=text], input[type=password] { - background-color: #f6f6f6; - border: none; - color: #0d0d0d; - padding: 15px 32px; - text-align: center; - text-decoration: none; - display: inline-block; - font-size: 16px; - margin: 5px; - width: 85%; - border: 2px solid #f6f6f6; - -webkit-transition: all 0.5s ease-in-out; - -moz-transition: all 0.5s ease-in-out; - -ms-transition: all 0.5s ease-in-out; - -o-transition: all 0.5s ease-in-out; - transition: all 0.5s ease-in-out; - -webkit-border-radius: 5px 5px 5px 5px; - border-radius: 5px 5px 5px 5px; -} - - - -input[type=text]:focus, input[type=password]:focus { - background-color: #fff; - border-bottom: 2px solid #5fbae9; -} - -input[type=text]::placeholder, input[type=password]::placeholder { - color: #cccccc; -} - -.bg{ - margin: 0; - padding: 0; - height: 100vh; - width: 100vw; - overflow-y: hidden; - overflow-x: hidden; -} - -/* ANIMATIONS */ - -/* Simple CSS3 Fade-in-down Animation */ -.fadeInDown { - -webkit-animation-name: fadeInDown; - animation-name: fadeInDown; - -webkit-animation-duration: 1s; - animation-duration: 1s; - -webkit-animation-fill-mode: both; - animation-fill-mode: both; -} - -@-webkit-keyframes fadeInDown { - 0% { - opacity: 0; - -webkit-transform: translate3d(0, -100%, 0); - transform: translate3d(0, -100%, 0); - } - 100% { - opacity: 1; - -webkit-transform: none; - transform: none; - } -} - -@keyframes fadeInDown { - 0% { - opacity: 0; - -webkit-transform: translate3d(0, -100%, 0); - transform: translate3d(0, -100%, 0); - } - 100% { - opacity: 1; - -webkit-transform: none; - transform: none; - } -} - -/* Simple CSS3 Fade-in Animation */ -@-webkit-keyframes fadeIn { from { opacity:0; } to { opacity:1; } } -@-moz-keyframes fadeIn { from { opacity:0; } to { opacity:1; } } -@keyframes fadeIn { from { opacity:0; } to { opacity:1; } } - -.fadeIn { - opacity:0; - -webkit-animation:fadeIn ease-in 1; - -moz-animation:fadeIn ease-in 1; - animation:fadeIn ease-in 1; - - -webkit-animation-fill-mode:forwards; - -moz-animation-fill-mode:forwards; - animation-fill-mode:forwards; - - -webkit-animation-duration:1s; - -moz-animation-duration:1s; - animation-duration:1s; -} - -.fadeIn.first { - -webkit-animation-delay: 0.4s; - -moz-animation-delay: 0.4s; - animation-delay: 0.4s; -} - -.fadeIn.second { - -webkit-animation-delay: 0.6s; - -moz-animation-delay: 0.6s; - animation-delay: 0.6s; -} - -.fadeIn.third { - -webkit-animation-delay: 0.8s; - -moz-animation-delay: 0.8s; - animation-delay: 0.8s; -} - -.fadeIn.fourth { - -webkit-animation-delay: 1s; - -moz-animation-delay: 1s; - animation-delay: 1s; -} - -/* Simple CSS3 Fade-in Animation */ -.underlineHover:after { - display: block; - left: 0; - bottom: -10px; - width: 0; - height: 2px; - //background-color: #5E89FF; - background-color: #5E89FF; - content: ""; - transition: width 0.2s; -} - -.underlineHover:hover { - color: #0d0d0d; -} - -.underlineHover:hover:after{ - width: 100%; -} - -h1{ - color: black; -} - -/* OTHERS */ - -*:focus { - outline: none; -} - -#icon { - width:30%; -} diff --git a/src/app/beforeConnexion/login/page-login/page-login.component.spec.ts b/src/app/beforeConnexion/login/page-login/page-login.component.spec.ts deleted file mode 100644 index 5cb4241..0000000 --- a/src/app/beforeConnexion/login/page-login/page-login.component.spec.ts +++ /dev/null @@ -1,25 +0,0 @@ -import { ComponentFixture, TestBed } from '@angular/core/testing'; - -import { PageLoginComponent } from './page-login.component'; - -describe('PageConnexionComponent', () => { - let component: PageLoginComponent; - let fixture: ComponentFixture; - - beforeEach(async () => { - await TestBed.configureTestingModule({ - declarations: [ PageLoginComponent ] - }) - .compileComponents(); - }); - - beforeEach(() => { - fixture = TestBed.createComponent(PageLoginComponent); - component = fixture.componentInstance; - fixture.detectChanges(); - }); - - it('should create', () => { - expect(component).toBeTruthy(); - }); -}); diff --git a/src/app/beforeConnexion/login/page-login/page-login.component.ts b/src/app/beforeConnexion/login/page-login/page-login.component.ts deleted file mode 100644 index 6ee3e78..0000000 --- a/src/app/beforeConnexion/login/page-login/page-login.component.ts +++ /dev/null @@ -1,101 +0,0 @@ -import {Component, OnInit} from '@angular/core'; -import {MessageService} from "../../../utils/services/message/message.service"; -import {Router} from "@angular/router"; -import {ThemeService} from "../../../utils/services/theme/theme.service"; -import {MatDialog} from "@angular/material/dialog"; -import {PopupForgottenPasswordComponent} from "../popup-forgotten-password/popup-forgotten-password.component"; -import {MatSnackBar} from "@angular/material/snack-bar"; -import {ProfilService} from "../../../utils/services/profil/profil.service"; - - - -@Component({ - selector: 'app-page-login', - templateUrl: './page-login.component.html', - styleUrls: ['./page-login.component.scss'] -}) -export class PageLoginComponent implements OnInit -{ - email: string = "" ; - password: string = "" ; - hasError: boolean = false; - errorMessage: string = ""; - - - constructor( private messageService: MessageService, - private router: Router, - public themeService: ThemeService, - public dialog: MatDialog, - private snackBar: MatSnackBar, - private profilService: ProfilService) { } - - - ngOnInit(): void {} - - - onSeConnecter(): void - { - this.checkError(); - - if(!this.hasError) - { - let data = { - email: this.email, - hashPass: this.password - }; - this.messageService - .post('user/auth', data) - .subscribe( retour => this.onSeConnecterCallback(retour), err => this.onSeConnecterCallback(err)); - } - } - - - onSeConnecterCallback(retour): void - { - if(retour.status !== "success") { - console.log(retour); - this.errorMessage = retour.error.reason; - this.hasError = true; - } - else { - this.profilService.setId(retour.data.id); - this.profilService.setProfileImageUrl(retour.data.profileImageUrl); - if(retour.data.role.name === "user") this.router.navigateByUrl( '/user/search'); - else if(retour.data.role.name === "advertiser") this.router.navigateByUrl( '/advertiser/adList'); - else if(retour.data.role.name === "admin" || retour.data.role.name === "superAdmin") this.router.navigateByUrl( '/admin/userList'); - } - } - - - onForgottenPassword(): void - { - this.dialog - .open(PopupForgottenPasswordComponent, {width: '30%'}) - .afterClosed() - .subscribe(result => { - if((result !== null) && (result !== undefined)) - { - const config = { duration: 5000, panelClass: "custom-class" }; - this.snackBar.open( "Un mail de réinitialisation de mot de passe vous a été envoyé.", "", config); - } - }); - } - - - checkError(): void - { - if(this.email === "") { - this.errorMessage = "Veuillez remplir le champ email" ; - this.hasError = true; - } - else if(this.password === "") { - this.errorMessage = "Veuillez remplir le champ mot de passe" ; - this.hasError = true; - } - else { - this.errorMessage = "" ; - this.hasError = false; - } - } - -} diff --git a/src/app/beforeConnexion/login/popup-forgotten-password/popup-forgotten-password.component.html b/src/app/beforeConnexion/login/popup-forgotten-password/popup-forgotten-password.component.html deleted file mode 100644 index c34b58e..0000000 --- a/src/app/beforeConnexion/login/popup-forgotten-password/popup-forgotten-password.component.html +++ /dev/null @@ -1,24 +0,0 @@ -

Récupération du mot de passe

- -
- - -
- - Email - - -
- - -
- {{errorMessage}} -
- - - - - - - - diff --git a/src/app/beforeConnexion/login/popup-forgotten-password/popup-forgotten-password.component.scss b/src/app/beforeConnexion/login/popup-forgotten-password/popup-forgotten-password.component.scss deleted file mode 100644 index fa75013..0000000 --- a/src/app/beforeConnexion/login/popup-forgotten-password/popup-forgotten-password.component.scss +++ /dev/null @@ -1,12 +0,0 @@ -h4 { - text-align: center; -} - -.myDiv { - text-align: center; - font-size: small; -} - -.myError { - text-align: center; -} diff --git a/src/app/beforeConnexion/login/popup-forgotten-password/popup-forgotten-password.component.spec.ts b/src/app/beforeConnexion/login/popup-forgotten-password/popup-forgotten-password.component.spec.ts deleted file mode 100644 index ebf101c..0000000 --- a/src/app/beforeConnexion/login/popup-forgotten-password/popup-forgotten-password.component.spec.ts +++ /dev/null @@ -1,25 +0,0 @@ -import { ComponentFixture, TestBed } from '@angular/core/testing'; - -import { PopupForgottenPasswordComponent } from './popup-forgotten-password.component'; - -describe('PopupForgottenPasswordComponent', () => { - let component: PopupForgottenPasswordComponent; - let fixture: ComponentFixture; - - beforeEach(async () => { - await TestBed.configureTestingModule({ - declarations: [ PopupForgottenPasswordComponent ] - }) - .compileComponents(); - }); - - beforeEach(() => { - fixture = TestBed.createComponent(PopupForgottenPasswordComponent); - component = fixture.componentInstance; - fixture.detectChanges(); - }); - - it('should create', () => { - expect(component).toBeTruthy(); - }); -}); diff --git a/src/app/beforeConnexion/login/popup-forgotten-password/popup-forgotten-password.component.ts b/src/app/beforeConnexion/login/popup-forgotten-password/popup-forgotten-password.component.ts deleted file mode 100644 index 1ff70ce..0000000 --- a/src/app/beforeConnexion/login/popup-forgotten-password/popup-forgotten-password.component.ts +++ /dev/null @@ -1,47 +0,0 @@ -import { Component } from '@angular/core'; -import {MatDialogRef} from "@angular/material/dialog"; - - - -@Component({ - selector: 'app-popup-forgotten-password', - templateUrl: './popup-forgotten-password.component.html', - styleUrls: ['./popup-forgotten-password.component.scss'] -}) -export class PopupForgottenPasswordComponent -{ - email: string; - hasError: boolean = false; - errorMessage: string = ""; - - - constructor(public dialogRef: MatDialogRef) {} - - - // Click sur valider - onValidate() - { - if(this.email.length === 0) { - this.errorMessage = "Veuillez remplir le champ 'email'." ; - this.hasError = true; - } - else if(!this.isValidEmail(this.email)) { - this.errorMessage = "Email invalide." ; - this.hasError = true; - } - else { - this.errorMessage = "" ; - this.hasError = false; - this.dialogRef.close(true); - } - } - - - // Indique si email a bien le format d'un email - isValidEmail(email): boolean - { - 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); - } - -} diff --git a/src/app/beforeConnexion/register/input-interests-register/input-interests-register.component.html b/src/app/beforeConnexion/register/input-interests-register/input-interests-register.component.html deleted file mode 100644 index 2a7c484..0000000 --- a/src/app/beforeConnexion/register/input-interests-register/input-interests-register.component.html +++ /dev/null @@ -1,43 +0,0 @@ - - - - - Centres d'intérêt - - - - - - - {{interest}} - - - - - - - - - - - - {{interest}} - - - - - - diff --git a/src/app/beforeConnexion/register/input-interests-register/input-interests-register.component.scss b/src/app/beforeConnexion/register/input-interests-register/input-interests-register.component.scss deleted file mode 100644 index c7acb4b..0000000 --- a/src/app/beforeConnexion/register/input-interests-register/input-interests-register.component.scss +++ /dev/null @@ -1,3 +0,0 @@ -mat-form-field { - width: 100%; -} diff --git a/src/app/beforeConnexion/register/input-interests-register/input-interests-register.component.spec.ts b/src/app/beforeConnexion/register/input-interests-register/input-interests-register.component.spec.ts deleted file mode 100644 index 9917b1a..0000000 --- a/src/app/beforeConnexion/register/input-interests-register/input-interests-register.component.spec.ts +++ /dev/null @@ -1,25 +0,0 @@ -import { ComponentFixture, TestBed } from '@angular/core/testing'; - -import { InputInterestsRegisterComponent } from './input-interests-register.component'; - -describe('InputInterestsRegisterComponent', () => { - let component: InputInterestsRegisterComponent; - let fixture: ComponentFixture; - - beforeEach(async () => { - await TestBed.configureTestingModule({ - declarations: [ InputInterestsRegisterComponent ] - }) - .compileComponents(); - }); - - beforeEach(() => { - fixture = TestBed.createComponent(InputInterestsRegisterComponent); - component = fixture.componentInstance; - fixture.detectChanges(); - }); - - it('should create', () => { - expect(component).toBeTruthy(); - }); -}); diff --git a/src/app/beforeConnexion/register/input-interests-register/input-interests-register.component.ts b/src/app/beforeConnexion/register/input-interests-register/input-interests-register.component.ts deleted file mode 100644 index 537cf45..0000000 --- a/src/app/beforeConnexion/register/input-interests-register/input-interests-register.component.ts +++ /dev/null @@ -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 {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"; - - - -@Component({ - selector: 'app-input-interests-register', - templateUrl: './input-interests-register.component.html', - styleUrls: ['./input-interests-register.component.scss'] -}) -export class InputInterestsRegisterComponent implements OnInit -{ - selectable = true; - removable = true; - separatorKeysCodes: number[] = [ENTER, COMMA]; - formControl = new FormControl(); - filteredInterests: Observable; - @Input() myInterests: string[] = []; - allInterests: string[] = []; - @Output() eventEmitter = new EventEmitter(); - @ViewChild('tagInput') tagInput: ElementRef; - 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)); - } - -} diff --git a/src/app/beforeConnexion/register/page-register/page-register.component.html b/src/app/beforeConnexion/register/page-register/page-register.component.html deleted file mode 100644 index 4d7b629..0000000 --- a/src/app/beforeConnexion/register/page-register/page-register.component.html +++ /dev/null @@ -1,161 +0,0 @@ -
-
- - - - - - - - - -
- - - Utilisateur standard    - Annonceur - - - -
- -
-
-
- - - - -
- - - - -
- {{errorMessage}} -
- - -
- - -
-
-
- -
- -
-
- - - - - - - -
-
- - -
-

Compte

- - - - Pseudo - - -
- - - - Mot de passe - - -
- - - - Confirmation mot de passe - - -
- - -
-

Informations personelles

- - - - Email - - -
- - - - Homme     - Femme - -

- - - - Date de naissance - - - - - -
- -
-
- - - - - - - - - - - Entreprise - - -
- - - - Pseudo - - -
- - - - Email - - -
- - - - Mot de passe - - -
- - - - Confirmation mot de passe - - - -
diff --git a/src/app/beforeConnexion/register/page-register/page-register.component.scss b/src/app/beforeConnexion/register/page-register/page-register.component.scss deleted file mode 100644 index 5f0dc53..0000000 --- a/src/app/beforeConnexion/register/page-register/page-register.component.scss +++ /dev/null @@ -1,47 +0,0 @@ -.myContainer { - width: 100vw; - height: 100vh; -} - - -mat-stepper { - width: 60%; - margin: 10vh auto; - border: solid 1px black; - border-radius: 20px; -} - - -.leftCol { - border-right: solid 1px #dcdcdc; -} - - -.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; -} - - -// ------------------------------------------------------------------------- - - -::ng-deep .mat-radio-inner-circle { - color: black !important; - background-color: black !important; -} - -::ng-deep .mat-radio-outer-circle{ - color: black !important; - border: solid 1px gray !important; -} diff --git a/src/app/beforeConnexion/register/page-register/page-register.component.spec.ts b/src/app/beforeConnexion/register/page-register/page-register.component.spec.ts deleted file mode 100644 index 5cff194..0000000 --- a/src/app/beforeConnexion/register/page-register/page-register.component.spec.ts +++ /dev/null @@ -1,25 +0,0 @@ -import { ComponentFixture, TestBed } from '@angular/core/testing'; - -import { PageRegisterComponent } from './page-register.component'; - -describe('PageRegisterComponent', () => { - let component: PageRegisterComponent; - let fixture: ComponentFixture; - - beforeEach(async () => { - await TestBed.configureTestingModule({ - declarations: [ PageRegisterComponent ] - }) - .compileComponents(); - }); - - beforeEach(() => { - fixture = TestBed.createComponent(PageRegisterComponent); - component = fixture.componentInstance; - fixture.detectChanges(); - }); - - it('should create', () => { - expect(component).toBeTruthy(); - }); -}); diff --git a/src/app/beforeConnexion/register/page-register/page-register.component.ts b/src/app/beforeConnexion/register/page-register/page-register.component.ts deleted file mode 100644 index 833a656..0000000 --- a/src/app/beforeConnexion/register/page-register/page-register.component.ts +++ /dev/null @@ -1,135 +0,0 @@ -import { Component } from '@angular/core'; -import {MessageService} from "../../../utils/services/message/message.service"; -import {Router} from "@angular/router"; -import {MatDialog} from "@angular/material/dialog"; -import {PopupConfirmationComponent} from "../popup-confirmation/popup-confirmation.component"; -import {ThemeService} from "../../../utils/services/theme/theme.service"; -import {User} from "../../../utils/interfaces/user"; - - - -@Component({ - selector: 'app-page-register', - templateUrl: './page-register.component.html', - styleUrls: ['./page-register.component.scss'] -}) -export class PageRegisterComponent -{ - password: string = ""; - confirmPassword: string = ""; - hasError: boolean = false; - errorMessage: string = ""; - user: User = { - _id: "", - login: "", - hashPass: "", - email: "", - role: { - name: "user", - permission: 0, - isAccepted: false, - }, - profileImageUrl: "", - dateOfBirth: null, - gender: "man", - interests: [], - company: "", - isActive: true, - createdAt: new Date(), - updatedAt: new Date(), - lastConnexion: null - }; - - - constructor( private messageService: MessageService, - private router: Router, - public dialog: MatDialog, - public themeService: ThemeService ) { } - - - // Envoie de l'utilisateur au backend - onEnregistrer(): void - { - this.checkField(); - if(!this.hasError) - { - let data: any = Object.assign({}, this.user); - if(this.user.role.name === "user") data.role = "user" ; - else data.role = "advertiser"; - data.hashPass = this.password; - this.messageService - .post('user/create', data) - .subscribe(retour => this.onEnregistrerCallback(retour), err => this.onEnregistrerCallback(err)); - } - } - - - // Gestion de la réponse du backend - onEnregistrerCallback(retour): void - { - if(retour.status !== "success") { - console.log(retour); - } - else - { - const config = { - width: '25%', - data: {roleName: this.user.role.name} - }; - this.dialog - .open(PopupConfirmationComponent, config) - .afterClosed() - .subscribe(result => this.router.navigateByUrl( '/login' )); - } - } - - - // Check les champs saisies par l'utilisateur - checkField(): void - { - if((this.user.role.name === 'advertiser') && (this.user.company.length === 0)) { - this.errorMessage = "Veuillez remplir le champ 'entreprise'."; - this.hasError = true; - } - else if(this.user.login.length === 0) { - this.errorMessage = "Veuillez remplir le champ 'pseudo'."; - this.hasError = true; - } - else if(this.user.email.length === 0) { - this.errorMessage = "Veuillez remplir le champ 'email'."; - this.hasError = true; - } - else if(!this.isValidEmail(this.user.email)) { - this.errorMessage = "Email invalide."; - this.hasError = true; - } - else if(this.password.length === 0) { - this.errorMessage = "Veuillez remplir le champ 'mot de passe'."; - this.hasError = true; - } - else if(this.password !== this.confirmPassword) { - this.errorMessage = "Le mot de passe est différent de sa confirmation."; - this.hasError = true; - } - else { - this.errorMessage = "" ; - this.hasError = false; - } - } - - - // Indique si email a bien le format d'un email - isValidEmail(email): boolean - { - 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); - } - - - // Récupère la liste des centres d'intérets (car celle-ci est remplie à l'aide d'un component intermédiaire) - onEventInputInterests(myInterets: string[]): void - { - this.user.interests = myInterets; - } - -} diff --git a/src/app/beforeConnexion/register/popup-confirmation/popup-confirmation.component.html b/src/app/beforeConnexion/register/popup-confirmation/popup-confirmation.component.html deleted file mode 100644 index 1cd51fe..0000000 --- a/src/app/beforeConnexion/register/popup-confirmation/popup-confirmation.component.html +++ /dev/null @@ -1,11 +0,0 @@ -

- Votre inscription a bien été effectuée. -

- -

- Votre inscription est en cours de validation. -

- -
- -
diff --git a/src/app/beforeConnexion/register/popup-confirmation/popup-confirmation.component.scss b/src/app/beforeConnexion/register/popup-confirmation/popup-confirmation.component.scss deleted file mode 100644 index 85730e0..0000000 --- a/src/app/beforeConnexion/register/popup-confirmation/popup-confirmation.component.scss +++ /dev/null @@ -1,7 +0,0 @@ -p { - font-size: small; -} - -div { - font-size: small; -} diff --git a/src/app/beforeConnexion/register/popup-confirmation/popup-confirmation.component.spec.ts b/src/app/beforeConnexion/register/popup-confirmation/popup-confirmation.component.spec.ts deleted file mode 100644 index d6f9908..0000000 --- a/src/app/beforeConnexion/register/popup-confirmation/popup-confirmation.component.spec.ts +++ /dev/null @@ -1,25 +0,0 @@ -import { ComponentFixture, TestBed } from '@angular/core/testing'; - -import { PopupConfirmationComponent } from './popup-confirmation.component'; - -describe('PopupConfirmationComponent', () => { - let component: PopupConfirmationComponent; - let fixture: ComponentFixture; - - beforeEach(async () => { - await TestBed.configureTestingModule({ - declarations: [ PopupConfirmationComponent ] - }) - .compileComponents(); - }); - - beforeEach(() => { - fixture = TestBed.createComponent(PopupConfirmationComponent); - component = fixture.componentInstance; - fixture.detectChanges(); - }); - - it('should create', () => { - expect(component).toBeTruthy(); - }); -}); diff --git a/src/app/beforeConnexion/register/popup-confirmation/popup-confirmation.component.ts b/src/app/beforeConnexion/register/popup-confirmation/popup-confirmation.component.ts deleted file mode 100644 index 2152f9b..0000000 --- a/src/app/beforeConnexion/register/popup-confirmation/popup-confirmation.component.ts +++ /dev/null @@ -1,15 +0,0 @@ -import {Component, Inject} from '@angular/core'; -import {MAT_DIALOG_DATA, MatDialogRef} from "@angular/material/dialog"; - - - -@Component({ - selector: 'app-popup-confirmation', - templateUrl: './popup-confirmation.component.html', - styleUrls: ['./popup-confirmation.component.scss'] -}) -export class PopupConfirmationComponent -{ - constructor( public dialogRef: MatDialogRef, - @Inject(MAT_DIALOG_DATA) public data) {} -} diff --git a/src/app/beforeConnexion/utils/navbar-before-connexion/navbar-before-connexion.component.html b/src/app/beforeConnexion/utils/navbar-before-connexion/navbar-before-connexion.component.html deleted file mode 100644 index d4ad9f5..0000000 --- a/src/app/beforeConnexion/utils/navbar-before-connexion/navbar-before-connexion.component.html +++ /dev/null @@ -1,40 +0,0 @@ - -
- -
- - - - - - -
- -
diff --git a/src/app/beforeConnexion/utils/navbar-before-connexion/navbar-before-connexion.component.scss b/src/app/beforeConnexion/utils/navbar-before-connexion/navbar-before-connexion.component.scss deleted file mode 100644 index e1fefaa..0000000 --- a/src/app/beforeConnexion/utils/navbar-before-connexion/navbar-before-connexion.component.scss +++ /dev/null @@ -1,79 +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; -} - - -// Recherche, Mes Playlists, Historique -.nav-link { - color: white; -} -.nav-link:hover { - color: grey; -} - - -// Bonton deconnexion -.btnDeconnexion { - font-size: medium; - margin: 0px 10px 0px 10px -} -.btnDeconnexion:hover { - color: grey; -} - - -.monLi { - margin: 0px 10px 0px 10px; -} - - -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; -} diff --git a/src/app/beforeConnexion/utils/navbar-before-connexion/navbar-before-connexion.component.spec.ts b/src/app/beforeConnexion/utils/navbar-before-connexion/navbar-before-connexion.component.spec.ts deleted file mode 100644 index f3f7f27..0000000 --- a/src/app/beforeConnexion/utils/navbar-before-connexion/navbar-before-connexion.component.spec.ts +++ /dev/null @@ -1,25 +0,0 @@ -import { ComponentFixture, TestBed } from '@angular/core/testing'; - -import { NavbarBeforeConnexionComponent } from './navbar-before-connexion.component'; - -describe('NavbarBeforeConnexionComponent', () => { - let component: NavbarBeforeConnexionComponent; - let fixture: ComponentFixture; - - beforeEach(async () => { - await TestBed.configureTestingModule({ - declarations: [ NavbarBeforeConnexionComponent ] - }) - .compileComponents(); - }); - - beforeEach(() => { - fixture = TestBed.createComponent(NavbarBeforeConnexionComponent); - component = fixture.componentInstance; - fixture.detectChanges(); - }); - - it('should create', () => { - expect(component).toBeTruthy(); - }); -}); diff --git a/src/app/beforeConnexion/utils/navbar-before-connexion/navbar-before-connexion.component.ts b/src/app/beforeConnexion/utils/navbar-before-connexion/navbar-before-connexion.component.ts deleted file mode 100644 index 3085e5c..0000000 --- a/src/app/beforeConnexion/utils/navbar-before-connexion/navbar-before-connexion.component.ts +++ /dev/null @@ -1,12 +0,0 @@ -import {Component, Input} from '@angular/core'; - - -@Component({ - selector: 'app-navbar-before-connexion', - templateUrl: './navbar-before-connexion.component.html', - styleUrls: ['./navbar-before-connexion.component.scss'] -}) -export class NavbarBeforeConnexionComponent -{ - @Input() pour = "login"; -} diff --git a/src/app/user/history/page-history-user/page-history-user.component.html b/src/app/user/history/page-history-user/page-history-user.component.html deleted file mode 100644 index 97f7344..0000000 --- a/src/app/user/history/page-history-user/page-history-user.component.html +++ /dev/null @@ -1,70 +0,0 @@ -
-
- - -

- - - -
- -
-
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Aperçu -
- - -
-
Titre {{video.title}} Date - {{video.date | date:'dd/LL/YYYY à HH:mm:ss'}} - Source {{video.source}} Action - -
Aucune vidéo ne correspond au filtre: "{{input.value}}"
-
- -
-

- -
-
diff --git a/src/app/user/history/page-history-user/page-history-user.component.scss b/src/app/user/history/page-history-user/page-history-user.component.scss deleted file mode 100644 index bbd894d..0000000 --- a/src/app/user/history/page-history-user/page-history-user.component.scss +++ /dev/null @@ -1,46 +0,0 @@ -.myContainer { - max-width: 100vw; - height: 100vh; - overflow-x: hidden; -} - -table { - width: 80%; - margin: 0 auto; -} - - -th.mat-sort-header-sorted { - color: black; -} - - -input { - width: 35%; - font-size: large; -} - -// ------------------------------------------------------- - -.imgsContainer { - position: relative; - width: 20vw; - height: 15vh; - cursor: pointer; -} - -.imgPlay { - position: absolute; - margin-left: 9vw; - width: 3vw; - margin-top: 5vh; - height: 6vh; - padding: 0px 0px 0px 0px; -} - -.imgVideo { - border: solid 1px black; - width: 20vw; - height: 15vh; - padding: 0px 0px 0px 0px; -} diff --git a/src/app/user/history/page-history-user/page-history-user.component.spec.ts b/src/app/user/history/page-history-user/page-history-user.component.spec.ts deleted file mode 100644 index 9fd31c3..0000000 --- a/src/app/user/history/page-history-user/page-history-user.component.spec.ts +++ /dev/null @@ -1,25 +0,0 @@ -import { ComponentFixture, TestBed } from '@angular/core/testing'; - -import { PageHistoryUserComponent } from './page-history-user.component'; - -describe('PageHistoriqueComponent', () => { - let component: PageHistoryUserComponent; - let fixture: ComponentFixture; - - beforeEach(async () => { - await TestBed.configureTestingModule({ - declarations: [ PageHistoryUserComponent ] - }) - .compileComponents(); - }); - - beforeEach(() => { - fixture = TestBed.createComponent(PageHistoryUserComponent); - component = fixture.componentInstance; - fixture.detectChanges(); - }); - - it('should create', () => { - expect(component).toBeTruthy(); - }); -}); diff --git a/src/app/user/history/page-history-user/page-history-user.component.ts b/src/app/user/history/page-history-user/page-history-user.component.ts deleted file mode 100644 index 53ec37d..0000000 --- a/src/app/user/history/page-history-user/page-history-user.component.ts +++ /dev/null @@ -1,116 +0,0 @@ -import {AfterViewInit, Component, ViewChild} from '@angular/core'; -import {ThemeService} from "../../../utils/services/theme/theme.service"; -import {MessageService} from "../../../utils/services/message/message.service"; -import {MatTableDataSource} from "@angular/material/table"; -import {MatSort} from "@angular/material/sort"; -import {MatPaginator} from "@angular/material/paginator"; -import {FictitiousVideosService} from "../../../utils/services/fictitiousDatas/fictitiousVideos/fictitious-videos.service"; -import {VideoAll} from "../../../utils/interfaces/video"; -import {Router} from "@angular/router"; - - - -@Component({ - selector: 'app-page-history-user', - templateUrl: './page-history-user.component.html', - styleUrls: ['./page-history-user.component.scss'] -}) -export class PageHistoryUserComponent implements AfterViewInit -{ - displayedColumns: string[] = [ 'aperçu', 'title', 'date', 'source', 'action' ]; - dataSource ; - @ViewChild(MatSort) sort: MatSort; - @ViewChild(MatPaginator) paginator: MatPaginator; - - - constructor( public themeService: ThemeService, - private messageService: MessageService, - private fictitiousVideosService: FictitiousVideosService, - private router: Router ) { } - - - // charge la page - ngAfterViewInit(): void - { - this.messageService - .get("user/history") - .subscribe(ret => this.ngAfterViewInitCallback(ret), err => this.ngAfterViewInitCallback(err)); - } - - - ngAfterViewInitCallback(retour: any): void - { - if(retour.status !== "success") { - console.log(retour); - } - else { - const tabVideoHistory = retour.data.map( video => { - return { - _id: video._id, - videoId: video.videoId, - imageUrl: video.imageUrl, - title: video.title, - date: video.watchedDate, - source: video.source, - } - }); - this.dataSource = new MatTableDataSource(tabVideoHistory); - this.dataSource.sort = this.sort; - this.dataSource.paginator = this.paginator; - this.dataSource = this.dataSource; - } - } - - - // Applique le filtre - applyFilter(event: Event): void - { - const filterValue = (event.target as HTMLInputElement).value; - this.dataSource.filter = filterValue.trim().toLowerCase(); - } - - - // Supprime la video - onDelete(video: any): void - { - this.messageService - .put("video/update/"+video._id, { watchedDates: []}) - .subscribe(ret => this.onDeleteCallback(ret, video), err => this.onDeleteCallback(err, video)) - } - - - onDeleteCallback(retour: any, video: any): void - { - if(retour.status !== "success") { - console.log(retour); - } - else { - const index = this.dataSource.data.indexOf(video); - this.dataSource.data.splice(index, 1); - this.dataSource.data = this.dataSource.data; - this.dataSource = this.dataSource; - } - } - - - onVideo(video: VideoAll): void - { - this.messageService - .put("video/update/"+video._id, {watchedDate: true}) - .subscribe(ret => this.onVideoCallback(ret), err => this.onVideoCallback(err)); - - const params = { - videoId: video.videoId, - source: video.source, - from: "history", - }; - this.router.navigate(['/user/watching'], { queryParams: params }); - } - - - onVideoCallback(retour: any): void - { - if(retour.status !== "success") console.log(retour); - } - -} diff --git a/src/app/user/myPlaylists/page-my-playlists/page-my-playlists.component.html b/src/app/user/myPlaylists/page-my-playlists/page-my-playlists.component.html deleted file mode 100644 index c92a060..0000000 --- a/src/app/user/myPlaylists/page-my-playlists/page-my-playlists.component.html +++ /dev/null @@ -1,35 +0,0 @@ -
-
- - -
- -
-
- - - - - - - - - - - - - - - - - - -
- -
-
- -
- -
-
diff --git a/src/app/user/myPlaylists/page-my-playlists/page-my-playlists.component.scss b/src/app/user/myPlaylists/page-my-playlists/page-my-playlists.component.scss deleted file mode 100644 index fad665f..0000000 --- a/src/app/user/myPlaylists/page-my-playlists/page-my-playlists.component.scss +++ /dev/null @@ -1,48 +0,0 @@ -.lightTheme { - border-color: black; -} -.darkTheme { - border-color: white; -} -.myContainer { - text-align: center; - max-width: 100vw; - height: 100vh; - overflow-x: hidden; -} - -// Liste des vidéos ------------------------------------------------- - -.celluleListeVideo { - margin: 0px 0px 0px 0px; -} - -// Liste des playlists --------------------------------------------- - -.celluleListePlaylist { - margin: 0px 0px 0px 0px; -} - -// Pub ------------------------------------------------------------- - -.cellulePub { - padding: 0px 10px 0px 10px; - width: 100%; - text-align: center; - justify-content: center; -} - -.conteneurPub { - //height: 85vh; - text-align: center; - justify-content: center; - vertical-align: middle; - display: block; - width: 75%; - margin-left: auto; - margin-right: auto; - position: absolute; - top: 50%; - -ms-transform: translateY(-50%); - transform: translateY(-50%); -} diff --git a/src/app/user/myPlaylists/page-my-playlists/page-my-playlists.component.spec.ts b/src/app/user/myPlaylists/page-my-playlists/page-my-playlists.component.spec.ts deleted file mode 100644 index 2dba23b..0000000 --- a/src/app/user/myPlaylists/page-my-playlists/page-my-playlists.component.spec.ts +++ /dev/null @@ -1,25 +0,0 @@ -import { ComponentFixture, TestBed } from '@angular/core/testing'; - -import { PageMyPlaylistsComponent } from './page-my-playlists.component'; - -describe('PageMesPlaylistsComponent', () => { - let component: PageMyPlaylistsComponent; - let fixture: ComponentFixture; - - beforeEach(async () => { - await TestBed.configureTestingModule({ - declarations: [ PageMyPlaylistsComponent ] - }) - .compileComponents(); - }); - - beforeEach(() => { - fixture = TestBed.createComponent(PageMyPlaylistsComponent); - component = fixture.componentInstance; - fixture.detectChanges(); - }); - - it('should create', () => { - expect(component).toBeTruthy(); - }); -}); diff --git a/src/app/user/myPlaylists/page-my-playlists/page-my-playlists.component.ts b/src/app/user/myPlaylists/page-my-playlists/page-my-playlists.component.ts deleted file mode 100644 index 877dde8..0000000 --- a/src/app/user/myPlaylists/page-my-playlists/page-my-playlists.component.ts +++ /dev/null @@ -1,69 +0,0 @@ -import { Component, OnInit } from '@angular/core'; -import {ThemeService} from "../../../utils/services/theme/theme.service"; -import {Advert} from "../../../utils/interfaces/advert"; -import {MessageService} from "../../../utils/services/message/message.service"; -import {HttpParams} from "@angular/common/http"; - - - -@Component({ - selector: 'app-page-my-playlists', - templateUrl: './page-my-playlists.component.html', - styleUrls: ['./page-my-playlists.component.scss'] -}) -export class PageMyPlaylistsComponent implements OnInit -{ - ad: Advert; // pub - playlist: any; // la playlist sélectionnée - - - constructor( public themeService: ThemeService, - private messageService: MessageService ) { } - - - ngOnInit(): void - { - let params = new HttpParams(); - params = params.append("quantity", 1); - this.messageService - .get("user/ad", params) - .subscribe(ret => this.adCallback(ret), err => this.adCallback(err)); - } - - - adCallback(retour: any): void - { - if(retour.status !== "success") { - console.log(retour); - } - else { - this.ad = retour.data[0]; - } - } - - - transmitPlaylistToVideoList(playlist): void - { - if ((playlist === null) || (playlist === undefined)) { - this.playlist = playlist; - } - else { - this.messageService - .get("playlist/findOne/" + playlist.id) - .subscribe(ret => this.afterReceivingPlaylistWithVideo(ret, playlist), err => this.afterReceivingPlaylistWithVideo(err, playlist)); - } - } - - - afterReceivingPlaylistWithVideo(retour: any, playlist): void - { - if(retour.status !== "success") { - console.log(retour); - this.playlist = playlist; - } - else { - this.playlist = retour.data; - } - } - -} diff --git a/src/app/user/myPlaylists/playlist-list/playlist-list.component.html b/src/app/user/myPlaylists/playlist-list/playlist-list.component.html deleted file mode 100644 index 2185a77..0000000 --- a/src/app/user/myPlaylists/playlist-list/playlist-list.component.html +++ /dev/null @@ -1,48 +0,0 @@ -
-
- - -
-
- -
-
- - - - -
-
-
- -
-
- -
-
- {{playlist.name}}
- {{playlist.videoIds.length}} vidéo - {{playlist.videoIds.length}} vidéos -
-
- -
-
- -
-
-
- - - - -
- -
- -
-
diff --git a/src/app/user/myPlaylists/playlist-list/playlist-list.component.scss b/src/app/user/myPlaylists/playlist-list/playlist-list.component.scss deleted file mode 100644 index 0376ee3..0000000 --- a/src/app/user/myPlaylists/playlist-list/playlist-list.component.scss +++ /dev/null @@ -1,94 +0,0 @@ -.myContainer { - background-color: white ; - text-align: center; - width: 35vw; - margin: 1vh 0vh 3vh 0vh; - padding: 0px; - border: solid 2px black; - border-radius: 10px; - box-shadow: 10px 5px 5px black; -} - -// SearchBar ----------------------------------------------------------- - -.searchBarContainer { - text-align: center; - margin: 0px 0px 0px 0px; - padding: 10px 0px 10px 0px; - //background-color: #dcdcdc; - background: linear-gradient(top, rgba(38,38,38,0.8), #e6e6e6 25%, #fff 38%, #c5c5c5 87%, rgba(38,38,38,0.8)); - background: -webkit-linear-gradient(top, #c5c5c5, #e6e6e6 25%, #fff 38%, #c5c5c5 87%, #c5c5c5); - font-size: large; - border-bottom: solid 1px black; - border-top-left-radius: 10px; - border-top-right-radius: 10px; -} - -.inputSearchBar { - width: 70%; - border-radius: 5px; -} - - -// Liste des playlists ------------------------------------------------- - -.playlistListContainer { - max-width: 100%; - height: 60vh; - overflow-y: scroll; - padding: 0px; - overflow-x: hidden; -} - -.playlistContainer { - max-width: 100%; - padding: 0px; - overflow-x: hidden; -} - - -.btnPlaylist { - background-color: white; - padding: 20px; - border-bottom: solid 1px black; - //width: 100%; - width: 35vw; - overflow-x: hidden; -} -.btnPlaylist:hover { - background-color: #f0f0f0; -} - -.btnPlaylistFocus { - background-color: #e6e6e6; -} -.btnPlaylistFocus:hover { - background-color: #e6e6e6; -} - - -.playListCount { - color: gray; - font-style: italic; -} - -// Bouton creer playlist ------------------------------------------------- - -.btnCreerPlaylistContainer { - margin: 0px 0px 0px 0px; - background-color: #dcdcdc; - font-size: large; - border-top: solid 1px black; - border-bottom-left-radius: 10px; - border-bottom-right-radius: 10px; -} - -.btnCreerPlaylist { - margin: 0px 0px 0px 0px; - border-bottom-left-radius: 10px; - border-bottom-right-radius: 10px; - background: linear-gradient(top, rgba(38,38,38,0.8), #e6e6e6 25%, #fff 38%, #c5c5c5 87%, rgba(38,38,38,0.8)); - background: -webkit-linear-gradient(top, #c5c5c5, #e6e6e6 25%, #fff 38%, #c5c5c5 87%, #c5c5c5); - //background: linear-gradient(180deg, #e6e6e6 0%, rgba(0,0,0,0.25) 49%, rgba(38,38,38,0.6) 51%, rgba(0,0,0,0.25) 100%); -} - diff --git a/src/app/user/myPlaylists/playlist-list/playlist-list.component.spec.ts b/src/app/user/myPlaylists/playlist-list/playlist-list.component.spec.ts deleted file mode 100644 index 9308f2c..0000000 --- a/src/app/user/myPlaylists/playlist-list/playlist-list.component.spec.ts +++ /dev/null @@ -1,25 +0,0 @@ -import { ComponentFixture, TestBed } from '@angular/core/testing'; - -import { PlaylistListComponent } from './playlist-list.component'; - -describe('PlaylistListComponent', () => { - let component: PlaylistListComponent; - let fixture: ComponentFixture; - - beforeEach(async () => { - await TestBed.configureTestingModule({ - declarations: [ PlaylistListComponent ] - }) - .compileComponents(); - }); - - beforeEach(() => { - fixture = TestBed.createComponent(PlaylistListComponent); - component = fixture.componentInstance; - fixture.detectChanges(); - }); - - it('should create', () => { - expect(component).toBeTruthy(); - }); -}); diff --git a/src/app/user/myPlaylists/playlist-list/playlist-list.component.ts b/src/app/user/myPlaylists/playlist-list/playlist-list.component.ts deleted file mode 100644 index f97fa1e..0000000 --- a/src/app/user/myPlaylists/playlist-list/playlist-list.component.ts +++ /dev/null @@ -1,164 +0,0 @@ -import {Component, EventEmitter, Input, OnInit, Output} from '@angular/core'; -import {ThemeService} from "../../../utils/services/theme/theme.service"; -import {PlaylistDB} from "../../../utils/interfaces/playlist"; -import {MatDialog} from "@angular/material/dialog"; -import {MatSnackBar} from "@angular/material/snack-bar"; -import {PopupCreateOrUpdatePlaylistComponent} from "../popup-create-or-update-playlist/popup-create-or-update-playlist.component"; -import {FictitiousVideosService} from "../../../utils/services/fictitiousDatas/fictitiousVideos/fictitious-videos.service"; -import {PopupDeletePlaylistComponent} from "../popup-delete-playlist/popup-delete-playlist.component"; -import {MessageService} from "../../../utils/services/message/message.service"; - - - -@Component({ - selector: 'app-playlist-list', - templateUrl: './playlist-list.component.html', - styleUrls: ['./playlist-list.component.scss'] -}) -export class PlaylistListComponent implements OnInit -{ - allPlaylists: PlaylistDB[] = []; // toutes les playlists - @Output() eventEmitter = new EventEmitter(); // pour envoyer au parent la playlist selectionner - search: string = "" ; // contenu de la barre de recherche - tabPlaylist: PlaylistDB[] = []; // playlist affichées - playlistFocusedOn: PlaylistDB; - - - constructor( public themeService: ThemeService, - public dialog: MatDialog, - public snackBar: MatSnackBar, - private fictitiousVideosService: FictitiousVideosService, - private messageService: MessageService ) { } - - - ngOnInit(): void - { - this.messageService - .get("playlist/findAll") - .subscribe( retour => this.ngOnInitCallback(retour), err => this.ngOnInitCallback(err) ); - } - - - ngOnInitCallback(retour: any): void - { - if(retour.status !== "success") { - console.log(retour); - } else { - const aux = retour.data.filter( x => x.isActive === true); - this.allPlaylists = aux.map(x => { - x["_id"] = x.id ; - return x; - }); - this.tabPlaylist = [].concat(this.allPlaylists); - } - } - - - // s'execute lorsqu'on écrit sur la barre de recherche - whileSearch() - { - this.tabPlaylist = []; - for(let playlist of this.allPlaylists) - { - if(playlist.name.includes(this.search)) this.tabPlaylist.push(playlist); - } - } - - - // click sur créer playlist - onCreatePlaylist(): void - { - const config = { - data: { - action: "create", - tabPlaylist: this.tabPlaylist, - } - }; - this.dialog - .open(PopupCreateOrUpdatePlaylistComponent, config ) - .afterClosed() - .subscribe(playlist => { - - const config = { duration: 1500, panelClass: "custom-class" }; - if((playlist === null) || (playlist === undefined)) { - this.snackBar.open("Opération annulée", "", config); - } - else { - playlist["_id"] = playlist.id; - this.allPlaylists.push(playlist); - this.tabPlaylist.push(playlist); - this.snackBar.open(`La playlist '${playlist.name}' a bien été créée ✔`, "", config); - } - }); - } - - - // click sur update playlist - onUpdatePlaylist(playlistToUpdate: PlaylistDB): void - { - const config = { - data: { - action: "update", - tabPlaylist: this.tabPlaylist, - playlistName: playlistToUpdate.name, - playlistId: playlistToUpdate._id - } - }; - this.dialog - .open(PopupCreateOrUpdatePlaylistComponent, config) - .afterClosed() - .subscribe(newName => { - - const config = { duration: 1500, panelClass: "custom-class" }; - if((newName === null) || (newName === undefined)) { - this.snackBar.open("Opération annulée", "", config); - } - else { - let index = this.allPlaylists.findIndex( elt => (elt._id === playlistToUpdate._id)); - this.allPlaylists[index].name = newName; - index = this.tabPlaylist.findIndex( elt => (elt._id === playlistToUpdate._id)); - this.tabPlaylist[index].name = newName; - this.snackBar.open(`La playlist '${playlistToUpdate.name}' a bien été mise à jour ✔`, "", config); - this.eventEmitter.emit(this.tabPlaylist[index]); - this.playlistFocusedOn = this.tabPlaylist[index] - } - }); - } - - - // click sur supprimer playlist - onDeletePlaylist(playlist: PlaylistDB): void - { - const config = {data: playlist}; - this.dialog - .open(PopupDeletePlaylistComponent, config) - .afterClosed() - .subscribe(retour => { - - const config = { duration: 1500, panelClass: "custom-class" }; - if((retour === null) || (retour === undefined)) { - this.snackBar.open("Opération annulée", "", config); - } - else { - let index = this.allPlaylists.indexOf(playlist); - if(index >= 0) this.allPlaylists.splice(index, 1); - - index = this.tabPlaylist.indexOf(playlist); - if(index >= 0) this.tabPlaylist.splice(index, 1); - - this.eventEmitter.emit(null); - this.playlistFocusedOn = null; - this.snackBar.open(`La playlist '${playlist.name}' a bien été suprimée ✔`, "", config); - } - }); - } - - - // retourne la class CSS de conteneur de playlist - getClassOfPlaylistContainer(playlist: PlaylistDB): string - { - if(playlist === this.playlistFocusedOn) return "row btnPlaylist btnPlaylistFocus" ; - else return "row btnPlaylist" ; - } - -} diff --git a/src/app/user/myPlaylists/popup-create-or-update-playlist/popup-create-or-update-playlist.component.html b/src/app/user/myPlaylists/popup-create-or-update-playlist/popup-create-or-update-playlist.component.html deleted file mode 100644 index d88fa34..0000000 --- a/src/app/user/myPlaylists/popup-create-or-update-playlist/popup-create-or-update-playlist.component.html +++ /dev/null @@ -1,19 +0,0 @@ -
- -
- - Nom de la playlist - - - {{errorMessage}} -
- -
- - -
- -
diff --git a/src/app/user/myPlaylists/popup-create-or-update-playlist/popup-create-or-update-playlist.component.scss b/src/app/user/myPlaylists/popup-create-or-update-playlist/popup-create-or-update-playlist.component.scss deleted file mode 100644 index e69de29..0000000 diff --git a/src/app/user/myPlaylists/popup-create-or-update-playlist/popup-create-or-update-playlist.component.spec.ts b/src/app/user/myPlaylists/popup-create-or-update-playlist/popup-create-or-update-playlist.component.spec.ts deleted file mode 100644 index 640bdbc..0000000 --- a/src/app/user/myPlaylists/popup-create-or-update-playlist/popup-create-or-update-playlist.component.spec.ts +++ /dev/null @@ -1,25 +0,0 @@ -import { ComponentFixture, TestBed } from '@angular/core/testing'; - -import { PopupCreateOrUpdatePlaylistComponent } from './popup-create-or-update-playlist.component'; - -describe('PopupCreatePlaylistComponent', () => { - let component: PopupCreateOrUpdatePlaylistComponent; - let fixture: ComponentFixture; - - beforeEach(async () => { - await TestBed.configureTestingModule({ - declarations: [ PopupCreateOrUpdatePlaylistComponent ] - }) - .compileComponents(); - }); - - beforeEach(() => { - fixture = TestBed.createComponent(PopupCreateOrUpdatePlaylistComponent); - component = fixture.componentInstance; - fixture.detectChanges(); - }); - - it('should create', () => { - expect(component).toBeTruthy(); - }); -}); diff --git a/src/app/user/myPlaylists/popup-create-or-update-playlist/popup-create-or-update-playlist.component.ts b/src/app/user/myPlaylists/popup-create-or-update-playlist/popup-create-or-update-playlist.component.ts deleted file mode 100644 index a6ce4b6..0000000 --- a/src/app/user/myPlaylists/popup-create-or-update-playlist/popup-create-or-update-playlist.component.ts +++ /dev/null @@ -1,92 +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"; -import {PlaylistDB} from "../../../utils/interfaces/playlist"; - - - -@Component({ - selector: 'app-popup-create-or-update-playlist', - templateUrl: './popup-create-or-update-playlist.component.html', - styleUrls: ['./popup-create-or-update-playlist.component.scss'] -}) -export class PopupCreateOrUpdatePlaylistComponent implements OnInit -{ - name: string = "" ; - hasError: boolean = false; - tabNomPlaylist: string[] = []; - errorMessage: string = "" ; - action: string = ""; - - - - constructor( public dialogRef: MatDialogRef, - @Inject(MAT_DIALOG_DATA) public data, - private messageService: MessageService) { } - - - ngOnInit(): void - { - this.action = this.data.action; - this.tabNomPlaylist = this.data.tabPlaylist.map( playlist0 => playlist0.name ); - if(this.action === "update") this.name = this.data.playlistName; - } - - - onValider(): void - { - this.checkError(); - if(!this.hasError) - { - if(this.action === "create") - { - this.messageService - .post("playlist/create", {name: this.name}) - .subscribe(retour => this.onValiderCallback(retour), err => this.onValiderCallback(err)); - } - else if(this.action === "update") - { - this.messageService - .put("playlist/update/"+this.data.playlistId, {name: this.name}) - .subscribe(retour => this.onValiderCallback(retour), err => this.onValiderCallback(err)); - } - } - } - - - onValiderCallback(retour): void - { - if(retour.status !== "success") { - console.log(retour); - this.dialogRef.close(null); - } - else { - if(this.action === "create") this.dialogRef.close(retour.data); - else if(this.action === "update") this.dialogRef.close(this.name); - } - } - - - checkError(): void - { - if(this.name === "") { - this.errorMessage = "Le nom ne peut pas être vide" ; - this.hasError = true; - } - else if(this.tabNomPlaylist.includes(this.name)){ - this.errorMessage = "Ce nom est déjà utilisé" ; - this.hasError = true; - } - else { - this.hasError = false; - this.errorMessage = "" ; - } - } - - - onAnnuler(): void - { - this.dialogRef.close(null); - } - -} diff --git a/src/app/user/myPlaylists/popup-delete-playlist/popup-delete-playlist.component.html b/src/app/user/myPlaylists/popup-delete-playlist/popup-delete-playlist.component.html deleted file mode 100644 index 0335139..0000000 --- a/src/app/user/myPlaylists/popup-delete-playlist/popup-delete-playlist.component.html +++ /dev/null @@ -1,8 +0,0 @@ - - Êtes-vous sûr de vouloir supprimer {{playlist.name}} ? - - - - - - diff --git a/src/app/user/myPlaylists/popup-delete-playlist/popup-delete-playlist.component.scss b/src/app/user/myPlaylists/popup-delete-playlist/popup-delete-playlist.component.scss deleted file mode 100644 index e69de29..0000000 diff --git a/src/app/user/myPlaylists/popup-delete-playlist/popup-delete-playlist.component.spec.ts b/src/app/user/myPlaylists/popup-delete-playlist/popup-delete-playlist.component.spec.ts deleted file mode 100644 index 83d1cf7..0000000 --- a/src/app/user/myPlaylists/popup-delete-playlist/popup-delete-playlist.component.spec.ts +++ /dev/null @@ -1,25 +0,0 @@ -import { ComponentFixture, TestBed } from '@angular/core/testing'; - -import { PopupDeletePlaylistComponent } from './popup-delete-playlist.component'; - -describe('PopupDeletePlaylistComponent', () => { - let component: PopupDeletePlaylistComponent; - let fixture: ComponentFixture; - - beforeEach(async () => { - await TestBed.configureTestingModule({ - declarations: [ PopupDeletePlaylistComponent ] - }) - .compileComponents(); - }); - - beforeEach(() => { - fixture = TestBed.createComponent(PopupDeletePlaylistComponent); - component = fixture.componentInstance; - fixture.detectChanges(); - }); - - it('should create', () => { - expect(component).toBeTruthy(); - }); -}); diff --git a/src/app/user/myPlaylists/popup-delete-playlist/popup-delete-playlist.component.ts b/src/app/user/myPlaylists/popup-delete-playlist/popup-delete-playlist.component.ts deleted file mode 100644 index 2cc06ec..0000000 --- a/src/app/user/myPlaylists/popup-delete-playlist/popup-delete-playlist.component.ts +++ /dev/null @@ -1,41 +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-playlist', - templateUrl: './popup-delete-playlist.component.html', - styleUrls: ['./popup-delete-playlist.component.scss'] -}) -export class PopupDeletePlaylistComponent implements OnInit -{ - playlist; - - constructor( public dialogRef: MatDialogRef, - @Inject(MAT_DIALOG_DATA) public data, - private messageService: MessageService ) { } - - ngOnInit(): void - { - this.playlist = this.data; - } - - onValidate(): void - { - this.messageService - .delete("playlist/delete/"+this.playlist._id) - .subscribe( retour => this.onValidateCallback(retour), err => this.onValidateCallback(err)); - } - - onValidateCallback(retour: any): void - { - if(retour.status !== "success") { - console.log(retour); - this.dialogRef.close(null); - } - else { - this.dialogRef.close(true); - } - } - -} diff --git a/src/app/user/myPlaylists/video-list/video-list.component.html b/src/app/user/myPlaylists/video-list/video-list.component.html deleted file mode 100644 index 1954fee..0000000 --- a/src/app/user/myPlaylists/video-list/video-list.component.html +++ /dev/null @@ -1,91 +0,0 @@ -
-
- - -
- - -
- - - - {{playlist.name}} - - - - - Aucune playlist selectionnée - - -
- - - - - - -
-
- - -
- - - -
- - - - - - - - - - -
-
- - -
-
-
- - - - - - -
- - - - {{video.title}} - - -
-
- - - -
-
- -
-
- - - - - - -
-
a
-
- -
-
diff --git a/src/app/user/myPlaylists/video-list/video-list.component.scss b/src/app/user/myPlaylists/video-list/video-list.component.scss deleted file mode 100644 index e3af7ce..0000000 --- a/src/app/user/myPlaylists/video-list/video-list.component.scss +++ /dev/null @@ -1,83 +0,0 @@ -.myContainer { - //background-color: white ; - background: linear-gradient(top, rgba(38,38,38,0.8), #e6e6e6 25%, #fff 38%, #c5c5c5 87%, rgba(38,38,38,0.8)); - background: -webkit-linear-gradient(top, #c5c5c5, #e6e6e6 25%, #fff 38%, #c5c5c5 87%, #c5c5c5); - text-align: center; - width: 35vw; - margin: 1vh 0vh 3vh 0vh; - padding: 0px; - border: solid 2px black; - border-radius: 10px; - box-shadow: 10px 5px 5px black; -} - -// TopBorder -------------------------------------------------------- - -.topBorder { - margin: 0px 0px 0px 0px; - //background-color: #dcdcdc; - background: linear-gradient(top, rgba(38,38,38,0.8), #e6e6e6 25%, #fff 38%, #c5c5c5 87%, rgba(38,38,38,0.8)); - background: -webkit-linear-gradient(top, #c5c5c5, #e6e6e6 25%, #fff 38%, #c5c5c5 87%, #c5c5c5); - text-align: left; - padding: 5px 0px 5px 5px; - border-bottom: solid 1px black; - border-top-left-radius: 10px; - border-top-right-radius: 10px; -} - -.spanPlayListTitle { - font-size: large; - font-weight: bold; -} - -// Liste des videos ------------------------------------------------ - -.listVideoContainer { - height: 65vh; - background-color: white; - padding: 0px; - overflow-y: scroll; -} - -.videoContainer { - border-bottom: solid 1px black; - padding: 15px 0px 15px 0px; - width: 100%; -} - -.imgsContainer { - position: relative; - width: 20vw; - height: 15vh; - cursor: pointer; -} - -.imgPlay { - position: absolute; - margin-left: 9vw; - width: 3vw; - margin-top: 5vh; - height: 6vh; - padding: 0px 0px 0px 0px; -} - -.imgVideo { - border: solid 1px black; - width: 20vw; - height: 15vh; - padding: 0px 0px 0px 0px; -} - -// BottomBorder -------------------------------------------------------- - -.bottomBorder { - margin: 0px 0px 0px 0px; - //background-color: #dcdcdc; - background: linear-gradient(top, rgba(38,38,38,0.8), #e6e6e6 25%, #fff 38%, #c5c5c5 87%, rgba(38,38,38,0.8)); - background: -webkit-linear-gradient(top, #c5c5c5, #e6e6e6 25%, #fff 38%, #c5c5c5 87%, #c5c5c5); - border-top: solid 1px black; - border-bottom: solid 1px black; - font-size: large; - border-bottom-left-radius: 10px; - border-bottom-right-radius: 10px; -} diff --git a/src/app/user/myPlaylists/video-list/video-list.component.spec.ts b/src/app/user/myPlaylists/video-list/video-list.component.spec.ts deleted file mode 100644 index 403cc76..0000000 --- a/src/app/user/myPlaylists/video-list/video-list.component.spec.ts +++ /dev/null @@ -1,25 +0,0 @@ -import { ComponentFixture, TestBed } from '@angular/core/testing'; - -import { VideoListComponent } from './video-list.component'; - -describe('VideoListComponent', () => { - let component: VideoListComponent; - let fixture: ComponentFixture; - - beforeEach(async () => { - await TestBed.configureTestingModule({ - declarations: [ VideoListComponent ] - }) - .compileComponents(); - }); - - beforeEach(() => { - fixture = TestBed.createComponent(VideoListComponent); - component = fixture.componentInstance; - fixture.detectChanges(); - }); - - it('should create', () => { - expect(component).toBeTruthy(); - }); -}); diff --git a/src/app/user/myPlaylists/video-list/video-list.component.ts b/src/app/user/myPlaylists/video-list/video-list.component.ts deleted file mode 100644 index 0919e1a..0000000 --- a/src/app/user/myPlaylists/video-list/video-list.component.ts +++ /dev/null @@ -1,92 +0,0 @@ -import {Component, Input, OnChanges, SimpleChanges} from '@angular/core'; -import {ThemeService} from "../../../utils/services/theme/theme.service"; -import {AddVideoToPlaylistsService} from "../../utils/services/addVideoToPlaylists/add-video-to-playlists.service"; -import {MessageService} from "../../../utils/services/message/message.service"; -import {MatSnackBar} from "@angular/material/snack-bar"; -import {Router} from "@angular/router"; -import {ProfilService} from "../../../utils/services/profil/profil.service"; - - - -@Component({ - selector: 'app-video-list', - templateUrl: './video-list.component.html', - styleUrls: ['./video-list.component.scss'] -}) -export class VideoListComponent implements OnChanges -{ - @Input() playlist: any; - videosInPlaylist: any[] = []; - - - constructor( private messageService: MessageService, - public themeService: ThemeService, - private addVideoToPlaylistsService: AddVideoToPlaylistsService, - private snackBar: MatSnackBar, - private profilService: ProfilService, - private router: Router ) { } - - - ngOnChanges(changes: SimpleChanges): void - { - if((this.playlist !== null) && (this.playlist !== undefined)) this.videosInPlaylist = this.playlist.videos; - } - - - onAddToPlaylist(video: any): void - { - this.addVideoToPlaylistsService.run(video.videoId, video.source, video.interest); - } - - - onDelete(video0: any, indexVideo: number): void - { - const data = { - videoId: { - id: video0._id, - action: "delete" - } - } - this.messageService - .put("playlist/update/"+this.playlist._id, data) - .subscribe( ret => this.onDeleteCallback(ret, indexVideo), err => this.onDeleteCallback(err, indexVideo)); - } - - - onDeleteCallback(retour: any, indexVideo: number): void - { - if(retour.status !== "success") { - console.log(retour); - } - else { - this.playlist.videos.splice(indexVideo, 1); - this.videosInPlaylist.splice(indexVideo, 1); - let message = "La video a bien été supprimé de la playlist"; - const config = { duration: 1000, panelClass: "custom-class" }; - this.snackBar.open( message, "", config); - } - } - - - onVideo(video: any): void - { - this.messageService - .put("video/update/"+video._id, {watchedDate: true}) - .subscribe(ret => this.onVideoCallback(ret), err => this.onVideoCallback(err)); - - const params = { - videoId: video.videoId, - source: video.source, - _idPlaylist: this.playlist._id, - from: "myPlaylists", - }; - this.router.navigate(['/user/watching'], { queryParams: params }); - } - - - onVideoCallback(retour: any): void - { - if(retour.status !== "success") console.log(retour); - } - -} diff --git a/src/app/user/myProfil/input-interests-profil/input-interests-profil.component.html b/src/app/user/myProfil/input-interests-profil/input-interests-profil.component.html deleted file mode 100644 index be2bd07..0000000 --- a/src/app/user/myProfil/input-interests-profil/input-interests-profil.component.html +++ /dev/null @@ -1,39 +0,0 @@ - - - - - - - - {{interest}} - - - - - - - - - - - - {{interest}} - - - - - - diff --git a/src/app/user/myProfil/input-interests-profil/input-interests-profil.component.scss b/src/app/user/myProfil/input-interests-profil/input-interests-profil.component.scss deleted file mode 100644 index 7628dd4..0000000 --- a/src/app/user/myProfil/input-interests-profil/input-interests-profil.component.scss +++ /dev/null @@ -1,20 +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; -} - -mat-option { - font-size: small; -} diff --git a/src/app/user/myProfil/input-interests-profil/input-interests-profil.component.spec.ts b/src/app/user/myProfil/input-interests-profil/input-interests-profil.component.spec.ts deleted file mode 100644 index 0dd8314..0000000 --- a/src/app/user/myProfil/input-interests-profil/input-interests-profil.component.spec.ts +++ /dev/null @@ -1,25 +0,0 @@ -import { ComponentFixture, TestBed } from '@angular/core/testing'; - -import { InputInterestsProfilComponent } from './input-interests-profil.component'; - -describe('InputInterestsComponent', () => { - let component: InputInterestsProfilComponent; - let fixture: ComponentFixture; - - beforeEach(async () => { - await TestBed.configureTestingModule({ - declarations: [ InputInterestsProfilComponent ] - }) - .compileComponents(); - }); - - beforeEach(() => { - fixture = TestBed.createComponent(InputInterestsProfilComponent); - component = fixture.componentInstance; - fixture.detectChanges(); - }); - - it('should create', () => { - expect(component).toBeTruthy(); - }); -}); diff --git a/src/app/user/myProfil/input-interests-profil/input-interests-profil.component.ts b/src/app/user/myProfil/input-interests-profil/input-interests-profil.component.ts deleted file mode 100644 index 8ceb7c1..0000000 --- a/src/app/user/myProfil/input-interests-profil/input-interests-profil.component.ts +++ /dev/null @@ -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 {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"; - - - -@Component({ - selector: 'app-input-interests-profil', - templateUrl: './input-interests-profil.component.html', - styleUrls: ['./input-interests-profil.component.scss'] -}) -export class InputInterestsProfilComponent implements OnInit -{ - selectable = true; - removable = true; - separatorKeysCodes: number[] = [ENTER, COMMA]; - formControl = new FormControl(); - filteredInterests: Observable; - @Input() myInterests: string[] = []; - allInterests: string[] = []; - @Output() eventEmitter = new EventEmitter(); - @ViewChild('tagInput') tagInput: ElementRef; - 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)); - } - -} diff --git a/src/app/user/myProfil/page-profil-user/page-profil-user.component.html b/src/app/user/myProfil/page-profil-user/page-profil-user.component.html deleted file mode 100644 index 7e69ded..0000000 --- a/src/app/user/myProfil/page-profil-user/page-profil-user.component.html +++ /dev/null @@ -1,92 +0,0 @@ -
-
- - - - - -
- - -
- -
- - -
- - -
- - -
- -
- -
- -
-
- - - - - - -
- - -
-
Pseudo:
-
{{user.login}}
-
- - -
-
Mail:
-
{{user.email}}
-
- - -
-
Sexe:
-
- Homme - Femme -
-
- - -
-
Date de création:
-
{{ user.createdAt | date:'dd/LL/YYYY' }}
-
- -
-
- - - - - - -
- - -
-
Date de naissance:
-
{{ user.dateOfBirth | date:'dd/LL/YYYY' }}
-
- - -
-
Centres d'intérêt:
-
-
-
{{interest}}
-
-
-
- -
-
diff --git a/src/app/user/myProfil/page-profil-user/page-profil-user.component.scss b/src/app/user/myProfil/page-profil-user/page-profil-user.component.scss deleted file mode 100644 index ae34d41..0000000 --- a/src/app/user/myProfil/page-profil-user/page-profil-user.component.scss +++ /dev/null @@ -1,80 +0,0 @@ -.myContainer { - max-width: 100vw; - height: 100vh; - overflow-x: hidden; -} - - -.boite { - margin-left: auto; - margin-right: auto; - width: 70%; - 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; -} - -// -------------------------------------------------------------------------------------------- - -.interestsContainer { - width: 70%; - height: 15vh; - overflow-y: scroll; - border: 1px solid black; -} - -.interest { - border-bottom: 1px solid #dcdcdc; - padding: 5px 5px 5px 5px; -} - -// -------------------------------------------------------------------------------------------- - -.btnContainer { - text-align: center; - margin-top: 40px; -} -.myBtn { - border: solid 1px black; - background-color: white; -} - - diff --git a/src/app/user/myProfil/page-profil-user/page-profil-user.component.spec.ts b/src/app/user/myProfil/page-profil-user/page-profil-user.component.spec.ts deleted file mode 100644 index e8722af..0000000 --- a/src/app/user/myProfil/page-profil-user/page-profil-user.component.spec.ts +++ /dev/null @@ -1,25 +0,0 @@ -import { ComponentFixture, TestBed } from '@angular/core/testing'; - -import { PageProfilUserComponent } from './page-profil-user.component'; - -describe('PageProfilUserComponent', () => { - let component: PageProfilUserComponent; - let fixture: ComponentFixture; - - beforeEach(async () => { - await TestBed.configureTestingModule({ - declarations: [ PageProfilUserComponent ] - }) - .compileComponents(); - }); - - beforeEach(() => { - fixture = TestBed.createComponent(PageProfilUserComponent); - component = fixture.componentInstance; - fixture.detectChanges(); - }); - - it('should create', () => { - expect(component).toBeTruthy(); - }); -}); diff --git a/src/app/user/myProfil/page-profil-user/page-profil-user.component.ts b/src/app/user/myProfil/page-profil-user/page-profil-user.component.ts deleted file mode 100644 index 33ed891..0000000 --- a/src/app/user/myProfil/page-profil-user/page-profil-user.component.ts +++ /dev/null @@ -1,90 +0,0 @@ -import { Component, OnInit } from '@angular/core'; -import {ThemeService} from "../../../utils/services/theme/theme.service"; -import {User} from "../../../utils/interfaces/user"; -import {MatDialog} from "@angular/material/dialog"; -import {MatSnackBar} from "@angular/material/snack-bar"; -import {PopupUpdateUserComponent} from "../popup-update-user/popup-update-user.component"; -import {MessageService} from "../../../utils/services/message/message.service"; -import {ProfilService} from "../../../utils/services/profil/profil.service"; - - - -@Component({ - selector: 'app-page-profil-user', - templateUrl: './page-profil-user.component.html', - styleUrls: ['./page-profil-user.component.scss'] -}) -export class PageProfilUserComponent implements OnInit -{ - user: User = { - _id: "", - login: "", - hashPass: "", - email: "", - role: { - name: "user", - permission: 0, - isAccepted: false, - }, - 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.user = retour.data; - } - } - - - onModifier() - { - const config = { - width: '70%', - data: { user: this.user } - }; - this.dialog - .open(PopupUpdateUserComponent, 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.user = retour; - } - }); - } - -} diff --git a/src/app/user/myProfil/popup-update-user/popup-update-user.component.html b/src/app/user/myProfil/popup-update-user/popup-update-user.component.html deleted file mode 100644 index 1e583c7..0000000 --- a/src/app/user/myProfil/popup-update-user/popup-update-user.component.html +++ /dev/null @@ -1,125 +0,0 @@ -
- - -
-
- -

- - -
- - -
- - -
-
{{errorMessage}}
-
- - -
- - -
- -
- - - - - - - -
- - -
- -
- -
-
- - -
- -
- -
-
- - -
- - Homme     - Femme - -
- - -
- -
- -
-
- - -
- -
- -
-
- - -
- -
- -
-
- -
-
- - - - - - - -
- - -
- -
- -
-
- -
-
diff --git a/src/app/user/myProfil/popup-update-user/popup-update-user.component.scss b/src/app/user/myProfil/popup-update-user/popup-update-user.component.scss deleted file mode 100644 index 636928e..0000000 --- a/src/app/user/myProfil/popup-update-user/popup-update-user.component.scss +++ /dev/null @@ -1,81 +0,0 @@ -.myContainer { - 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; -} - -.inputUrlImage { - width: 80%; - text-align: center; - margin-left: 10%; - margin-right: 10%; - font-size: small; - border-radius: 5px; -} - -input { - font-size: small; -} - -// ------------------------------------------------------------------------- - -.myRow { - margin: 15px 0px 15px 0px; -} -.myLeftLabel { - text-align: right; - padding: 0px 0px 0px 0px; - margin: 0px 0px 0px 0px; - font-weight: bold; -} -.myRightLabel { - text-align: left; - padding: 0px 0px 0px 0px; - margin: 0px 0px 0px 0px; - font-weight: bold; -} -.myValue { - text-align: left; - padding: 0px 0px 0px 0px; - margin: 0px 0px 0px 0px; -} - -// ------------------------------------------------------------------------- - -// 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; -} - -// ------------------------------------------------------------------------- - -::ng-deep .mat-radio-inner-circle { - color: black !important; - background-color: black !important; -} - -::ng-deep .mat-radio-outer-circle{ - color: black !important; - border: solid 1px gray !important; -} diff --git a/src/app/user/myProfil/popup-update-user/popup-update-user.component.spec.ts b/src/app/user/myProfil/popup-update-user/popup-update-user.component.spec.ts deleted file mode 100644 index a5126ad..0000000 --- a/src/app/user/myProfil/popup-update-user/popup-update-user.component.spec.ts +++ /dev/null @@ -1,25 +0,0 @@ -import { ComponentFixture, TestBed } from '@angular/core/testing'; - -import { PopupUpdateUserComponent } from './popup-update-user.component'; - -describe('PopupUpdateUserComponent', () => { - let component: PopupUpdateUserComponent; - let fixture: ComponentFixture; - - beforeEach(async () => { - await TestBed.configureTestingModule({ - declarations: [ PopupUpdateUserComponent ] - }) - .compileComponents(); - }); - - beforeEach(() => { - fixture = TestBed.createComponent(PopupUpdateUserComponent); - component = fixture.componentInstance; - fixture.detectChanges(); - }); - - it('should create', () => { - expect(component).toBeTruthy(); - }); -}); diff --git a/src/app/user/myProfil/popup-update-user/popup-update-user.component.ts b/src/app/user/myProfil/popup-update-user/popup-update-user.component.ts deleted file mode 100644 index 0e1c5d3..0000000 --- a/src/app/user/myProfil/popup-update-user/popup-update-user.component.ts +++ /dev/null @@ -1,133 +0,0 @@ -import {Component, Inject, OnInit} from '@angular/core'; -import {MAT_DIALOG_DATA, MatDialogRef} from "@angular/material/dialog"; -import {User} from "../../../utils/interfaces/user"; -import {MessageService} from "../../../utils/services/message/message.service"; -import {ProfilService} from "../../../utils/services/profil/profil.service"; - - - -@Component({ - selector: 'app-popup-update-user', - templateUrl: './popup-update-user.component.html', - styleUrls: ['./popup-update-user.component.scss'] -}) -export class PopupUpdateUserComponent implements OnInit -{ - userCopy: User; - newPassword: string = ""; - confirmNewPassword: string = "" ; - changePassword: boolean = false ; - hasError: boolean = false; - errorMessage: string = "" ; - - - constructor( public dialogRef: MatDialogRef, - @Inject(MAT_DIALOG_DATA) public data, - private messageService: MessageService, - private profilService: ProfilService ) { } - - - ngOnInit(): void - { - const user0 = this.data.user; - this.userCopy = { - _id: user0._id, - login: user0.login, - hashPass: user0.hashPass, - email: user0.email, - role: { - name: user0.role.name, - permission: user0.role.permission, - isAccepted: user0.role.isAccepted, - }, - profileImageUrl: user0.profileImageUrl, - dateOfBirth: user0.dateOfBirth, - gender: user0.gender, - interests: [], - company: "", - isActive: user0.isActive, - createdAt: user0.createdAt, - updatedAt: user0.updatedAt, - lastConnexion: new Date() - }; - for(let interest of user0.interests) this.userCopy.interests.push(interest); - } - - - onValider() - { - this.checkField(); - if(!this.hasError) - { - if(this.changePassword) this.userCopy.hashPass = this.newPassword; - const data = { - login: this.userCopy.login, - hashPass: this.userCopy.hashPass, - email: this.userCopy.email, - profileImageUrl: this.userCopy.profileImageUrl, - dateOfBirth: this.userCopy.dateOfBirth, - gender: this.userCopy.gender, - interests: this.userCopy.interests, - }; - 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.userCopy.profileImageUrl); - this.dialogRef.close(this.userCopy); - } - } - - - checkField() - { - if(this.userCopy.login.length === 0) { - this.errorMessage = "Veuillez remplir le champ 'pseudo'." ; - this.hasError = true; - } - else if(this.userCopy.email.length === 0) { - this.errorMessage = "Veuillez remplir le champ 'email'." ; - this.hasError = true; - } - else if(!this.isValidEmail(this.userCopy.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); - } - - - onEventInputInterests(myInterets: string[]) - { - this.userCopy.interests = myInterets; - } - -} diff --git a/src/app/user/search/page-search/page-search.component.html b/src/app/user/search/page-search/page-search.component.html deleted file mode 100644 index 0039bdd..0000000 --- a/src/app/user/search/page-search/page-search.component.html +++ /dev/null @@ -1,80 +0,0 @@ -
-
- - -
- -
- - - - - - -
- - -
-
- - -
-
- - -
- - -   - - logo - -   - - - -   - - logo - -   - -
- -
- - - - - - - - - - -
- -
-
- - - -
- -
-
- - - -
- -
-
- -
-

- -
-
diff --git a/src/app/user/search/page-search/page-search.component.scss b/src/app/user/search/page-search/page-search.component.scss deleted file mode 100644 index f80fc45..0000000 --- a/src/app/user/search/page-search/page-search.component.scss +++ /dev/null @@ -1,90 +0,0 @@ -.lightTheme { - color: black; - border-color: black; -} -.darkTheme { - color: white; - border-color: white; -} -.myContainer { - text-align: center; - max-width: 100vw; - height: 100vh; - overflow-x: hidden; - overflow-y: scroll; -} - -//-------------------------------------------------------------------------------------------- - -.inputSearchBar { - width: 40%; - font-size: large; - border-bottom: 10px; - border-radius: 5px; -} - -//-------------------------------------------------------------------------------------------- - -.celluleGrilleVideo { - border: solid 2px; - border-radius: 5px; - width: 100%; -} -.lightTheme .celluleGrilleVideo{ - border-color: black; - background-color: #f0f0f0; -} -.darkTheme .celluleGrilleVideo{ - border-color: white; - background-color: #646464; -} - -.conteneurVideosGrid { - height: 75vh; - width: 100%; -} - -//-------------------------------------------------------------------------------------------- - -.cellulePub { - padding: 0px 10px 0px 10px; - width: 100%; - text-align: center; - justify-content: center; -} - -.conteneurPub { - height: 75vh; - text-align: center; - justify-content: center; - vertical-align: middle; - display: block; - width: 75%; - margin-left: auto; - margin-right: auto; - position: absolute; - top: 50%; - -ms-transform: translateY(-50%); - transform: translateY(-50%); -} - - - -// ------------------------------------------------------------------------- - - -// 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 { - border: solid 1px black !important; - background-color: white !important; -} diff --git a/src/app/user/search/page-search/page-search.component.spec.ts b/src/app/user/search/page-search/page-search.component.spec.ts deleted file mode 100644 index 79e1a03..0000000 --- a/src/app/user/search/page-search/page-search.component.spec.ts +++ /dev/null @@ -1,25 +0,0 @@ -import { ComponentFixture, TestBed } from '@angular/core/testing'; - -import { PageSearchComponent } from './page-search.component'; - -describe('PageSearchComponent', () => { - let component: PageSearchComponent; - let fixture: ComponentFixture; - - beforeEach(async () => { - await TestBed.configureTestingModule({ - declarations: [ PageSearchComponent ] - }) - .compileComponents(); - }); - - beforeEach(() => { - fixture = TestBed.createComponent(PageSearchComponent); - component = fixture.componentInstance; - fixture.detectChanges(); - }); - - it('should create', () => { - expect(component).toBeTruthy(); - }); -}); diff --git a/src/app/user/search/page-search/page-search.component.ts b/src/app/user/search/page-search/page-search.component.ts deleted file mode 100644 index 7ab145f..0000000 --- a/src/app/user/search/page-search/page-search.component.ts +++ /dev/null @@ -1,119 +0,0 @@ -import { Component, OnInit } from '@angular/core'; -import {MessageService} from "../../../utils/services/message/message.service"; -import {VideoAll} from "../../../utils/interfaces/video"; -import {ThemeService} from "../../../utils/services/theme/theme.service"; -import {HttpParams} from "@angular/common/http"; -import {ActivatedRoute} from "@angular/router"; - - - -let TAB_PLATEFORM = [ - { name: "Youtube", isSelected: true }, - { name: "Dailymotion", isSelected: true } -]; - - - -@Component({ - selector: 'app-page-search', - templateUrl: './page-search.component.html', - styleUrls: ['./page-search.component.scss'] -}) -export class PageSearchComponent implements OnInit -{ - tabPlateform = TAB_PLATEFORM; - tabVideo: VideoAll[] = []; - search: string = ""; - ad1: any; - ad2: any; - sources: string = "" ; - indexPage: number = 0; - - - constructor( private messageService: MessageService, - public themeService: ThemeService, - private activatedRoute: ActivatedRoute ) { } - - - ngOnInit(): void - { - // parametre de la route - this.activatedRoute - .queryParams - .subscribe(paramsFromOldPage => { - if(paramsFromOldPage.hasOwnProperty("search")) this.search = paramsFromOldPage.search; - if(paramsFromOldPage.hasOwnProperty("sources")) - { - this.sources = paramsFromOldPage.sources; - if(this.sources === "yt") { - this.tabPlateform[0].isSelected = true; - this.tabPlateform[1].isSelected = false; - } - else if(this.sources === "dm") { - this.tabPlateform[0].isSelected = false; - this.tabPlateform[1].isSelected = true; - } - else if(this.sources === "yt,dm") { - this.tabPlateform[0].isSelected = true; - this.tabPlateform[1].isSelected = true; - } - } - if(paramsFromOldPage.hasOwnProperty("indexPage")) this.indexPage = parseInt(paramsFromOldPage.indexPage, 10); - this.onSearch(); - }); - - // Ask for ads - let params = new HttpParams(); - params = params.append("quantity", 2); - this.messageService - .get("user/ad", params) - .subscribe(ret => this.adCallback(ret), err => this.adCallback(err)); - } - - - adCallback(retour: any): void - { - if(retour.status !== "success") { - console.log(retour); - } - else { - this.ad1 = retour.data[0]; - this.ad2 = retour.data[1]; - } - } - - - onSearch() - { - let params = new HttpParams(); - params = params.append('q', this.search); - - if(this.tabPlateform[0].isSelected && this.tabPlateform[1].isSelected) this.sources = "yt,dm" ; - else if((!this.tabPlateform[0].isSelected) && this.tabPlateform[1].isSelected) this.sources = "dm" ; - else if(this.tabPlateform[0].isSelected && (!this.tabPlateform[1].isSelected)) this.sources = "yt" ; - else this.sources = "" ; - params = params.append('sources', this.sources); - - this.messageService - .get("video/search", params) - .subscribe(ret => this.onSearchCallback(ret), err => this.onSearchCallback(err)); - } - - - onSearchCallback(retour: any): void - { - if(retour.status !== "success") { - console.log(retour); - } - else { - this.tabVideo = retour.data; - } - } - - - onEnterOnSearchBar(event) - { - if(event.key === 'Enter') this.onSearch(); - } - -} diff --git a/src/app/user/search/video-grid/video-grid.component.html b/src/app/user/search/video-grid/video-grid.component.html deleted file mode 100644 index 841d5c3..0000000 --- a/src/app/user/search/video-grid/video-grid.component.html +++ /dev/null @@ -1,76 +0,0 @@ - - - - -
- - -
- - - -
- - -
- - - - - - - - ytb - dlm - - - - -
- {{tronquage(tabVideo[indexPage+k].title)}} -
- - {{tabVideo[indexPage+k].views | number: '1.0-0'}} vues. - Il y a {{dateToElapsedTime(tabVideo[indexPage+k].publishedAt)}}. - -
-
- - - - - - -
- - -
-
-
-
- - - - - -
- - -   - - - - - {{page}}  - - - {{page}}  - -   - - - - -
diff --git a/src/app/user/search/video-grid/video-grid.component.scss b/src/app/user/search/video-grid/video-grid.component.scss deleted file mode 100644 index 6819fd8..0000000 --- a/src/app/user/search/video-grid/video-grid.component.scss +++ /dev/null @@ -1,84 +0,0 @@ -mat-grid-list { - margin: 0px 0px 0px 0px; - padding: 0px 0px 0px 0px; - border: none; -} - -mat-grid-tile { - margin: 0px 0px 0px 0px; - padding: 0px 0px 0px 0px; -} - -.myCell { - margin: 7px 0px 0px 0px; - padding: 0px 0px 0px 0px; - background-color: white; - border: solid 1px black; - border-bottom-left-radius: 2px; - border-bottom-right-radius: 2px; - cursor: pointer; -} -.myCell:hover { - background-color: #d2d2d2; -} - - -// --------------------------------------------------------------------------------------------- - - -.imgsContainer { - //width: 20vw; - width: 18vw; - height: 15vh; -} - -.imgPlay { - position: absolute; - margin-left: 8vw; - width: 2.5vw; - margin-top: 5vh; - height: 5vh; - padding: 0px 0px 0px 0px; -} - -.imgVideo { - width: 18vw; - height: 15vh; - padding: 0px 0px 0px 0px; -} - - -// --------------------------------------------------------------------------------------------- - - -.mat-grid-list-info-video { - margin: 0px 0px 0px 0px; - font-size: small; -} - -.mat-grid-tile-info-video { - border: none; - font-size: x-small; - //background: linear-gradient(top, rgba(38,38,38,0.8), #e6e6e6 25%, #fff 38%, #c5c5c5 87%, rgba(38,38,38,0.8)); - //background: -webkit-linear-gradient(top, #c5c5c5, #e6e6e6 25%, #fff 38%, #c5c5c5 87%, #c5c5c5); -} - -mat-icon { - text-align: right; -} - - -// --------------------------------------------------------------------------------------------- - - -.paginatorContainer { - margin: 0px 0px 0px 0px; - padding: 5px 0px 0px 0px; - text-align: center; - background-color: white; -} - -.btnPaginator { - margin: 0px 0px 0px 0px; - padding: 0px 0px 0px 0px; -} diff --git a/src/app/user/search/video-grid/video-grid.component.spec.ts b/src/app/user/search/video-grid/video-grid.component.spec.ts deleted file mode 100644 index 17cea62..0000000 --- a/src/app/user/search/video-grid/video-grid.component.spec.ts +++ /dev/null @@ -1,25 +0,0 @@ -import { ComponentFixture, TestBed } from '@angular/core/testing'; - -import { VideoGridComponent } from './video-grid.component'; - -describe('VideoGridComponent', () => { - let component: VideoGridComponent; - let fixture: ComponentFixture; - - beforeEach(async () => { - await TestBed.configureTestingModule({ - declarations: [ VideoGridComponent ] - }) - .compileComponents(); - }); - - beforeEach(() => { - fixture = TestBed.createComponent(VideoGridComponent); - component = fixture.componentInstance; - fixture.detectChanges(); - }); - - it('should create', () => { - expect(component).toBeTruthy(); - }); -}); diff --git a/src/app/user/search/video-grid/video-grid.component.ts b/src/app/user/search/video-grid/video-grid.component.ts deleted file mode 100644 index 6e13887..0000000 --- a/src/app/user/search/video-grid/video-grid.component.ts +++ /dev/null @@ -1,129 +0,0 @@ -import {Component, Input, OnChanges, OnInit, SimpleChanges} from '@angular/core'; -import {VideoAll} from "../../../utils/interfaces/video"; -import {AddVideoToPlaylistsService} from "../../utils/services/addVideoToPlaylists/add-video-to-playlists.service"; -import {Router} from "@angular/router"; -import {MessageService} from "../../../utils/services/message/message.service"; - - - -@Component({ - selector: 'app-video-grid', - templateUrl: './video-grid.component.html', - styleUrls: ['./video-grid.component.scss'] -}) -export class VideoGridComponent implements OnChanges -{ - @Input() tabVideo: VideoAll[] = []; - @Input() search: string = ""; - @Input() sources: string = ""; - @Input() indexPage: number = 0; - tabPage: number[] = []; - - - constructor( private addVideoToPlaylistsService: AddVideoToPlaylistsService, - private router: Router, - private messageService: MessageService ) {} - - - ngOnChanges(changes: SimpleChanges): void - { - if(this.tabVideoExists()) - { - const nbVideo = this.tabVideo.length; - let nbPage = Math.floor(nbVideo/9); - if((nbVideo%9) !== 0) nbPage += 1; - this.tabPage = []; - for(let i=1 ; i<=nbPage ; i++) this.tabPage.push(i); - } - } - - - onAddToPlaylist(video: VideoAll): void - { - this.addVideoToPlaylistsService.run(video.videoId, video.source, video.interest); - } - - - tronquage(str: string) - { - if(str.length < 30) return str; - else return str.substring(0, 27) + "..." ; - } - - - onVideo(video: VideoAll): void - { - const data = { source: video.source, interest: video.interest }; - this.messageService - .post("video/create/"+video.videoId, data) - .subscribe(ret => this.onVideoCallback(ret,video), err => this.onVideoCallback(err,video)); - } - - - onVideoCallback(retour: any, video: VideoAll): void - { - if(retour.status !== "success") { - console.log(retour); - } - else { - const params = { - videoId: video.videoId, - source: video.source, - from: "search", - search: this.search, - sources: this.sources, - indexPage: this.indexPage - }; - this.router.navigate(['/user/watching'], { queryParams: params }); - } - } - - - dateToElapsedTime(date0): string - { - const ellapsedTimeInMilliSeconds = (new Date()).getTime() - (new Date(date0)).getTime(); - - // seconde - const ellapsedTimeInSeconds = Math.trunc(ellapsedTimeInMilliSeconds / 1000); - if(ellapsedTimeInSeconds < 60) { - if(ellapsedTimeInSeconds <= 1)return ellapsedTimeInSeconds + " seconde" ; - else return ellapsedTimeInSeconds + " secondes" ; - } - // minute - const ellapsedTimeInMinutes = Math.trunc(ellapsedTimeInSeconds / 60); - if(ellapsedTimeInMinutes < 60) { - if(ellapsedTimeInMinutes <= 1) return ellapsedTimeInMinutes + " minute" ; - else return ellapsedTimeInMinutes + " minutes" ; - } - // heure - const ellapsedTimeInHours = Math.trunc(ellapsedTimeInMinutes / 60); - if(ellapsedTimeInHours < 24) { - if(ellapsedTimeInHours <= 1) return ellapsedTimeInHours + " heure" ; - else return ellapsedTimeInHours + " heures" ; - } - // jour - const ellapsedTimeInDays = Math.trunc(ellapsedTimeInHours / 24); - if(ellapsedTimeInDays < 31) { - if(ellapsedTimeInDays <= 1) return ellapsedTimeInDays + " jour" ; - else return ellapsedTimeInDays + " jours" ; - } - // mois - const ellapsedTimeInMonths = Math.trunc(ellapsedTimeInDays / 31); - if(ellapsedTimeInMonths < 12) { - return ellapsedTimeInMonths + " mois" ; - } - // an - const ellapsedTimeInYears = Math.trunc(ellapsedTimeInMonths / 12); - if(ellapsedTimeInYears <= 1) return ellapsedTimeInYears + " an" ; - else return ellapsedTimeInYears + " ans" ; - } - - - tabVideoExists(): boolean - { - if((this.tabVideo === null) || (this.tabVideo === undefined)) return false; - else if(this.tabVideo.length === 0) return false; - else return true; - } - -} diff --git a/src/app/user/utils/components/advert/advert.component.html b/src/app/user/utils/components/advert/advert.component.html deleted file mode 100644 index b1c034a..0000000 --- a/src/app/user/utils/components/advert/advert.component.html +++ /dev/null @@ -1,26 +0,0 @@ -
- - - - -
- - - - - - - - diff --git a/src/app/user/utils/components/advert/advert.component.scss b/src/app/user/utils/components/advert/advert.component.scss deleted file mode 100644 index ab03155..0000000 --- a/src/app/user/utils/components/advert/advert.component.scss +++ /dev/null @@ -1,41 +0,0 @@ -.myContainer { - margin: 0; - position: absolute; - top: 50%; - -ms-transform: translateY(-50%); - transform: translateY(-50%); -} - -#imgFromSearchOrMyPlaylists { - max-width: 100%; - max-height: 100%; - border: solid 3px black; - vertical-align: middle; - cursor: pointer; -} - -.helper { - display: inline-block; - height: 100%; - vertical-align: middle; -} - -// ------------------------------------------------------------------------------ - -#imgFromWatchingLeft { - width: 14vw; - height: 70vh; - border: solid 3px black; - position: fixed; - left: 1vw; - cursor: pointer; -} - -#imgFromWatchingRight { - width: 15vw; - height: 70vh; - border: solid 3px black; - position: fixed; - right: 1vw; - cursor: pointer; -} diff --git a/src/app/user/utils/components/advert/advert.component.spec.ts b/src/app/user/utils/components/advert/advert.component.spec.ts deleted file mode 100644 index 08b7e86..0000000 --- a/src/app/user/utils/components/advert/advert.component.spec.ts +++ /dev/null @@ -1,25 +0,0 @@ -import { ComponentFixture, TestBed } from '@angular/core/testing'; - -import { AdvertComponent } from './advert.component'; - -describe('PubComponent', () => { - let component: AdvertComponent; - let fixture: ComponentFixture; - - beforeEach(async () => { - await TestBed.configureTestingModule({ - declarations: [ AdvertComponent ] - }) - .compileComponents(); - }); - - beforeEach(() => { - fixture = TestBed.createComponent(AdvertComponent); - component = fixture.componentInstance; - fixture.detectChanges(); - }); - - it('should create', () => { - expect(component).toBeTruthy(); - }); -}); diff --git a/src/app/user/utils/components/advert/advert.component.ts b/src/app/user/utils/components/advert/advert.component.ts deleted file mode 100644 index 00b8b44..0000000 --- a/src/app/user/utils/components/advert/advert.component.ts +++ /dev/null @@ -1,40 +0,0 @@ -import {Component, Input, OnChanges, SimpleChanges} from '@angular/core'; - - - -@Component({ - selector: 'app-advert', - templateUrl: './advert.component.html', - styleUrls: ['./advert.component.scss'] -}) -export class AdvertComponent implements OnChanges -{ - @Input() ad: any; - @Input() from: string = "search"; - image: any; - imageExist: boolean = false; - - - constructor() { } - - - ngOnChanges(changes: SimpleChanges): void - { - if((this.ad !== null) && (this.ad !== undefined)) - { - const nbImages = this.ad.images.length; - const indexImage = Math.floor(Math.random() * nbImages); - this.image = this.ad.images[indexImage]; - this.imageExist = true; - } - } - - - onClick(): void - { - if((this.ad.url !== "") && (this.ad.url !== null) && (this.ad.url !== undefined)) { - document.location.href = this.ad.url; - } - } - -} diff --git a/src/app/user/utils/components/navbar-user/navbar-user.component.html b/src/app/user/utils/components/navbar-user/navbar-user.component.html deleted file mode 100644 index 605e192..0000000 --- a/src/app/user/utils/components/navbar-user/navbar-user.component.html +++ /dev/null @@ -1,41 +0,0 @@ - diff --git a/src/app/user/utils/components/navbar-user/navbar-user.component.scss b/src/app/user/utils/components/navbar-user/navbar-user.component.scss deleted file mode 100644 index 285d629..0000000 --- a/src/app/user/utils/components/navbar-user/navbar-user.component.scss +++ /dev/null @@ -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; -} diff --git a/src/app/user/utils/components/navbar-user/navbar-user.component.spec.ts b/src/app/user/utils/components/navbar-user/navbar-user.component.spec.ts deleted file mode 100644 index 5d03960..0000000 --- a/src/app/user/utils/components/navbar-user/navbar-user.component.spec.ts +++ /dev/null @@ -1,25 +0,0 @@ -import { ComponentFixture, TestBed } from '@angular/core/testing'; - -import { NavbarUserComponent } from './navbar-user.component'; - -describe('NavbarUserComponent', () => { - let component: NavbarUserComponent; - let fixture: ComponentFixture; - - beforeEach(async () => { - await TestBed.configureTestingModule({ - declarations: [ NavbarUserComponent ] - }) - .compileComponents(); - }); - - beforeEach(() => { - fixture = TestBed.createComponent(NavbarUserComponent); - component = fixture.componentInstance; - fixture.detectChanges(); - }); - - it('should create', () => { - expect(component).toBeTruthy(); - }); -}); diff --git a/src/app/user/utils/components/navbar-user/navbar-user.component.ts b/src/app/user/utils/components/navbar-user/navbar-user.component.ts deleted file mode 100644 index 5947c0b..0000000 --- a/src/app/user/utils/components/navbar-user/navbar-user.component.ts +++ /dev/null @@ -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-user', - templateUrl: './navbar-user.component.html', - styleUrls: ['./navbar-user.component.scss'] -}) -export class NavbarUserComponent -{ - routes: string[] = [ - "/user", // 0 - "/user/search", // 1 - "/user/myPlaylists", // 2 - "/user/history", // 3 - "/user/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); - } - -} diff --git a/src/app/user/utils/components/popup-add-video-to-playlists/popup-add-video-to-playlists.component.html b/src/app/user/utils/components/popup-add-video-to-playlists/popup-add-video-to-playlists.component.html deleted file mode 100644 index 115b281..0000000 --- a/src/app/user/utils/components/popup-add-video-to-playlists/popup-add-video-to-playlists.component.html +++ /dev/null @@ -1,42 +0,0 @@ -

Ajouter dans

- - - - - -
-
- {{playlist.name}} -
-
- - - - - -
- -
- -
- - Nom playlist - - - -
- - - - - - {{errorMessage}} - - - - diff --git a/src/app/user/utils/components/popup-add-video-to-playlists/popup-add-video-to-playlists.component.scss b/src/app/user/utils/components/popup-add-video-to-playlists/popup-add-video-to-playlists.component.scss deleted file mode 100644 index a6f9d32..0000000 --- a/src/app/user/utils/components/popup-add-video-to-playlists/popup-add-video-to-playlists.component.scss +++ /dev/null @@ -1,39 +0,0 @@ -h3 { - text-align: center; - margin-bottom: 10px -} - -.conteneurPlaylists { - margin-top: 10px; - margin-bottom: 10px; -} - -.conteneurBtnCreerPlaylist { - margin-top: 10px; - margin-bottom: 10px; -} - -.conteneurInputNewPlaylist { - margin-top: 10px; - margin-bottom: 10px; -} - - -// ------------------------------------------------------------------------- - - -// 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 { - border-color: black !important; - background-color: white !important; -} diff --git a/src/app/user/utils/components/popup-add-video-to-playlists/popup-add-video-to-playlists.component.spec.ts b/src/app/user/utils/components/popup-add-video-to-playlists/popup-add-video-to-playlists.component.spec.ts deleted file mode 100644 index 5ace846..0000000 --- a/src/app/user/utils/components/popup-add-video-to-playlists/popup-add-video-to-playlists.component.spec.ts +++ /dev/null @@ -1,25 +0,0 @@ -import { ComponentFixture, TestBed } from '@angular/core/testing'; - -import { PopupAddVideoToPlaylistsComponent } from './popup-add-video-to-playlists.component'; - -describe('PopupAddVideoToPlaylistsComponent', () => { - let component: PopupAddVideoToPlaylistsComponent; - let fixture: ComponentFixture; - - beforeEach(async () => { - await TestBed.configureTestingModule({ - declarations: [ PopupAddVideoToPlaylistsComponent ] - }) - .compileComponents(); - }); - - beforeEach(() => { - fixture = TestBed.createComponent(PopupAddVideoToPlaylistsComponent); - component = fixture.componentInstance; - fixture.detectChanges(); - }); - - it('should create', () => { - expect(component).toBeTruthy(); - }); -}); diff --git a/src/app/user/utils/components/popup-add-video-to-playlists/popup-add-video-to-playlists.component.ts b/src/app/user/utils/components/popup-add-video-to-playlists/popup-add-video-to-playlists.component.ts deleted file mode 100644 index 6a2d58d..0000000 --- a/src/app/user/utils/components/popup-add-video-to-playlists/popup-add-video-to-playlists.component.ts +++ /dev/null @@ -1,141 +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-add-video-to-playlists', - templateUrl: './popup-add-video-to-playlists.component.html', - styleUrls: ['./popup-add-video-to-playlists.component.scss'] -}) -export class PopupAddVideoToPlaylistsComponent implements OnInit -{ - _idVideo: string = ""; - videoId: string = ""; - source: string = ""; - interest: string = ""; - - tabPlaylistAndBool = []; - - goToCreatePlaylist = false; - newPlaylistName = ""; - hasError: boolean = false; - tabNomPlaylist: string[] = []; - errorMessage: string = "" ; - - - constructor( public dialogRef: MatDialogRef, - @Inject(MAT_DIALOG_DATA) public data, - private messageService: MessageService) { } - - - ngOnInit(): void - { - this._idVideo = this.data._idVideo; - this.videoId = this.data.videoId; - this.source = this.data.source; - this.interest = this.data.interest; - - for(let playlist of this.data.playlists) - { - if(playlist.videoIds.includes(this._idVideo)) playlist["isSelected"] = true; - else playlist["isSelected"] = false; - this.tabPlaylistAndBool.push(playlist); - this.tabNomPlaylist.push(playlist.name); - } - } - - - onValider(): void - { - this.checkError(); - if(!this.hasError) - { - // --- Existing playlists --- - let listeDesPlaylistsSelected = "" ; - let listeDesPlaylistsNotSelected = "" ; - for(let playlist of this.tabPlaylistAndBool) - { - if(playlist.isSelected) listeDesPlaylistsSelected += playlist.id + "," ; - else listeDesPlaylistsNotSelected += playlist.id + "," ; - } - if(listeDesPlaylistsSelected.endsWith(",")) listeDesPlaylistsSelected = listeDesPlaylistsSelected.slice(0, listeDesPlaylistsSelected.length-1); - if(listeDesPlaylistsNotSelected.endsWith(",")) listeDesPlaylistsNotSelected = listeDesPlaylistsNotSelected.slice(0, listeDesPlaylistsNotSelected.length-1); - - if(listeDesPlaylistsSelected !== "") - { - const data1 = { videoId: { id: this._idVideo, action: "add" } }; - this.messageService - .put( "playlist/update/"+listeDesPlaylistsSelected, data1) - .subscribe( ret => this.callbackForExistingPlaylists(ret), err => this.callbackForExistingPlaylists(err)); - } - if(listeDesPlaylistsNotSelected !== "") - { - const data2 = { videoId: { id: this._idVideo, action: "delete" } }; - this.messageService - .put( "playlist/update/"+listeDesPlaylistsNotSelected, data2) - .subscribe( ret => this.callbackForExistingPlaylists(ret), err => this.callbackForExistingPlaylists(err)); - } - - - // --- New playlists --- - if(this.goToCreatePlaylist) - { - const data3 = { - name: this.newPlaylistName, - video: {videoId: this.videoId, interest: this.interest, source: this.source} - }; - this.messageService - .post("playlist/create", data3) - .subscribe( ret => this.callbackForNewPlaylist(ret), err => this.callbackForNewPlaylist(err)); - } - - - // --- Finalement --- - this.dialogRef.close("success"); - } - } - - - callbackForExistingPlaylists(retour: any): void - { - if(retour.status !== "success") { - console.log(retour); - this.dialogRef.close(null); - } - } - - - callbackForNewPlaylist(retour: any): void - { - if(retour.status !== "success") { - console.log(retour); - this.dialogRef.close(null); - } - } - - - onAnnuler(): void - { - this.dialogRef.close("annulation"); - } - - - checkError(): void - { - if(this.goToCreatePlaylist && (this.newPlaylistName === "")) { - this.errorMessage = "Le nom ne peut pas être vide" ; - this.hasError = true; - } - else if(this.goToCreatePlaylist && this.tabNomPlaylist.includes(this.newPlaylistName)){ - this.errorMessage = "Ce nom est déjà utilisé" ; - this.hasError = true; - } - else { - this.hasError = false; - this.errorMessage = "" ; - } - } - -} diff --git a/src/app/user/utils/services/addVideoToPlaylists/add-video-to-playlists.service.spec.ts b/src/app/user/utils/services/addVideoToPlaylists/add-video-to-playlists.service.spec.ts deleted file mode 100644 index 6097218..0000000 --- a/src/app/user/utils/services/addVideoToPlaylists/add-video-to-playlists.service.spec.ts +++ /dev/null @@ -1,16 +0,0 @@ -import { TestBed } from '@angular/core/testing'; - -import { AddVideoToPlaylistsService } from './add-video-to-playlists.service'; - -describe('PlaylistService', () => { - let service: AddVideoToPlaylistsService; - - beforeEach(() => { - TestBed.configureTestingModule({}); - service = TestBed.inject(AddVideoToPlaylistsService); - }); - - it('should be created', () => { - expect(service).toBeTruthy(); - }); -}); diff --git a/src/app/user/utils/services/addVideoToPlaylists/add-video-to-playlists.service.ts b/src/app/user/utils/services/addVideoToPlaylists/add-video-to-playlists.service.ts deleted file mode 100644 index 50a5606..0000000 --- a/src/app/user/utils/services/addVideoToPlaylists/add-video-to-playlists.service.ts +++ /dev/null @@ -1,102 +0,0 @@ -import { Injectable } from '@angular/core'; -import {MessageService} from "../../../../utils/services/message/message.service"; -import {MatDialog} from "@angular/material/dialog"; -import {PopupAddVideoToPlaylistsComponent} from "../../components/popup-add-video-to-playlists/popup-add-video-to-playlists.component"; -import {MatSnackBar} from "@angular/material/snack-bar"; -import {FictitiousVideosService} from "../../../../utils/services/fictitiousDatas/fictitiousVideos/fictitious-videos.service"; - - - -@Injectable({ - providedIn: 'root' -}) -export class AddVideoToPlaylistsService -{ - private _idVideo: string = "" ; - private videoId: string = "" ; - private source: string = "" ; - private interest: string = "" ; - - - constructor( private messageService: MessageService, - public dialog: MatDialog, - private fictitiousVideosService: FictitiousVideosService, - private snackBar: MatSnackBar ) { } - - - run(videoId: string, source: string, interest: string): void - { - this.videoId = videoId; - this.source = source; - this.interest = interest; - - const data = { source: this.source, interest: this.interest }; - this.messageService - .post("video/create/"+this.videoId, data) - .subscribe(ret => this.afterCreatingVideo(ret), err => this.afterCreatingVideo(err)); - } - - - private afterCreatingVideo(retour: any): void - { - if(retour.status !== "success") { - console.log(retour); - } - else { - this._idVideo = retour.data.id; - this.messageService - .get('playlist/findAll') - .subscribe( ret => this.afterReceivingPlaylists(ret), ret => this.afterReceivingPlaylists(ret) ); - } - } - - - - private afterReceivingPlaylists(retour: any): void - { - if(retour.status !== "success") { - console.log(retour); - } - else - { - const config = { - width: '30%', - data: { - _idVideo: this._idVideo, - videoId: this.videoId, - source: this.source, - interest: this.interest, - playlists: retour.data.filter(x => x.isActive === true) - } - }; - this.dialog - .open(PopupAddVideoToPlaylistsComponent, config) - .afterClosed() - .subscribe(retour => this.afterClosingDialog(retour)); - } - } - - - - private afterClosingDialog(retour): void - { - let message = "" ; - switch (retour) - { - case "error": - message = "Echec de l'opération ❌" ; - break; - case "success": - message = "La vidéo a bien été ajoutée ✔" ; - break; - case "annulation": - case null: - case undefined: - message = "Opération annulée" ; - break; - } - const config = { duration: 1000, panelClass: "custom-class" }; - this.snackBar.open( message, "", config); - } - -} diff --git a/src/app/user/watching/page-watching-video/page-watching-video.component.html b/src/app/user/watching/page-watching-video/page-watching-video.component.html deleted file mode 100644 index 9cf8392..0000000 --- a/src/app/user/watching/page-watching-video/page-watching-video.component.html +++ /dev/null @@ -1,233 +0,0 @@ - - - -
-
- - -
- -
- - - - -
- - -
-
- - -
-
- - -
- - -   - - logo - -   - - - -   - - logo - -   - -
- -
- - - - -
- - -
- - - -

- -
-
- - - - - - - -
- - -
- -
- - -
-
-
- - -
- -
- -
-
- - - - - - - -
- - -
- -
- - -
-
-
- - -
-
-
- -
-
- - - - - - - - - -
- - -
- -
- - -
- -
- -
- - - -
- - -
- ytb - dlm -
  {{video.title}}
-
- - -
- -
- - -
- Vues: - {{video.views | number: '1.0-0'}} -
- - -
- Date de publication: - {{ video.publishedAt | date:'dd/LL/YYYY à HH:mm:ss' }} -
- - -
-
- Description - expand_more - expand_less -
-
- {{video.description}} -
-
- -
- -
- - - - - - - -
- - -
- {{playlist.name}} -
- - - -
-
-
-
- - -
-
-
{{video0.title}}
-
- - {{video.views | number: '1.0-0'}} vues -
- - Publiée le {{ video.publishedAt | date:'dd/LL/YYYY à HH:mm:ss' }} - -
-
-
-
- - - - - -
-
diff --git a/src/app/user/watching/page-watching-video/page-watching-video.component.scss b/src/app/user/watching/page-watching-video/page-watching-video.component.scss deleted file mode 100644 index d3f10e8..0000000 --- a/src/app/user/watching/page-watching-video/page-watching-video.component.scss +++ /dev/null @@ -1,159 +0,0 @@ -.lightTheme { - color: black; - border-color: black; -} -.darkTheme { - color: white; - border-color: white; -} -.myContainer { - text-align: center; - max-width: 100vw; - height: 100vh; - overflow-x: hidden; - overflow-y: scroll; -} - -//-------------------------------------------------------------------------------------------- - -.inputSearchBar { - width: 40%; - font-size: large; - border-bottom: 10px; - border-radius: 5px; -} - -//-------------------------------------------------------------------------------------------- -// --- Playlist --- - -.playlistContainer { - border: solid 1px black; - width: 98%; - border-top-right-radius: 10px; - border-top-left-radius: 10px; -} - -.topBorder { - margin: 0px 0px 0px 0px; - //background-color: #dcdcdc; - background: linear-gradient(top, rgba(38,38,38,0.8), #e6e6e6 25%, #fff 38%, #c5c5c5 87%, rgba(38,38,38,0.8)); - background: -webkit-linear-gradient(top, #c5c5c5, #e6e6e6 25%, #fff 38%, #c5c5c5 87%, #c5c5c5); - text-align: left; - padding: 5px 0px 5px 5px; - border-bottom: solid 1px black; - border-top-right-radius: 10px; - border-top-left-radius: 10px; -} - -.listVideoContainer { - height: 70vh; - background-color: white; - overflow-y: scroll; -} - -.videoCell { - margin: 0px 0px 0px 0px; - padding: 10px 0px 10px 10px; - border-bottom: solid 1px black; - cursor: pointer; -} -.videoCell:hover { - background-color: #f0f0f0; -} - -.videoCellFocus { - background-color: #e6e6e6; -} -.videoCellFocus:hover { - background-color: #e6e6e6; -} - - -// ---- - -.imgsContainer { - position: relative; - width: 13vw; - height: 10vh; - float: left; -} - -.imgVideo { - border: solid 1px black; - width: 13vw; - height: 10vh; - padding: 0px 0px 0px 0px; -} - -.imgPlay { - position: absolute; - margin-left: 6vw; - width: 2vw; - margin-top: 3vh; - height: 4vh; - padding: 0px 0px 0px 0px; -} - -// ---- - -.infoContainer { - display: table-cell; - margin-left: 13vw; - height: 10vh; - padding-left: 5px; - vertical-align: middle; -} - -.titleContainer { - font-weight: bold; - text-align: left; -} - -.viewsContainer { - text-align: left; - display: flex; - align-items: center; - font-size: x-small; - color: grey; -} -mat-icon { - vertical-align: middle; - //font-size: x-small; -} - -.publishedAtContainer { - text-align: left; - font-size: x-small; - color: grey; -} - - -// ---- - -.bottomBorder { - margin: 0px 0px 0px 0px; - background-color: #dcdcdc; - border-top: solid 1px black; - border-bottom: solid 1px black; - font-size: 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 { - border: solid 1px black !important; - background-color: white !important; -} diff --git a/src/app/user/watching/page-watching-video/page-watching-video.component.spec.ts b/src/app/user/watching/page-watching-video/page-watching-video.component.spec.ts deleted file mode 100644 index 6790456..0000000 --- a/src/app/user/watching/page-watching-video/page-watching-video.component.spec.ts +++ /dev/null @@ -1,25 +0,0 @@ -import { ComponentFixture, TestBed } from '@angular/core/testing'; - -import { PageWatchingVideoComponent } from './page-watching-video.component'; - -describe('PageWatchingVideoComponent', () => { - let component: PageWatchingVideoComponent; - let fixture: ComponentFixture; - - beforeEach(async () => { - await TestBed.configureTestingModule({ - declarations: [ PageWatchingVideoComponent ] - }) - .compileComponents(); - }); - - beforeEach(() => { - fixture = TestBed.createComponent(PageWatchingVideoComponent); - component = fixture.componentInstance; - fixture.detectChanges(); - }); - - it('should create', () => { - expect(component).toBeTruthy(); - }); -}); diff --git a/src/app/user/watching/page-watching-video/page-watching-video.component.ts b/src/app/user/watching/page-watching-video/page-watching-video.component.ts deleted file mode 100644 index b632ac6..0000000 --- a/src/app/user/watching/page-watching-video/page-watching-video.component.ts +++ /dev/null @@ -1,264 +0,0 @@ -import { Component, OnInit } from '@angular/core'; -import {VideoAll} from "../../../utils/interfaces/video"; -import {MessageService} from "../../../utils/services/message/message.service"; -import {FictitiousVideosService} from "../../../utils/services/fictitiousDatas/fictitiousVideos/fictitious-videos.service"; -import {FictitiousAdvertsService} from "../../../utils/services/fictitiousDatas/fictitiousAdverts/fictitious-adverts.service"; -import {ThemeService} from "../../../utils/services/theme/theme.service"; -import {ActivatedRoute, Router} from "@angular/router"; -import {AddVideoToPlaylistsService} from "../../utils/services/addVideoToPlaylists/add-video-to-playlists.service"; -import {PlaylistDB} from "../../../utils/interfaces/playlist"; -import {DomSanitizer, SafeResourceUrl} from "@angular/platform-browser"; -import {HttpParams} from "@angular/common/http"; - - - -let TAB_PLATEFORM = [ - { name: "youtube", isSelected: false }, - { name: "dailymotion", isSelected: false } -]; - - - -@Component({ - selector: 'app-page-watching-video', - templateUrl: './page-watching-video.component.html', - styleUrls: ['./page-watching-video.component.scss'] -}) -export class PageWatchingVideoComponent implements OnInit -{ - tabPlateform = TAB_PLATEFORM; - sources: string = ""; - video = { - title: "", - videoId: "", - views: 0, - publishedAt: null, - description: "", - source: "", - interest: "" - }; - search: string = ""; - - ad1: any; - ad2: any; - from: string = ""; - - playlist: any; - videosInPlaylist: any[] = []; - - paramsFromOldPage ; - - hiddenDescription: boolean = true; - iframeStyle: string = ""; - containerStyle: string = ""; - - - constructor( private messageService: MessageService, - private fictitiousVideosService: FictitiousVideosService, - private fictitiousAdvertsService: FictitiousAdvertsService, - public themeService: ThemeService, - private activatedRoute: ActivatedRoute, - private router: Router, - private _sanitizer: DomSanitizer, - private addVideoToPlaylistsService: AddVideoToPlaylistsService ) { } - - - - ngOnInit(): void - { - // Ask for videos - this.activatedRoute - .queryParams - .subscribe(paramsFromOldPage => { - - this.paramsFromOldPage = paramsFromOldPage; - const videoId = paramsFromOldPage.videoId; - let source = paramsFromOldPage.source; - - let params = new HttpParams(); - if(source === "Youtube") source = "yt"; - else if(source === "Dailymotion") source = "dm" ; - params = params.append("source", source); - this.messageService - .get("video/get/"+videoId, params) - .subscribe(ret => this.findVideoCallback(ret), err => this.findVideoCallback(err)); - }); - - - // Ask for adverts - let params = new HttpParams(); - params = params.append("quantity", 2); - this.messageService - .get("user/ad", params) - .subscribe(ret => this.findAdCallback(ret), err => this.findAdCallback(err)); - - - // Si on vient de la page "search" - if(this.router.url.includes("search")) - { - this.from = "search" ; - this.activatedRoute - .queryParams - .subscribe(paramsFromOldPage => { - if(paramsFromOldPage.hasOwnProperty("search")) this.search = paramsFromOldPage.search; - if(paramsFromOldPage.hasOwnProperty("sources")) { - this.sources = paramsFromOldPage.sources; - if(this.sources === "yt") { - this.tabPlateform[0].isSelected = true; - this.tabPlateform[1].isSelected = false; - } - else if(this.sources === "dm") { - this.tabPlateform[0].isSelected = false; - this.tabPlateform[1].isSelected = true; - } - else if(this.sources === "yt,dm") { - this.tabPlateform[0].isSelected = true; - this.tabPlateform[1].isSelected = true; - } - } - }); - } - // si on vient de la page "myPlaylists" - else if(this.router.url.includes("myPlaylists")) - { - this.from = "myPlaylists"; - this.activatedRoute - .queryParams - .subscribe(paramsFromOldPage => { - const _idPlaylist = paramsFromOldPage._idPlaylist; - this.messageService - .get("playlist/findOne/"+_idPlaylist) - .subscribe(ret => this.afterReceivingPlaylistWithVideo(ret), err => this.afterReceivingPlaylistWithVideo(err)); - }); - - } - // si on vient de la page "history" - else if(this.router.url.includes("history")) this.from = "history"; - - - // style - if(this.from === 'search' || this.from === 'history') { - this.containerStyle = "margin: 0 auto; width: 64vw;" ; - this.iframeStyle = "width: 64vw; height: 60vh;" ; - } - else { - this.containerStyle = "margin: 0 auto; width: 48vw;" ; - this.iframeStyle = "width: 48vw; height: 45vh;" ; - } - } - - - - findVideoCallback(retour: any): void - { - if(retour.status !== "success") { - console.log("findVideoCallback: "); - console.log(retour); - } - else { - this.video = retour.data; - } - } - - - findAdCallback(retour: any): void - { - if(retour.status !== "success") { - console.log("findAdCallback: "); - console.log(retour); - } - else { - this.ad1 = retour.data[0]; - this.ad2 = retour.data[1]; - } - } - - - afterReceivingPlaylistWithVideo(retour: any): void - { - if(retour.status !== "success") { - console.log("afterReceivingPlaylistWithVideo"); - console.log(retour); - } - else { - this.playlist = retour.data; - this.videosInPlaylist = retour.data.videos; - } - } - - - onSearch() - { - if(this.tabPlateform[0].isSelected && this.tabPlateform[1].isSelected) this.sources = "yt,dm" ; - else if((!this.tabPlateform[0].isSelected) && this.tabPlateform[1].isSelected) this.sources = "dm" ; - else if(this.tabPlateform[0].isSelected && (!this.tabPlateform[1].isSelected)) this.sources = "yt" ; - else this.sources = "" ; - let options = { - queryParams: { - search: this.search, - sources: this.sources, - indexPage: 0, - } - }; - this.router.navigate(['/user/search'], options); - } - - - onAddToPlaylist(): void - { - this.addVideoToPlaylistsService.run(this.video.videoId, this.video.source, this.video.interest); - } - - - onRetour(): void - { - let url: string[] = []; - let options = {}; - - if(this.from === 'search') - { - url = ['/user/search']; - options = { - queryParams: { - search: this.paramsFromOldPage.search, - sources: this.paramsFromOldPage.sources, - indexPage: this.paramsFromOldPage.indexPage, - } - }; - } - else if(this.from === 'myPlaylists') url = ["/user/myPlaylists"]; - else if(this.from === 'history') url = ["/user/history"]; - - this.router.navigate(url, options); - } - - - safeUrl(videoId: string, source: string): SafeResourceUrl - { - let videoUrl = "" ; - if(source === 'Youtube') videoUrl = "https://www.youtube.com/embed/" + videoId + "?autoplay=1"; - else if(source === 'Dailymotion') videoUrl = "https://www.dailymotion.com/embed/video/" + videoId + "?autoplay=true"; - return this._sanitizer.bypassSecurityTrustResourceUrl(videoUrl); - } - - - // retourne la classe CSS de videoCell - getClassOfVideoCell(video0: VideoAll): string - { - if(video0 === this.video) return "videoCell videoCellFocus" ; - else return "videoCell" ; - } - - - onEnterOnSearchBar(event) - { - if(event.key === 'Enter') this.onSearch(); - } - - - playlistExists(): boolean - { - return ((this.playlist !== null) && (this.playlist !== undefined)); - } - -} diff --git a/src/app/utils/interfaces/advert.ts b/src/app/utils/interfaces/advert.ts deleted file mode 100644 index 55da7c0..0000000 --- a/src/app/utils/interfaces/advert.ts +++ /dev/null @@ -1,39 +0,0 @@ -export interface Advert -{ - _id: string, - userId: string, - title: string, - url: string, - images: { - url: string, - description: string, - }[], - interests: string[], - comment: string, - views: Date[], - isVisible: boolean, - isActive: boolean, - createdAt: Date, - updatedAt: Date, -} - - - -export interface AdvertWithCountViews { - id: string, - userId: string, - title: string, - url: string, - images: { - url: string, - description: string, - }[], - interests: string[], - comment: string, - views: Date[], - countViews: number, - isVisible: boolean, - isActive: boolean, - createdAt: Date, - updatedAt: Date, -} diff --git a/src/app/utils/interfaces/playlist.ts b/src/app/utils/interfaces/playlist.ts deleted file mode 100644 index 4ffa611..0000000 --- a/src/app/utils/interfaces/playlist.ts +++ /dev/null @@ -1,10 +0,0 @@ -export interface PlaylistDB -{ - _id: string, - userId: string, - name: string, - videoIds: string[], - isActive: boolean - createdAt: Date, - updatedAt: Date -} diff --git a/src/app/utils/interfaces/user.ts b/src/app/utils/interfaces/user.ts deleted file mode 100644 index f46977f..0000000 --- a/src/app/utils/interfaces/user.ts +++ /dev/null @@ -1,33 +0,0 @@ -export interface User -{ - _id: string, - email: string, - hashPass: string, - login: string, - role: { - name: string, - permission: number, - isAccepted: boolean, - }, - profileImageUrl: string, - dateOfBirth: Date, - gender: string, - interests: any[], - company: string, - isActive: boolean, - lastConnexion: Date, - createdAt: Date, - updatedAt: Date -} - - -interface VideoCategorie -{ - id: number - interest: string - categories: { - id: string - name: string - source: string - } -} diff --git a/src/app/utils/interfaces/video.ts b/src/app/utils/interfaces/video.ts deleted file mode 100644 index 1c93427..0000000 --- a/src/app/utils/interfaces/video.ts +++ /dev/null @@ -1,32 +0,0 @@ -export interface VideoDB -{ - _id: string, - userId: string, - videoId: string, - source: string, - tags: string[], - interest: string, - watchedDates: Date[], - createdAt: Date, - updatedAt: Date -} - - -export interface VideoAll -{ - _id: string, - userId: string, - videoId: string, - source: string, - tags: String[], - interest: string, - watchedDates: Date[], - createdAt: Date, - updatedAt: Date - - title: string, - views: number, - publishedAt: Date, - description: string, - imageUrl: string -} diff --git a/src/app/utils/services/fictitiousDatas/fictitiousAdverts/fictitious-adverts.service.spec.ts b/src/app/utils/services/fictitiousDatas/fictitiousAdverts/fictitious-adverts.service.spec.ts deleted file mode 100644 index 0cd9f3c..0000000 --- a/src/app/utils/services/fictitiousDatas/fictitiousAdverts/fictitious-adverts.service.spec.ts +++ /dev/null @@ -1,16 +0,0 @@ -import { TestBed } from '@angular/core/testing'; - -import { FictitiousAdvertsService } from './fictitious-adverts.service'; - -describe('FictitiousAdvertsService', () => { - let service: FictitiousAdvertsService; - - beforeEach(() => { - TestBed.configureTestingModule({}); - service = TestBed.inject(FictitiousAdvertsService); - }); - - it('should be created', () => { - expect(service).toBeTruthy(); - }); -}); diff --git a/src/app/utils/services/fictitiousDatas/fictitiousAdverts/fictitious-adverts.service.ts b/src/app/utils/services/fictitiousDatas/fictitiousAdverts/fictitious-adverts.service.ts deleted file mode 100644 index 2dd7702..0000000 --- a/src/app/utils/services/fictitiousDatas/fictitiousAdverts/fictitious-adverts.service.ts +++ /dev/null @@ -1,130 +0,0 @@ -import { Injectable } from '@angular/core'; -import {Advert} from "../../../interfaces/advert"; -import {FictitiousUtilsService} from "../fictitiousUtils/fictitious-utils.service"; - - - -const TAB_ADVERT: Advert[] = [ - { - _id: "idNutella", - userId: "userId", - title: "pot de nutella XXL", - url: "https://www.nutella.com/fr/fr/", - images: [ - { url: "nutella_v_1.jpeg", description: "image nutella 1" }, - { url: "nutella_v_2.png", description: "image nutella 2" }, - { url: "nutella_v_3.jpg", description: "image nutella 3" } - ], - interests: [ "rock", "basket" ], - comment: "pub pour vacances de noêl", - views: [ - new Date(2021,10,1), - new Date(2021,10,2), - new Date(2021,10,3), - new Date(2021,10,3), - new Date(2021,10,5), - new Date(2021,10,5), - new Date(2021,10,5), - new Date(2021,10,5), - new Date(2021,10,5), - new Date(2021,10,7) - ], - isVisible: true, - isActive: true, - createdAt: new Date(), - updatedAt: new Date(), - }, - { - _id: "idRolex", - userId: "userId", - title: "Rolex", - url: "https://www.rolex.com", - images: [ - { url: "rolex_v_1.jpg", description: "rolex 1" }, - { url: "rolex_v_2.png", description: "rolex 2" }, - ], - interests: [ "rock", "rap" ], - comment: "pub pour cette année", - views: [ - new Date(2021,10,5), - new Date(2021,10,6), - new Date(2021,10,7), - new Date(2021,10,8), - new Date(2021,10,8), - new Date(2021,10,8), - new Date(2021,10,25), - new Date(2021,10,25), - new Date(2021,10,25), - new Date(2021,10,27) - ], - isVisible: true, - isActive: true, - createdAt: new Date(), - updatedAt: new Date(), - }, - { - _id: "idAlbion", - userId: "userId", - title: "Albion new version", - url: "https://www.rolex.com", - images: [ - { url: "rolex_v_1.jpg", description: "albion 1" }, - { url: "rolex_v_2.png", description: "albion 2" }, - ], - interests: [ "rock", "rap" ], - comment: "pub pour cette année", - views: [ - new Date(2021,10,3), - new Date(2021,10,4), - new Date(2021,10,4), - new Date(2021,10,5), - new Date(2021,10,5), - new Date(2021,10,6), - new Date(2021,10,6), - new Date(2021,10,8), - new Date(2021,10,8), - new Date(2021,10,8) - ], - isVisible: true, - isActive: true, - createdAt: new Date(), - updatedAt: new Date(), - } -]; - - - -@Injectable({ - providedIn: 'root' -}) -export class FictitiousAdvertsService -{ - - constructor(private fictitiousUtilsService: FictitiousUtilsService) {} - - - getAdvert(): Advert - { - const idx = Math.floor(Math.random() * TAB_ADVERT.length); - let advert = Object.assign({}, TAB_ADVERT[idx]); - advert._id = advert._id + this.fictitiousUtilsService.makeid(5); - advert.interests = advert.interests.slice(); - advert.isVisible = (Math.random() < 0.5); - return advert; - } - - - getTabAdvert(n: number): Advert[] - { - let tabAdvert = []; - for(let i=0 ; i { - let service: FictitiousUsersService; - - beforeEach(() => { - TestBed.configureTestingModule({}); - service = TestBed.inject(FictitiousUsersService); - }); - - it('should be created', () => { - expect(service).toBeTruthy(); - }); -}); diff --git a/src/app/utils/services/fictitiousDatas/fictitiousUsers/fictitious-users.service.ts b/src/app/utils/services/fictitiousDatas/fictitiousUsers/fictitious-users.service.ts deleted file mode 100644 index e629e97..0000000 --- a/src/app/utils/services/fictitiousDatas/fictitiousUsers/fictitious-users.service.ts +++ /dev/null @@ -1,128 +0,0 @@ -import { Injectable } from '@angular/core'; -import {User} from "../../../interfaces/user"; -import {FictitiousUtilsService} from "../fictitiousUtils/fictitious-utils.service"; - - - -const USER: User = { - _id: "ririId", - login: "Riri", - hashPass: "agourgroou", - email: "riri@gmail.com", - role: { - name: "user", - permission: 0, - isAccepted: true, - - }, - profileImageUrl: "https://www.figurines-goodies.com/1185-thickbox_default/huey-duck-tales-disney-funko-pop.jpg", - dateOfBirth: new Date(), - gender: "man", - interests: ["foot", "jeux-vidéo"], - company: "", - isActive: true, - lastConnexion: new Date(), - createdAt: new Date(), - updatedAt: new Date() -}; - -const ADVERTISER: User = { - _id: "fifiId", - login: "Fifi", - hashPass: "agourgroou", - email: "fifi@gmail.com", - role: { - name: "advertiser", - permission: 5, - isAccepted: true, - - }, - profileImageUrl: "https://www.figurines-goodies.com/1188-large_default/dewey-duck-tales-disney-funko-pop.jpg", - dateOfBirth: null, - gender: "", - interests: [], - company: "My company", - isActive: true, - lastConnexion: new Date(), - createdAt: new Date(), - updatedAt: new Date(), -}; - -const ADMIN: User = { - _id: "loulouId", - login: "Loulou", - hashPass: "agourgroou", - email: "loulou@gmail.com", - role: { - name: "admin", - permission: 5, - isAccepted: true, - }, - profileImageUrl: "https://www.reference-gaming.com/assets/media/product/41195/figurine-pop-duck-tales-n-309-loulou.jpg?format=product-cover-large&k=1519639530", - dateOfBirth: null, - gender: "", - interests: [], - company: "", - isActive: true, - lastConnexion: new Date(), - createdAt: new Date(), - updatedAt: new Date(), -}; - - - -@Injectable({ - providedIn: 'root' -}) -export class FictitiousUsersService -{ - - constructor(private fictitiousUtilsService: FictitiousUtilsService) { } - - private getUserOrAdvertiserOrAdmin(modele: User): User - { - const res = Object.assign({}, modele); - res._id += this.fictitiousUtilsService.makeid(5); - res.login += (Math.floor(Math.random() * 1000)).toString(); - res.email = res.login + "@gmail.com" ; - res.role.isAccepted = (Math.random() < 0.5); - res.isActive = (Math.random() < 0.5); - res.dateOfBirth = this.fictitiousUtilsService.randomDate(new Date(1900, 0, 1), new Date()); - res.lastConnexion = this.fictitiousUtilsService.randomDate(new Date(2000, 0, 1), new Date()); - return res; - } - - getUser(): User { - return this.getUserOrAdvertiserOrAdmin(USER); - } - - getAdvertiser(): User { - return this.getUserOrAdvertiserOrAdmin(ADVERTISER); - } - - getAdmin(): User { - return this.getUserOrAdvertiserOrAdmin(ADMIN); - } - - getTabUser(n: number): User[] - { - const res: User[] = []; - for(let i=0 ; i { - let service: FictitiousUtilsService; - - beforeEach(() => { - TestBed.configureTestingModule({}); - service = TestBed.inject(FictitiousUtilsService); - }); - - it('should be created', () => { - expect(service).toBeTruthy(); - }); -}); diff --git a/src/app/utils/services/fictitiousDatas/fictitiousUtils/fictitious-utils.service.ts b/src/app/utils/services/fictitiousDatas/fictitiousUtils/fictitious-utils.service.ts deleted file mode 100644 index 4c06ecf..0000000 --- a/src/app/utils/services/fictitiousDatas/fictitiousUtils/fictitious-utils.service.ts +++ /dev/null @@ -1,33 +0,0 @@ -import { Injectable } from '@angular/core'; - - -@Injectable({ - providedIn: 'root' -}) -export class FictitiousUtilsService -{ - - makeid(length) - { - let res = ''; - const characters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789'; - for( let i = 0; i < length; i++ ) { - const k = Math.floor(Math.random() * characters.length); - res += characters.charAt(k); - } - return res; - } - - - randomDate(start, end): Date - { - return new Date(start.getTime() + Math.random() * (end.getTime() - start.getTime())); - } - - - getTags(): string[] - { - return [ "musique", "rap", "rock", "sport", "foot", "basket", "tennis", "film", "action", "aventure", "horreur", "romance", "comedie"]; - } - -} diff --git a/src/app/utils/services/fictitiousDatas/fictitiousVideos/fictitious-videos.service.spec.ts b/src/app/utils/services/fictitiousDatas/fictitiousVideos/fictitious-videos.service.spec.ts deleted file mode 100644 index e604845..0000000 --- a/src/app/utils/services/fictitiousDatas/fictitiousVideos/fictitious-videos.service.spec.ts +++ /dev/null @@ -1,16 +0,0 @@ -import { TestBed } from '@angular/core/testing'; - -import { FictitiousVideosService } from './fictitious-videos.service'; - -describe('FictitiousVideosService', () => { - let service: FictitiousVideosService; - - beforeEach(() => { - TestBed.configureTestingModule({}); - service = TestBed.inject(FictitiousVideosService); - }); - - it('should be created', () => { - expect(service).toBeTruthy(); - }); -}); diff --git a/src/app/utils/services/fictitiousDatas/fictitiousVideos/fictitious-videos.service.ts b/src/app/utils/services/fictitiousDatas/fictitiousVideos/fictitious-videos.service.ts deleted file mode 100644 index e0e0b4a..0000000 --- a/src/app/utils/services/fictitiousDatas/fictitiousVideos/fictitious-videos.service.ts +++ /dev/null @@ -1,289 +0,0 @@ -import { Injectable } from '@angular/core'; -import {VideoAll} from "../../../interfaces/video"; -import {PlaylistDB} from "../../../interfaces/playlist"; -import {FictitiousUtilsService} from "../fictitiousUtils/fictitious-utils.service"; - - - -const TAB_VIDEO: VideoAll[] = [ - { - _id: "Mowgli", - //videoId: "https://www.youtube.com/watch?v=medPORJ8KO0", - videoId: "medPORJ8KO0", - userId: "userId", - source: "youtube", - tags: [ "rap", "musique" ], - interest: "PNL", - watchedDates: [ - new Date(2021, 10, 15), - new Date(2021, 10, 16), - new Date(2021, 10, 17), - new Date(2021, 10, 18), - new Date(2021, 10, 19), - new Date(2021, 10, 20), - ], - createdAt: new Date(), - updatedAt: new Date(), - - title: "PNL - Mowgli", - views: 999999999, - publishedAt: new Date(), - imageUrl: "https://i.ytimg.com/vi/CaeH7TRnI3s/hq720.jpg?sqp=-oaymwEcCOgCEMoBSFXyq4qpAw4IARUAAIhCGAFwAcABBg==&rs=AOn4CLCr4TMUqy_Lqi9_zh7efICrF_V_Vw", - description: "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed non risus. Suspendisse lectus tortor, dignissim sit amet, adipiscing nec, ultricies sed, dolor. Cras elementum ultrices diam. Maecenas ligula massa, varius a, semper congue, euismod non, mi. Proin porttitor, orci nec nonummy molestie, enim est eleifend mi, non fermentum diam nisl sit amet erat. Duis semper. Duis arcu massa, scelerisque vitae, consequat in, pretium a, enim. Pellentesque congue. Ut in risus volutpat libero pharetra tempor. Cras vestibulum bibendum augue. Praesent egestas leo in pede. Praesent blandit odio eu enim. Pellentesque sed dui ut augue blandit sodales. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Aliquam nibh. Mauris ac mauris sed pede pellentesque fermentum. Maecenas adipiscing ante non diam sodales hendrerit. " - }, - { - _id: "Mexico", - //videoId: "https://www.youtube.com/watch?v=LZx6oeNeoWM", - videoId: "LZx6oeNeoWM", - userId: "userId", - source: "youtube", - tags: [ "rap", "musique" ], - interest: "PNL", - watchedDates: [new Date()], - createdAt: new Date(), - updatedAt: new Date(), - - title: "PNL - Mexico", - views: 999999, - publishedAt: new Date(), - imageUrl: "https://i.ytimg.com/vi/LZx6oeNeoWM/hq720.jpg?sqp=-oaymwEcCOgCEMoBSFXyq4qpAw4IARUAAIhCGAFwAcABBg==&rs=AOn4CLAIJsokYSLBB3TrnKhX5V1beCTrpQ", - description: "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed non risus. Suspendisse lectus tortor, dignissim sit amet, adipiscing nec, ultricies sed, dolor. Cras elementum ultrices diam. Maecenas ligula massa, varius a, semper congue, euismod non, mi. Proin porttitor, orci nec nonummy molestie, enim est eleifend mi, non fermentum diam nisl sit amet erat. Duis semper. Duis arcu massa, scelerisque vitae, consequat in, pretium a, enim. Pellentesque congue. Ut in risus volutpat libero pharetra tempor. Cras vestibulum bibendum augue. Praesent egestas leo in pede. Praesent blandit odio eu enim. Pellentesque sed dui ut augue blandit sodales. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Aliquam nibh. Mauris ac mauris sed pede pellentesque fermentum. Maecenas adipiscing ante non diam sodales hendrerit. " - }, - { - _id: "Luz de luna", - //videoId: "https://www.youtube.com/watch?v=fGoPhSV2Jic", - videoId: "fGoPhSV2Jic", - userId: "userId", - source: "youtube", - tags: [ "rap", "musique" ], - interest: "PNL", - watchedDates: [new Date()], - createdAt: new Date(), - updatedAt: new Date(), - - title: "PNL - Luz de luna", - views: 999999, - publishedAt: new Date(), - imageUrl: "https://i.ytimg.com/vi/fGoPhSV2Jic/hq720.jpg?sqp=-oaymwEcCOgCEMoBSFXyq4qpAw4IARUAAIhCGAFwAcABBg==&rs=AOn4CLBICz3ZfnjAXQNZQniiCTRLbdyLcg", - description: "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed non risus. Suspendisse lectus tortor, dignissim sit amet, adipiscing nec, ultricies sed, dolor. Cras elementum ultrices diam. Maecenas ligula massa, varius a, semper congue, euismod non, mi. Proin porttitor, orci nec nonummy molestie, enim est eleifend mi, non fermentum diam nisl sit amet erat. Duis semper. Duis arcu massa, scelerisque vitae, consequat in, pretium a, enim. Pellentesque congue. Ut in risus volutpat libero pharetra tempor. Cras vestibulum bibendum augue. Praesent egestas leo in pede. Praesent blandit odio eu enim. Pellentesque sed dui ut augue blandit sodales. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Aliquam nibh. Mauris ac mauris sed pede pellentesque fermentum. Maecenas adipiscing ante non diam sodales hendrerit. " - }, - { - _id: "Blanka", - //videoId: "https://www.youtube.com/watch?v=u8bHjdljyLw", - videoId: "u8bHjdljyLw", - userId: "userId", - source: "youtube", - tags: [ "rap", "musique" ], - interest: "PNL", - watchedDates: [new Date()], - createdAt: new Date(), - updatedAt: new Date(), - - title: "PNL - Blanka", - views: 999999, - publishedAt: new Date(), - imageUrl: "https://i.ytimg.com/vi/PCwZnN4zDiY/hq720.jpg?sqp=-oaymwEcCOgCEMoBSFXyq4qpAw4IARUAAIhCGAFwAcABBg==&rs=AOn4CLCaA-xe5rkkYJbNCbSg0z27Lm1Hgw", - description: "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed non risus. Suspendisse lectus tortor, dignissim sit amet, adipiscing nec, ultricies sed, dolor. Cras elementum ultrices diam. Maecenas ligula massa, varius a, semper congue, euismod non, mi. Proin porttitor, orci nec nonummy molestie, enim est eleifend mi, non fermentum diam nisl sit amet erat. Duis semper. Duis arcu massa, scelerisque vitae, consequat in, pretium a, enim. Pellentesque congue. Ut in risus volutpat libero pharetra tempor. Cras vestibulum bibendum augue. Praesent egestas leo in pede. Praesent blandit odio eu enim. Pellentesque sed dui ut augue blandit sodales. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Aliquam nibh. Mauris ac mauris sed pede pellentesque fermentum. Maecenas adipiscing ante non diam sodales hendrerit. " - }, - { - _id: "Mowgli 2", - //videoId: "https://www.dailymotion.com/video/x7ahxdn", - videoId: "x7ahxdn", - userId: "userId", - source: "dailymotion", - tags: [ "rap", "musique" ], - interest: "PNL", - watchedDates: [new Date()], - createdAt: new Date(), - updatedAt: new Date(), - - title: "PNL - Mowgli 2", - views: 999999, - publishedAt: new Date(), - imageUrl: "https://i.ytimg.com/vi/tno1qRfO894/hq720.jpg?sqp=-oaymwEcCOgCEMoBSFXyq4qpAw4IARUAAIhCGAFwAcABBg==&rs=AOn4CLCOBBR6c3woXXIbOSdU06quQcN7pw", - description: "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed non risus. Suspendisse lectus tortor, dignissim sit amet, adipiscing nec, ultricies sed, dolor. Cras elementum ultrices diam. Maecenas ligula massa, varius a, semper congue, euismod non, mi. Proin porttitor, orci nec nonummy molestie, enim est eleifend mi, non fermentum diam nisl sit amet erat. Duis semper. Duis arcu massa, scelerisque vitae, consequat in, pretium a, enim. Pellentesque congue. Ut in risus volutpat libero pharetra tempor. Cras vestibulum bibendum augue. Praesent egestas leo in pede. Praesent blandit odio eu enim. Pellentesque sed dui ut augue blandit sodales. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Aliquam nibh. Mauris ac mauris sed pede pellentesque fermentum. Maecenas adipiscing ante non diam sodales hendrerit. " - }, - { - _id: "Etre humain", - //videoId: "https://www.youtube.com/watch?v=gfVo39B92Ow", - videoId: "gfVo39B92Ow", - userId: "userId", - source: "youtube", - tags: [ "rap", "musique" ], - interest: "Nekfeu", - watchedDates: [new Date()], - createdAt: new Date(), - updatedAt: new Date(), - - title: "PNL - Etre humain", - views: 999999, - publishedAt: new Date(), - imageUrl: "https://i.ytimg.com/vi/gfVo39B92Ow/hq720.jpg?sqp=-oaymwEcCOgCEMoBSFXyq4qpAw4IARUAAIhCGAFwAcABBg==&rs=AOn4CLCPJpBqTYk5Nj3RSgase3GdbT7_Pg", - description: "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed non risus. Suspendisse lectus tortor, dignissim sit amet, adipiscing nec, ultricies sed, dolor. Cras elementum ultrices diam. Maecenas ligula massa, varius a, semper congue, euismod non, mi. Proin porttitor, orci nec nonummy molestie, enim est eleifend mi, non fermentum diam nisl sit amet erat. Duis semper. Duis arcu massa, scelerisque vitae, consequat in, pretium a, enim. Pellentesque congue. Ut in risus volutpat libero pharetra tempor. Cras vestibulum bibendum augue. Praesent egestas leo in pede. Praesent blandit odio eu enim. Pellentesque sed dui ut augue blandit sodales. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Aliquam nibh. Mauris ac mauris sed pede pellentesque fermentum. Maecenas adipiscing ante non diam sodales hendrerit. " - }, - { - _id: "Humanoide", - //videoId: "https://www.youtube.com/watch?v=MiyIg__WNOw", - videoId: "MiyIg__WNOw", - userId: "userId", - source: "youtube", - tags: [ "rap", "musique" ], - interest: "Nekfeu", - watchedDates: [new Date()], - createdAt: new Date(), - updatedAt: new Date(), - - title: "Nekfeu - Humanoide", - views: 999999, - publishedAt: new Date(), - imageUrl: "https://i.ytimg.com/vi/MiyIg__WNOw/hq720.jpg?sqp=-oaymwEcCOgCEMoBSFXyq4qpAw4IARUAAIhCGAFwAcABBg==&rs=AOn4CLDboAq0TRqXBFGgXdpOD_HOsRZucw", - description: "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed non risus. Suspendisse lectus tortor, dignissim sit amet, adipiscing nec, ultricies sed, dolor. Cras elementum ultrices diam. Maecenas ligula massa, varius a, semper congue, euismod non, mi. Proin porttitor, orci nec nonummy molestie, enim est eleifend mi, non fermentum diam nisl sit amet erat. Duis semper. Duis arcu massa, scelerisque vitae, consequat in, pretium a, enim. Pellentesque congue. Ut in risus volutpat libero pharetra tempor. Cras vestibulum bibendum augue. Praesent egestas leo in pede. Praesent blandit odio eu enim. Pellentesque sed dui ut augue blandit sodales. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Aliquam nibh. Mauris ac mauris sed pede pellentesque fermentum. Maecenas adipiscing ante non diam sodales hendrerit. ", - }, - { - _id: "Dernier soupir", - //videoId: "https://youtu.be/0GqjIF-4QQM?list=PLqeKQSn3LuAmpF-uIu39RIQRQkUzVol5l", - videoId: "0GqjIF-4QQM", - userId: "userId", - source: "youtube", - tags: [ "rap", "musique" ], - interest: "Nekfeu", - watchedDates: [new Date()], - createdAt: new Date(), - updatedAt: new Date(), - - title: "Nekfeu - Dernier soupir", - views: 999999, - publishedAt: new Date(), - imageUrl: "https://i.ytimg.com/vi/-S5IKBvT34c/hqdefault.jpg?sqp=-oaymwEcCOADEI4CSFXyq4qpAw4IARUAAIhCGAFwAcABBg==&rs=AOn4CLC1kVCIB2bQGmOH74I5puXIhn7HRQ", - description: "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed non risus. Suspendisse lectus tortor, dignissim sit amet, adipiscing nec, ultricies sed, dolor. Cras elementum ultrices diam. Maecenas ligula massa, varius a, semper congue, euismod non, mi. Proin porttitor, orci nec nonummy molestie, enim est eleifend mi, non fermentum diam nisl sit amet erat. Duis semper. Duis arcu massa, scelerisque vitae, consequat in, pretium a, enim. Pellentesque congue. Ut in risus volutpat libero pharetra tempor. Cras vestibulum bibendum augue. Praesent egestas leo in pede. Praesent blandit odio eu enim. Pellentesque sed dui ut augue blandit sodales. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Aliquam nibh. Mauris ac mauris sed pede pellentesque fermentum. Maecenas adipiscing ante non diam sodales hendrerit. ", - }, - { - _id: "Les prélis", - //videoId: "https://www.dailymotion.com/video/x4trtkd", - videoId: "x4trtkd", - userId: "userId", - source: "dailymotion", - tags: [ "rap", "musique" ], - interest: "Columbine", - watchedDates: [new Date()], - createdAt: new Date(), - updatedAt: new Date(), - - title: "Columbine - Les prélis", - views: 999999, - publishedAt: new Date(), - imageUrl: "https://s2.dmcdn.net/v/HPPjj1NtysAaAttYk/x240", - description: "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed non risus. Suspendisse lectus tortor, dignissim sit amet, adipiscing nec, ultricies sed, dolor. Cras elementum ultrices diam. Maecenas ligula massa, varius a, semper congue, euismod non, mi. Proin porttitor, orci nec nonummy molestie, enim est eleifend mi, non fermentum diam nisl sit amet erat. Duis semper. Duis arcu massa, scelerisque vitae, consequat in, pretium a, enim. Pellentesque congue. Ut in risus volutpat libero pharetra tempor. Cras vestibulum bibendum augue. Praesent egestas leo in pede. Praesent blandit odio eu enim. Pellentesque sed dui ut augue blandit sodales. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Aliquam nibh. Mauris ac mauris sed pede pellentesque fermentum. Maecenas adipiscing ante non diam sodales hendrerit. ", - }, - { - _id: "Pierre feuille ciseau", - //videoId: "https://www.dailymotion.com/video/x6agl6i", - videoId: "x6agl6i", - userId: "userId", - source: "dailymotion", - tags: [ "rap", "musique" ], - interest: "Columbine", - watchedDates: [new Date()], - createdAt: new Date(), - updatedAt: new Date(), - - title: "Columbine - Pierre feuille ciseau", - views: 999999, - publishedAt: new Date(), - imageUrl: "https://i.ytimg.com/vi/tTo7CrPlbpI/hq720.jpg?sqp=-oaymwEcCOgCEMoBSFXyq4qpAw4IARUAAIhCGAFwAcABBg==&rs=AOn4CLAhC5bWURH9R8Icdkv6LWRgsW2G-Q", - description: "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed non risus. Suspendisse lectus tortor, dignissim sit amet, adipiscing nec, ultricies sed, dolor. Cras elementum ultrices diam. Maecenas ligula massa, varius a, semper congue, euismod non, mi. Proin porttitor, orci nec nonummy molestie, enim est eleifend mi, non fermentum diam nisl sit amet erat. Duis semper. Duis arcu massa, scelerisque vitae, consequat in, pretium a, enim. Pellentesque congue. Ut in risus volutpat libero pharetra tempor. Cras vestibulum bibendum augue. Praesent egestas leo in pede. Praesent blandit odio eu enim. Pellentesque sed dui ut augue blandit sodales. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Aliquam nibh. Mauris ac mauris sed pede pellentesque fermentum. Maecenas adipiscing ante non diam sodales hendrerit. ", - }, -]; - - - -@Injectable({ - providedIn: 'root' -}) -export class FictitiousVideosService -{ - - constructor(private fictitiousUtilsService: FictitiousUtilsService) {} - - - getVideoAll(): VideoAll - { - const index = Math.floor(Math.random() * TAB_VIDEO.length); - return TAB_VIDEO[index]; - } - - - getVideoByVideoId(videoId: string): VideoAll - { - return TAB_VIDEO.find(video => video.videoId === videoId); - } - - - getTabVideoAll(nbVideo: number): VideoAll[] - { - let tabVideo = []; - for(let i=0 ; i x._id), - isActive: true, - createdAt: new Date(), - updatedAt: new Date() - }); - } - - return tabPlaylist; - } - - - getNoRandomTabPlaylistDB(nbPlaylist: number): PlaylistDB[] - { - let tabPlaylist: PlaylistDB[] = []; - - for(let i = 0; i < nbPlaylist; i++) - { - const videoIds = []; - for(let j=0 ; j { - let service: MessageService; - - beforeEach(() => { - TestBed.configureTestingModule({}); - service = TestBed.inject(MessageService); - }); - - it('should be created', () => { - expect(service).toBeTruthy(); - }); -}); diff --git a/src/app/utils/services/message/message.service.ts b/src/app/utils/services/message/message.service.ts deleted file mode 100644 index a50e75c..0000000 --- a/src/app/utils/services/message/message.service.ts +++ /dev/null @@ -1,40 +0,0 @@ -import { Injectable } from '@angular/core'; -import {HttpClient, HttpParams} from "@angular/common/http"; -import {environment} from "../../../../environments/environment"; -import {Observable} from "rxjs"; - - - -@Injectable({ - providedIn: 'root' -}) -export class MessageService -{ - - constructor( private http: HttpClient ) { } - - post(url: string, data: any): Observable - { - const urlComplete = environment.debutUrl + url ; - return this.http.post(urlComplete, data, {withCredentials: true}); - } - - get(url: string, params:HttpParams = new HttpParams()): Observable - { - const urlComplete = environment.debutUrl + url ; - return this.http.get(urlComplete,{ withCredentials: true, params: params }); - } - - put(url: string, data: any): Observable - { - const urlComplete = environment.debutUrl + url ; - return this.http.put(urlComplete, data, {withCredentials: true}); - } - - delete(url: string): Observable - { - const urlComplete = environment.debutUrl + url ; - return this.http.delete(urlComplete,{withCredentials: true}); - } - -} diff --git a/src/app/utils/services/profil/profil.service.spec.ts b/src/app/utils/services/profil/profil.service.spec.ts deleted file mode 100644 index 5cee000..0000000 --- a/src/app/utils/services/profil/profil.service.spec.ts +++ /dev/null @@ -1,16 +0,0 @@ -import { TestBed } from '@angular/core/testing'; - -import { ProfilService } from './profil.service'; - -describe('ProfilService', () => { - let service: ProfilService; - - beforeEach(() => { - TestBed.configureTestingModule({}); - service = TestBed.inject(ProfilService); - }); - - it('should be created', () => { - expect(service).toBeTruthy(); - }); -}); diff --git a/src/app/utils/services/profil/profil.service.ts b/src/app/utils/services/profil/profil.service.ts deleted file mode 100644 index 86ed4a2..0000000 --- a/src/app/utils/services/profil/profil.service.ts +++ /dev/null @@ -1,30 +0,0 @@ -import {Injectable} from '@angular/core'; - - -@Injectable({ - providedIn: 'root' -}) -export class ProfilService -{ - - getId(): string - { - return localStorage.getItem('id'); - } - - getProfileImageUrl(): string - { - return localStorage.getItem('profileImageUrl'); - } - - setId(id: string): void - { - localStorage.setItem('id', id); - } - - setProfileImageUrl(profileImageUrl: string): void - { - localStorage.setItem('profileImageUrl', profileImageUrl); - } - -} diff --git a/src/app/utils/services/theme/theme.service.spec.ts b/src/app/utils/services/theme/theme.service.spec.ts deleted file mode 100644 index 1c2957b..0000000 --- a/src/app/utils/services/theme/theme.service.spec.ts +++ /dev/null @@ -1,16 +0,0 @@ -import { TestBed } from '@angular/core/testing'; - -import { ThemeService } from './theme.service'; - -describe('ThemeService', () => { - let service: ThemeService; - - beforeEach(() => { - TestBed.configureTestingModule({}); - service = TestBed.inject(ThemeService); - }); - - it('should be created', () => { - expect(service).toBeTruthy(); - }); -}); diff --git a/src/app/utils/services/theme/theme.service.ts b/src/app/utils/services/theme/theme.service.ts deleted file mode 100644 index bc69016..0000000 --- a/src/app/utils/services/theme/theme.service.ts +++ /dev/null @@ -1,15 +0,0 @@ -import { Injectable } from '@angular/core'; - -@Injectable({ - providedIn: 'root' -}) -export class ThemeService -{ - isLightTheme = true; - - getClassTheme(): string - { - if(this.isLightTheme) return "lightTheme" ; - else return "darkTheme" - } -} diff --git a/src/assets/.gitkeep b/src/assets/.gitkeep deleted file mode 100644 index e69de29..0000000 diff --git a/src/assets/darkBackground.webp b/src/assets/darkBackground.webp deleted file mode 100644 index 0d0692b8c331ccbacf8631b679686525fbb5c85a..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 712 zcmV;(0yq6qNk&G%0ssJ4MM6+kP&gp80ssJT9{`;JDl7rX06uLtl}V%`q@*AzD3A?_ zX>Q;>iAE?`%wEA-e#t&cS2sEVL07u^sZrqsT6dzFocOE$D}N9a`+e=cBzb{tX3C$6 z`JjfvGgt7TCyvjjE@>oSX9ZB1OKeqFB!YU~3e=Y2c>LbjX|bA4kb>`bZKE&s)+3cK ziS>GAQA-|XOMCr*P6Ld>)qNAXehBN&;~&ABz91L*f_chJs=5}TKoSj&gup&Qh>R{?2zoLudAm(GKCT$mY19@0$Yp^J(I{jF_ zTh^F;q47k3=N6hdQkrFLlCCd};Aq%CBZGm_xY=j{8CCDn-coDhs9Is=q!xDp00d&Xw+z=+UJ_Ul^?Ey)j=!ToVfd(TJITP(l4FX(pMPFJ8$Tt*ygc`di8ywz=8G0u9Aae(C4`14{8J(Y7`D`n7x*WM?_ z7^kW4&$!t*rB*u19QNC9=-4~#L1nh6TXkBHT{O-Fty(wdC_`&y$FPzx~fY7 zZX>4<SE z$9f@rSjf^42nK^77$9iu-%u8WfWxgYRwxt-g9gLPhIu(#w$PRn^hCp0Tb@c9_@BwPOY%w6V%%|DDm$B8Q+k3o0mnixjihNh6^ zGT#iCUmvy)TZT`3HqWWe&Ml*GZ^_mF26u|P=ckTVd;7~fY~xZ9MJ~o$Rx@uldvDqf zuV{8RKX7k+z-$gx3-tHHf?E_4O&(10xJlG&^Ssymd+*P+`%2tcYVx59qh>x50 z^ky*BFx0jymRaP_eD$oj`BlVRF@N4gF{t@ zJQBs#NY0ao3Vy%oFq^_`ZfW6pEw(?L&)lTbWcp^1_9gs>4|w_`EyPwknVbTt#rKgH6_@;aMa13{ zgg~0h!~0@Y87!gX_XR8Yzbm%GH<*ZTGm(Gh$iRh|EgrVPwAM<0(r$YGK%|Ri$zH+q zt-i>Gi+Rk&z;s`E#-~i%+6IjxQ`mQr`_Jzf<1X|$tS-ee0z2Gg7OaA zWZ)0-j`9ocodRA)p?aV@WVt4io*`DX8~N*dZMUb-a~W((8VqECO^vFIsxHIlyaD_5 zt-PwtU`R`X%Y-->#~n4XB+rV|{}#rYJ*T27&^@3<7Ld><$!=-$pt!a%4U6-|+Y#F{ z6FQt*om*#mDrXDw;=!C-nT%FqAgB1@D!@tT;%_CcU$0^2u1r_>T6V6g%l!D4cr)-U z(6%T3A&=}8H zvVm#mqh($1AvotVNgv5ibN8v-q{vQ4ZFG6qBp58TnX{$6BXn^+G6Lt8;=L^Dt$=`+ zp(vhKjFStQD2|>Cw=5kM{rEL(M3trc82}%r6BM>Zy*NG7hkIIRL7m3Hv}J^cf#`WtMI0Fjrd*|iLCvhmrlYkR@s1T~&7#*HMzU*R`Th!Zn#}VES zNw^|~WKWH_Mj)5m4 zx>OtzLme!HZWcm=h4bQa8VE$SXuogBJ{81;NVzJ&ZVDD(AYNi*%n#4Bs*tC zwx&D&;2K(md?u~POp<8@b}>=J-cM(c^*0NtpbxT-yXjTk2b22V zW4}&b)wX1IO3nAm2p49`FDrKAO4#CG&RRC5jeVL%lce9`1%NSD6}#La*S%W@TQ%-4 z<9b*q`w@{W=X^r?1k(D-&Qrxs!A_j@uUtyV#1>}RULb{UHVlV0TA#X)+x%okfM5e z&8G6mJvF>TPLWFPezva^c}0{}!BjP)z=KX&CZ>dY(KDJD`>;vW?kRB@BoT$nrq~2N z=`}qZ%qFrhHXg{$I>J77ICrn=a1M7BXCej=34{;DA?MI1930)vza_4Qa$vEbn)yV; zrQ&a~7#$%(LSS556TcI^u}0s{AV(!FnTQ;0374qJ-5wwRabe7SFw+_M*8(J9x~GwI zskKs6zr`svUIG0U79?SZRrs1_W{QP2#VINX5=Xkh8+8uS8=V~yNj5ssaiJyOou3Qr zz(#-w?8THI!+WtM(TWYwdZ6=O3x#7e)mJMR_Qk2~c+j`Blh26?nd)}@bd_+oPMMjE z3h~g?N|#Z5OdBt|0BZ=-S_sk;iOG9-Fldj8EQ0hV2S-h#k?e>_z)OVl(FHFv)ke6s z*yO|pQAl8`)Fz@gwum5yWFZJ<1%pf|r2DV8sKj=Ayl-){Xu-5_c@3U^#AkhVxYP=C zL6(HixGxc&tqA7mnck=nsL|*EGN&WF0?$0Skm@X%5$@iK&h6l4TcY$T4m zSLe}n8{Xlc?Yr}JOwOrJrhg|WE{5XA3-D7R%k9=rb48s&)@Y)*f-eD*gQM<J zCnoy74Lo_i+Qg4w0tHl*^y%EOB^*Qfr0Y9~BPU&Qp$|&z;0W^4F+*ckv;cS~lbIz8 z=EHTc%Z{jX^usQ~sH~S7pO%`(m+!RW`F)snGJ&mdgU_K77LZE#;YR-sxbK$@E)SJ_ zF_E1)RRx5rr=r3pC%9QmcGM2#dgc}x535inL_E}0m%|l7LwH3W+(5&XCn={%`buPt zxC6VwTjxdsz~^BH;c+41a5orH<$qJ7Dv=N*M7H+4VWR2)ak-cIHu(9RONf^f@9xdasAnuyZH!Bj>(HwAsN<7YEr|SAjCgrz^(M(V>JV_`@xp7PZ#1YHn-?59 z=dQ^K7V~VnR&bZ0=9B(rBJYFy8oC*Tf(TZ$+Mr{)9pki_KyhT?Q$h5r)Oxl4Vl?p%u zra3Yh-LGQ$piJ<7yqM!fbr$O?h`su(wGX72({<>_OQ9m9(GBK}m4(COh;O^WcB_k! z;Y@y~ThYO~kZ|{68Q*A$E^0{wdU^(>yb^i5Qpa2C7g8PY3LQ*@SxB=A%Qob2rSM@x z!6x1wK>>|N`n$f;+i?C6(YuN+B@%_E^>DX!09UQFNJ@{Jo^CP^O*s^heIX6Sch_f; z0W3<)WA?$M*cT3XozBTwQeHXrJ@*$!mUWTc+cIw#f0-3dRV$bAjWtD4yQqrWMY|U zoI_+4(bt7@#2py5Eb*-FBZQM=yf96ar>W6!bcSSFvs@x_#xr$@J{>B%d9TzOq=PF8 z%eTPHMr0v7sKuG{BZRi8HiQ7;@JF!y1V8vu-OShB5q&NWcoUiBAC?CIuu9W#!!i(! z4`iRpzp;15Y@*eFdGDCj7P$`0WJP|leSIth`fwvBqUUQ@I z;)%I^^g8RTmDVn zulJQ3ZnXSSHu&d12dXC)WnYzjHv8chWzTno{cL&QkAl(0KgXbV+m@f2x+DH}DDYm; zneYEH-3mH$b|ZLl2xopKeI8slDt*p3)>ot9bN{g&mPZzfMomyfL-5%5alO1!H$rJkw&kc$X z66`kTbz6bUF-n3P|U?9ad>>2yl3{Kp^xrQ%Vh>E7-3 z9rEi=*PXB1_I`$Fq!@>3JuCDd=qd8=X%2WqT*3#!#2F~Gg;Q4GV-L>%D~ha3E22hBaH z?Kh+=%^}NAp|=S~Y=*7Gwv|)lY?i;I%$AYsAC;^qJD+uAR%<~2y`;v+f)mo)ypuJ!P<`EP*Uz#4 zP;TatZtqQv$Xb;~i^#SsC3tkLO2c(3ez~$lE54|koA^9i6nMdR@Id{?g==~T1Bd;e z*d5*3ynLNUkB8aA%-VsCXo_h1uxHh0xSzmc<@g>dKpCJ+e^HuHx(Ht#Pa5Hss-m6< zCYY{deU7gdD+BUthj}LrXDzbWpFD-rKMjrw9AH%i(WrNKpAJ6KII8Qf&5*D5d4g&& za2tkkc|2NI)FXtp;iT;W?4ed=^H3K}>IBs3r}f<_Cywa+o?3Z+XWG(!qxS5n_4o2q z+pooopU^3V^A-_oTm9-O0*dN`2E;hom8z=at>SHlIpf6bfBMNjVBLE*c_QZ?TkTdv zJ*8lCqOEZoLSHxR8X)g+o@LZOMYS{rBs{d6x2{zL4}Zq|{&A^X$)_p&9kjEzrl zKbsT-abfZ1w)OkXghA6J0M=J7B7B^1U76N$T{D!|Dp-{85Vh_5flAhqAR7JF>Hdd=9P5#C;4x*FhoD*>~#4*@@N;0WpnQ`BP%zonevcdhQVyzpx1EZb&B8f_SZ zmfDwXvnP$#=huzq*H>n=jzNN`7mb1ycbh;i$gi&(-TP;y$5YoAwB;vf5A(`C4eBQ4 z9hg0Y`}ri2wW|kTJ1XRzyqjPBZ<=JbS5P-OJ)@PjTKX(Mdv(gQ{NN+zj8;K(?5?%L zJRqkwd$rHAwR&ctpl;N|{_qIC?pGvhM}F-+UezuUZfDsQwdg<_uH;|gb68)m^{Cv^ zK2Ynj<=LFD!JxU|au4-?W{o&)m9j`a74`S(7v%%e?v!m#S%laje**iiskCYA+W!MZ C8Oa_1 diff --git a/src/assets/logo.png b/src/assets/logo.png deleted file mode 100644 index 93b93755e49963d09c63cbd0df33669376c8f90d..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 5798 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 diff --git a/src/assets/logo_plateforms/dailymotion.png b/src/assets/logo_plateforms/dailymotion.png deleted file mode 100644 index d35ee8a8b0e209615e57966d3d6f108844b2135d..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 6478 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 diff --git a/src/assets/play.png b/src/assets/play.png deleted file mode 100644 index 194f73beb22f040cf7ef156fe3f6403c1b5323e0..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3586 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¥elov_Rg)4Hg+_ZX@^s2A`i^iF;C$nj6$_vFr0?$ zt8*341ewX!ys%;vn~QijK0~}L(nUPmyp~(cautW-lIBS=yR%N8xpk0_G{1};^#VwW zr!yDiczZ+WuiK{;Y|HW?JV`)aUV*Yv;vGQC)-N4iU)YatRC!R zk!&+sj=Gk4#eJXQdv9yA*u;3oDo~IQnB|W$v{Nmo#aYyb z!?@DgFlHU`v&mzte((p7dEdu)&s6XgV8nUeyithU$&zF^=Qu7rIN|K(!lxTQc>VFQ z)Q;5mkx`>OS$m#b#&=IFhYYbI{neogp|T4TzbJ@3?(L1%*HzBcJp}NhL4$4cuZHr`uLXiOw2H3$2l3WS@9vzVBRu&m0f#%6#XU)PvQX zZ8g$7vs@o8<*Y{~bTC26Z0!hD00uZc;4Y46<72y)R82(qqG_=?ca2TR*B2qiN&5!^ zk%uW`mHfPXt@??FE=7fsB0O2%H3D|pp$k2xhAIiR!^F}Enu_cRpqsE z>JFEXCjTh^bysl?l{a(AdR)y3fn~P$KT!Lv@6?*uEXI4dK5<-3OH7D(*4A+lpyo=n z`$jkdJ=l-#u{5Mg)sjLMQUGP z#}~?p2Mo7Op6m1_cvqTUz4?%=M#EHLgc(>0Z-A%Id+wTYzAojtZ8)EE`48&cGbZ1e zw|m`+TkpMj$GJ!P{J~+@8fs)UZq)lFi#JaGeEti!N`?^nW#{_~4&5D9?Gag5WU|N8 z)s^A{Z|nNzkNY28yhDxQ8p;U#=1IP#Rd6t$;+t$XU*>nJ{%nK$^xE4;lTSP`J8P7d zdD-1pobQEf(lMi=ZI&rJ-e;pb-NIOPK-P8uq8VrjLlwu%w_oV*`Sul<1bpCP!zL(< zv}HKSWVDB&Cx)aDw&)y))Jh?5xiYN$_>J6Ytr%A+x=mWYTkp4i|3u5Bes0vg&s2{? zUqza$FS~9vO*cWNw$z@+ncX99d^G$hMR`av{u(e{$r^)Na@2-!_j2AL-vq%2G)3f) z?4>scNJ4z)b&U(Mt{hwvoVfB@t^RPZ6nA7*{R>gypzPDzPNq$mMG%s4%P(S=-oqBL zW9H-Knmmzm+#3ChtDw3tqZKl*^40eaU+N?}$q$Lu_(xcIi53^ZlA$hFu8u|ex>9yY zR3>ky_9wY!JC*P0a>-rnlRDj&d-juN$H++g!>Y~KQn}qnzP{XTZ)cJ&U3oZhICW=+ zjDex>5!3Vn5Mw?(QeUu($_ zHp{li)z=l60FM~kw=-k^!v(LIM&?~5{r$kLR_mo^NNx0(Ko@TGZ#i$44>AzQ?x97y&oI86f5<)R zP(_(gX!5?UhK0ms#mwB$kB2XA+1L@Du># zvAR_r0b>KMD~RD}g!u5_S>DwxP=%OBZ=@o;!J8>vYd6fmsw94QHEn&EVls9lsD(G2RA!8p|9&22DEnY@` z2_rDR>Jp}MN;2}kUGy&Pb8n+g_MT4?e!A_x&Z_l^&1#xV9}&3zIa%aKg5#@O@Gvb@1SD_7)PfDZToSybT@XY$CQ+mPKU1!HKxWg z^KMA@Qi3am$eZ>m`<>d%ta6jkTKi)nr-yZVhIwHvCpM^G52m5tY=pZAdBj>`;Er2G z%i?nF8fyKL3`lY^;Tdh+?tMdb!=ncjzgkkYl?sE7ASkeGXl5 z7DCO2PTscen(2Lo)h?Uq%SYywl`51?*5XFOe)>6D_3X!b^Ef z+}w*adKqmq*LkxgSiDTrTjFF+>AT`ts1-e(M>9p%67=E|*M`>UdXEKNJP}nt7M!?} z4T}9`I-%8L-Qw~uzP%5xwfr()FXwo(erWBr`Mre##@MH*iBMxu#2P1TESCoVQjb_ss0fXi%T% zY6v?98U$HHM-l%xvP;jxho0cTTx}66LmHag__W>Q*nEn)i)RzBzFPZYmO-{=`@1c* zc>)W0PR@I4x9`Oaw}!254i8g$C6*;)_oR5Exk&6q`D@JU@)qyvBM7C(u1%W6sux`> zqc_9;w5IWj!KPLTF6}K8%Z+WdSD%O+PKk9jGQV&hBQRn%Jfdh9-1wU2vh7~Pi2B2Z zH|lDvLi0!2ewdzeceYG94>14w9K>a0=wnOEc;t*J^~T5keUBcT$B}B)UG6NI-gUF) ziy1oau}kOYll8({jfsmNcN3l$VgWJac=L?mY#!6Zzv;GTW<>q|Qbr9G7WCjgmfA-Q zRPb3}wPSh<^!SdXhom2$%$ca$rG#vLR-=C)rdF)+gzQ_bHJ#PfTnE<;Y@W1DHcv1EmJIGz#^cj%Jr)d!cYtE z`l_!s!|mMZ55!?n`WWzn1Q_6i;$2J!aq04q4}=ZZ=hk-OsTq~Us&c8ydB;SZI0$~n z?bBs6-R$kL-71t585cgjus&vx_i)q!QoTluZelE>DI49YEORlu0ff4HA8I{P%stE} z4Ls#6tjRJj4X38t3UwTwm;Ht)zL0SXN!dP3LD@#GZ-a z3a-4AAMqmhTdani*p@S$NkY%k$GANjJ2E0;U^G*2;#}10T-2ZO zZ`NU-@+SXHZ4~pTa%k%BBnEX*{QjFDZR$&%@e=AwdB`&)h!yXxhnhjTX%K{p!|!Y~ zwjKkSeS5f!MaTnxw0t`1m(7kWMTdKd2LZVL8@J*t7YDHc@QI!ogP;+Fi60*!#RHDR z^%^t|0!3nfvhg(dUg-7U8V~tTV$yMsv;WNrf{|0j(fN1{_uK2oqV&3tu3Az-^t1N+ z-ty~*0Z(dI3_XOZ@MMk(4fSVv`DLHBcNp%*VJJD_@}s15qb$kin;^lxh7>>fzSyf} ze*UfNDS?Twme0`!ZTW9g7Rh?0^E@9{4(CGxT9+7`KegMlt~J{`Vdmha0yP zv`&g|phfI>qn*N7sN`?l-OAEVGhjZ@c$gVz-d5e(m^S&)+F?N>STG*@U}^=;A509a zwy3<4WfUxdG%?FI$;?$V3oLlvWiyeTwLg7F8=xI@bZw?7XxCmu$IvV{jXpUu7xIQh z+7fRk{A$h1+@QKkt{y`cL5`*tjh1u`A?$lJrDbC5TsK`8g*6>FXp zyY2L`gXZQuZq2l4Ba(S#y=orn&}BGmr- zmv=@_nRG1ql;lk3rfxRhs?kb(s!S9+s4MP}7A5J0U5sM~p)WV`(~q&AmhbWveBC}{ z-&N3uX1dg^)}%+7+R*4F53O-AXU|{2{hZv{Kd6`Hps1{W_}aUx37b=WuVaS0SX)8a z-Pn_=s?&zPj_Kh(?t~53I?z(glB8bEy77F9Ja=!YRO2)y(n45O--$BE?@+w1zw=Y4 zToSi-GDS3xo%-_Pg$Y8N3Z#RxuXL}!8S~}MMx&i9zkQokgtIZ50%AXnXKp4>#|oaeX)*TP5BhZU2@P#0E3{wS^?{I>iM?0fhB3$8@`%9}FyotO3e&PKVh=(_)r z*L&N~^f5R1inGhL_%8Y?FbFORaXAj|4cRO-<8Hb(H!l1`|K5WId*>U|t&4jM=bekY zl;uLK42`;NJ)N9&+c51103%I~{)v4bJ_=V22r8Bf`(CAfqdz>YGThHcOOG&VBBR8w z-NcO4EF0Nr=3Lb~yc9rjAd+AxHIYXQMLHEd66DCL2ybx7l0Z#KiN9*Xrtm zN&=#k!hQFA&WkEXhoo32DwA`J_Ig#1iOHC5GZEOMp3A)Me>yblH1|^@g>?0=o9zrr z>IowwI{tt)SaAXx3-;yN($H4MjSUhHO`LM|^jh|q4=@xp_^nP$3T@Npp_b|$P?FF);3gsHf%~>j*JADY zb8FV`jtGNqHoEyXNYeGIWEEnr9tZ z)!k}@DQ*4aIF08IEr|&!(c53=iWC_0w&WW=Zzp_3Y4ebJ-R1mmrM$YEEmeF`rWxb4nK04M}UV%89JDrm|R$5jXFXv=sbuHN^JmG$#-sY{^+Y6!_4n+J? zZmyOEHB+_?Q~^qYgOOcYLS@u}nM2GA3`fP860L?DmJ;J=POmUZ=k0loUPS@MY9)?E zoH=!?#`8JjhOzYPTT#oFI_-O-YMYioyjulwk46kZrXUA#g>{AzwF=b|diM59zp|wn zrP>nKG5A*QcwrFNEHfMF%v;r`DUH^m=N{;dIXv!JbMadbdZww+f2P7;Bxj4kQR3EG z!9!;qUx>;ZsmNR&EsVTqM)@Y&8Qv*yWyByc`cb-xMFhH%^a7fZh!ee}ZsE^Yn=N`G_;3!HP#}w2|?)Sq3=YBcfcvW4V#X z5eR9n<6Phu;sb&Y!F`7pVbb+uRLTa_sa^P={+y*;`Yq&MROH&On;nyU{T*9js^wQ^ zBVy(2uX)ZE{GDJ7%Mb(DI0`m^r?(73mmkvV9*F<4xENosCWR+WdMpR03q4%UHbZ! zA^7C?`*wGQsX6Uo!aPXrb3wy5e_>ne13n^a&#gMb%*VH5u;!4aAKb0S+G8=WC>9Pr zmI`2G&(S!~~_?Vl~9S(?z_7DEr>-_6yJg#sB>6*1FkXj zE7$n@%ukNQ^eE2Sr)^!o`_74-yXV(yp4e4E{5;SD==PxfVF%oe$#g1LXSgMAWIXf{ z%Yb);R7n+4Gr}_7K~Jom9_To^KEpkCt`Hof@!>Q3L%D+c=f7@kShoCosdv;xeHc`d z-ClKd=XI^a_lna)Gd4an>NLS0zQK>Zdeb%0CNJ8)i)tzE+7!Gp!Y4VXAl<~!)2w0^ zEF1_qSY!9~e%q+YW7JmaLc}4QLF7KG4Pimo<#Ei|%rEja9E2bwjvnm8f~(6JhKq9B_(9qPaP0J7qr^o+5ttzn@XhkS3cd?>&U`spv=y4)&6{!-x9@lzfAQ@ z#v0ZSP|khK?j=e!q%b`dd-$GL&lrWpfysWJl`UE3HJ_lB7)7U`8>OV@0X&6!z?4DBpP;^t&uLwW*kfP(1 zl!nT8v|KgK`WB;cSmpw}&_xk^UHOWzJ?e?by-R$3YcoMNQK@YcefZ*cLN6`39MDmT z7+&)J6S{z^cMC0Q@3p=@YR99pw3H1U#SAB%mFcF>xH@_fZYJ^aB)LR8K#e<4&|JE1 z7Z#a7JK_*Rsyd)~=Bg@ptb6W2rvPWVR?i=^mV53hL)ol z(H)Pkw$5!U+eKwxy?A)6YSnz?OJU{;rb;1|a{ju)gDZXq7(Se2;qMhFJmilslw(HSS+{?|^UouWOVpzM)u> zE4NmEH$whFGzNiCJgl#|RtWe41^DF2V zNO>XgLupW&yGg^R&0w{kgOCHH>_x12fNt#FWS851@^WA31nm_OMDDFqg>NMS%9ni|?iK12xfI##R|Q4p);Qi&QENxopkXj!l$vH34UbtNC%R2vn5_LJ6q6-#=%z@JaT(Dt0y@@F*#X+Q4 z020DIH7soAg{2l~?Sop5(=uRz)h-TVKS-Et(xzCl1&|^T8IudmJKroYo|ysx#w3Yx z7-BtuY=7n;7G)bCYRD!IqCN^N=?);CRq1|EvaBQm2RuB9COfgtauClWhX^d$r2*LJ z)tWHP_s|O45;$`VXn8_TUnjsp=Uw2fWN5{>U$q8(pBTwOY-QbGd{M<^SY5Xlu62o0 zx=VQW0z9;t5z9g7aMuzTrc+o}!bN!jpWC48YLy6YCU6jvsIT2<_Qw1H)*jGnHlO+q z$S8#-2Z!-SqNy33q?IG-|01=LjnecbpukI5mM|JVh0e=|Rt4=y4DBGGIC{X7Y{F7P z*a9wMfCq00w07R}P`M1t(AR|#GUQe3T3VytYpeD}$=5Y;Gkfh#kG~br6mY%O#8qi= zWiS=Oh3^mqO}^%90OWIb2*Z+DBEp8RcKn@u2EZ4)7{CPRh}NMQ=2IkAk{(MQ3PUX# zm$`$v*^~kXMaKtYy<#E+l ze08uUa1~+xHag#uok*xavCnIXzWV&`z5SC*rn%-B5tT2J^n3dIMVSo?TIgyGf(#zv z`Z+arqy;d>?DUa1g78j;&0Y3{EXW|Q7eX0 zKx6C1jBbaY@%J37Uw^q`uJ>yf-5XQ@_HO@`i>&{hdffbLUm6!c>ynX{QX1W!tJYm9 zUCDn$3m#k-mSGJr$EhBOEwBXZtCDCdKo(df(DcS#jIhI1@` zu=l$_YI9X(iV9u`jV1!p4GCV*05+1K%`Rg{4lF!GFW)CIBv)X9R*<9ga}pBW`{8+* zG~(aA{;CP7(R`6O4g8Fh4-@EmcO^>{Bm;xUlhX~P;mdac-{G?=Ot?$y-wS;r4H20V zC1A*APlnjXSZnkRF;ZySP}hX#Kl+do8Qimu1o{wY`uYbIuN_SpTzE6M2ka((Q$R^- zh$FH6TA@lF^tdcUT@TG$-`?}RAFTDimo4U-U#NT5V+~rF8wLmI6SF2KSje`_@+u@aMBb-;53?fqfz*-x{erl2vH+YtC3 zlU+*2yRN(NcJ{l#dr4bI{0QHg=u^D_uM$9%Mg`T)rv_oA?1W6HDRKbjZUA2~{_(D! ziGCYW1S~EZY`Q^L4&rdEpbt~&`x7=bvDPJkHq_LAx{akn?nvj;us^UpABJE%5!s10 zm2I81R6l2cG$_(=V>^1R7T5}|k?*(P2UYdALjo_m>WEz+1GT@?2GIn*2YZ)iz%+Xx zh8XlYRmTSY+)f&+TmX**{)HmL_cSxANHuWEMU{itrYAQIkBaxivDg60+^u8Po0$(x z_i4kvH-H4hvG88}4|h@DL5gOf;tCU(Hg5dNqs;7q?)W$s!v+L%11ufXpKrv7Z0Dm-C}9j2xfR)!$g&0W1e`h3d|EVOG=~uy8XbBM*TfWcjlt<%Fo_S>` zD{m4b>?qcL`5+w#Vg}9PLywv~2a0ob616Y{w)vfT4uU2C{doINa!kh>!PQj1YNkvC(=IH1zj_~LvHc=$53e5iBUT(ZMfNl_(cGr- z&$bh^7141218L>ufxPnoDy0{*8R0E2dB&?}Hl8pxEXx*l{0l zi1$F5xg`DZ5$bZ?`<9R6U#Xa&(E3BB0lvN)gvEa5J7yX8)c(AM@ibIGV_ZjeYG%A% ztzOY2<`2^o;!6ChtZXx|`HPu!g^^ z_GR#4UP1P@?}J$b=DEc(Y-x5_6YM8XnybdLbiC*A2XYUkQ(6adXI*)q#ih;*5_D&(&Pk@?A3*d;rgTE`NzW%6F5EYJ9hu%8iTQ17f9>AS+QUnlu=4-oZs z{8C#GdfYD#8eD=;fYO1(VlFs(U>5}iivZlDh=$-Ad$0o@4=hs@!QTC0eTbtu02%|- z__{?ByyX~eAsQOhrxG~`)pi1HYw@%SKr3@~O{~4XavVhC5^5@ABh<`P0AHG71;UbT z697o-9;-&PR7kK5bkbiVzo0fQ{Iq}Z+v;r~`go;uZ*_=9JjN6(X03w3`Gbg?B1dzn zLQ!4u)4Ni`2MQTZ^Z=;9kI*n*wuP)(7dtlFS4!Dvt94~a_zRyC08amnDcc0a7U``@ z?$Tqu#&@ynSB0i6poIyrW&A-djv`0phWDOf-yw}#vY(@=fmE;}8V2*Jpfi6HT=f(1 za_i^nzUTu}FI7om4H(1kZf3BN`Ex9B(nmDKP%9P$HD%i1^a3#Vk+H=rx*U3Cv512p zZG&inW95G>g0VO7-W}{<(zrEa1;iehAZVrh74hGd!!^**tY!*_bbG-_>@bS9pI|Vs zdZ-_)KN&3c`~p2@+G1c~f|t#}1A(RQu;@mOKk!7&SE8}Ya`QreFmjU)2>T(+|3n`lC=+veDF=q-kYvrbiUZcbKpe{j17I zv3`0Eb3I(U2U(78lT*MrbDd z<)-`s*ML>jdH@Z8O~D9bS^eAlaS|;2e|5%PDR#~e;rqPCAflB3(UMzv5L1xATD1bN z2kwIf+Wr4RIm?(Mr$z~;S~xooFG;iJMD+9Dx>qmMq&m1<&5!vZL9uPW0yIIAM{5?C;jDv2Im_& zX@ZwGUkczm!J}}3_krH-t_3r|oPxeyi-yR%7%QL93z7^=aFWR6G%O0_d<&$f(P8MV zWt*sNRq@E$ao-a(-WphpY7wH40a6lMtS0gtVd;+PMQiob%uo#%Pvsr@UOtvPEKf1jBW&Ql4c;hgOzM^RBFV|gKxF_`D25C5!S3n{Z zTyg1j2MzaG=VIPVvx6m$rn#ZH#!P!hkF1mK32zFn^x^xVKV?*!%zis@;Usli{bWc? z<71`S->Vp_rYmXxUlcOl{cWVezBs3GdrNvV;D_`Yfdh-+r>bmq%N3n|cP|gW8^Ck4 zNcQNcTXqM5B|kJ?ORQqq zaS-wDFtAt5&kJlVKO}vDt_pqmiG%2u0s%$L*sAZU;P~?}7KmEQvMxX*cdsN}oAL^9>LEk&2GGm0+LBL-Sc zy?)x=*dDV0U${O!hfq1&8L~=Z9xS^}#aEyhkp!BcTCc+3+)@I(r-?2^4@N0fLqH6+ zAkm5K@o!)rTN^RFnn8cTP3V>N9XKEI#(jjKxNuho(nHg>a1b-RAXBhF7J@gGVL{^X zU0(|{*n{ekvJ%>l>e)0njlMcx?ETIq!f5W;=icJ0k8XSG9bFP!QC$tH0SQNmYOwmB z6~808jyVPa{alqT{zVL+5U=gPr9OZiuMsDj;63-)Y3Ol^|7K{ASW94KrT*(**eAh8 zUfo84s8@x6s|{gc2rZ&8-h~e$m)?g~K0=2cSuT1&gS{L?&*trDvcK=%!6EoWKX~MmVgex7;>*whRIWMjg!xzarA+|rkL!WmSMdZ3+n{J#&`&O_nq@};)ScZ2(u{jp zL&n(FBJino&2WqQ*S81ZW-RYzrfO_yW1H_4FYo@VeWl8&ZS_Z+GIIwQ!Tj_G0K?vA zfH)?ABm&L9_>W$Z_@`IY8e`iCEbR@1{auD-9(MM||qiYB5 zp#(fJkpr7lG?mCr)dOo7V`tlPu4|YS7t?J7Xh)vDvOeFVyy|$oSoPq!vV+QB@-|qX zetp)^W3WUhT*mfbtnAMvPb!n;kVikYS6w(5bk4x!)~mi~!|?9E{PD%9s`n|iYt9g-Y?9V4b zp8k&ye;jJg{!=9l@#mu;?}Em;KaPKt`;w*iozZ(ob1P&0b__jhjKBcNrP+6A@*32l zAezC0UQu|@2m0v#e>byH#R$SKt!@5I$y>^3%e5{jhC3P9*y~k9dN9fN@jUk80nEYI zEsKi_D!ZIaAFF+AcVByx*Vi`F+0M&p)3(>efvfy_nbYbzP6^aor#NZ@304d_l*} zr}8hqYY-SUdrc|!-PU|G1AR1e>*WDyD^gaUH*`nkf#^tLKrvPnc#InQdgajf$^?of z*(m$ZI8&bB4OZIcAwx9mt5Em$)c0@`&HBn7FHb$cFi=RXXfnio=N-(r)0sQLc*y}_tMl~Ec86sP7&wKd1L}!P9eu2ly95y_;Yhnh)KnLRzRUQP6AFN$Z<(U{v}K-?p`USippk#AG@jXHpx z?tpqBUj0`5)r5Ca?>mv+onuQ%TkN?7B8zGA1t-W84I4Vo(swXetbD6^GNQ1V;fR+Y zhZ*dICd>;;sEQdzbvjxzW8%9EQR22b*+JR%_=J*#uV#vjMlFr#eX~Oupu2CkLCj?$ z8Txw_H}&Qq=eVBd1v}(?CYG9*^HM)jkIR7~EUi)tm{px34rFQqE!96zh3Es%=P5+{ zmAxzJGn4xv_yvy_X}XY=8Py@ISXqSnl&dXm&C`XxU_Oh}WjSfLORhk6UgkEN;V6iH zzm$7x*RoXHQYa@Xi(v<3;7=ABSZWeI`m#hsKG%m*ciQAI1yi+(EqyOPq4mWQUr0eyvJ~ z&Pa&KOs~52jY@`++NQzFb9jY_eq+mvN3u9s>@&tx-8yrxvRUKCac+Ic^KQaPIsO=- z?Fn;NlNB{PtWDqNp$zZL^UvkbfTZ-_+!O%4F?b_QltPnOgy(F?1+C=-^~rh9&~iah z#W2dH)rZ8$zzFYiZwWyOE^q}lJ_R8TDVUo7gM@Peb^i3Nij-%F`<_H;^acQu(#CGl z!XU3+lQUcSboyPnI@6y$?!g3^?ypStaIRA1BPaTIL-;$lRp27S@}=UA(3f%Mt%+Y` z5}+{{i%zVj`SZnwv|9GT_xyCXGm$#b)DKX9|9lheq0H>a(`$sdeZL@qX1)%4pL7*) zFo7!!|0?T&raP7l(|3#NxE<;3C)0fOdBA4l^OjSLe7Mf7E(vBDgh+TDhUHU%6S{Rn1S55c$RmxGq`t1XKC6+G8~6)t zktZuZQ7+hyH)*@cXjt_b&|AGbUtMHX!)&dZWEbFGq`ebIVjZB+Ww{&)LA}@K{M+?x zN5Aez5i~Pnid+qQcs9`;Xhzqw@2X9k&R9;9Y>G5Zb{V9cm#nTn;v6kF^=!57FomG@ z9RZXrF{a?j49zh6pQav9Wq-fv<{Ya&Nc$~fIgOvLLIW{GLf$aR%3EM$t<2o)FsPLnD!HPCHO z5+Dr8(3W|9X4Vk=TK@cVtOuhFag?HS=*R0;o(V=%XMzK%VyVZ?r zu$XEUeMhzhRRdPUndZhyax>VGwp?Jl01-2DqUJtbTt*<-b*6hwMfnx4du`{S$MMIW zQ_&Ty;fIRwQOLF%q6R_!4IKqK40fxf_<-?x(g)ygRG*J1A84>hO8zJ-d7tu00BCwI z!#~212YjgbmfgLd9_7#?aK#e4-jcke0}S4>HY}u-O*{%y&<>+NoXYP zr6hG+42&6}GK-HU?qF=aTSlLkPvnSIQO`=Hl>8d@Rl8-<=fV3hs4y860=wS5pdfm; znq#DUVcRQQBBL1cOGdpar;&SaqH#06e|y|EPM`us@g~c_pICFux7wt8)rUhR>O)9( z^K|N@C$X!;?e}0lrssU1Qha$jGI?SBUQE`h9{dH=kO}P@m(AaUt4c!vG*XH9j_3YO zav6mUJ`Sew1p}Qw{T`G1me%KHU2H}p*4-a~5IzN5Hwdfx=bwAzB|6;1U*%c?w}N)y^_9edDZ%>`NLYI886To zr)GZSeUeP)xUHN3?sPcld7m5%btzAb{r$`lQloJx4QCBX+2`5f zO7>64fb61+;WTZY4z{5`^X&d;P^_{=cPf9kIGE*u{*lnSLiHCjcYWZWc<#a^;XKMy zKyW(_{NlS!lQZ@Mm~9&Yoa4ujM0R>e@NZOK1!?}ir1z2LJ39FfPK@u*CJbrbQ#^a% zO*z0O0XG1=e|Yh~gv}?6>bcE3|MWdazcK3nCl@$B zMq=^bpT=)(Tscx*w^i|RDI)0*v?fS$cqB%yZfg_FGVoxNj1HnBEvw_-ODNcwRC8Lh z)C?u#=(F_4dscy&?70hdVQx_|*X{<-hze!9c#iOgu_rdizwLKrHIg@a-}!`v=_V`1 z4}>={nB-jE$B;`^?9k4yYf@%uDZI9>yvKZ!8Z z-NmQRiQPEu)fo}>Zcqaup<|R;aHZEcb7AqyyG9+O1P`Octf>NkM*%Fbwiq0yc3>ZV zmbeU}4#9i`PU=KayH^d?3L>{L*jJxKyOU0<^2UgCXK~8AsLQV!q1Zbz`PtRQL@(q< zis^OyAt*C8Am-8`+Xz7R|4Pne#DK}#W#UI0fRMW|iEx%a0#0AV9^L3V5t!)(ds+u2 z?C+6ZR6GjE*6JAu8`_wze>A}KnWw3)Zt8GTX&1dKM=ohTdx4w^NO2i)o3b+o?TnFC z8%Ml~5AdoDNB%)Y^Ge;1GW~j7$+H~;2f|8Gls2Fx_;dpCY_?XMVkEt?3vjo!o&X%@ zC0j%;xNpW_FCNi4dw8zUc#%C>ZIwTc1O*Q45b|d$X$`U;>HBp!tw@uY6ZY2#{u^?H zNnHX=&Xp6@F~F+lk^?ix-(!}$Q9^`kzp?Q&sC_Z|8JdF8(xoO)02p%2fYjd@emv{7m026>U)Gu}8S&W%FbLmmviJ~rZ z@$SjI7bYW#h!jDD6%y|;wh5b&sUiq(7|+k1W%q2p>R1Hqm34lNS#If$_V|@@3GZH? zCjV<4(#IR7S7_CJ??rh9?0Tobc^MHhqT`EbHZyyJKZjwn&}E}!+ofI1Jg0XOdws2n zkwLP!MucvXk7)+@ZQMlYu1$v*y@kF?4UTA)v#L+YRdG#PTRPucyCGtbul|15rB|D#GpTu1JZ9-sUDj5PYe z4*mayuv7ieT=sriN_;~17ft9p7W^lg5Y-AdgwqJlr*hX7dgJDy=V`!CA%W9k3c zf~0~2jcWV-HkY(EC+W|5-F2^752^@l-EN6QJ?!&~8GTJP)nnxzg@i}NXSK9HS`sbC zjH|-d&YRYJ+Pfxey-?&i_Y7DbUx?QhE*6eA7;VehA}Zz0EA&KyT^K`wwPtszzEu#t zDlhWv+WFp23AiYMe5B`{a6!pG3Nrx;F9=O#=A6C7{EOB!32z37KhG`7s-=XxZX0amiv^Jy(p#2SE zk0&5-cf<)jo$F_CuQhlMIxAeAyl#Nc4iPAO&VBQ=*Nod?Wu#jWqpsYq9)+=P&-25& zKYYRQX7VyJr`i|YedX&E(Pi%{=If#+<S>O1>sx$ zyI~F)SXo{U>=dCPsdv(%l;8-xnljgYD7b`>iL4Jag_~&3N5FJDdRrL<2C{#56k<-QX-; zQ{^X|ei79azkQHkwK}>qd2{#{nm5DFg_#B1qe$Wg3LeoDLv0(uFrZi+{u<-9d*&jZ zjGtw^A>TFMQm1O3d5r^G)FIBGZEEZtSDUe)gyJ>XDjJTNv@RDECLP}mJVbmv)C#&N zW6Oq5IU$kpROI0dBGXPOO1b+3OgDX`S8UEsy{78D!YdAauCtXUTpc>CP7$|buJoPL z^v+_3|MDGZUrBj^bOPSy%54jWfReKH-KBE|u_sW8-VGp^se!AOH@T?24`w14*_x{`ard9ToC|@W8%o#5^m&c!ol=KLUoN{;!$o9`N2@(7{M^8 zqk4Rogg%Erx8B?0&+i@im+b(8us;!T0hL4dYx z6qq;LfPm4A0uRCgf;WpJUK|VELo*Va_Or+_&2ntvB;$Ow030X+a=eCK$cC$P)R0!H z_F5ozCe5|LH|x>FrLT&%ER~_Y)0QV*)HqA*iH!D{P_9h#DmpKiYH5nByeSnIy_ocL z;jG#TUN!VvXn42}FK3U+c~#nCl*(nHtm)Gx0-FPREq8J^N{o|GdbNIiB07+Dx_GJ~?kVB=y8kXlDO9hdw)$m9?C60JuIYNVF<pv5HUc~Rb*-T5s>f^3#fGglW$4dYrfQt&({aVa&Emy4~c*$e7=r}EMxvrzLU@z3h|KOuX6 zFppY}&l&tL;47WV{3T$Hxkoq_%3E`c;`aT`&1+4%0el~0DI>4@I|nWewF(T(l|Ed2 z8#arjBo#u%l=99zuVp(rQOEkIx?0I;#->ftZ4Epbw(AP6Lu@+1i@lg;;6q?84GUpA2<0FUzoF4SuuiRL9h{n10-a^h2CBctCOA2|pbkjc^`#(t2)$Kh{RB z3&c+0ga+P@gzOnvxT(qx)*R(0P||AH&Y&sp6euNw7h**QuhYHA72%;Wp*pttvR-Iy6q4a^^I!La{jv-UufGlCnXz47!|P zMbS0`tOF9DMXSU0)e(dsym#P02Z|Vf4NT|B*Al*)6yh+-z=lA&!QmZMV5}1Cf_Mk) z8uiTXKLi6WxF_@qy=(UeUmdc14Y>b?fG-35#7DytO32 zW6GW-0m^yIwakX67GEFWxiP+U-p-Jx|Jo%oX_#cN_tG! zrb^;s+&3ls*2Qna%`cS!Oxmuw;b+IwaOd6IXLa=1u~SlfCGTKby*ppn2QImK`?~4UCd@a42zR|!TuA1p zO>?|cG*mWLlNZ`OpF=BRRtn4w1$+%P5Hg_Mh419lPkP#W-#__{vHyv60$J^cxrh{lXfJzzlU&b|Py-sDdzyXB zlW1cX!E@}QnQ8-X650C)iH>Z6U9>Qn+ekL@_d-SGw_&tEkpaz+_3RtwvZ9 zvxvAQ&4K^yTr^ys`moMXK0flW+w)DPbULo!-b_{JyjZW^x~QU1(!f>KUpT-7g=+?+ z#z0{IWLo%d*)3zaKWsKZIVAglt$$Dmo&h6-UBpKbz-8hLyfbuu-V&tRHT>I1^Y4jv z%^QE9L;+*ePb1rc`S#HgLm$ZB*ujnvt z`8w}E>giPf-RtrM#=eICq9mDR-KIGJR%F|+`}UO!@8ihjGS*H#Kw|m_nhB` zSQ1)mODB@f9J}Y{_Sy2vrSo^h`54N?7dXj|z}+}bx}1VtCb5X)rY9!p-4$^{8FO0^ zmN!osIz^e_7h{u3txrc^N$Gqo)L`@JH|t9RmmEO}CL}i`cJbMO985kzKh`lOti`^P z^$NsBkW2gOTDlYYHz-4=5?lhW)gdK-(U&X8B)Ydl$9jivqs_vBj-dQ@inz-i49>)r zl@Hlul$rMtIF7dsM$e34>!T`Q#|VsXT9vD9zQRuv!ox@=uFp1Syt&F z=H}(f6N)Ed-AJhQBfzN}eE$1)Odj+cLSKU%=fdeXQm1szhCT9b#}5VRZ}KBJiF88o zIEM4>OO88xNE*$1HM*zXB|{jx92J_qr80`NLF=l_%f6ScWXp+le!4TC-Vyz(Dx=0$ z`t+Kh=4O6@ZI*>M1eYZ;Y`cpqpypN5mE4S4w3a!>Rd)vbRcFOT5?QyC5ODg=OZ8oER*xVzcf=zr!5{p5H^I=$@=#Rg)>b}ySTPi9m?spxdrKin?k_BdXE`6g(=8p zH%K6^o)nL!bSr^->(fcdx0EyFB;AVifv zIRz08K8!aXJA{qxGKS1a zZSh;gD+xWX?~nKI?{{kykpob&Ui?toj9RcGIt)zBAAQ z${?O|#TM+v{DX#HIVYj=YKs5GaJ)+&gNl0FHjbcBX&BhT?Iu(=Sk8C=K7@KPoDn{> zB95nG*EGvj6q)9rLA?x0B~zl9M#aUr2pk%gKI;Rt5G&+=8SetIMet|;uTOYE z@B*fhu{YXVzM!XVHOVRWKFC|O7+}FsUmPN;3$hEAi7D+vx7JX7we`*QggcA^WoNBj zOwuCci)$YUZh~Ke9UqBlX5+n#uk9r|88^f|c5am$5{R;o1C-chK5oh0InuS59tQ|X5nU_ZJiLdsAACEK`L{uu3O$v2sr4{S5 zTXzS1FcWFlQL<#WKH(@*rXj-qUG%XhS@TY)`HIvQ!t0273H~Z z=?V*n@ZthjQ)7Yslsd&aH2414pVs$d4YL4Dc8dj;p`MQTNQC5tt+r{zbB zQ6+A7_B8#920IN)!#j;o5JuZ99fcKB6laZ_VJRD3P03JtqL^_ptq!Z`2PwHIuXvXl zgcah|7$A(CNy}TAWo!c+Y;-`TOnw2J@a-2jjKqy{9cd=`y^NE65`V?CXMU4)?@Bm_Q$U3QcZy880h>B&(MXt3 z8EA|-H$RVdGlp;{b6pjl(=z^x(qQijJLa9?k?zD_KAv|sm;zfZnG zJy+EJq4*I5@bS(8<;g2Z`!%lH2H`VOfEMly=IUaJLJ^&?Gg%0iT!m3~bw3E#dh+GR zJhdUpFC@DoRWt&ak{pNgO^px(y^)6-A<;XwTyGpMS-7i+L3?{^Diu~glv^6z8By5C z+2q&RH)}D!V>Tl}xk=bral(2IX~i~Z#i-ouA!z8R@F#qFSA_qfn`-C%zW#EKnM`S_ z!IAO#S0+2=9mb_%MqySleWl)lA~-wo`a|X;7@}Rf%~_f#!WfMmfeX4`B6?zHLj2`t zXo$Ml#xKkrtz2iq&LN;fFTfEnE%_4#Gfl-(_@^vb-Q)Y;R`m$mV@GW7bY${%x^Y0b?P_ zSi0D#YNB?#13R~{Y~*Qi2mQR$Byk;AnVOzd32pv$&0fZ&WUN>@9;lfXRWrqAkPd#u zvlcFOmvsFCi)^gMEv?kJbgy;we<}tLUYx&d>q=A7(Jqk~4758DEq!8g@z1aOyJA5EI0YIUKFH0i>jKt)gQ4w|IFt(;)>wn}m|BiHps z73&n{V{g^kc%5T#-^10{4evFS&$&S2WmC4q-XSE#T>YFTEhg1~hLKt%55oDt zRD#x7r%b&})5C7}PK$1*?4_jXZ&X34_dib%N$xgQh~`e5n0|j9y42}I&+ieiw$cA! z@+^ZEcfrQQ#Jfq0pzCf0GI&${HA@6eFw$=Ytr$vFXtbe zo^!`P7NG%$%HP@}nmDx!2uEHhFe9C%EWBjA`iDPt*Z6NG+{(Whv#93}P~t{QBWvH0B4B@gD<(7gugs?uQE2r(dNG~Zr5Ok5Cf!O=tS zr)zuEV&gWN{~pRYugXWF!h3eb9Veo&J)QJ{U?!qs_hW@GAvhi;K&hDZ3`EU#4(jA2 z69j{Ce5QfAP5zN7>!x^^Kx zvDie{Ovk5c$;Ywc$#Ez_=*ZCF^@ z5MY#(=IAG;Bfq)?l@KqP;TZ+W+TOZIvH;M0qyXOlWeOjn9jvM_O?0{)25ij`ui=hL zH?^>!PP2Lw01O#1A?oz8_WqOR%h{s%tqJ?;5lQ5`qX+g3wjWMyY~@8t_rIpx0$`{X z9#X9|T$*=e%w1!%ER8LTB{OY@p5Z>Nevs_W7v$(_c&GS{%7UArhg%wFKzq;Ht39BV zO9h+F|HkOOcXJQDcy|G3O7zNT;Ww&)ux_llW+59-Fq+-|p?R+Yz9HRreJGO;kmcV7 z-TlvHC?4ob1|I&KpZ3URdLMVKxXO*qN2NFATcq_WgLO0d$m$g6X4%H3B-SkXJ5$gh zj6KgZK)}z$s1q2qszHc?!1A1x%MmO5eKs#X7VYK=7b8yR5YSygn&-GpY(ArK-d16+nMZbhQy&l)wY=*kV=hnaWbh@SnonJuQnf)nI9`aF@9iO;;C>%h}hWUVsOJu>_sbw zWd*s5)ZlIknbJyloVRj|h_tpc;PyYi-6QY3PJr38L(ho5ES!3nR>1C!tsIOw$gLPT zeaj@vlA*qLct7#pRB>JA>cElWO2TgcJUW*WAi;9cDzaJjgN#>sr!^~tX*G~;XWw_t zDN`Y$c)&pNLype57+3G8H%p(2F^sX##4xn6?T923R8jGpF%H9 zt%vV;fI3xFot|ZJy(=-nW#T_SYaO9m^)}G6<}$gERie&#gYp}R?eIF$aQ-W!F^-Wz zsgydS!3d=?z=u|bstUbz?H9lwjA|R@bz!-k9zX0-GwZALjz&H0#uZ!U0jL=9F0k`Y zgwz6r6KI@%Kb&0JY`_>wIR#S~Bbm>5YZOC6Hu_OSt?MzZ_Z!BV4If_|+#NB;X!A7J zYwmB^MRts?&E-o1!6gx0qhTO=%?iF23z6YG&CHTdnaG#E0y z(iIb_wT#TSvh}*Na3EfDz2_3Xr=|`@;q1+kSNrXMjkU34_x(*$!E;cWC_GC#XN3iA zRQu(^42i>+GYARuLC=8z2Gc;H1VE{IQY#Xd#!cZK+OoIsYq>w9SMG`9aXoRl8pAM} zRIr-jMV~_MFu71fcm2e7FsU!qqhH#*<_1pB@cR1b^P@OSLSk;Inn6E36R3^3^&odj zSfoh_i(5P~v_F*50?4G{fV701u;9Jee!rES%;WXB`LanA3L=e@X1SIHJEO=GUd&=(jDPq~-p#Lmpjh+u33rVm6pBccj{02u?2NV75W8gYO^?^d>U zNJC;4-cKH>ku<(NSgU(e^*lMnXb3GOe{_VnIuFM51vE!BY4c@EU#7hmW+0_8%M!=s zXz}zL)ir6N)huh_R@?^;=s$teV?XM*n=RW{)p)$9nsAt)VGq4uKX ztZ<6R9CwfvCSP+RwkA=`5%~I6am1hwVVT1E`YV8Q8Xlf!>nhq=1cJp5ojAsEF8(_$$}?6l9t)y4fQ!Jm*nlxI=zTe`DtxsI-9z?5yr7`7VW6D} z=_4YNWCANcx(V-`twL}57hKLFEYEF)ko*EzD{CqVYPHH{F*Q*0CV|Ih(KXr+RJ0s^ z>4nYTOON|3{DN)sa`j6Q#QQc1n_}12p&0mV8@}p0t3g8i5DhF>+LK)78PBh^)rkGG&%TIoG&K|-<)N+O$!b|B%{{m(yweBGMPT)?Z*V@9&#kq!3Im|t! z=rFNZ@MO0qb3{R8ZW6b`1FaTysB`g7pp;38m-o`>C?b{EcciK`wt~i@nTT7M85Nvx zI$r#pxSb1rnQ2n1doLKKk>c51MpZ&y7<%yK#Y%4+sF5pXCxy&vuHpmG8_YH-R`f=g+8bg_de(|+vC0wExo9Fj$1=S`pfV${&D{8?BnD@q)r7L zX0UyUTLY7Q!OmGzezhl7>2b37`Qk1?*R(>l=h%&5)@zgK*e=|9ul`Q4e4^RG=-Mp) zmH|=ZWULc2{2h{0fw5X%R0jVwWQ%m0W$L6%lIIzzA_3#dkQ&EP*;Bt2I7}kifuhzk zqbb5YmmCY|2_x|V=LOv2p4ncm0q(rxlKrDG49%y&k=g~Z3f$GlAgho+i>{opP-&W~ z6!D(R?;UuDP+N@6;X|b0_o5gS!brR~6fu^XdQ@4=Jc*j3Tx6+)DN2& zJ=Mq5sX-UqS=qbn&uCfwhg4&U#T3!u|=nm2qxQ^Th}o6ITlqk{Sp?3dW$q` zRvf2fLVE5UnA#G=O2buu$>zLtbZ03m<*UqcJ8~jZqK0@6l4!a&R9&75JWY1KNlZdjBB7< zMgR%%QcIp0Be||6FWcSEU3s%Co?o^qNx-xL!B%Y6c{_(3YNR?*D`q`AaSqlxp+n^@bg9bE9D*?9iJn>*y{fa83HMP#gQ!jeVJt3mt`t2XYuO>lX%FTV*PNJDSr zj*WuhaC%6J+_UoDZ&X9WKc{m2h^}c~egpEk1B|Lbi~j#&^lkJIrvk?DX8}LJ^Wrtc zV&5#Kb@k_QPs`cgz1#ro^}p{x|J!6VH|}qdF@IN4{FWVl^eZ1}vj4jV^f-023Smo6 zd_9mVhUQh;P;Fds@)s^sHN;G|G!_~GK6$~whIH47{Lydq0t)#mjdu4NnXzh zV0m9v9(Fb1OHh_vR_YOkW8j)NX?OhyIO>B35xoj+z;OI<9uN2*%s`km%CYr>fv&9s z(M#Zc0pMe6j~vLpyK4Xp0kyA*=)FQ{BWFi{11{Gb2|O+9JM7u?&!)#Wv1)ybA za&GMll^)q6tH`L$%i!ZZhg;%KDc~-B#E5p&RRHDKeRVl*QMRpEns_;bqK>RxCI^s! zdkEN5VG-Z_j#r596Z%GV9{5y~hJkf7%7mnMq|vs>Kym;UsI7r7iRKR>jjgXBY@PnT zMF70Q-#Ga|Hi+4tA@D^1f6V*&+jiaGQ)mAn(1;=cOjrB)kGS^7iDqv5aWz}yG?<_& zfF|zk-g@44KEY#F_SSsg2Y;VThgd`t9px9GiNhjdY-x#YM{wPIqOei@$ne~32l_Nj zn4p^D=*2qng77E{C(RB;TT})^bv1{aXYnakD-+Rnj9ie{^fLm(QTh%LDs-lbB%XR^1xP3+-}sq*~|3xa=?LznuGaAv~7DftW(~85e7D$gsu+nfQO%Y%{}As18=GzhLQ0PddSTO ze|jt)E)rIzz_>d=wcGam8vidb~G=gc5j^MJj-?B z?8Ao-HP2jfBTfTuk-1kOyy3uj{rqefI9T=KD21!`E2fQYEnV0-S3M8a|=)C=YM>gkYp=ZWLLfnUF-TtUn&F^(J7KsZT4WWaBTavyGXxZg&n%0J+F z>`q+gYXLS(RPdheyK^@KV<6XUth56h9cdZEe2HdWza0bm-H6$VPqKn(j_e!v&s0Ec zbVdsl6=ncg^P{8P}jVy%0=@&R-#TL*yYN z3Fs*??!b-vZuh_V*dEbB15QI}@G>AX?ii57OM%Y=ZH1F`K!YJbE^Qc?80m;4<&#^1 zG11%{k|=T?y%1DwLo|mEECs+Jm{JkK(#C8i1aNbeT0i!&00U+P#!0}>5Q037z|V{W zoNKuFpf1@Hhdcx=wGl0>fWw82q{B8C1c3j-z8`q!RI0yGB_fN!H6Rk}?EV{aVe2_) z{ai{HgV~!DRT@IcN?$o9kElGU^U2!Tl9GbcWvrg<@#Al=Hy+%WxOH*oq6MGQnVY0m zz_a3YkPMbD=hk$H?sRbLNYCSJNUthY8j40K4I5>+Yv|-JB#$Ko8H_41V`6{7V?;X_ zRCyo9-e_;UEPbgo!@lYRZ(osPgYrQZ>@pjz6_05c@1!TNN!Te4|Uh z39-yNy%ZMB9RMRiG<>l#sbwdDrjk0MG_-SQY2R-}|IQjFn+c_A(N)-(b46o(okQW% z!Hfi!mwmn!^j^sQRI?D9V*Es5wVCEk-JTQ@R zZq?Zp{bak#4E6oV2>#CxktA|k+V(J!h!sRS0&4@I+$5P% z1Q}O=N=p-j0g*Ih2Pj7Hjd~I{_y}P=*>k3pv0cyprepfe3Qtwg+FAW5S@rT$HgcW& z=Qo*BZvZ1}n;|6^i_2m+fS)Zbd>Xuag2)OynH3|z2es&qUa=Gof{`g@=6x&lx#HKF z$%E>6#0^Alzjm)TUKmp#dbRd+Sd7waFUumkMu4Vh0O+*?5JlL?R0yY8(ghW5;0-m60M`HyUmGPf05y!GFd`NV021Ax10~uZ97((f zXe$z67ggEc2Oe`dv+OXzBB-)77gQ1J7gp{rm|Rc{6US#b^ImMINtNwmXl*NXO{bvp zn@Zgk9}9M;Juab&T|BOY=)T(5*P{Mqi9%Vz?H}&r+)DfUit`&9UpF?qD9Fa)0xTBO z0}39+Tim-Jz>}61#pK$;x^SPP&MEzaf}8|goJ-lIJEPMyOGEG4h|;_5j(zK?Vjl(n zNAT)5yevdFtSvoT3e@Y(lw3RXR*<<_4<@`STFAy2WSSmdV9XPdr)Mt{pU0si53e>w zS4J0bTEB3Y1q>!CWGeAB$Y&plf!4kbU>Zsw@&mV}Fvf3tBuM;-1MzN#(udf8*me@I zdD=lA|HqR6x$Q~(^GTrejSARq;n_~t2kL>i51D)CQ%UOsiGP6S)c#8d3uGdkWDUCd z!y5Ql<{v7_Cyak3!#017J8|X^xt|8q6=2~F1d$a8hyiqE2af^VbO)m2F?fXqftN>Y z15hs>82)$X=}O2yP*;Fd@xS6~wf^Q?9Qub`MS#9fY@^UIAIVO@#~@WS-RNM=(HX>9 zw`|tNQ59NwEZYVgjBmFI?2r}2{N~QzG_rAb2>s=37^iJc5Hn4zSqvrS-zrcrR)r>R zBX59vCiu$yi+z1~(m+(lU^muFN#)mo75gF+%xK(>aXGDVxO6s=B%8d#2RsA!!A8R8QX%UY8g|;&; zW1~Bkwx4YboC4f@m@!`Ne(vHJ6=n=y*$X|EqQQ4uC9jo}?w;Z+8QTDp*pBZTB<$Of z8&vFyT`t4Tp2DvH&34BmzNPaLyF2rp(F#;}_n{@JpVQisSi(it-KYc>0IymMQ<<2l zLE>0Rp6QEwRhfNU$zv2L`g2ClvdRi`gx?u~r%Uy^^ASw~h|ja3*%usn#Q^vSod2E? zWIWRW)94YP8J}J(!SleDSGId`1jWNEEYTyO4~f*pcG{KnyaXm&%ShOFuk1hlV%=Td zFn03_II^SkUEZ%$*?D)QPU0EoJY9W)`1Iw~v)5QzQxB>1U_B7PlY>|D9CtG%zXZEa z)A#sH^k&nLku@1@5uB8wj~tRlVldSHI=SP#* z3!sGyU$`#dKQ*aIsZpp)$*wRHY!-8OD?5QLq*)g=xi-T?unjLE`r8bBNeQaU%Ud^< zTb)Qs>iC8JhM$vk6%9+gD< zZqM)G*Wis;Gfqc~M}jI&7Go#8kii^v(itGYAlo%1sb8+!3sXSa^J^)0*x?onxJx4h zbvcYR9%pLjxk{%jxr#yf5C`+pJ>q8Op2)rQW-km!!r%UMNjYN2K z`KeU%pHOREA2zr%yz38?5>G=}jFWhFDme&auF2hxov7yJkGr_;+I*e>wsJ8EEKeS% zen!Y>F9JQe$}Hu;6aUhBkmC3?C()SH2wu(rq+dx2OMo|G08rpstwDA&)sUzEcSY&@tc@;yQg{%Z~vaX z)hk|ycfuG%w4JN{bx;*VWb9T|8oeh{xoXRVAFagkXuN+G(J{Vy+28-Pbun$k2izIC z5J(yDurVW@9oYX!oDD#^g3kKVgP!oxW}DA!nG%C>5Y}sHqDxtFZzg=>UAqZ4NXe9o z85l1aGr*cktzM5xxz||dZX{nd)y5i?nAKQplu*E%QfyJ6nP_HlC)56Q^^U<=(tRK% z8P;0oh?9=smh8AAGUR7+dh9aB_&q_!aA~1$`>}Cp#(k3lR_N_FcPkYNTj?HDR8VZIOPv&& zC}(4%$0BnzZub$;o_oMMY|oLO0Avk4HthWrg}VCr=||2aLjt7R@H)TeIcUe)jM73~ z^?hD%XI@af$&l|=|MAzS3O_l9U7gn1@uqYj@p`l4ef!k-#Me$8EoW?edS3UJT_R#| zZIS$SO@z3Jv|p;nC;PeGPCk7pfq7s5aW^S!YBSPC-Cc8!VV?5DY*+dhyad!k`qFzr z{W?#}jNm)73fv5$li5jEGnz@(FD6rN{;K}_Mh|}rag{k5XW5GiB z1fiZD9@7eCY5H_Rt6P|NESt>xhn1PF1qpYp3(Q1&OLR=u%+lXii(ps{XrA=}okxp2 zx_oQ92K|E#m?F zk9#)i=5uP?GVcO{9Ij#V4NH2MYM$|lm>j##I{Tw4`E|7;cd_`CzG4fCRnTvANDpF$ zP8$j7aqvE@Xg$sm`DW~)@ALy+zBtc^vNZo5k!_CgO`~S< z5{Z*&AvEk%{~k{h3h~ew^=i@q!hyWTerW;-(oO?UW_LBgn09wXMZm=S{-*#L8U_R=@1r4YhZ3cU^92P+)fHkUSAQ`m$>h5}6$ zFfabxj&B}!JroXsT`O>X6gEFEjhVEd^dlTlYJN0X?((DC2S(_$(^bD7XgPwH2O%qM zz?l9$&|F!=hiCUNSOZGMKsYPKmz6}oO)L8naXRya2eh9cSLLA{BB6H7U)aJ9+%XmmA%=Wc=Tst#L`Z)<);FkMl+JJD= zIzy&-!iL`Aq2%1o`>Us0Z&`f}aEn`XZ7T;870?v***XLn3Zwg7m||Vugk6nx>b|1l z#Qs6be6m|xM{3+drWBP|tzFKOu0LUeI8XUFWhzX)t4csHhjf~C*t;0bA)O*Hrp4+l zs)%z9noJ9&IuDC^opo-fNVKfz7`hY=l21Y?10bqe5#C`#q98t>MWhS z=l-^zWkNT{@h)9_Bh8CQpjQnuCZ~c|rr|UQYzZDXaYfc=izwBw4nN9H1TR#{;4b1I-ig0TQkG z7Z7AMNQ?R#)paNYKz{%Uj+{UpZS4st(%1$6vGf4!?*D7=+ry!1`?g0&MNP8HCR0%=No5vV6ks7GE!yvjHc-}+i?Dc?2{|Rd&5&Ul}j3LT>Z(?#V-7}T2RB(<`u0&b9VurpEn{~H0j4G%t$NU_t50&8{S=2 zaW*hNUAsNJJiEzCwaLV(Hp74ckP2;wWeGGcdT;$C+e?r?>c;){!ItZf9^HLx(Q>X- z=(zcjU3*Z#V;ZG+DoinLo#@Sjz^dIy{*`>TVa@vti$bIKnFrHO=g9YJ#X4?^RoJKv zv@beu-utR|@sXr+YrYiLcP`#3$Gh;NXf>NV6ArC|-gaT%43rapdi;E&Iimg-O8?J5 z>35J8++sgr_Aj9SsDEUPDaw01b8p5Re#r4W85isbRwNvb7L zGR~|%b9Fx3Ai<-k@mM2n)2S$ctFOWJNaEUBk#NUR39v8`Lj^#IE!ellUkNOa{!GJb ze&8@4lbc*%+zogs!vSJU@dR|KNBVHls`tvCwkOIy`dKm7C01oMXAh2&l_Ja2%2-(| zPw6QYG?vUn864thK&93J?=h3-@v=C^C_Dk){`WHqvi&wY;!eS*B`cTdX_UR&l4g;# z{z$CGfh*56UsMF=yo}s?_#re)fF4tKfq@j==#nECmHD(@!R)OzyrQFVg^5;u%lx2W zEPu;E=7P6jsHUaZ)!IZtYx*1JO3-qBnRP%T>|OI1yL6Tf;Kh?5VaCrYk+Si~GOP?V zQTW)z5m}ne4Od+w(1G0&(5O){TqFEzfeE9fdiU}1aT|>icIgI4?HsRu-tpeNrIa^7 ze^@PV6y!FB3QRh{M5#pFjKA4Cwgu8GG79d=i4t|_Of6NTCok$`=PT*lu~uox*R|X3 z2u+GHF~gR;Py^Z&gqU$N7~q<+2?Qagvj=2=-%%`X<^hrp;2IfXyBiYjR*B&(VkiIy zBfS~RK}U{A9TeO!gN)q*YYI#P(d@A@Vn7~^T8 z6XWS;e1405@y!!m80AxVZw6peEH!5DhZ;&aX8_chN_RtS8~)%}s{wB$L2q+;W92WJ z*rR7`Wg!Qvm4iFz5fhI2P)NwY3K4-5x4?THJ zL@oybHKBTGnNN3|KH|9FJB`~ckx4V9f?DQUvjOYfN>%xmmLJ_Gr z)~{e`4~E+TBgwFW%6XOg`>_Ne8^$W2Nnh9=yfP!;pOb(nHSwx&v;fPgp9p_JVL0Ic zdU=)v7iK781s>}^ zwtdVCc+m#JIWQr~f8)jj0dz8do}Dnu<>b*L4RshMf}0ViyleWy3H|pb8C*+HvY&0^ zQOCKsad?ac1b_J=7;5gM*$E6M4&TQEo_$yLVW^?Xj{x3>JbE31w``<73mw&C?;9rN zOpoN;9mZ!%R21S3-&362f-ar~tvisYpR0fRX)7;Kwnkgq9i_J044?0`ZU5L=B`=}g zR4K1gDp$F7`!<0yxbPSI4b}$pNB5iKRm%IOrZ2WB2ZG{u3YYbdE&Qg+kZV zPIM%xo@-g3WPJ0~v1|r|CewIlxO7W#OU1s3O~yNJ9^drrE=}_7cJuQGozv{O(whI0 z`zT@Jvonsx=42|?ee>?-0zUU@)0Dce(O8ks?|5nG-#LJf%?bUG_b`OzPv`IGdq-~k zT)6BK*5|wO4_@!50%bBf1&A@v%Y3xIs>jV&zXS~ZIYmt8p8}X>Jo-OUl^FLa-0kGQ zae15&t~+}d=;q8D#Q@y>5Ti7YYk>=W&*8P4RR(Ca2d-BF2g;b|;6nh>&7zeV-Fg9}>{p0;pc(>oU_4h8c~duIh}8fYc>~BVhUc0~r<$5FKz9lUr0Iu#Q{h_h zU5)FXIHPjs5#Fcztyo2^GZLoox!WqJwd>udp(fGxe6U;!v?G$3_hY zug8rlom8C=AfZbd`hatFXBOSCG#}gF-n65gSg`HRL?fl{0Obw`&}E`yc)y@d?8hPL zr*LyUzepH#(vg!&k_Oy?fjaO&T?1vl*}=j0H$iWp1@w@nFA5&}Kls7#Ln`p&-jwH5 z?j7Y~3iqg;EIB@7klL1n&IxD(suqd4qa-J8DppXBBAx3)5%$wc$nEuZ{dni3D+YUtjD+s*u(Nj zD%EUDw)6!^{Ig8aPH9lvBtkO*EZpRP3)}1qDm>_4H8K{MlU*+gCC^j6MOh~O(1afV zUL!xbvStE_2cuGlaEa2UDV)d+hi()PX=AKVvr==7z(1%finSRHe)AWaxkbf^cY=s4 zY3RmC`+-VKAjI)y;7ZAh;qXfAww50Ff+{2kAKF{gnlozF=68gFO~1HVHB((Mp)=Jb zz5Qd?hec~V#4@v+isT~OAOHw5K9f3|kcfU(EZ7ycF$DlFAcjPx{OAmTu^YQLV?^l# zbmmHqg}CRrbH$H5og440lk&=FIdt~^Ba_yfR#sLUKeuzKlXjpnnAqTZX(DO??K3~^ zi9)fXjCEvB#|utBCZ6Vg*j@8Os@z+JE9s{E>x}AyH%CP})f#tb#SW!^u27f>gi2pR zZl<#;qz=n3C?QH21~EHgO@bBjMw=Y7M)A+lqZqfov+aEx8Rn#K?kL!fujE(s)~ZBA zOp&Mf0p({v-ub9x-*kFoW04E8ng#xgUIc_JE(JjjR}T2y2QqO;BpPgmH2PI&Muh`V z5ZYy&>)5O+sRM+bO9cQ;amLV)vsGafETRT6>^R+0L}K)5`}EyNAfLe6-O3T8Ppqie{~PG^A_ zC3Ock4Pw0G=mMh?eklE;=->EZGC0_XWDtD|t zPV+;4h5L=997|-S2&)TR#fW7Hz}M=9+@ALYT7IQjsQ!(s_JI!zEoQqx4fl`+ z9PFgy4T4Us3Z~nLG5Z8zS&4~d1@xRc%0o-svNFkMYNsO&6E&g=uOagHCXLf~M|Fvs zowqu++@7+K(s*^_o9?Mq#7zH1Z=Y;^`#3!d^%@aad*5zZZ>^Hvj*1G4X`82$3Zm>6 z4|Q`srC|>FX^aLjrPK!BNp$z~Ta<28u(~CUt2_6;f7!EiyUfkDS_l2tZB{${vY7PA zUq_^KALE1GW)XwxXnj>znX5zlp1;%-dVFuWE-G-5ni!N8Hwy9%zC!LzoGV#qs0Gnt zEQ_HjUsEYojaR5Z^9^1Mh@|^#92^hpG|sTK))lo=Y!YT{QBCwe+p{(MeuXQRnOYDI z^Ko-PQbi2IJ*8H<3Hz;p6NS9bAG>cXxLdRtso#mC;fqbfsWLh5>V!Dbup^xq zhF#kW;)z)Xd(%M(y41}MXjxwg*wHkZi7{*hv_`ujtNUq?*Ij*A zhvUZ``C2W#Emu@7Ei5=_toUe+TsO77pFUOwwTIKufmn6U#+JSY9fxjzyH)#Y^?k6F z50Bj`e>iZlu;9FbvZw3m;{K)_ZG~U5I&Ahns#!Uc9&Q0H*f5F`hIPow(o#`K;&y1 zjhpUbJ_bdgQRNh2N%k|d(%q^K#v-A?d$AYKM;|(nXuLc7Y{#K=&D^wg=n3*5Z8D1K zJuneXbNN)jQ^Gk!Bd>C}O%yyq2$cx0VYH{C-Ir_rWGZXT2gyU8#P4V9&z}v znAMB@7es^)tVr4YM7g!#A8k=DV&+qs9(}iyo&;H|%87r`P8#(?a2+&veaG!k{}iT@ zwaEIv;e`Xd^#gaqP&1#NRehS;S(mwR?+~3901w(}rzk%J!XuZ2(8+iMpD-~jzr?J@ybDS-KuMNAqWW(p{A%n8x zrI)8E*2;j48oG=BM*v+E@||aWX=!CMa*6_$-0nhZR=_o;A!`!_?iHKMyqwuO1ahfW zY;L-!@00rs$EX|^{9;15;q}Y6aRuTOc}#FVsNc~qf9b_tF7RAzqR^iZbc0jZIWTZ5Qr z!Whls2;K3@9WPpv>w%joW$ogM=vzIf%Z=F@*iysc+Y6lqPSH10G*W`fjbqaf#%kR> zIkTw-H+5uw(j|svaG)Dx66F+tNt{WdMUn*L9*eNzY!U`mE)LkvB@Rh?S0ys`i}zvGZ={ecSC!RKZ)c>emr*MWqV* z_7N{h8uNvag&coGX|u&cJ+a^nt(9RawhH?)ca#|4yW7z3_*zc^S)cw8Kz7Q|Ec+fn z6y`f#OzM5@w#e9Fy7NzUr_Pb)Nlh6NFFNC`slCp2Ub|$&K=SzKlH09`Ujsvb^e$Nd zM*NO9>sjy@J*YdE00Gm{EZd3hPuB^A41%r9tCRq1QJQ<=||9< zbpZ7mzRkpNWQrLAR^lg=+gp38ai>&1Q^|z=z|QTCy$EYODj=s1B6HS&`1O$>(%nOu z(VaEq?8P;XArbc>fW4gsp=Cdl3ua;-4~qA9-AaoT#K%YN-lG2JS2Yqhu(HxO5 z5dDI1d#`7&w&mHfmwhYH{7fPnb9aX2f;l!{ugR=l(>{Xna;t2Bj7K) zIh%7Edm;XScUY|!wdf~ng37vf)^l+8Q?K)#H}<&iR3w*wnu(SC&}%k38}5jYstLG z(K`^iVN2FS&2n#CT7ChVzu=%L_WAYVC8}8_N{gwGO_@Yr{ z8u(HL!PxnEKwqpdQ`(4o2P+6CDT{D0u>RwkM}(MiDR)e}tQveIeLl*0@F?}*DK5kGa)ePE3`;L+sRy zqYUAiu~tdlhN={+l~T{~*5xh4tcTYkI}(>d*qLTK=GX;oY5l_Pv(etu$)_;tUPULxQmIqaw@bY zO5iE+HFgIR7orNE+;BErqA~N#N&Oqg-4}=LPH?aZNd8A#*E#GYa80|d6?iSSgMzNR zh@p6D4=KX?)`5LDc0T7Av}}$)(qUw_nah1`+Vlql^FEtw8 z;UMV|KIvgrKy!O+?F@y2bH zaeE%@(As!5e{-XA+8NfirLTA7W$&+|6 zwSCarEs!&Hmc{_-ouy+bSX8u@AReISYu|n}_u5tfN+klw$9AU{Wp*R?25CIX&kgW) zQgJ}sUjbkP!|CZ3bDGx2kn~_t^IiOZ^s|BQI;u(@wbQ73$-Y^LwVg|v!goNdcvzQV zeIU?B$?sUts5Y{~_*Xe^Ew`Y_Jmfvo?tbq%k&*bNi4!HZbfYZ=S2Z%;<`hYzEhVm| z1g8jS!ST%l=7C*DHr4DFwtF6J7+!WqH})I}?O0%*bRs3N>V?OK>a6Nc3G*}|b=%lq zhV7rlrd^0(5iW|!$2P_6Q?wwC#UP8{GfL<*364lBYZt@yBe`Aq9&C#a9~+G@7J6#O z+4Bm**p!|NTexLyLK#uCx5#4?b{xOH==FE9&MSO~lz&pp{hBoA7Dk8jti%17^tKM` zif6hmj?Vn$g@pye8w5qSmP#4QoL+Eu(}R@@3XQ%6Xd@#F#WiJ?q4}2{zfwYD)cezS z-`uD$VUD9KMiEj)DmX6X9LLD;5an<}Dz4|uVd=heWsdnzlvOhYr#?LlyXn?a`FB)$ zo@Dg~{gyb8^~irS8rdZqir4wd?76rafI?`%wZ$+&IrPI#49@~15q8fEd^)?Kn* z^N0rjO0Fr0mrbZo6)Zv-T4J&g9QNI&o}F{O zsan<#Cuo?!BCDLOi^MGZ#3niJ?>~iQRCv_w0}Yc}|2N+eGah-=b|CP6Z*~bvi-~X7 z;4JrGi59^-7_H{qM*;GK+mFK2^o2y(1P0r-C=twlU=P=I6HP2-8-bsG>I) zZJ}D5^jX{59No__b?(;oxqHm<<%`2u`I3&K_u@U{H0;^Nd9at8GoN~HE3>oHT3<$- zp_eXiR?N3SE^KA0aq^8ysZDp+UV8LMY!_+?mr}ZAY37n_I7a2};DhonD2L-i22C+{ z&M=$8Teg~=kCHU9JA2^ezHMn6L3JHW^Q%GP%@gB~p@w&*o4caytwpY;qeZhgFAGl7 zwl+UKl4?cb>t-HK2==qxZ@cNpi)hbNgS0iF>Cw%x``%CN$BN^BFy6msKH7htQDo2? zUO;6Jra@LRW)CXqAryC9>BN6upnAL$5!46RY0I37*)Xvb&9#|Zwgt$O72I^3BYq(e zT;6Xk^WRjESpLCDfyxxoxv&u~C9B{ZT)oDN{1aBVyh4l2IgFYKskbM}}iT1)hK zhvu=DZCA~sGlVR*KaP%g^1(+@_o0%stJPp0Qsj@q-cDNVzp4P!b5@Y4fGIm_Goi}F zsP&v#r;{4Wl+2YnW~UPJ!c;MJN6*G1SB@X+8TUIKDJeqnSR5jKpN ziM-RVxw2wefC#e2P5cY0EMkW4fFQ`Pd4Is?-pqyv~)RAEDhjBwr4QVNErU?Z7%k#pa{t7`bGH2*I zRDKW}hMCl)L!8}A3a1_tpR}A-$91<8+wi=|mb_78nDCBv7Ketj0Mh->_XYSfSFOt_ z6LfxXp=`<h8yuB;%=kLRhS8NKUI(*nb_U`vs+T?q0TVp zV4@EECk*p2@op%0nI;v?QUM4JRKYijT5*m?ev&uZguFW^>M{R*UB^CnFy}&a~KQM6ghQQmuTYz|hKg zSZ(}+{FeL#vPI#Zq|aN^45Ljhcpd*#7v1C5Q8jt~?YZ|D^hsHHrk%#E1Hqe)tv?do z?Vt*@KDXUY@{%!GWHeZ3xVgOQG&iXg5dskpwXKQuEB8UpQBP_hX;Hzko?*+xU-Fp> zZ3kkzxm!PP8hr?7S-2=IsICxeD+Y;bN1E_U>&}`D!lWT>7RVF>(HvEH8xZ$4<~~&0 zsSF96-!* ziBKu6K%OS!xrxR+JTBzr=Pll+x$jyD;f$l$;k2MzD}wi`)d>-m-)6ks;^|_)O;uq7 zE?Frvb7ZtTJ3CO?+S(~Ku&bj>HDuA6YrFM@wi#r|xEq9t35y*$%x{KTaQ|)?SI!kZ z5uCTacYW_h^qrAz z8uVNUfCbK%Zg>e1f;Tl=U-eR6Ic#>U%SB?Vp_k%dkyL%k#MGGR@WSn~N|@4@XVV|; z&v(j{S+Gl>L)4O~#KuF#gSafiOXM8orAP%OD?JLU(`9YE^D%yTk-|^|XA?v9aq6^I zRAjPsJ0ZN{;>Yk@4eMd`uEhnbg@b7s3WZ@t@otfpo1D$2eMZ zib;O*1?5VVDpk3=#zdtUzj)Gm*MqIE&Ug}ejk7>P@)q9sE>!N|I#_LUSn>R|1}H{oK9N(KXB1G>VWkdv&Ew>(tnJUTDz-KEUBa~=0C|@*8NQl|2!hzuu$`#@EHNn| zBu*I^+#lRVJh%<(@%cpn=!P<9&th;VLEuh4!T^%F0*cZU#NGw;FS;RuU|Z!s3MaCi z1FA4fIbNXpI9+D9mgT{2WnEM!~tfDmN*qNe{fDMae-2j}N-p`AF|g-#aP z-gOj~+FIheN!tZTRG56)dH1&g=9d9?fj1JStw29C$h9{ww{e|QFLPCokz|7#u2z8+0fLa7_7f%J>D_hg3qn&CkzP8Swe#Dcz zyFp>fS+QNQ=QKMMSqxT$jk4U!l#y|uMefG6DO#G0W>wn|)(F^|vQ06Q{ht!H0ihG-f3&+cuN;W->6+hgSQK*i(vlx-L*J^1f9LWH z{3zg)7UQ0ey*3S}WNVc9K6B`%1R*?31)^GMpPuOS(*dnB)3;^~Nc{!wH5o464_#9S z#S==qPJ6f9y0P%q$wP<=E*CRu%G6-BaPMQcBFz|yoQ-N|89zJbt+XENHouwvtorOc zhaAROuqu?T@=iRMX0o8ugux2u&C=02n{XzoZnd}DhI4g$&Yxo2cUgeg7p5ba~Bq(<4Gv%LPw+(Vr52PjZX z{nH;ZaMiqx8^1wqlSb;4S)iu&{#|zme6gqj>{B4peY=}-oXFOuwgVW<0xY*1c)7V8 z@3+pH{RmFWquI)Sf{gtR6%`7+mcQ9N?g5aKodI!22CAk*>6}QE-^jP;V4(7^OJ@HW zE#m*-V#{;h(-%Q3?NVsX>f**?#S+ruOc;hEb>8&7nHHlb)nAgzl&@hoHoA2fZ@rwE z^EluQb&b4&4E9lSBFcue>m-??MMm}k?MG9Ndri*}@@ z`5lI&U z3x={JE_=NKb~DQ5ufo@OJveQ3`I_=N&t8g=8}$+@-$9f{G>Em9|{nxhU`;8rgv#31+Vcp%o9nscuuAbzMt8 z#?j^``tj2-q8-*{anOo@ZG^L>J?T+X(m9cG31%k7t z8Ax8{Dra$%5LxGzr$^feE+yg?7SH6>TW%#SZEzjUr0M3Y4O|o}7p98h-*e=M42mBG zU4h!%p#EAABl7ftY*7NiWw4@3sx)~TL@bpMj90)8Ay!tC;u49 z3fC;ykb&&N{tZqwQI2&lgm+uZ;!&|DO=i1ZY2t?Ck65#Bi%z?>ybotbzE zX#GAE7z9P$u0?!0P)QzxtOLDK-aA&wU0^toPP#0+NS-ueDg+qYVHb~p(P{kE=;}Bd zAYM?P6Dh^OMuV!Muk98x_DUB>(_9a+_ug?Voi$0n!P@UAnLS5u&nA9$1&e*SHwr^T z|86wcQeQxl_r}9$kU_t3z z5MkVL5Q>tt$sB16ImI^qMcj~MnOlxnvI@9&jJE}vp)e8!tBvIEqj-TP znirY%5Vt^Qxe=}{X=OiYMs)JgEzISvrMdBn;r-}L)r>+H6Za%oi zGHUO~BMl8fim11`sCogTZgl=5sFOJUifmw7fWv%psfGU)LU=NI_xJ9sul8v7{zGmh z>Z=ymtZdOw;xj7%|_7Lu+oJ*(7<9jD(K*%*ly&^)SwAmC99LxcJxVl zVpbA%x8-hKR}cnCzIkL?ox6XRv^B1z5XuBSIWmjc(sltI7{-2lRMHB@=eYF`nP}R& z!t~0zQ1Pc_r(V8jEt2Y_+78Ei-C1+vv$7Xu0iKYz=V{*Vx-BUWtj zWx;>U$b#>e5CJ~nw!p3WsCA(Jv5HhmS};r%#jb{>Y2@I{$gyihs|l}4la?^1l0PP7 zx|K^6CWWVUMm`w5O?LYw!qxCh-jd27q!D_CA0acQS(|{E^wNMDjL;<8*L0bmGUGyQ zs;ynQ+p5C4YdZTFnbfcX>qmSjqen2QOk_x^W`Y!Zs$gr`Lq2l@(x){5Hfe43bQ1(G zncf%FakmwOus&%e0bMQ`=V*dIR*>Jx^0ieqh4W~N8N=7!(fGD@>dQxqui3p(0laU{ z@-w;H1CQiBT`jZxoG!*3*!DL34cp#7lEqf6`{_(JsRi7E0}Wy?C%IkpSK7c^`_OQX z@*A06j~Lwi&T9l=3?MuU{G|Q%U;DaE{voxie!+iRRu|v-av7$P(3|J_s&1msUI-Co z!j3fD{3PZeznrkThf*1efbRx;OKo%2h9q1bF2Xc;a{V)IQULC>R%=xK-xo&S~UH8tjpbg}fdT^2+&39~>?VC}h>UWsg>N%yw9K&L_w)AcZBIHc$ zkSL2wS^+9+?{#nr;RU+KQ(Um?UOmN&64LiD&PJSQ05yUKL(>%JR*qg;hh}!xuf;N> z9_nw_+|ozX!FV2k+PwuCUJc$7(N>lP)BCmZDx@BfZz!;I>mwx4&}GW78AYP684F~L zp5@+FO*CIg*ifS${@^k39wEWRfY+?yN&k3+C5xqD@fy?bqi@};)SX2s%+8_Yy;sV7 z@>ywgN?Y@DPj>U_5XUIRPABr{KQP_DhAPpYq!7D3bEkh1+Nd7S6vXEkq8pV z5`VUc9}W(c%?G8;k{Q_Ju2a$iZmN!ye3X)@A$&P)aL@_a5LMdiPNQJTosf0)Pf}KN z>^@7*Hpq_#w2Pv{Ur>^7XPa2txGyNqq&5LMmdNa6*}%6m{Ir?5ckb35&byL19in5O zqMZRu4l0TyUs2NtF}kld$#mdfkGI>(OWlfdw|``1W%rr~X(^AI=X8oF;ZBlZ9m{Uh ztCRj3d$`#+$2u854d!XRrG?Xx$daAJC>`{JkDHzQhg4wuGO7E)Jw%~SBZY+LCAI8| z7(@0mR-8~d&SVtVJpjRSiRGCE6MhggEh0--^!c$59AWtRw0iX3urXI{E5d=H_xFRZ zMH%Ggzqs@=MznE#>uOA6<)v$KN2==7Z3E)G2D~`6uqm<(&{YDr4({gIAq_>!#5(r2 z2=Z%61d*gTDm{@`?6`75f^5UIC35tSgLwuKcnhxY9$7>Gu@S{+%D4?}`^0Nmu1q>Y&wYMGSVOxBcMflolMDDK#D``ERVK8n4 zPP)o;17K1O8ZQ5Ws&??kfmgYkPJ!jA70TCeXk-N}NUsZ1!^`*`V5Wxvu@CM2q;6`t zzt$?la@nmdj|*_gZ8Z<@@V>5!3dPJrW;vHXk12$-e6*?2c~%zD%{wdp2e^vX9Ig_O zi+lUI@LQb=v`GCeE6Km@w+KoS|08`Q|M|W+;F}J*?KjuGvlc&^{xd#6X1 zf;vMSTLl{GWw@fC+!OTTMOs5p2LXse;^frN0Xs#K5k;wrr?dk4 z)iRLt-IPT-@l%6yea}{w-BZwY{y&9%=4eS`(||LlfE?6j^Fr;tNHujf-%lEkw(P($ zOu*8#*Kz~^IgY+;O$dl}2ZQOSM$MQg$NUfppH6;!Rl}<2nxQBD!zFn*>l*MM zlfk04>G>}3!6+}#&1woXxg*GXz^T&E@OsS50|+_T%){Yrz*8$ZyE=he64;MxKz1;G z>xnlWe0D7;z9VlT+9#?r+m!SLr5@9JX55cFn=h$xcEbNzUJ(I>EO8=#ZbDXr%Fg2` zs1I!HGX`e3?zfMx<7o6mXs8LyUg`#3*qEFRb%R8A{5q-49;uyXoddWTg|-B#0;s|K z`S&#)p?*OvbO2QfEK*NdfPk;Fv<#vtf~vSO6QWg?<6%$;qQ!z74`|APqfieQQx3I3 zoj684Xfn41h^u8Alnp(f!aVZlz`s?3+q(Q4?qR{4Tv#s^)ugBK`4Y=P(?ANkqF>mHlVHsx|*}OtxS{lly zX2TFRb*5qNFO8SZYwk3(9|nn+x$)eAuSe?z65;9lu~UVJMJzBz>)I(GWhsz3W z@pC8DqvmpHugRT$<2>KH#L!=lFPPs(`Sm8|~}5Ft?HiINz7b7hjD{!6&S|}NRb6H zPicy%)b=a(S zf5f=hegO+&=C7xM4&Ax`-}>9B4f?3BqX5*nAE$bPPktN4_o4h4#sAv@fA5L{LxjGx F{~z)5VRrxk diff --git a/src/assets/pub/nutella_v_2.png b/src/assets/pub/nutella_v_2.png deleted file mode 100644 index c733397d3644bf9ea2f7a815e63405c31a5fa720..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 57279 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
@uNRycJ>$PW6e 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 z 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�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 W))&U{e-LaOz5R8?@PF_6Ech=tm5O`- diff --git a/src/assets/pub/rolex_v_2.png b/src/assets/pub/rolex_v_2.png deleted file mode 100644 index b1e07d9856e00b2b3e14fc361bd441c52c44ea40..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 50514 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 diff --git a/src/assets/uploadFile.png b/src/assets/uploadFile.png deleted file mode 100644 index cff9f3853d882c8079b4aeaffa40aa2b728d57fd..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 8853 zcmeHtd05PQ-~Xqn%w!n3TdYGNrKTDxscBLXkrob`lMd6K45ek#s!Wzcl=jkMJK4fi z3@J=P`*K1xmEveYO*st_%JcqyJLmVC=XuWkoO7=0xv%T~<8fWCKJ)s%m)Cp!jJ|$! zv|l@Q^6be7p{eU^R&PQ`j*tB%$pK=i6}}pN$a!1ZSt3*rPyXsE51-ZCZ8q5<6t)&brq%FxHOb!h^bz4%EBTB0ZVINR`u%>KRAOAG z6K;i~XANX(UmsAAL3uYixs8~V-kjY;F#uiy(FCyg31NEnqBYKMiFSNEjr?e>%&|KH)?UopWwYt6xA7Gl` zQ7{3}!tl>Qel0ITv1o!kkBCn*)lp-?837MWSzI{Oft#St{!P;RV-wEDr|sItVT_nh zbK!)jW@<6@22eKT4@}s&y>#Ni6Yh+Y7%vM0u1XSqPHbXxkeKVm-V(Qhu5kvYBJ|-J;S7aZ z&TW_%veB=k=;DFOl)4@A-?;U)cILhoY?+$9Zr28WNt@M?Y#`Y^-A-graSrmoc_wdskg}q?dj5+Q@Ds9^(*O+#E=?!lR1mTOHcVZni?n$<1AO56s*gk5!tzN3U4+RDUqz zwraQ)@FF)#xc<5$vBJE3Qq1uWcX4z4C1B3|E;KHfL!1~qa=s%LxX{HVfY|KLxV;ot zHz=fbWHHtG6j0C=@SgBB<(gfsN%@bs{-z_b(LzGr4IMv;VqVaidnpa!Q-miw$_OU} z2JpC zCXnxVGj8u2iEU(t@K5^*c;&!0Mn0&9>%U?o7P6@)qEJA?)XSQ5w~#tFlc^q5s}b@# zMf~F3fPy7k=7$2R3nkp@buxq1xUjvf2Z(|?5GuwW*A-D+%;E6~74`QJ{}gaUP3t(L zFW|kx9T|cnGXPb<`+NXls$=90E4cm21 z>On#(%_m#T4#mMOMO0c6Q=LRR?JVH+6l%uieLvl*ghRCTav<3SR#DqL8LZ{uR*Ec( zU=Fbca$FZcB)54mSVSB&;t=~?9Y_T7#RFpY4+9EkEVsrs&TcPjYgMx1xda?;ZlyF= z^o=5lpejdE+uNFCR7B;ZFx5BLYlK|P5VK40 zD9`b!oKpbSQfU`c#OyCPXzR&n#iI~5wNggPa}+OoSd%^!PzQbl$tqBf7qfTZlDs17 zKs=}Y2~P>C)aTkD!|e&#oZLoBB}?B6?9dxh*CHY1Tq;c zN4<8-w*Qb0j-o}PzJ4|wu6q8c1ytnOyJ!L0S`;5aygZz z#S^O?V`BvNCBq4)VgvTwptLgiBv+1rM@t1!p+?BeQy>6cL?D}bGb$Aa6kI(9*=6Y* z;;f?>f!CnF3h!WQA=SfYB$hr~$7<$bv06DK;Aa@wSA43+EG*NOYdOU4VcE<)$YAj! zzyaQ`ucO6kHMsfNV16c;uLA!WVE!;uot9xc$loB~#XZ6TFs$Y#EEOp|_y>%94Ulcc zt-5oFOJXo4K1alAKk+qVf8sBQeJP@Bf(d0!PU~>pC*UPN#Px;Tgr-)d2QQ#^T|r<0 zRyW6`?Uw5yZ3MEmC&Q)+{99~|r7O2vRs$*7fGX-CH-^m{+>asrF)(`^*DnKo$UhC%1|Mqiv=$?! z4E1fp>U-cpE2W75oE3GfSaR)_ZBQQaFNq8qxVnnFItZ>bMq>F0^1oF?X_}4kr!Q-_ zboRjbukm2mTmk;JkUyBM8!(!JhZ-U2xneclB5cJh1pQzrkZ}l~Z7$%w7h?WtC&g-a zar3qir~~LzAby>8%g@jhf&NugFW~Qo@h=l{h;L3Z)oUxMwDg0Zg;!m+fO_5=i=U0a zWPOfe9&F7g1ys3ktMp9UK{~bF61PtFWRRv6XvSW;&67V>M2#K7o1V;Okk;aMws|l} z@i20ypnAt!DG!{1iIQG%`5F$)P% zb9W%^DqIj-0S;hj9%RDm!p?8-1TO)zoB@TGd!hadMU)2vcvO?XfjRDgD&Wy!YW7Xh zvDz04W?}Q19kLyKM*?SfuKl4cT1`PBoxw@~V`p2jx*Y~naMQpEgTRxD`g8DU4LMKi zc#|VmqvbHw2{j8(?*jW%!mUjED5^{lc-gA7fPdN+Kv*DhszDW8#Y5f>Hn;LgZ<0WX z$5ekFP?c>C)&p?KIS@Zw8$nf6+GlqLsm9aci10u!JRTNdhIWD>Xn9k2Ya0g$i3XC7 zHA2GN7^GJPnycBCNdUS42;Cdz3Sbcie#ar6f%^%D=a5(}xjZL9k2Sr?yxmd@cIOZN zRoNpViq-c63e#DROaNhb)&&xe2>{H%L0tf0cM`~#p?aQ0n&(}&#@?vrDz1k(%3T63 zY!UDrp=5HZn;&r%-?ANS&UKWXwFYn+4weDvhDGrUSd1J{*a`sa+_a9J z$HZz+;W~(se^f|~4Fga)gzp2ZR_V+d4rWH zbjOuzIK-H9_{kPd@a=BX3LUHUUJO!xT}}e*9Q!JOKj6;wKxxf@!V>7%WGGB)99Ata zXo?MRX~f8XS45S|^K`H|nNM00FIJ;7!>x`2`5u^GFITKGb|MO)s8I9#ib3{9)pkqv zJUrwy5Y@-n=U0Kv$>CO$-K=evfYYl5n&;K@iob)LuwfTXXZgb>V^0SHu|NPOl%o~C*ANn`$;n9SptrS9yt3#!YOMv$jFk6Vl{~G3)zX1fG^r>~=9=-#~sUC-@ zAG0C6v#ub>8c_INTgNID=5Ho+xGh||HQ*`^cf|u&1tO(F!$EezT&Riy7L?&buA&xf z2g0#6;8deP(?cPjG%HiA<_OnYD%_cepcct+7sOcifc`%qKzay&W+Dh^WBya1s_VTl z|5jiUE|*zxD(dBYs$8|VLnRyd&jffXz(@8kkn_6r_S+@`=i$of1Vo}C6eEw+;8zFm zPXI(9BlzZyf0R>2@Fg4n_;-Xbojjyzq2Ij!MqG-Mv^yyw zsf+;n=R#5$!Bqd)(%%)riuR|Lq=c}_N)eZG_s2p~x&7x&@ppx!a*L@-agwqmB_y3& zXw*L!lFA5l^FOg9EmX7cFZ8~Y-@lX#DZl?FVg8j|NOcEfNILaW36m0%YN6lS+QL;3 zKa%9c2yaq4JT;o|>DztVmvjFAj`>Sg|B}#ucl~>b{+ORsi({&PDkRmIn5vXJDNBD> z=y!_$Kc`j>anzht7Ma{DhSEPGeTrhfA`EXNpg1 zD%>(hmpku{o53PRyhRqLZek0`f^DS4`V#pT2~Q99>+=WSV+w68JJ@0goCv!LB6#x1 z(0LBl8O}YR5WUscy;OMT`2`A^^7h0yp?{ZoFk(A~eAFAg&}rHgs*wD}(sN0lVmoDc$vmJg>p)JMJ=`?U9d zS=*4RDxya--Fu(4#-zBsgf~XykkQ*Kx5F0%@vLI{<8kX;%|5};3#TEUnwMs}U9%R@|#yWyBS-}w3_;jOjv11FSx@c&xHj35_ z4OyapKFg19U;V9{r74TjpTuM(MtYVe2iz;W^Tav?RP^*TuCM<*NymigWHJW{v+8U6 z)`u=>pBzTZZRn|=1aD>>Qj?rK<+l#oUjPF&xykR{7BA_4){)S+LLCX?_S6Oj-p)$< zuGyG%Wz-g4T%?N_>#MIc-78yvqNdK|(Gqws^X|id)+>i@Gq<1k#2`9xSW>Tm=)5i+ zvGMc`N5fZFbU)5|dmf?h+D^@H2&oBMr}Kz;zFd^+WU7ON$$FJHf4X~qT}=E=jc*xL zdorRQJSFLvOVjtNF3OAyy(%G~4KHs6M2717ZhBq*IjElNhNA6UP8Jnu^Yen8ujvhh z1j(SEOtK6D?0(eGe|kie^wGo!2@mPf46av?P0|VV-BYb#PeJ?>;YAB?rHnRhJsRor zMZ&HR;iBl^uTkb3-`bv1{@S`Vz;k=|dxUn~*7oj65N1|L0)tQNJ%FOm&8>Y?e61tx z)~5I6B}|9Ph83%jaN{`r+vee#Q_AC?PSgd53ciy=W{>ScE$3;C%BPN(%Q`cSyH88x5!E!k zr6tMf17=KDl$&PajvBLXb?5F1E7nP2b~f}bF)3dn8-4BT51q~}^xFhKF z#*f`S#b=sl+`sw@asLld1@~^5Y6(u$&`^}exR zgf{#6aeH+>+&{kCE@Gx}-y@?Pv9c&}(T+-yZub_Qn3M>EzTU1ZTXeBi!-Uc0^Xh88 zq2!EN`mq4FsJ1t9(b{))?k5tRLk)DMM$)g0vIeW_z3!#RMsJ^6JJfsCq@#XLrs2ow zcMWIsT(Z|jo85PGrq{HE*(Oa|nfKjrS=O5y1PhgGRlA07Hg`T<&zt|0Icj0=KZlI8 z-(4#eJi1?9*wlSESSzhNH7m_MdmGYfem+|FbtC2Gr{={|_j4Q?z61)MkdgIgm#E_7 zU7a-f#?=sYr->`x!6oKtw~!!46H-LE3H>($P(H$ri~4xP!n!uOrK`?Xo3-;-ae z@o|L+(GyDoE$xREUT^w&W!BZ+>QY8UkM(#m1<^z=Bh;?fY8JND%*hG*I6XIYWrJ;Y z5MpII^c-+$Y1uY7)SksO(Y)SJXU{;ivg4sY)Qfemhkc#Yf07?z*O}vO@)6O~ulI;Y zzsw!@^{RvEcx!ys9Erf}$tW@UV2ROCZC9_wb-(>hqZRu(QM!IrMPozQ9=<<(A#}&R zcFDr@74jL~rC;r%%6PCIOBU=uIqlXcF-yML%)UWBH28!>4PGZt>nrkDY7K(sZRR0Uy zwX_$%^D`kd9xEU9y_e1`HghWW*5IeU`Sf*lPHtb%_n~X-KQL~fi=AV|8sU;2mt6hs zLjxZz^naKN1jn`tq9$<7e)@Np=}dKuaUYnib^X8sur}9^eT-&@%cmx-Q*7 zciFPd%M45nj7$yaI&``zoxV}vWcr^JcKdnk^a}mw3TpjBhp@ocS=+C^X2m}6A7w5| AOaK4? diff --git a/src/environments/environment.prod.ts b/src/environments/environment.prod.ts deleted file mode 100644 index a27a700..0000000 --- a/src/environments/environment.prod.ts +++ /dev/null @@ -1,4 +0,0 @@ -export const environment = { - production: true, - debutUrl: "https://polynotfound.herokuapp.com/api/" -}; diff --git a/src/environments/environment.ts b/src/environments/environment.ts deleted file mode 100644 index 31c7c5f..0000000 --- a/src/environments/environment.ts +++ /dev/null @@ -1,17 +0,0 @@ -// This file can be replaced during build by using the `fileReplacements` array. -// `ng build --prod` replaces `environment.ts` with `environment.prod.ts`. -// The list of file replacements can be found in `angular.json`. - -export const environment = { - production: false, - debutUrl: "http://127.0.0.1:3000/api/" -}; - -/* - * For easier debugging in development mode, you can import the following file - * to ignore zone related error stack frames such as `zone.run`, `zoneDelegate.invokeTask`. - * - * This import should be commented out in production mode because it will have a negative impact - * on performance if an error is thrown. - */ -// import 'zone.js/dist/zone-error'; // Included with Angular CLI. diff --git a/src/favicon.ico b/src/favicon.ico deleted file mode 100644 index 997406ad22c29aae95893fb3d666c30258a09537..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 948 zcmV;l155mgP)CBYU7IjCFmI-B}4sMJt3^s9NVg!P0 z6hDQy(L`XWMkB@zOLgN$4KYz;j0zZxq9KKdpZE#5@k0crP^5f9KO};h)ZDQ%ybhht z%t9#h|nu0K(bJ ztIkhEr!*UyrZWQ1k2+YkGqDi8Z<|mIN&$kzpKl{cNP=OQzXHz>vn+c)F)zO|Bou>E z2|-d_=qY#Y+yOu1a}XI?cU}%04)zz%anD(XZC{#~WreV!a$7k2Ug`?&CUEc0EtrkZ zL49MB)h!_K{H(*l_93D5tO0;BUnvYlo+;yss%n^&qjt6fZOa+}+FDO(~2>G z2dx@=JZ?DHP^;b7*Y1as5^uphBsh*s*z&MBd?e@I>-9kU>63PjP&^#5YTOb&x^6Cf z?674rmSHB5Fk!{Gv7rv!?qX#ei_L(XtwVqLX3L}$MI|kJ*w(rhx~tc&L&xP#?cQow zX_|gx$wMr3pRZIIr_;;O|8fAjd;1`nOeu5K(pCu7>^3E&D2OBBq?sYa(%S?GwG&_0-s%_v$L@R!5H_fc)lOb9ZoOO#p`Nn`KU z3LTTBtjwo`7(HA6 z7gmO$yTR!5L>Bsg!X8616{JUngg_@&85%>W=mChTR;x4`P=?PJ~oPuy5 zU-L`C@_!34D21{fD~Y8NVnR3t;aqZI3fIhmgmx}$oc-dKDC6Ap$Gy>a!`A*x2L1v0 WcZ@i?LyX}70000 - - - - StreamNotFound - - - - - - - - - - - diff --git a/src/main.ts b/src/main.ts deleted file mode 100644 index c7b673c..0000000 --- a/src/main.ts +++ /dev/null @@ -1,12 +0,0 @@ -import { enableProdMode } from '@angular/core'; -import { platformBrowserDynamic } from '@angular/platform-browser-dynamic'; - -import { AppModule } from './app/app.module'; -import { environment } from './environments/environment'; - -if (environment.production) { - enableProdMode(); -} - -platformBrowserDynamic().bootstrapModule(AppModule) - .catch(err => console.error(err)); diff --git a/src/polyfills.ts b/src/polyfills.ts deleted file mode 100644 index 3e93392..0000000 --- a/src/polyfills.ts +++ /dev/null @@ -1,65 +0,0 @@ -/** - * This file includes polyfills needed by Angular and is loaded before the app. - * You can add your own extra polyfills to this file. - * - * This file is divided into 2 sections: - * 1. Browser polyfills. These are applied before loading ZoneJS and are sorted by browsers. - * 2. Application imports. Files imported after ZoneJS that should be loaded before your main - * file. - * - * The current setup is for so-called "evergreen" browsers; the last versions of browsers that - * automatically update themselves. This includes Safari >= 10, Chrome >= 55 (including Opera), - * Edge >= 13 on the desktop, and iOS 10 and Chrome on mobile. - * - * Learn more in https://angular.io/guide/browser-support - */ - -/*************************************************************************************************** - * BROWSER POLYFILLS - */ - -/** - * IE11 requires the following for NgClass support on SVG elements - */ -// import 'classlist.js'; // Run `npm install --save classlist.js`. - -/** - * Web Animations `@angular/platform-browser/animations` - * Only required if AnimationBuilder is used within the application and using IE/Edge or Safari. - * Standard animation support in Angular DOES NOT require any polyfills (as of Angular 6.0). - */ -// import 'web-animations-js'; // Run `npm install --save web-animations-js`. - -/** - * By default, zone.js will patch all possible macroTask and DomEvents - * user can disable parts of macroTask/DomEvents patch by setting following flags - * because those flags need to be set before `zone.js` being loaded, and webpack - * will put import in the top of bundle, so user need to create a separate file - * in this directory (for example: zone-flags.ts), and put the following flags - * into that file, and then add the following code before importing zone.js. - * import './zone-flags'; - * - * The flags allowed in zone-flags.ts are listed here. - * - * The following flags will work for all browsers. - * - * (window as any).__Zone_disable_requestAnimationFrame = true; // disable patch requestAnimationFrame - * (window as any).__Zone_disable_on_property = true; // disable patch onProperty such as onclick - * (window as any).__zone_symbol__UNPATCHED_EVENTS = ['scroll', 'mousemove']; // disable patch specified eventNames - * - * in IE/Edge developer tools, the addEventListener will also be wrapped by zone.js - * with the following flag, it will bypass `zone.js` patch for IE/Edge - * - * (window as any).__Zone_enable_cross_context_check = true; - * - */ - -/*************************************************************************************************** - * Zone JS is required by default for Angular itself. - */ -import 'zone.js/dist/zone'; // Included with Angular CLI. - -/*************************************************************************************************** - * APPLICATION IMPORTS - */ -import '@angular/localize/init'; diff --git a/src/proxy.conf.json b/src/proxy.conf.json deleted file mode 100644 index f1e4285..0000000 --- a/src/proxy.conf.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "/api/*": { - "target": "http://localhost:3000", - "secure": false, - "logLevel": "debug" - } -} diff --git a/src/styles.scss b/src/styles.scss deleted file mode 100644 index 80de7ef..0000000 --- a/src/styles.scss +++ /dev/null @@ -1,57 +0,0 @@ -@import "~@angular/material/prebuilt-themes/indigo-pink.css"; - ---root { - --dark-color: #f0f0f0; -} -html, body { height: 100%; } -body { margin: 0; } - - -.lightTheme { - background: url("assets/lightBackground.jpg") no-repeat center center fixed; - font-color: black; - border-color: black; - font-size: small; -} - - -.darkTheme { - background: url("assets/darkBackground.webp") no-repeat center center fixed; - font-color: white; - border-color: white; - font-size: small; -} - - -.lightTheme, .darkTheme { - -webkit-background-size: cover; - -moz-background-size: cover; - -o-background-size: cover; - background-size: cover; -} - - -.custom-dialog-container .mat-dialog-container { - margin: 0px 0px 0px 0px; - padding: 0px 0px 0px 0px; -} - - -// ------------------------------------------------------------------------- - - -// 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 { - border: solid 1px black !important; - background-color: white !important; -} diff --git a/src/test.ts b/src/test.ts deleted file mode 100644 index 50193eb..0000000 --- a/src/test.ts +++ /dev/null @@ -1,25 +0,0 @@ -// This file is required by karma.conf.js and loads recursively all the .spec and framework files - -import 'zone.js/dist/zone-testing'; -import { getTestBed } from '@angular/core/testing'; -import { - BrowserDynamicTestingModule, - platformBrowserDynamicTesting -} from '@angular/platform-browser-dynamic/testing'; - -declare const require: { - context(path: string, deep?: boolean, filter?: RegExp): { - keys(): string[]; - (id: string): T; - }; -}; - -// First, initialize the Angular testing environment. -getTestBed().initTestEnvironment( - BrowserDynamicTestingModule, - platformBrowserDynamicTesting() -); -// Then we find all the tests. -const context = require.context('./', true, /\.spec\.ts$/); -// And load the modules. -context.keys().map(context); diff --git a/tsconfig.app.json b/tsconfig.app.json deleted file mode 100644 index 82d91dc..0000000 --- a/tsconfig.app.json +++ /dev/null @@ -1,15 +0,0 @@ -/* To learn more about this file see: https://angular.io/config/tsconfig. */ -{ - "extends": "./tsconfig.json", - "compilerOptions": { - "outDir": "./out-tsc/app", - "types": [] - }, - "files": [ - "src/main.ts", - "src/polyfills.ts" - ], - "include": [ - "src/**/*.d.ts" - ] -} diff --git a/tsconfig.json b/tsconfig.json deleted file mode 100644 index 4a4dc62..0000000 --- a/tsconfig.json +++ /dev/null @@ -1,23 +0,0 @@ -/* To learn more about this file see: https://angular.io/config/tsconfig. */ -{ - "compileOnSave": false, - "compilerOptions": { - "baseUrl": "./", - "outDir": "./dist/out-tsc", - "sourceMap": true, - "declaration": false, - "downlevelIteration": true, - "experimentalDecorators": true, - "moduleResolution": "node", - "importHelpers": true, - "target": "es2015", - "module": "es2020", - "lib": [ - "es2018", - "dom" - ] - }, - "angularCompilerOptions": { - "enableI18nLegacyMessageIdFormat": false - } -} diff --git a/tsconfig.spec.json b/tsconfig.spec.json deleted file mode 100644 index 092345b..0000000 --- a/tsconfig.spec.json +++ /dev/null @@ -1,18 +0,0 @@ -/* To learn more about this file see: https://angular.io/config/tsconfig. */ -{ - "extends": "./tsconfig.json", - "compilerOptions": { - "outDir": "./out-tsc/spec", - "types": [ - "jasmine" - ] - }, - "files": [ - "src/test.ts", - "src/polyfills.ts" - ], - "include": [ - "src/**/*.spec.ts", - "src/**/*.d.ts" - ] -} diff --git a/tslint.json b/tslint.json deleted file mode 100644 index 277c8eb..0000000 --- a/tslint.json +++ /dev/null @@ -1,152 +0,0 @@ -{ - "extends": "tslint:recommended", - "rulesDirectory": [ - "codelyzer" - ], - "rules": { - "align": { - "options": [ - "parameters", - "statements" - ] - }, - "array-type": false, - "arrow-return-shorthand": true, - "curly": true, - "deprecation": { - "severity": "warning" - }, - "eofline": true, - "import-blacklist": [ - true, - "rxjs/Rx" - ], - "import-spacing": true, - "indent": { - "options": [ - "spaces" - ] - }, - "max-classes-per-file": false, - "max-line-length": [ - true, - 140 - ], - "member-ordering": [ - true, - { - "order": [ - "static-field", - "instance-field", - "static-method", - "instance-method" - ] - } - ], - "no-console": [ - true, - "debug", - "info", - "time", - "timeEnd", - "trace" - ], - "no-empty": false, - "no-inferrable-types": [ - true, - "ignore-params" - ], - "no-non-null-assertion": true, - "no-redundant-jsdoc": true, - "no-switch-case-fall-through": true, - "no-var-requires": false, - "object-literal-key-quotes": [ - true, - "as-needed" - ], - "quotemark": [ - true, - "single" - ], - "semicolon": { - "options": [ - "always" - ] - }, - "space-before-function-paren": { - "options": { - "anonymous": "never", - "asyncArrow": "always", - "constructor": "never", - "method": "never", - "named": "never" - } - }, - "typedef": [ - true, - "call-signature" - ], - "typedef-whitespace": { - "options": [ - { - "call-signature": "nospace", - "index-signature": "nospace", - "parameter": "nospace", - "property-declaration": "nospace", - "variable-declaration": "nospace" - }, - { - "call-signature": "onespace", - "index-signature": "onespace", - "parameter": "onespace", - "property-declaration": "onespace", - "variable-declaration": "onespace" - } - ] - }, - "variable-name": { - "options": [ - "ban-keywords", - "check-format", - "allow-pascal-case" - ] - }, - "whitespace": { - "options": [ - "check-branch", - "check-decl", - "check-operator", - "check-separator", - "check-type", - "check-typecast" - ] - }, - "component-class-suffix": true, - "contextual-lifecycle": true, - "directive-class-suffix": true, - "no-conflicting-lifecycle": true, - "no-host-metadata-property": true, - "no-input-rename": true, - "no-inputs-metadata-property": true, - "no-output-native": true, - "no-output-on-prefix": true, - "no-output-rename": true, - "no-outputs-metadata-property": true, - "template-banana-in-box": true, - "template-no-negated-async": true, - "use-lifecycle-interface": true, - "use-pipe-transform-interface": true, - "directive-selector": [ - true, - "attribute", - "app", - "camelCase" - ], - "component-selector": [ - true, - "element", - "app", - "kebab-case" - ] - } -} From 92edacb59d746f764f576d38fc589774b6d4b241 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Y=C3=BBki=20VACHOT?= Date: Sun, 26 Dec 2021 17:03:49 +0100 Subject: [PATCH 13/35] Update: Lancement en Local et Production en ligne sur Heroku --- README.md | 42 +++++++++++++++++++++++++++--------------- 1 file changed, 27 insertions(+), 15 deletions(-) diff --git a/README.md b/README.md index 13b2e84..5873d2a 100644 --- a/README.md +++ b/README.md @@ -1,27 +1,39 @@ -# Frontend +# PolyNotFound -This project was generated with [Angular CLI](https://github.com/angular/angular-cli) version 11.2.7. -## Development server +Le projet est séparé en 3 parties : -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. +- 2 Frontend : + - 1 partie Administrateur + - 1 partie pour les utilisateurs et les publicitaires +- 1 Backend -## 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`. +Nous avons décidé que chaque partie du projet a sa propre branche git et non leur propre répertoire git. -## Build +En effet, les branches concernées par le projet est : +- Frontend partie Administrateur : `front-admin` +- Frontend partie pour les utilisateurs et les publicitaires : `front-user-advertiser` +- Backend : `backend` -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. +Nous pouvons récupérer une branche git avec `git checkout `. -## Running unit tests +# Lancer le projet en Local -Run `ng test` to execute the unit tests via [Karma](https://karma-runner.github.io). +Pour lancer le projet en local dans son ensemble, il faut impérativement avoir les branches concernées dans leur propre dossier. +Il faudra donc __clone__ le projet 3 fois. -## Running end-to-end tests +Dans un dossier nommé par exemple `Polynotfound`: +- frontend-admin : `git clone --branch frontend-admin https://github.com/NyxiumYuuki/PolyNotFound.git polynotfound-frontend-admin` +- front-user-advertiser : `git clone --branch front-user-advertiser https://github.com/NyxiumYuuki/PolyNotFound.git polynotfound-front-user-advertiser` +- backend : `git clone --branch backend https://github.com/NyxiumYuuki/PolyNotFound.git polynotfound-backend` -Run `ng e2e` to execute the end-to-end tests via [Protractor](http://www.protractortest.org/). +Un README est disponible pour chaque branche pour lancer le projet en local soit en mode **production** soit en mode **développement**. -## Further help +# Lancer le projet en ligne avec Heroku -To get more help on the Angular CLI use `ng help` or go check out the [Angular CLI Overview and Command Reference](https://angular.io/cli) page. +Nous avons déployé le projet en ligne avec Heroku. + +Le projet est disponible sur ces URL : +- Partie Utilisateurs et Publicitaires : https://polynotfound.herokuapp.com/ +- Partie Administrateur : https://admin-polynotfound.herokuapp.com/ +- API : https://api-polynotfound.herokuapp.com/ \ No newline at end of file From 1419e97b2f78df649db3c24eca59d45c71b3bc40 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Y=C3=BBki=20VACHOT?= Date: Sun, 26 Dec 2021 17:11:40 +0100 Subject: [PATCH 14/35] Update: Ajout de NodeJS --- README.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 5873d2a..9ab8554 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,5 @@ # PolyNotFound - Le projet est séparé en 3 parties : - 2 Frontend : @@ -19,6 +18,8 @@ Nous pouvons récupérer une branche git avec `git checkout `. # Lancer le projet en Local +Dans un premier temps, il est obligatoire d'avoir NodeJS (version >12 au minimum), [téléchargeable sur cette page](https://nodejs.org/en/download/). + Pour lancer le projet en local dans son ensemble, il faut impérativement avoir les branches concernées dans leur propre dossier. Il faudra donc __clone__ le projet 3 fois. From 5495a8321a7dfe7098c182d7c7f62056fdd65443 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Y=C3=BBki=20VACHOT?= Date: Sun, 26 Dec 2021 18:00:43 +0100 Subject: [PATCH 15/35] Update: Add dev & prod local scripts --- package.json | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/package.json b/package.json index cd86e37..6a6e4f3 100644 --- a/package.json +++ b/package.json @@ -3,7 +3,11 @@ "version": "1.0.0", "scripts": { "ng": "ng", - "start": "node server.js" + "start": "node server.js", + "dev-win": "set NODE_ENV=development && node server.js", + "dev-nix": "export NODE_ENV=development && node server.js", + "prod-win": "set NODE_ENV=production && node server.js", + "prod-nix": "export NODE_ENV=production && node server.js" }, "private": true, "dependencies": { From a330e718608acadaa5db12611fb043ec31cd9fea Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Y=C3=BBki=20VACHOT?= Date: Sun, 26 Dec 2021 18:02:42 +0100 Subject: [PATCH 16/35] Update: Dev & Prod Backend explanations --- README.md | 70 +++++++++++++++++++++++++++++++++++++++++++------------ 1 file changed, 55 insertions(+), 15 deletions(-) diff --git a/README.md b/README.md index 13b2e84..73dd10c 100644 --- a/README.md +++ b/README.md @@ -1,27 +1,67 @@ -# Frontend +# PolyNotFound - Partie Backend en local -This project was generated with [Angular CLI](https://github.com/angular/angular-cli) version 11.2.7. +## Lancement du Backend -## Development server +### 1.1 Installation des différentes librairies avec npm -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. +Si NodeJS est installé ([téléchargeable ici](https://nodejs.org/en/download/)), il suffit de faire un `npm install`. -## 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`. +### 1.2 Création d'une base de données MongoDB en local avec Docker -## Build +Il faudra **Docker** ([téléchargeable ici](https://docs.docker.com/desktop/#download-and-install)) -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. +Puis dans un terminal, pour lancer le serveur MongoDB -## Running unit tests +`docker run -d -p 27017:27017 --ip 127.0.0.1 --name polynotfound-mongodb mongo:latest` -Run `ng test` to execute the unit tests via [Karma](https://karma-runner.github.io). +_L'image de Mongo sera automatiquement téléchargé si elle n'existe pas en local._ -## Running end-to-end tests +1. Si vous avez MongoDB Compass ([téléchargeable ici](https://www.mongodb.com/try/download/compass)): +- Se connecter au serveur `mongodb://localhost:27017/?readPreference=primary&appname=MongoDB%20Compass&ssl=false` +- Create Database : + - Database Name : polynotfound + - Collection Name : users -Run `ng e2e` to execute the end-to-end tests via [Protractor](http://www.protractortest.org/). +2. Sinon avec MongoShell ([téléchargeable ici](https://www.mongodb.com/try/download/shell)): +- Se connecter au serveur + - Linux: `mongo mongodb://localhost:27017/?readPreference=primary&appname=MongoDB%20Compass&ssl=false` + - Windows: `mongo.exe mongodb://localhost:27017/?readPreference=primary&appname=MongoDB%20Compass&ssl=false` +- Créer la base de données : `use polynotfound` -## Further help +### 1.3 Initialisation des variables d'environnements -To get more help on the Angular CLI use `ng help` or go check out the [Angular CLI Overview and Command Reference](https://angular.io/cli) page. +5 variables d'environnements sont nécessaires pour lancer le backend correctement. +- **DATABASE** : url de connexion à la base de données (utilisé seulement en production) + - Sur Windows : `set DATABASE=` + - Sur Linux : `export DATABASE=` +- Token de connexion + - **JWTRS256_PUBLIC_KEY** : clé publique pour les tokens de connexion + - **JWTRS256_PRIVATE_KEY** : clé privée pour les tokens de connexion + + Lancer le script de génération des clés `jwtRS256.sh`, un fichier `.env` sera créé. + Il faudra `set` ou `export` ces 2 variables dans vos variables d'environnements. + - Sur Windows : + - `set JWTRS256_PUBLIC_KEY=` + - `set JWTRS256_PRIVATE_KEY=` + - Sur Linux : + - `export JWTRS256_PUBLIC_KEY=` + - `export JWTRS256_PRIVATE_KEY=` + +- **YOUTUBE_API_KEY** : Clé de connexion à l'API Youtube ([récupérable ici](https://developers.google.com/youtube/v3/getting-started?hl=fr)) +- **DAILYMOTION_API_KEY** : Clé de connexion à l'API Dailymotion ([récupérable ici](https://www.dailymotion.com/profile/developer)) + + _A noté que la clé d'API de Dailymotion n'est pas utilisée mais cela peut changer dans le temps._ + +Après l'initialisation de ces variables d'environnements, il faudra surement redémarrer votre ordinateur. (Fermer et rouvrir un terminal peut être suffisant dans certain cas) + +#### 1.3.1 Lancement en mode développement + +Pour lancer le backend en mode développement, il faudra simplement exécuter dans un terminal: +- Windows : `npm dev-win` +- Linux & Mac : `npm dev-nix` + +#### 1.3.2 Lancement en mode production + +Pour lancer le backend en mode production, il faudra simplement exécuter dans un terminal: +- Windows : `npm prod-win` +- Linux & Mac : `npm prod-nix` \ No newline at end of file From b26c75f16342def89e6cd29049ebedf28c4f6378 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Y=C3=BBki=20VACHOT?= Date: Wed, 29 Dec 2021 17:30:37 +0100 Subject: [PATCH 17/35] Update: Remove Origin --- config/cors.config.js | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/config/cors.config.js b/config/cors.config.js index 068cc23..e7aac87 100644 --- a/config/cors.config.js +++ b/config/cors.config.js @@ -5,7 +5,8 @@ const allowList = [ 'http://127.0.0.1:4200', 'http://127.0.0.1:4201', 'https://admin-polynotfound.herokuapp.com', - 'https://polynotfound.herokuapp.com' + 'https://polynotfound.herokuapp.com', + ]; const corsOptionsDelegate = function(req, callback) { @@ -13,13 +14,13 @@ const corsOptionsDelegate = function(req, callback) { let corsOptions; if (allowList.indexOf(req.header('Origin')) !== -1) { corsOptions = { - origin: true, + origin: false, credentials: true } } else { corsOptions = { origin: false, - credentials: false + credentials: true } } console.log(corsOptions); From 086d54a84b25e7208941deea80069f293d23ed63 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Y=C3=BBki=20VACHOT?= Date: Wed, 29 Dec 2021 17:34:42 +0100 Subject: [PATCH 18/35] Update: Change Cors Origin False --- routes/user.routes.js | 26 +++++++++++++------------- server.js | 6 ++++++ 2 files changed, 19 insertions(+), 13 deletions(-) diff --git a/routes/user.routes.js b/routes/user.routes.js index 4d62364..3e7d2fa 100644 --- a/routes/user.routes.js +++ b/routes/user.routes.js @@ -1,43 +1,43 @@ const users = require("../controllers/user.controller"); -const {cors, options} = require("../config/cors.config"); +//const {cors, options} = require("../config/cors.config"); module.exports = app => { let router = require("express").Router(); // Authenticate a User - router.post("/user/auth", cors(options), users.auth); + router.post("/user/auth", users.auth); // Logout a User - router.delete("/user/logout", cors(options), users.logout); + router.delete("/user/logout", users.logout); // Request password reset with email - router.post("/user/resetPass", cors(options), users.resetPass); + router.post("/user/resetPass", users.resetPass); // Create and Save a new User - router.post("/user/create", cors(options), users.create); + router.post("/user/create", users.create); // Retrieve all Users if admin - router.get("/user/findAll", cors(options), users.findAll); + router.get("/user/findAll", users.findAll); // Find single User from id if admin or session id - router.get("/user/findOne/:id", cors(options), users.findOne); + router.get("/user/findOne/:id", users.findOne); // Update a User from id if admin or session id - router.put("/user/update/:id", cors(options), users.update); + router.put("/user/update/:id", users.update); // Delete a User from id if admin or session id - router.delete("/user/delete/:id", cors(options), users.delete); + router.delete("/user/delete/:id", users.delete); // Delete all Users if superAdmin - router.delete("/user/deleteAll", cors(options), users.deleteAll); + router.delete("/user/deleteAll", users.deleteAll); // Get all Roles depending on the User session id - router.get("/user/roles", cors(options), users.roles); + router.get("/user/roles", users.roles); // Get 1 or multiple ad adapted to the User session id - router.get("/user/ad", cors(options), users.ad); + router.get("/user/ad", users.ad); // Get History - router.get("/user/history", cors(options), users.history); + router.get("/user/history", users.history); app.use('/api', router); }; diff --git a/server.js b/server.js index c17846b..44c348d 100644 --- a/server.js +++ b/server.js @@ -2,6 +2,12 @@ const express = require('express'); const app = express(); const port = process.env.PORT || 3000; +const cors = require('cors'); +app.use(cors({ + origin: false, + credentials: true +})); + const cookieParser = require('cookie-parser'); app.use(cookieParser()); From 5ba903628924696dd72bbd738b0de4b098886a0a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Y=C3=BBki=20VACHOT?= Date: Wed, 29 Dec 2021 17:36:46 +0100 Subject: [PATCH 19/35] Update: Change Cors Origin Admin --- server.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/server.js b/server.js index 44c348d..6c55266 100644 --- a/server.js +++ b/server.js @@ -4,7 +4,7 @@ const port = process.env.PORT || 3000; const cors = require('cors'); app.use(cors({ - origin: false, + origin: 'https://admin-polynotfound.herokuapp.com', credentials: true })); From e8e66fe5055a8fe8654347ae449fb395b73bf872 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Y=C3=BBki=20VACHOT?= Date: Wed, 29 Dec 2021 17:50:45 +0100 Subject: [PATCH 20/35] Update: Allow Origin * --- server.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/server.js b/server.js index 6c55266..845f0fe 100644 --- a/server.js +++ b/server.js @@ -4,7 +4,7 @@ const port = process.env.PORT || 3000; const cors = require('cors'); app.use(cors({ - origin: 'https://admin-polynotfound.herokuapp.com', + origin: '*', credentials: true })); From 68e212fce97d2a302e438aae976656fa3a107c51 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Y=C3=BBki=20VACHOT?= Date: Wed, 29 Dec 2021 17:52:59 +0100 Subject: [PATCH 21/35] Update: Rollback Origin --- server.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/server.js b/server.js index 845f0fe..6c55266 100644 --- a/server.js +++ b/server.js @@ -4,7 +4,7 @@ const port = process.env.PORT || 3000; const cors = require('cors'); app.use(cors({ - origin: '*', + origin: 'https://admin-polynotfound.herokuapp.com', credentials: true })); From 7a9ee00eb5c04a9e6bc63c5eb8086ee1859a8f12 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Y=C3=BBki=20VACHOT?= Date: Wed, 29 Dec 2021 18:05:06 +0100 Subject: [PATCH 22/35] Update: Add Access Controls --- server.js | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/server.js b/server.js index 6c55266..b2f220a 100644 --- a/server.js +++ b/server.js @@ -3,6 +3,14 @@ const app = express(); const port = process.env.PORT || 3000; const cors = require('cors'); + +app.use(function(req, res, next) { + res.header("Access-Control-Allow-Origin", 'https://admin-polynotfound.herokuapp.com'); + res.header("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept"); + res.header('Access-Control-Allow-Methods', 'GET,PUT,POST,DELETE'); + next(); +}); + app.use(cors({ origin: 'https://admin-polynotfound.herokuapp.com', credentials: true From a9c959bf3f24c72f78b7ad50092eac6ebc5efa72 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Y=C3=BBki=20VACHOT?= Date: Wed, 29 Dec 2021 18:10:05 +0100 Subject: [PATCH 23/35] Update: Add console.log token --- config/sessionJWT.config.js | 1 + 1 file changed, 1 insertion(+) diff --git a/config/sessionJWT.config.js b/config/sessionJWT.config.js index 7dbc86c..3b0054a 100644 --- a/config/sessionJWT.config.js +++ b/config/sessionJWT.config.js @@ -81,6 +81,7 @@ function checkLogin(req, res, role=null){ if(typeof req.cookies !== 'undefined'){ const session = getSession(req.cookies.SESSIONID); const token = getToken(session); + console.log(token); if(typeof token.email === 'undefined' || token.email === -1 || typeof token.id === 'undefined' || From 3febde57bba5d97f579b17d8c50cd2e5558a81aa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Y=C3=BBki=20VACHOT?= Date: Wed, 29 Dec 2021 18:20:47 +0100 Subject: [PATCH 24/35] Update: Remove Allow from res --- server.js | 8 -------- 1 file changed, 8 deletions(-) diff --git a/server.js b/server.js index b2f220a..6c55266 100644 --- a/server.js +++ b/server.js @@ -3,14 +3,6 @@ const app = express(); const port = process.env.PORT || 3000; const cors = require('cors'); - -app.use(function(req, res, next) { - res.header("Access-Control-Allow-Origin", 'https://admin-polynotfound.herokuapp.com'); - res.header("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept"); - res.header('Access-Control-Allow-Methods', 'GET,PUT,POST,DELETE'); - next(); -}); - app.use(cors({ origin: 'https://admin-polynotfound.herokuapp.com', credentials: true From aca78238feec382ab10c787837712466674f6377 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Y=C3=BBki=20VACHOT?= Date: Wed, 29 Dec 2021 18:35:33 +0100 Subject: [PATCH 25/35] Update: Add Secure --- config/sessionJWT.config.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/config/sessionJWT.config.js b/config/sessionJWT.config.js index 3b0054a..64e1488 100644 --- a/config/sessionJWT.config.js +++ b/config/sessionJWT.config.js @@ -42,7 +42,7 @@ function createSessionCookie(req, res, payload) { else { jwtToken = createSessionJWT(payload.id, payload.email, payload.profileImageUrl, payload.role); } - res.cookie('SESSIONID', jwtToken, {httpOnly:true, secure:false}); + res.cookie('SESSIONID', jwtToken, {httpOnly: true, secure: process.env.NODE_ENV === "production"}); } function decodeSessionCookie(sessionid) { From 96481369da42e91a53030291c953dc9b0f4144d2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Y=C3=BBki=20VACHOT?= Date: Wed, 29 Dec 2021 18:39:15 +0100 Subject: [PATCH 26/35] Update: Add sameSite Cookie --- config/sessionJWT.config.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/config/sessionJWT.config.js b/config/sessionJWT.config.js index 64e1488..be7ae00 100644 --- a/config/sessionJWT.config.js +++ b/config/sessionJWT.config.js @@ -42,7 +42,7 @@ function createSessionCookie(req, res, payload) { else { jwtToken = createSessionJWT(payload.id, payload.email, payload.profileImageUrl, payload.role); } - res.cookie('SESSIONID', jwtToken, {httpOnly: true, secure: process.env.NODE_ENV === "production"}); + res.cookie('SESSIONID', jwtToken, {httpOnly: true, sameSite: 'strict', secure: process.env.NODE_ENV === 'production'}); } function decodeSessionCookie(sessionid) { From 3db7bfd7af053d2c2419ee8e963822c4b6cb723e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Y=C3=BBki=20VACHOT?= Date: Wed, 29 Dec 2021 18:42:10 +0100 Subject: [PATCH 27/35] Update: Add sameSite=None Cookie --- config/sessionJWT.config.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/config/sessionJWT.config.js b/config/sessionJWT.config.js index be7ae00..2fde996 100644 --- a/config/sessionJWT.config.js +++ b/config/sessionJWT.config.js @@ -42,7 +42,7 @@ function createSessionCookie(req, res, payload) { else { jwtToken = createSessionJWT(payload.id, payload.email, payload.profileImageUrl, payload.role); } - res.cookie('SESSIONID', jwtToken, {httpOnly: true, sameSite: 'strict', secure: process.env.NODE_ENV === 'production'}); + res.cookie('SESSIONID', jwtToken, {httpOnly: true, sameSite: 'None', secure: process.env.NODE_ENV === 'production'}); } function decodeSessionCookie(sessionid) { From c6e02cf7973e8dc811ebd22442c174e85912d7e5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Y=C3=BBki=20VACHOT?= Date: Wed, 29 Dec 2021 18:51:56 +0100 Subject: [PATCH 28/35] Update: Move Cors to Routes --- config/cors.config.js | 5 ++--- routes/user.routes.js | 26 +++++++++++++------------- server.js | 10 +++++----- 3 files changed, 20 insertions(+), 21 deletions(-) diff --git a/config/cors.config.js b/config/cors.config.js index e7aac87..8f6b845 100644 --- a/config/cors.config.js +++ b/config/cors.config.js @@ -5,8 +5,7 @@ const allowList = [ 'http://127.0.0.1:4200', 'http://127.0.0.1:4201', 'https://admin-polynotfound.herokuapp.com', - 'https://polynotfound.herokuapp.com', - + 'https://polynotfound.herokuapp.com' ]; const corsOptionsDelegate = function(req, callback) { @@ -14,7 +13,7 @@ const corsOptionsDelegate = function(req, callback) { let corsOptions; if (allowList.indexOf(req.header('Origin')) !== -1) { corsOptions = { - origin: false, + origin: true, credentials: true } } else { diff --git a/routes/user.routes.js b/routes/user.routes.js index 3e7d2fa..4d62364 100644 --- a/routes/user.routes.js +++ b/routes/user.routes.js @@ -1,43 +1,43 @@ const users = require("../controllers/user.controller"); -//const {cors, options} = require("../config/cors.config"); +const {cors, options} = require("../config/cors.config"); module.exports = app => { let router = require("express").Router(); // Authenticate a User - router.post("/user/auth", users.auth); + router.post("/user/auth", cors(options), users.auth); // Logout a User - router.delete("/user/logout", users.logout); + router.delete("/user/logout", cors(options), users.logout); // Request password reset with email - router.post("/user/resetPass", users.resetPass); + router.post("/user/resetPass", cors(options), users.resetPass); // Create and Save a new User - router.post("/user/create", users.create); + router.post("/user/create", cors(options), users.create); // Retrieve all Users if admin - router.get("/user/findAll", users.findAll); + router.get("/user/findAll", cors(options), users.findAll); // Find single User from id if admin or session id - router.get("/user/findOne/:id", users.findOne); + router.get("/user/findOne/:id", cors(options), users.findOne); // Update a User from id if admin or session id - router.put("/user/update/:id", users.update); + router.put("/user/update/:id", cors(options), users.update); // Delete a User from id if admin or session id - router.delete("/user/delete/:id", users.delete); + router.delete("/user/delete/:id", cors(options), users.delete); // Delete all Users if superAdmin - router.delete("/user/deleteAll", users.deleteAll); + router.delete("/user/deleteAll", cors(options), users.deleteAll); // Get all Roles depending on the User session id - router.get("/user/roles", users.roles); + router.get("/user/roles", cors(options), users.roles); // Get 1 or multiple ad adapted to the User session id - router.get("/user/ad", users.ad); + router.get("/user/ad", cors(options), users.ad); // Get History - router.get("/user/history", users.history); + router.get("/user/history", cors(options), users.history); app.use('/api', router); }; diff --git a/server.js b/server.js index 6c55266..3e99831 100644 --- a/server.js +++ b/server.js @@ -2,11 +2,11 @@ const express = require('express'); const app = express(); const port = process.env.PORT || 3000; -const cors = require('cors'); -app.use(cors({ - origin: 'https://admin-polynotfound.herokuapp.com', - credentials: true -})); +//const cors = require('cors'); +//app.use(cors({ +// origin: 'https://admin-polynotfound.herokuapp.com', +// credentials: true +//})); const cookieParser = require('cookie-parser'); app.use(cookieParser()); From f69ed4b3d488b8f18a8ccafe89f96da789166237 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Y=C3=BBki=20VACHOT?= Date: Wed, 29 Dec 2021 19:01:06 +0100 Subject: [PATCH 29/35] Update: Npm Cors Doc --- config/cors.config.js | 25 ++++++++----------------- routes/user.routes.js | 26 +++++++++++++------------- 2 files changed, 21 insertions(+), 30 deletions(-) diff --git a/config/cors.config.js b/config/cors.config.js index 8f6b845..34d81b6 100644 --- a/config/cors.config.js +++ b/config/cors.config.js @@ -1,28 +1,19 @@ const cors = require('cors'); module.exports.cors = cors; -const allowList = [ +const whitelist = [ 'http://127.0.0.1:4200', 'http://127.0.0.1:4201', 'https://admin-polynotfound.herokuapp.com', 'https://polynotfound.herokuapp.com' ]; -const corsOptionsDelegate = function(req, callback) { - console.log(req.header('Origin'), allowList.indexOf(req.header('Origin'))); - let corsOptions; - if (allowList.indexOf(req.header('Origin')) !== -1) { - corsOptions = { - origin: true, - credentials: true - } - } else { - corsOptions = { - origin: false, - credentials: true +module.exports.corsOptions = { + origin: function(origin, callback) { + if (whitelist.indexOf(origin) !== -1) { + callback(null, true); + } else { + callback(new Error('Not allowed by CORS')); } } - console.log(corsOptions); - callback(null, corsOptions) -} -module.exports.options = corsOptionsDelegate; \ No newline at end of file +} \ No newline at end of file diff --git a/routes/user.routes.js b/routes/user.routes.js index 4d62364..158acbb 100644 --- a/routes/user.routes.js +++ b/routes/user.routes.js @@ -1,43 +1,43 @@ const users = require("../controllers/user.controller"); -const {cors, options} = require("../config/cors.config"); +const {cors, corsOptions} = require("../config/cors.config"); module.exports = app => { let router = require("express").Router(); // Authenticate a User - router.post("/user/auth", cors(options), users.auth); + router.post("/user/auth", cors(corsOptions), users.auth); // Logout a User - router.delete("/user/logout", cors(options), users.logout); + router.delete("/user/logout", cors(corsOptions), users.logout); // Request password reset with email - router.post("/user/resetPass", cors(options), users.resetPass); + router.post("/user/resetPass", cors(corsOptions), users.resetPass); // Create and Save a new User - router.post("/user/create", cors(options), users.create); + router.post("/user/create", cors(corsOptions), users.create); // Retrieve all Users if admin - router.get("/user/findAll", cors(options), users.findAll); + router.get("/user/findAll", cors(corsOptions), users.findAll); // Find single User from id if admin or session id - router.get("/user/findOne/:id", cors(options), users.findOne); + router.get("/user/findOne/:id", cors(corsOptions), users.findOne); // Update a User from id if admin or session id - router.put("/user/update/:id", cors(options), users.update); + router.put("/user/update/:id", cors(corsOptions), users.update); // Delete a User from id if admin or session id - router.delete("/user/delete/:id", cors(options), users.delete); + router.delete("/user/delete/:id", cors(corsOptions), users.delete); // Delete all Users if superAdmin - router.delete("/user/deleteAll", cors(options), users.deleteAll); + router.delete("/user/deleteAll", cors(corsOptions), users.deleteAll); // Get all Roles depending on the User session id - router.get("/user/roles", cors(options), users.roles); + router.get("/user/roles", cors(corsOptions), users.roles); // Get 1 or multiple ad adapted to the User session id - router.get("/user/ad", cors(options), users.ad); + router.get("/user/ad", cors(corsOptions), users.ad); // Get History - router.get("/user/history", cors(options), users.history); + router.get("/user/history", cors(corsOptions), users.history); app.use('/api', router); }; From 32ceef171e47d45cbfe92d2270ca90aec113d8ff Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Y=C3=BBki=20VACHOT?= Date: Wed, 29 Dec 2021 19:02:31 +0100 Subject: [PATCH 30/35] Update: Add console log origin --- config/cors.config.js | 1 + 1 file changed, 1 insertion(+) diff --git a/config/cors.config.js b/config/cors.config.js index 34d81b6..6e73567 100644 --- a/config/cors.config.js +++ b/config/cors.config.js @@ -10,6 +10,7 @@ const whitelist = [ module.exports.corsOptions = { origin: function(origin, callback) { + console.log(whitelist, origin); if (whitelist.indexOf(origin) !== -1) { callback(null, true); } else { From e6b8eef43c6652493e342e0e99e5e23e6aa3e9f7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Y=C3=BBki=20VACHOT?= Date: Wed, 29 Dec 2021 19:08:52 +0100 Subject: [PATCH 31/35] Update: Move Cors to server.js --- routes/user.routes.js | 26 +++++++++++++------------- server.js | 29 ++++++++++++++++++++++++----- 2 files changed, 37 insertions(+), 18 deletions(-) diff --git a/routes/user.routes.js b/routes/user.routes.js index 158acbb..a7a9c38 100644 --- a/routes/user.routes.js +++ b/routes/user.routes.js @@ -1,43 +1,43 @@ const users = require("../controllers/user.controller"); -const {cors, corsOptions} = require("../config/cors.config"); +//const {cors, corsOptions} = require("../config/cors.config"); module.exports = app => { let router = require("express").Router(); // Authenticate a User - router.post("/user/auth", cors(corsOptions), users.auth); + router.post("/user/auth", users.auth); // Logout a User - router.delete("/user/logout", cors(corsOptions), users.logout); + router.delete("/user/logout", users.logout); // Request password reset with email - router.post("/user/resetPass", cors(corsOptions), users.resetPass); + router.post("/user/resetPass", users.resetPass); // Create and Save a new User - router.post("/user/create", cors(corsOptions), users.create); + router.post("/user/create", users.create); // Retrieve all Users if admin - router.get("/user/findAll", cors(corsOptions), users.findAll); + router.get("/user/findAll", users.findAll); // Find single User from id if admin or session id - router.get("/user/findOne/:id", cors(corsOptions), users.findOne); + router.get("/user/findOne/:id", users.findOne); // Update a User from id if admin or session id - router.put("/user/update/:id", cors(corsOptions), users.update); + router.put("/user/update/:id", users.update); // Delete a User from id if admin or session id - router.delete("/user/delete/:id", cors(corsOptions), users.delete); + router.delete("/user/delete/:id", users.delete); // Delete all Users if superAdmin - router.delete("/user/deleteAll", cors(corsOptions), users.deleteAll); + router.delete("/user/deleteAll", users.deleteAll); // Get all Roles depending on the User session id - router.get("/user/roles", cors(corsOptions), users.roles); + router.get("/user/roles", users.roles); // Get 1 or multiple ad adapted to the User session id - router.get("/user/ad", cors(corsOptions), users.ad); + router.get("/user/ad", users.ad); // Get History - router.get("/user/history", cors(corsOptions), users.history); + router.get("/user/history", users.history); app.use('/api', router); }; diff --git a/server.js b/server.js index 3e99831..fad2e85 100644 --- a/server.js +++ b/server.js @@ -2,11 +2,30 @@ const express = require('express'); const app = express(); const port = process.env.PORT || 3000; -//const cors = require('cors'); -//app.use(cors({ -// origin: 'https://admin-polynotfound.herokuapp.com', -// credentials: true -//})); +const cors = require('cors'); +const whitelist = [ + 'http://127.0.0.1:4200', + 'http://127.0.0.1:4201', + 'https://admin-polynotfound.herokuapp.com', + 'https://polynotfound.herokuapp.com' +]; +const corsOptionsDelegate = (req, callback) => { + let corsOptions; + + if (whitelist.indexOf(req.header('Origin')) !== -1) { + corsOptions = { + origin: true, + credentials: true + } + } else { + corsOptions = { + origin: false, + credentials: true + } + } + callback(null, corsOptions) +} +app.use(cors(corsOptionsDelegate)); const cookieParser = require('cookie-parser'); app.use(cookieParser()); From a428e5cff259db26359814927e700cbde4a1d3b7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Y=C3=BBki=20Vachot?= Date: Mon, 10 Jan 2022 12:07:45 +0100 Subject: [PATCH 32/35] Update: Admin can create Admin or Advertiser --- controllers/user.controller.js | 22 ++++++++++++++++++++-- 1 file changed, 20 insertions(+), 2 deletions(-) diff --git a/controllers/user.controller.js b/controllers/user.controller.js index 9af3856..2575ea1 100644 --- a/controllers/user.controller.js +++ b/controllers/user.controller.js @@ -73,10 +73,28 @@ exports.create = (req, res) => { if(typeof req.body.role !== 'undefined'){ switch(req.body.role){ case 'admin': - var_role = roles.Admin; + const token = checkLogin(req, res); + const role = roles.Admin; + if(token && 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))){ + var_role = roles.Admin; + var_role.isAccepted = true; + } else { + var_role = roles.Admin; + } break; case 'advertiser': - var_role = roles.Advertiser; + const token = checkLogin(req, res); + const role = roles.Admin; + if(token && 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))){ + var_role = roles.Advertiser; + var_role.isAccepted = true; + } else { + var_role = roles.Advertiser; + } break; default: var_role = roles.User; From 5e9e049cfcfef146a835b1cc626f4c78951365f2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Y=C3=BBki=20Vachot?= Date: Mon, 10 Jan 2022 12:22:03 +0100 Subject: [PATCH 33/35] Update: Admin can create Admin or Advertiser --- controllers/user.controller.js | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/controllers/user.controller.js b/controllers/user.controller.js index 2575ea1..6e2ded4 100644 --- a/controllers/user.controller.js +++ b/controllers/user.controller.js @@ -71,10 +71,10 @@ exports.create = (req, res) => { let user; let var_role; if(typeof req.body.role !== 'undefined'){ + const token = checkLogin(req, res); + const role = roles.Admin; switch(req.body.role){ case 'admin': - const token = checkLogin(req, res); - const role = roles.Admin; if(token && 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))){ @@ -85,8 +85,6 @@ exports.create = (req, res) => { } break; case 'advertiser': - const token = checkLogin(req, res); - const role = roles.Admin; if(token && 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))){ From 3ff902353d7c0912065fbe4ef6e9c42a5b029dad Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Y=C3=BBki=20Vachot?= Date: Mon, 10 Jan 2022 12:25:28 +0100 Subject: [PATCH 34/35] Update: User.create --- controllers/user.controller.js | 20 ++------------------ 1 file changed, 2 insertions(+), 18 deletions(-) diff --git a/controllers/user.controller.js b/controllers/user.controller.js index 6e2ded4..9af3856 100644 --- a/controllers/user.controller.js +++ b/controllers/user.controller.js @@ -71,28 +71,12 @@ exports.create = (req, res) => { let user; let var_role; if(typeof req.body.role !== 'undefined'){ - const token = checkLogin(req, res); - const role = roles.Admin; switch(req.body.role){ case 'admin': - if(token && 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))){ - var_role = roles.Admin; - var_role.isAccepted = true; - } else { - var_role = roles.Admin; - } + var_role = roles.Admin; break; case 'advertiser': - if(token && 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))){ - var_role = roles.Advertiser; - var_role.isAccepted = true; - } else { - var_role = roles.Advertiser; - } + var_role = roles.Advertiser; break; default: var_role = roles.User; From 7f3b7e936e26b26a092fcf04cd8bca74684380ae Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Y=C3=BBki=20Vachot?= Date: Mon, 10 Jan 2022 17:11:43 +0100 Subject: [PATCH 35/35] Update: User.ad randomize --- controllers/user.controller.js | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/controllers/user.controller.js b/controllers/user.controller.js index 9af3856..d01b6d2 100644 --- a/controllers/user.controller.js +++ b/controllers/user.controller.js @@ -401,7 +401,7 @@ exports.ad = (req, res) => { {$sort: {watchedDates: -1}}, {$limit: limit}, {$unwind: '$interest'}, - {$group: {_id: null, interests: {$push: '$interest'}}} + {$group: {_id: null, interests: {$addToSet: '$interest'}}} ]) .then(data => { if(typeof data[0] !== 'undefined' && @@ -410,15 +410,13 @@ exports.ad = (req, res) => { data[0].interests !== null){ interests = interests.concat(data[0].interests); } - let match, pick; + let match; 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)}}; } - + const pick = {$sample: {size: parseInt(quantity, 10)}}; Ad.aggregate([ match, pick