From e85127acaaf7aac2e64a1370a7a30256bb940641 Mon Sep 17 00:00:00 2001 From: Haupais Date: Wed, 10 Jan 2024 14:49:14 +0100 Subject: [PATCH] feat(v3.4) : release version EcoSonar 3.4 --- .github/workflows/publish-docker-image.yml | 2 +- API.md | 1450 +++++++++-------- CHANGELOG.md | 73 +- EcoSonar-API/README.md | 490 ++---- .../dataBase/bestPracticesRepository.js | 61 +- EcoSonar-API/dataBase/greenItRepository.js | 68 +- EcoSonar-API/dataBase/lighthouseRepository.js | 48 +- .../dataBase/models/tempurlsproject.js | 19 + EcoSonar-API/dataBase/projectsRepository.js | 109 +- .../dataBase/tempurlsProjectRepository.js | 79 + .../dataBase/urlsProjectRepository.js | 48 +- EcoSonar-API/dataBase/w3cRepository.js | 53 +- EcoSonar-API/package.json | 2 +- EcoSonar-API/routes/app.js | 233 ++- EcoSonar-API/services/bestPracticesService.js | 24 + .../services/crawler/crawlerService.js | 92 +- .../loginProxyConfigurationService.js | 49 +- EcoSonar-API/services/projectService.js | 72 +- .../services/urlConfigurationService.js | 107 +- .../utils/bestPractices/greenItData.json | 146 ++ .../lighthouseAccessibilityData.json | 272 ++++ .../lighthousePerformanceData.json | 169 ++ EcoSonar-SonarQube/README.md | 53 +- EcoSonar-SonarQube/package.json | 4 +- EcoSonar-SonarQube/pom.xml | 4 +- .../components/BestPracticesBody.js | 2 +- .../components/ConfigurationPage.js | 89 +- .../components/Crawler/CrawlerPage.js | 212 ++- .../src/main/js/services/crawlerService.js | 25 +- .../src/main/js/styles/_settings.scss | 5 +- .../main/js/styles/components/_urlConfig.scss | 39 +- .../src/main/js/utils/errors.json | 2 + README.md | 128 +- ROADMAP.md | 7 - USER_GUIDE.md | 364 ++++- images/delete-project.webp | Bin 0 -> 10202 bytes images/ecosonar-url-configuration.webp | Bin 27026 -> 19108 bytes images/ecosonar-url-crawler-result.webp | Bin 28992 -> 24334 bytes images/ecosonar-url-crawler-setup.webp | Bin 13358 -> 17354 bytes images/ecosonar-url-page.webp | Bin 0 -> 17870 bytes images/get-best-practices-documentation.webp | Bin 0 -> 9190 bytes images/get-crawler-result.webp | Bin 13674 -> 14792 bytes images/get-version.webp | Bin 0 -> 8426 bytes images/launch-crawler.webp | Bin 0 -> 17634 bytes images/save-login-and-proxy-for-project.webp | Bin 15660 -> 0 bytes images/save-login-for-project.webp | Bin 0 -> 15552 bytes images/save-proxy-for-project.webp | Bin 0 -> 14830 bytes 47 files changed, 3119 insertions(+), 1481 deletions(-) create mode 100644 EcoSonar-API/dataBase/models/tempurlsproject.js create mode 100644 EcoSonar-API/dataBase/tempurlsProjectRepository.js create mode 100644 EcoSonar-API/services/bestPracticesService.js create mode 100644 EcoSonar-API/utils/bestPractices/greenItData.json create mode 100644 EcoSonar-API/utils/bestPractices/lighthouseAccessibilityData.json create mode 100644 EcoSonar-API/utils/bestPractices/lighthousePerformanceData.json delete mode 100644 ROADMAP.md create mode 100644 images/delete-project.webp create mode 100644 images/ecosonar-url-page.webp create mode 100644 images/get-best-practices-documentation.webp create mode 100644 images/get-version.webp create mode 100644 images/launch-crawler.webp delete mode 100644 images/save-login-and-proxy-for-project.webp create mode 100644 images/save-login-for-project.webp create mode 100644 images/save-proxy-for-project.webp diff --git a/.github/workflows/publish-docker-image.yml b/.github/workflows/publish-docker-image.yml index c9c2974..085555c 100644 --- a/.github/workflows/publish-docker-image.yml +++ b/.github/workflows/publish-docker-image.yml @@ -36,7 +36,7 @@ jobs: uses: docker/metadata-action@9ec57ed1fcdbf14dcef7dfbe97b2010124a938b7 with: images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }} - tags: type=raw,value=3.3 + tags: type=raw,value=3.4 # This step uses the `docker/build-push-action` action to build the image, based on your repository's `Dockerfile`. If the build succeeds, it pushes the image to GitHub Packages. # It uses the `context` parameter to define the build's context as the set of files located in the specified path. For more information, see "[Usage](https://github.com/docker/build-push-action#usage)" in the README of the `docker/build-push-action` repository. # It uses the `tags` and `labels` parameters to tag and label the image with the output from the "meta" step. diff --git a/API.md b/API.md index 980467d..96a010f 100644 --- a/API.md +++ b/API.md @@ -1,6 +1,6 @@ **EcoSonar API** -New Postman Collection available with all endpoints : +New Postman Collection available with all endpoints : [![Run in Postman](https://run.pstmn.io/button.svg)](https://app.getpostman.com/run-collection/9592977-29c7010f-0efd-4063-b76a-5b0f455b1829?action=collection%2Ffork&collection-url=entityId%3D9592977-29c7010f-0efd-4063-b76a-5b0f455b1829%26entityType%3Dcollection%26workspaceId%3Df7ed92ee-00aa-4dc1-95aa-9f7d2da44e68) @@ -8,247 +8,685 @@ Swagger User Interface available at the link : `[ECOSONAR-API-URL]/swagger/` Locally, available at this address : `http://localhost:3002/swagger/` ----- +--- + +## **EcoSonar URL Configuration - GET URLs FROM PROJECT** -**EcoSonar URL Configuration - GET URLs FROM PROJECT** ----- ![GET URLs FROM PROJECT](./images/get-urls-from-project.webp) -* **URL** +- **URL** `/api/all?projectName=` -* **Method:** +- **Method:** `GET` - -* **URL Params** - PROJECT_NAME should match to the Project Key defined in your Sonarqube Project. +- **URL Params** + + PROJECT_NAME should match to the Project Key defined in your Sonarqube Project. + + **Required:** - **Required:** - - `PROJECT_NAME=[string]` + `PROJECT_NAME=[string]` -* **Data Params** +- **Data Params** None -* **Success Response:** +- **Success Response:** - * **Code:** 200
+ - **Code:** 200
**Content:** `[ - "url1", - "url2", - "url3"]` - -* **Error Response:** +"url1", +"url2", +"url3"]` + +- **Error Response:** When you don't have any URLs assigned to a project into EcoSonar - * **Code:** 400 BAD REQUEST
- **Content:** `{ - "error": "Your project has no url assigned into EcoSonar. You must at least add one url if you want to analyse ecodesign practices." - }` +- **Code:** 400 BAD REQUEST
+ **Content:** `{ +"error": "Your project has no url assigned into EcoSonar. You must at least add one url if you want to analyse ecodesign practices." +}` - OR +OR EcoSonar API is not able to request to the MongoDB Database : - * **Code:** 500 Internal Server Error
+- **Code:** 500 Internal Server Error
+ +## **EcoSonar URL Configuration - INSERT URLs IN PROJECT** -**EcoSonar URL Configuration - INSERT URLs IN PROJECT** ----- ![INSERT URLs IN PROJECT](./images/insert-urls-in-project.webp) -* **URL** +- **URL** `/api/insert` -* **Method:** +- **Method:** `POST` - -* **URL Params** - None +- **URL Params** + + None -* **Data Params** +- **Data Params** PROJECT_NAME should match to the Project Key defined in your Sonarqube Project. `{ - "projectName" : "PROJECT_NAME", - "urlName": ["url1", "url2"] - }` + "projectName" : "PROJECT_NAME", + "urlName": ["url1", "url2"] +}` + +- **Success Response:** -* **Success Response:** + - **Code:** 200
- * **Code:** 200
- -* **Error Response:** +- **Error Response:** When you have validation errors in the list of urls you want to insert (url invalid or duplicated), with the error index corresponding to the index url - * **Code:** 400 BAD REQUEST
- **Content:** `{ +- **Code:** 400 BAD REQUEST
+ **Content:** `{ "error": [ "Url has an invalid syntax", "URL was duplicated or already inserted" ] }` - OR +OR EcoSonar API is not able to request to the MongoDB Database : - * **Code:** 500 Internal Server Error
+- **Code:** 500 Internal Server Error
+ +## **EcoSonar URL Configuration - DELETE URL IN PROJECT** -**EcoSonar URL Configuration - DELETE URL IN PROJECT** ----- ![DELETE URL IN PROJECT](./images/delete-url-in-project.webp) You can delete one url at a time. -* **URL** +- **URL** `/api/delete` -* **Method:** +- **Method:** `DELETE` - -* **URL Params** - None +- **URL Params** -* **Data Params** + None + +- **Data Params** PROJECT_NAME should match to the Project Key defined in your Sonarqube Project. `{ - "projectName" : "PROJECT_NAME", - "urlName" : "url_to_delete" - }` + "projectName" : "PROJECT_NAME", + "urlName" : "url_to_delete" +}` + +- **Success Response:** -* **Success Response:** + - **Code:** 200
- * **Code:** 200
- -* **Error Response:** +- **Error Response:** When the url can't be found in your project - * **Code:** 400 BAD REQUEST
- **Content:** `{ - "error": "url_to_delete in PROJECT_NAME not found" - }` +- **Code:** 400 BAD REQUEST
+ **Content:** `{ + "error": "url_to_delete in PROJECT_NAME not found" +}` - OR +OR EcoSonar API is not able to request to the MongoDB Database : - * **Code:** 500 Internal Server Error
+- **Code:** 500 Internal Server Error
-**EcoSonar URL Configuration - GET CRAWLER RESULT** ----- -![GET CRAWLER RESULT](./images/get-crawler-result.webp) +## **EcoSonar URL Configuration - DELETE PROJECT** -* **URL** +![DELETE PROJECT](./images/delete-project.webp) + + +- **URL** + + `/api/project` + +- **Method:** + + `DELETE` + +- **URL Params** + + PROJECT_NAME should match to the Project Key defined in your Sonarqube Project. + + **Required:** + + `PROJECT_NAME=[string]` + +- **Data Params** + +None + +- **Success Response:** + + - **Code:** 200
+ +- **Error Response:** + +EcoSonar API is not able to request to the MongoDB Database : + +- **Code:** 500 Internal Server Error
+ +## **EcoSonar URL Configuration - LAUNCH CRAWLER** + +![LAUNCH CRAWLER](./images/launch-crawler.webp) + +- **URL** `/api/crawl` -* **Method:** +- **Method:** `POST` - -* **URL Params** + +- **URL Params** None -* **Data Params** - - PROJECT_NAME should match to the Project Key defined in your Sonarqube Project. - homepage_url is the home page of your website from where the crawler will start finding all pages within your website +- **Data Params** + PROJECT_NAME should match to the Project Key defined in your Sonarqube Project. + homepage_url is the home page of your website from where the crawler will start finding all pages within your website + save is a boolean value : if true, results will be saved in datatabse and pages will be audited by EcoSonar. If false, they will be saved in a temp collection to be reviewed by a user before being applied in EcoSonar configuration. -` -{ +`{ "projectName": "PROJECT_NAME", "mainUrl": "homepage_url" -} -` + "saveUrls": "save" +}` + +- **Success Response:** + + - **Code:** 202
+ +## **EcoSonar URL Configuration - GET CRAWLER RESULT** + +![GET CRAWLER RESULT](./images/get-crawler-result.webp) + +- **URL** + + `/api/crawl` + +- **Method:** + + `GET` + +- **URL Params** + + PROJECT_NAME should match to the Project Key defined in your Sonarqube Project. -* **Success Response:** + **Required:** - * **Code:** 200
+ `PROJECT_NAME=[string]` + +- **Data Params** + None + +- **Success Response:** + + - **Code:** 200
**Content:** `[ - "url1", - "url2", - "url3"]` - -* **Error Response:** +"url1", +"url2", +"url3"]` + +- **Error Response:** + +EcoSonar API failed to get crawler results: + +- **Code:** 400 BAD REQUEST
+ **Content:** `No crawled urls were saved for this project` + +OR + +- **Code:** 500 Internal Server Error
+ +## **EcoSonar Login Configuration - SAVE LOGIN FOR PROJECT** + +![SAVE LOGIN FOR PROJECT](./images/save-login-for-project.webp) + +- **URL** + + `/api/login/insert?projectName=` + +- **Method:** + + `POST` + +- **URL Params** + + PROJECT_NAME should match to the Project Key defined in your Sonarqube Project. + + **Required:** + + `PROJECT_NAME=[string]` -EcoSonar API failed to launch crawler: +- **Data Params** + `{ + "login": { + "authentication_url": "", + "steps": [] + } +}` + +- **Success Response:** + + - **Code:** 201
+ +- **Error Response:** + +EcoSonar API is not able to save into the MongoDB Database : + +- **Code:** 500 Internal Server Error
+ +## **EcoSonar Login Configuration - GET LOGIN FOR PROJECT** + +![GET LOGIN FOR PROJECT](./images/get-login-for-project.webp) + +- **URL** + + `/api/login/find?projectName=` + +- **Method:** + + `GET` + +- **URL Params** + + PROJECT_NAME should match to the Project Key defined in your Sonarqube Project. + + **Required:** + + `PROJECT_NAME=[string]` + +- **Data Params** + + None + +- **Success Response:** + + - **Code:** 200
+ **Content:** `{ + "authentication_url": "", + "steps": [] +}` + +- **Error Response:** + +When you don't have any login registered for your project into EcoSonar + +- **Code:** 400 BAD REQUEST
+ **Content:** `{ + "error": "Your project does not have login saved into database." +}` + +OR + +EcoSonar API is not able to request to the MongoDB Database : + +- **Code:** 500 Internal Server Error
- * **Code:** 500 Internal Server Error
+## **EcoSonar Login Configuration - DELETE LOGIN FOR PROJECT** + +![DELETE LOGIN FOR PROJECT](./images/delete-login-for-project.webp) + +- **URL** + + `/api/login?projectName=` + +- **Method:** + + `DELETE` + +- **URL Params** + + PROJECT_NAME should match to the Project Key defined in your Sonarqube Project. + + **Required:** + + `PROJECT_NAME=[string]` + +- **Data Params** + + None + +- **Success Response:** + + - **Code:** 200
+ +- **Error Response:** + +When you don't have any login registered for your project into EcoSonar and you want still to delete it + +- **Code:** 400 BAD REQUEST
+ **Content:** `{ + "error": "Project not found" +}` + +OR + +EcoSonar API is not able to request to the MongoDB Database : + +- **Code:** 500 Internal Server Error
+ +## **EcoSonar Proxy Configuration - SAVE PROXY FOR PROJECT** + +![SAVE PROXY FOR PROJECT](./images/save-proxy-for-project.webp) + +- **URL** + + `/api/proxy/insert?projectName=` + +- **Method:** + + `POST` + +- **URL Params** + + PROJECT_NAME should match to the Project Key defined in your Sonarqube Project. + + **Required:** + + `PROJECT_NAME=[string]` + +- **Data Params** + `{ + "proxy": { + "ipAddress": "", + "port": "" + } +}` + +- **Success Response:** + + - **Code:** 201
+ +- **Error Response:** + +EcoSonar API is not able to save into the MongoDB Database : + +- **Code:** 500 Internal Server Error
+ +## **EcoSonar Proxy Configuration - GET PROXY FOR PROJECT** + +![GET PROXY FOR PROJECT](./images/get-proxy-for-project.webp) + +- **URL** + + `/api/proxy/find?projectName=` + +- **Method:** + + `GET` + +- **URL Params** + + PROJECT_NAME should match to the Project Key defined in your Sonarqube Project. + + **Required:** + + `PROJECT_NAME=[string]` + +- **Data Params** + + None + +- **Success Response:** + + - **Code:** 200
+ **Content:** `{ + "ipAddress": "", + "port": "" +}` + +- **Error Response:** + +When you don't have any proxy registered for your project into EcoSonar + +- **Code:** 400 BAD REQUEST
+ **Content:** `{ + "error": "Your project does not have proxy configuration saved into database." +}` + +OR + +EcoSonar API is not able to request to the MongoDB Database : + +- **Code:** 500 Internal Server Error
+ +## **EcoSonar Proxy Configuration - DELETE PROXY FOR PROJECT** + +![DELETE PROXY FOR PROJECT](./images/delete-proxy-for-project.webp) + +- **URL** + + `/api/proxy?projectName=` + +- **Method:** + + `DELETE` + +- **URL Params** + + PROJECT_NAME should match to the Project Key defined in your Sonarqube Project. + + **Required:** + + `PROJECT_NAME=[string]` + +- **Data Params** + + None + +- **Success Response:** + + - **Code:** 200
+ +EcoSonar API is not able to request to the MongoDB Database : + +- **Code:** 500 Internal Server Error
+ +## **EcoSonar USER FLOW Configuration - SAVE USER FLOW for URL** + +![SAVE USER FLOW for URL](./images/save-user-flow-for-url.webp) + +- **URL** + + `/api/user-flow/insert` + +- **Method:** + + `POST` + +- **URL Params** + +None + +- **Data Params** + +`{ + "url": "", + "userFlow": { + "steps": [ + ] + } +}` + +- **Success Response:** + + - **Code:** 200
+ **Content:** `{ + "steps": [ + ] +}` + +- **Error Response:** + +You want to add user flow to unexisting url : + +- **Code:** 400 BAD REQUEST
+ **Content:** `{ + "error": "Url not found" +}` + +OR + +EcoSonar API is not able to request to the MongoDB Database : + +- **Code:** 500 Internal Server Error
+ +## **EcoSonar USER FLOW Configuration - GET USER FLOW for URL** + +![GET USER FLOW for URL](./images/get-user-flow-for-url.webp) + +- **URL** + + `/api/user-flow/find` + +- **Method:** + + `GET` + +- **URL Params** + +None + +- **Data Params** + + PROJECT_NAME should match to the Project Key defined in your Sonarqube Project. + +`{ + "url": "", + "projectName: "PROJECT_NAME" +}` + +- **Success Response:** + + - **Code:** 200
+ **Content:** `{ + "steps": [ + ] +}` + +- **Error Response:** + +When you don't have any user flow registered for the url into EcoSonar + +- **Code:** 400 BAD REQUEST
+ **Content:** `{ + "error": "Your project does not have user flow saved into database." +}` + +OR + +EcoSonar API is not able to request to the MongoDB Database : + +- **Code:** 500 Internal Server Error
+ +## **EcoSonar USER FLOW Configuration - DELETE USER FLOW FOR URL** + +![DELETE USER FLOW FOR URL](./images/delete-user-flow-for-url.webp) + +- **URL** + + `/api/user-flow` + +- **Method:** + + `DELETE` + +- **URL Params** + +None + +- **Data Params** + +`{ + "url": "" +}` + +- **Success Response:** + + - **Code:** 200
+ +EcoSonar API is not able to request to the MongoDB Database : + +- **Code:** 500 Internal Server Error
+ +## **EcoSonar LAUNCH ANALYSIS** -**EcoSonar LAUNCH ANALYSIS** ----- ![LAUNCH ANALYSIS](./images/launch-analysis.webp) EcoSonar analysis is launched through this API call either directly with a curl command or Postman request or through a Sonarqube Analysis. API call is done asynchronously to avoid performance issue ( ~ 3 seconds to analyse one page) -* **URL** +- **URL** `/api/greenit/insert` -* **Method:** +- **Method:** `POST` - -* **URL Params** - None +- **URL Params** -* **Data Params** + None + +- **Data Params** PROJECT_NAME should match to the Project Key defined in your Sonarqube Project. `{ - "projectName" : "PROJECT_NAME" - }` + "projectName" : "PROJECT_NAME" +}` -* **Success Response:** +- **Success Response:** - * **Code:** 202
+ - **Code:** 202
+ +## **EcoSonar ANALYSIS - RETRIEVE ANALYSIS PER PROJECT** -**EcoSonar ANALYSIS - RETRIEVE ANALYSIS PER PROJECT** ----- ![RETRIEVE ANALYSIS PER PROJECT](./images/retrieve-analysis-per-project.webp) -* **URL** +- **URL** `/api/project?projectName=` -* **Method:** +- **Method:** `GET` - -* **URL Params** - PROJECT_NAME should match to the Project Key defined in your Sonarqube Project. +- **URL Params** - **Required:** - - `PROJECT_NAME=[string]` + PROJECT_NAME should match to the Project Key defined in your Sonarqube Project. -* **Data Params** + **Required:** - None + `PROJECT_NAME=[string]` -* **Success Response:** +- **Data Params** - * **Code:** 200
+ None + +- **Success Response:** + + - **Code:** 200
**Content:** `{ "allowW3c": "true", "deployments": { @@ -351,57 +789,57 @@ EcoSonar analysis is launched through this API call either directly with a curl } } }` - -* **Error Response:** -When no analysis has been done yet on your project +- **Error Response:** - * **Code:** 400 BAD REQUEST
- **Content:** `{ +When no analysis has been done yet on your project + +- **Code:** 400 BAD REQUEST
+ **Content:** `{ "error": "No analysis found for PROJECT_NAME" }` - OR +OR When an error occured when generating the report - * **Code:** 400 BAD REQUEST
- **Content:** `{ +- **Code:** 400 BAD REQUEST
+ **Content:** `{ "error": "Error during generation of PROJECT_NAME analysis" }` EcoSonar API is not able to request to the MongoDB Database : - * **Code:** 500 Internal Server Error
+- **Code:** 500 Internal Server Error
+ +## **EcoSonar ANALYSIS - RETRIEVE ANALYSIS PER URL** -**EcoSonar ANALYSIS - RETRIEVE ANALYSIS PER URL** ----- ![RETRIEVE ANALYSIS PER URL](./images/retrieve-analysis-per-url.webp) -* **URL** +- **URL** `/api/greenit/url` -* **Method:** +- **Method:** `POST` - -* **URL Params** - None +- **URL Params** -* **Data Params** + None + +- **Data Params** PROJECT_NAME should match to the Project Key defined in your Sonarqube Project. `{ - "projectName" : "PROJECT_NAME", - "urlName": "url_to_retrieve" - }` + "projectName" : "PROJECT_NAME", + "urlName": "url_to_retrieve" +}` -* **Success Response:** +- **Success Response:** - * **Code:** 200
+ - **Code:** 200
**Content:** `{ "deployments": { "greenit": [ @@ -503,160 +941,158 @@ EcoSonar API is not able to request to the MongoDB Database : } } }` - -* **Error Response:** -When no analysis has been done yet on your url +- **Error Response:** - * **Code:** 400 BAD REQUEST
- **Content:** `{ +When no analysis has been done yet on your url + +- **Code:** 400 BAD REQUEST
+ **Content:** `{ "error": "No lighthouse and greenit analysis found for url url_to_retrieve in project PROJECT_NAME" }` - OR +OR EcoSonar API is not able to request to the MongoDB Database : - * **Code:** 500 Internal Server Error
+- **Code:** 500 Internal Server Error
+ +## **EcoSonar ANALYSIS - GET PROJECT SCORES** -**EcoSonar ANALYSIS - GET PROJECT SCORES** ----- ![GET PROJECT SCORES](./images/get-project-scores.webp) Retrieve current scores from EcoIndex, Lighthouse Performance and Accessibility and W3C Validator for the project -* **URL** +- **URL** `/api/ecosonar/scores?projectName=` -* **Method:** +- **Method:** `GET` - -* **URL Params** - PROJECT_NAME should match to the Project Key defined in your Sonarqube Project. +- **URL Params** - **Required:** - - `PROJECT_NAME=[string]` + PROJECT_NAME should match to the Project Key defined in your Sonarqube Project. + + **Required:** -* **Data Params** + `PROJECT_NAME=[string]` - None +- **Data Params** + + None -* **Success Response:** +- **Success Response:** - * **Code:** 200
+ - **Code:** 200
**Content:** ` - { - "ecoIndex": 0, - "perfScore": 0, - "accessibilityScore": 0, - "w3cScore": 0 - }` +{ + "ecoIndex": 0, + "perfScore": 0, + "accessibilityScore": 0, + "w3cScore": 0 +}` -* **Error Response:** +- **Error Response:** When no analysis found for the project - * **Code:** 400 BAD REQUEST
- **Content:** `{ +- **Code:** 400 BAD REQUEST
+ **Content:** `{ "error": "No Analysis found for project PROJECT_NAME" }` - OR +OR EcoSonar API is not able to request to the MongoDB Database : - * **Code:** 500 Internal Server Error
+- **Code:** 500 Internal Server Error
+ +## **EcoSonar ANALYSIS - GET AVERAGE OF ALL SCORES FOR PROJECTS REGISTERED IN ECOSONAR AT A DEFINED DATE** -**EcoSonar ANALYSIS - GET AVERAGE OF ALL SCORES FOR PROJECTS REGISTERED IN ECOSONAR AT A DEFINED DATE** ----- ![GET AVERAGE OF ALL SCORES FOR PROJECTS REGISTERED IN ECOSONAR AT A DEFINED DATE](./images/get-average-all-scores-projects.webp) Retrieve all EcoSonar projects average for all scores (EcoIndex, Google Lighthouse and W3C Validator). You can retrieve the scores at a date defined or for last analysis made if no date defined -* **URL** +- **URL** `/api/ecosonar/info` or `/api/ecosonar/info?date=` -* **Method:** +- **Method:** `GET` - -* **URL Params** - DATE is optional : if no date defined, will look at latest analysis otherwise search for the latest analysis made before that date. +- **URL Params** + + DATE is optional : if no date defined, will look at latest analysis otherwise search for the latest analysis made before that date. - **Optional:** - - `DATE=[string]` with format YYYY-MM-DD + **Optional:** -* **Data Params** + `DATE=[string]` with format YYYY-MM-DD - None +- **Data Params** -* **Success Response:** + None + +- **Success Response:** - * **Code:** 200
+ - **Code:** 200
**Content:** ` - { - "nbProjects": 0, - "ecoIndex": 0, - "perfScore": 0, - "accessibilityScore": 0, - "w3cScore": 0 - }` +{ + "nbProjects": 0, + "ecoIndex": 0, + "perfScore": 0, + "accessibilityScore": 0, + "w3cScore": 0 +}` -* **Error Response:** +- **Error Response:** If date format is wrong - * **Code:** 400 BAD REQUEST
- **Content:** `{ +- **Code:** 400 BAD REQUEST
+ **Content:** `{ "error": 'Bad date format: YYYY-MM-DD' }` - OR +OR EcoSonar API is not able to request to the MongoDB Database or other internal error: - * **Code:** 500 Internal Server Error
+- **Code:** 500 Internal Server Error
+ +## **EcoSonar ANALYSIS - GET ALL PROJECTS SCORES FROM DATE DEFINED** -**EcoSonar ANALYSIS - GET ALL PROJECTS SCORES FROM DATE DEFINED** ----- ![GET ALL PROJECTS SCORES FROM DATE DEFINED](./images/get-all-scores-projects.webp) Retrieve all EcoSonar projects and return the scores for each of them at the date defined, if date not filled it would be the latest analysis. -* **URL** +- **URL** `/api/project/all` or `/api/ecosonar/info?date=` or `/api/ecosonar/info?filterName=` - or + or `/api/ecosonar/info?date=&filterName=` - -* **Method:** +- **Method:** `POST` - -* **URL Params** - DATE is optional : if no date defined, will look at latest analysis otherwise search for the latest analysis made before that date. - FILTER-NAME is optional : retrieve projects whose name contains the string 'filterName' (case insensitive) if filled +- **URL Params** + + DATE is optional : if no date defined, will look at latest analysis otherwise search for the latest analysis made before that date. + FILTER-NAME is optional : retrieve projects whose name contains the string 'filterName' (case insensitive) if filled + **Optional:** - **Optional:** - - `DATE=[string]` with format YYYY-MM-DD - `FILTER-NAME=[string]` + `DATE=[string]` with format YYYY-MM-DD + `FILTER-NAME=[string]` -* **Data Params** +- **Data Params** CATEGORY in "filterScore" can take the following enum : ecoIndex, perfScore, accessScore, w3cScore. "score" is a value from 0 to 100, it will be the threshold for the CATEGORY. @@ -665,97 +1101,98 @@ Retrieve all EcoSonar projects and return the scores for each of them at the dat "order" can take the value "asc" or "desc" if you want to sort your projects according to the type. `{ - "filterScore" : { - "cat": "CATEGORY", - "score": 0, - "select": "upper" - }, - "sortBy": { - "type": "CATEGORY", - "order": "asc" - } - }` + "filterScore" : { + "cat": "CATEGORY", + "score": 0, + "select": "upper" + }, + "sortBy": { + "type": "CATEGORY", + "order": "asc" + } +}` -* **Success Response:** +- **Success Response:** - * **Code:** 200
- **Content:** + - **Code:** 200
+ **Content:** `{ - "nbProjects": 0, - "projects": { - "PROJECT": { - "ecoIndex": 0, - "perfScore": 0, - "accessScore": 0, - "w3cScore": 0, - "nbUrl": 0 - },` - -* **Error Response:** + "nbProjects": 0, + "projects": { + "PROJECT": { + "ecoIndex": 0, + "perfScore": 0, + "accessScore": 0, + "w3cScore": 0, + "nbUrl": 0 +},` + +- **Error Response:** If date format is wrong - * **Code:** 400 BAD REQUEST
- **Content:** `{ +- **Code:** 400 BAD REQUEST
+ **Content:** `{ "error": 'Bad date format: YYYY-MM-DD' }` - OR +OR EcoSonar API is not able to request to the MongoDB Database or other internal error: - * **Code:** 500 Internal Server Error
+- **Code:** 500 Internal Server Error
+ +## **EcoSonar ANALYSIS - RETRIEVE ECOSONAR AUDIT IN EXCEL FORMAT FOR PROJECT** -**EcoSonar ANALYSIS - RETRIEVE ECOSONAR AUDIT IN EXCEL FORMAT FOR PROJECT** ----- Retrieve audits from GreenIt-Analysis, Google Lighthouse and W3C Validator aggregated per project in an Excel format. -* **URL** +- **URL** `/api/export` -* **Method:** +- **Method:** `POST` - -* **URL Params** - None +- **URL Params** + + None -* **Data Params** +- **Data Params** PROJECT_NAME should match to the Project Key defined in your Sonarqube Project. `{ - "projectName" : "PROJECT_NAME" - }` + "projectName" : "PROJECT_NAME" +}` -* **Success Response:** +- **Success Response:** - * **Code:** 200
+ - **Code:** 200
**Content:** Excel file with the exported audit for the project -* **Error Response:** +- **Error Response:** When an error occured during file generation - * **Code:** 400 BAD REQUEST
- **Content:** `{ +- **Code:** 400 BAD REQUEST
+ **Content:** `{ "error": "Export Audit is not possible because urls were not inserted into project or analysis for project could not be retrieved" }` - OR +OR EcoSonar API is not able to request to the MongoDB Database : - * **Code:** 500 Internal Server Error
+- **Code:** 500 Internal Server Error
+ +## **EcoSonar ANALYSIS - SAVE PROCEDURE FOR THE PROJECT** -**EcoSonar ANALYSIS - SAVE PROCEDURE FOR THE PROJECT** ----- ![SAVE PROCEDURE FOR THE PROJECT](./images/save-procedure-for-the-project.webp) Procedure in Ecosonar are the configuration chosen by delivery teams to sort the EcoSonar recommandations related to ecodesign. You have 3 different configurations available in EcoSonar: + - `scoreImpact` : best practices will be sorted by descending order of implementation (best practices not implemented returned first) - `quickWins` : best practices will be sorted by ascending order of difficulty (best practices easy to implement returned first) - `highestImpact` : best practices will be sorted by order of impact to improve EcoSonar scores (best practices most efficient returned first) @@ -764,124 +1201,124 @@ You have 3 different configurations available in EcoSonar: `/api/procedure` -* **Method:** +- **Method:** `POST` - -* **URL Params** - None +- **URL Params** -* **Data Params** + None + +- **Data Params** PROJECT_NAME should match to the Project Key defined in your Sonarqube Project. selected_procedure can take 3 values : `scoreImpact`, `quickWins`, `highestImpact` `{ - "projectName" : "PROJECT_NAME", - "selectedProcedure": "selected_procedure" - }` + "projectName" : "PROJECT_NAME", + "selectedProcedure": "selected_procedure" +}` -* **Success Response:** +- **Success Response:** - * **Code:** 200
+ - **Code:** 200
**Content:** `{ - "procedure": "quickWins" - }` - -* **Error Response:** + "procedure": "quickWins" +}` + +- **Error Response:** When no procedure have been registered for your project - * **Code:** 400 BAD REQUEST
- **Content:** `{ +- **Code:** 400 BAD REQUEST
+ **Content:** `{ "error": "Procedure is not defined in project PROJECT_NAME" }` - OR +OR EcoSonar API is not able to request to the MongoDB Database : - * **Code:** 500 Internal Server Error
+- **Code:** 500 Internal Server Error
+ +## **EcoSonar ANALYSIS - RETRIEVE PROCEDURE SAVED FOR THE PROJECT** -**EcoSonar ANALYSIS - RETRIEVE PROCEDURE SAVED FOR THE PROJECT** ----- ![RETRIEVE PROCEDURE SAVED FOR THE PROJECT](./images/retrieve-procedure-saved-for-the-project.webp) Procedure in Ecosonar are the configuration chosen by delivery teams to sort the EcoSonar recommandations related to ecodesign. This request will return you the procedure chosen for this project. -* **URL** +- **URL** `/api/procedure?projectName=` -* **Method:** +- **Method:** `GET` - -* **URL Params** - PROJECT_NAME should match to the Project Key defined in your Sonarqube Project. +- **URL Params** + + PROJECT_NAME should match to the Project Key defined in your Sonarqube Project. + + **Required:** - **Required:** - - `PROJECT_NAME=[string]` + `PROJECT_NAME=[string]` -* **Data Params** +- **Data Params** - None + None -* **Success Response:** +- **Success Response:** - * **Code:** 200
+ - **Code:** 200
**Content:** `{ - "procedure": "quickWins" - }` - -* **Error Response:** + "procedure": "quickWins" +}` + +- **Error Response:** When no procedure have been registered for your project - * **Code:** 400 BAD REQUEST
- **Content:** `{ +- **Code:** 400 BAD REQUEST
+ **Content:** `{ "error": "Procedure is not defined in project PROJECT_NAME" }` - OR +OR EcoSonar API is not able to request to the MongoDB Database : - * **Code:** 500 Internal Server Error
+- **Code:** 500 Internal Server Error
+ +## **EcoSonar ANALYSIS - RETRIEVE BEST PRACTICES PER PROJECT** -**EcoSonar ANALYSIS - RETRIEVE BEST PRACTICES PER PROJECT** ----- ![RETRIEVE BEST PRACTICES PER PROJECT](./images/retrieve-best-practices-per-project.webp) Retrieve audits from GreenIt-Analysis and Google Lighthouse aggregated per project. -* **URL** +- **URL** `/api/bestPractices/project?projectName=` -* **Method:** +- **Method:** `GET` - -* **URL Params** - PROJECT_NAME should match to the Project Key defined in your Sonarqube Project. +- **URL Params** + + PROJECT_NAME should match to the Project Key defined in your Sonarqube Project. + + **Required:** - **Required:** - - `PROJECT_NAME=[string]` + `PROJECT_NAME=[string]` -* **Data Params** +- **Data Params** - None + None -* **Success Response:** +- **Success Response:** - * **Code:** 200
+ - **Code:** 200
**Content:** `{ "ecodesign": { "printStyleSheet": { @@ -925,52 +1362,52 @@ Retrieve audits from GreenIt-Analysis and Google Lighthouse aggregated per proje } } }` - -* **Error Response:** -When no analysis has been done yet on your project +- **Error Response:** - * **Code:** 400 BAD REQUEST
- **Content:** `{ +When no analysis has been done yet on your project + +- **Code:** 400 BAD REQUEST
+ **Content:** `{ "error": "No analysis found for PROJECT_NAME" }` - OR +OR EcoSonar API is not able to request to the MongoDB Database : - * **Code:** 500 Internal Server Error
+- **Code:** 500 Internal Server Error
+ +## **EcoSonar ANALYSIS - RETRIEVE BEST PRACTICES PER URL** -**EcoSonar ANALYSIS - RETRIEVE BEST PRACTICES PER URL** ----- ![RETRIEVE BEST PRACTICES PER URL](./images/retrieve-best-practices-per-url.webp) Retrieve audits from GreenIt-Analysis and Google Lighthouse per url audited. -* **URL** +- **URL** `/api/bestPractices/url` -* **Method:** +- **Method:** `POST` - -* **URL Params** - None +- **URL Params** + + None -* **Data Params** +- **Data Params** PROJECT_NAME should match to the Project Key defined in your Sonarqube Project. `{ - "projectName" : "PROJECT_NAME", - "urlName": "url_to_retrieve" - }` + "projectName" : "PROJECT_NAME", + "urlName": "url_to_retrieve" +}` -* **Success Response:** +- **Success Response:** - * **Code:** 200
+ - **Code:** 200
**Content:** `{ "ecodesign": { "printStyleSheet": { @@ -1014,363 +1451,82 @@ Retrieve audits from GreenIt-Analysis and Google Lighthouse per url audited. } } }` - -* **Error Response:** -When no analysis has been done yet on your project +- **Error Response:** - * **Code:** 400 BAD REQUEST
- **Content:** `{ +When no analysis has been done yet on your project + +- **Code:** 400 BAD REQUEST
+ **Content:** `{ "error": "No analysis found for url url_to_retrieve into project PROJECT_NAME" }` - OR +OR EcoSonar API is not able to request to the MongoDB Database : - * **Code:** 500 Internal Server Error
- -**EcoSonar Login Configuration - SAVE LOGIN AND PROXY FOR PROJECT** ----- -![SAVE LOGIN AND PROXY FOR PROJECT](./images/save-login-and-proxy-for-project.webp) - -* **URL** - - `/api/login/insert?projectName=` - -* **Method:** - - `POST` - -* **URL Params** - - PROJECT_NAME should match to the Project Key defined in your Sonarqube Project. - - **Required:** - - `PROJECT_NAME=[string]` - -* **Data Params** - `{ - "login": { - "authentication_url": "", - "steps": [] - }, - "proxy": { - "ipAddress": "", - "port": "" - } -}` - -* **Success Response:** - - * **Code:** 201
- -* **Error Response:** - -EcoSonar API is not able to save into the MongoDB Database : +- **Code:** 500 Internal Server Error
- * **Code:** 500 Internal Server Error
+## **EcoSonar Infos - GET VERSION** -**EcoSonar Login Configuration - GET LOGIN FOR PROJECT** ----- -![GET LOGIN FOR PROJECT](./images/get-login-for-project.webp) +![GET VERSION](./images/get-version.webp) -* **URL** +- **URL** - `/api/login/find?projectName=` + `/api/version` -* **Method:** +- **Method:** `GET` - -* **URL Params** - PROJECT_NAME should match to the Project Key defined in your Sonarqube Project. - - **Required:** - - `PROJECT_NAME=[string]` - -* **Data Params** +- **URL Params** None -* **Success Response:** - - * **Code:** 200
- **Content:** `{ - "authentication_url": "", - "steps": [] -}` - -* **Error Response:** - -When you don't have any login registered for your project into EcoSonar - - * **Code:** 400 BAD REQUEST
- **Content:** `{ - "error": "Your project does not have login saved into database." -}` - - OR - -EcoSonar API is not able to request to the MongoDB Database : - - * **Code:** 500 Internal Server Error
- -**EcoSonar Login Configuration - GET PROXY FOR PROJECT** ----- -![GET PROXY FOR PROJECT](./images/get-proxy-for-project.webp) - -* **URL** - - `/api/proxy/find?projectName=` - -* **Method:** - - `GET` - -* **URL Params** - - PROJECT_NAME should match to the Project Key defined in your Sonarqube Project. - - **Required:** - - `PROJECT_NAME=[string]` - -* **Data Params** +- **Data Params** None -* **Success Response:** - - * **Code:** 200
- **Content:** `{ - "ipAddress": "", - "port": "" -}` - -* **Error Response:** - -When you don't have any proxy registered for your project into EcoSonar +- **Success Response:** - * **Code:** 400 BAD REQUEST
+ - **Code:** 200
**Content:** `{ - "error": "Your project does not have proxy configuration saved into database." + "version": "X.X" }` - OR - -EcoSonar API is not able to request to the MongoDB Database : - - * **Code:** 500 Internal Server Error
+- **Error Response:** -**EcoSonar Login Configuration - DELETE LOGIN FOR PROJECT** ----- -![DELETE LOGIN FOR PROJECT](./images/delete-login-for-project.webp) +- **Code:** 400 BAD REQUEST
-* **URL** +## **EcoSonar Infos - GET BEST PRACTICES DOCUMENTATION** - `/api/login?projectName=` +![GET BEST PRACTICES DOCUMENTATION](./images/get-best-practices-documentation.webp) -* **Method:** +- **URL** - `DELETE` - -* **URL Params** + `/api/best-practices-rules` - PROJECT_NAME should match to the Project Key defined in your Sonarqube Project. +- **Method:** - **Required:** - - `PROJECT_NAME=[string]` + `GET` -* **Data Params** +- **URL Params** None -* **Success Response:** - - * **Code:** 200
- -* **Error Response:** - -When you don't have any login registered for your project into EcoSonar and you want still to delete it - - * **Code:** 400 BAD REQUEST
- **Content:** `{ - "error": "Project not found" -}` - - OR - -EcoSonar API is not able to request to the MongoDB Database : - - * **Code:** 500 Internal Server Error
- - -**EcoSonar Login Configuration - DELETE PROXY FOR PROJECT** ----- -![DELETE PROXY FOR PROJECT](./images/delete-proxy-for-project.webp) - -* **URL** - - `/api/proxy?projectName=` - -* **Method:** - - `DELETE` - -* **URL Params** - - PROJECT_NAME should match to the Project Key defined in your Sonarqube Project. - - **Required:** - - `PROJECT_NAME=[string]` - -* **Data Params** +- **Data Params** None -* **Success Response:** - - * **Code:** 200
- -EcoSonar API is not able to request to the MongoDB Database : - - * **Code:** 500 Internal Server Error
- -**EcoSonar USER FLOW Configuration - GET USER FLOW for URL** ----- -![GET USER FLOW for URL](./images/get-user-flow-for-url.webp) - -* **URL** - - `/api/user-flow/find` - -* **Method:** - - `GET` - -* **URL Params** - -None - -* **Data Params** - - PROJECT_NAME should match to the Project Key defined in your Sonarqube Project. - -` -{ - "url": "", - "projectName: "PROJECT_NAME" -} -` - -* **Success Response:** - - * **Code:** 200
- **Content:** `{ - "steps": [ - ] -}` - -* **Error Response:** - -When you don't have any user flow registered for the url into EcoSonar - - * **Code:** 400 BAD REQUEST
- **Content:** `{ - "error": "Your project does not have user flow saved into database." -}` - - OR - -EcoSonar API is not able to request to the MongoDB Database : - - * **Code:** 500 Internal Server Error
- -**EcoSonar USER FLOW Configuration - SAVE USER FLOW for URL** ----- -![SAVE USER FLOW for URL](./images/save-user-flow-for-url.webp) - -* **URL** - - `/api/user-flow/insert` - -* **Method:** - - `POST` - -* **URL Params** - -None - -* **Data Params** - -` -{ - "url": "", - "userFlow": { - "steps": [ - ] - } -} -` - -* **Success Response:** - - * **Code:** 200
- **Content:** `{ - "steps": [ - ] -}` - -* **Error Response:** - -You want to add user flow to unexisting url : +- **Success Response:** - * **Code:** 400 BAD REQUEST
+ - **Code:** 200
**Content:** `{ - "error": "Url not found" + "greenitDocs": {}, + "lighthousePerformanceDocs": {}, + "lighthouseAccessbilityDocs": {} }` - OR - -EcoSonar API is not able to request to the MongoDB Database : - - * **Code:** 500 Internal Server Error
- -**EcoSonar USER FLOW Configuration - DELETE USER FLOW FOR URL** ----- -![DELETE USER FLOW FOR URL](./images/delete-user-flow-for-url.webp) - -* **URL** - - `/api/user-flow` - -* **Method:** - - `DELETE` - -* **URL Params** - -None - -* **Data Params** - -` -{ - "url": "" -} -` - -* **Success Response:** - - * **Code:** 200
- -EcoSonar API is not able to request to the MongoDB Database : +- **Error Response:** - * **Code:** 500 Internal Server Error
\ No newline at end of file +- **Code:** 400 BAD REQUEST
\ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md index 9a63def..262090b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,12 +4,33 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). +## Version 3.4 , 11/01/2024 + +### Added + +- Delete a project in EcoSonar +- Retrieve EcoSonar version with a new endpoint +- Retrieve best practices documentation with a new endpoint + +### Removed + +### Changed + +- Change the way to handle the crawler. The crawler request is now asynchronous and you will have two saving options. Either, you can save in a temporary table or you can save directly in the URL configuration table as to be audited by EcoSonar. +- Seperate save login and save proxy as two independent endpoints +- Made easier to launch locally EcoSonar by adding the MongoDB database setup in the Docker Compose file +- Fix bug : insert login without having a procedure +- Fix security vulnerability : upgrade SonarQube dependency to version 9.4 in EcoSonar SonarQube plugin + +--- + ## Version 3.3 , 07/11/2023 ### Added -- Integrate new EcoCode features including : - - additional rules for Python and PHP - - new languages covered : Javascript, Typescript, Android and iOS + +- Integrate new EcoCode features including : + - additional rules for Python and PHP + - new languages covered : Javascript, Typescript, Android and iOS - Implement Swagger User Interface for a more friendly user interface of the API - Automatically push a new Docker Image as a Github package for each new commit in the 'main' branch of the Github repository - Add new API Endpoints to retrieve projects scores average at a selected date with filter and sorting configuration @@ -17,6 +38,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). ### Removed ### Changed + - Fix some security vulnerabilities --- @@ -24,6 +46,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). ## Version 3.2 , 10/08/2023 ### Added + - Include Ecocode documentation into EcoSonar website - Update best practices documentation - Add MongoDB Community Server connection as a potential database for EcoSonar @@ -31,6 +54,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). ### Removed ### Changed + - BUG FIX: user journey flow not working when some CSS selectors are hidden in the page --- @@ -38,52 +62,57 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). ## Version 3.1 , 27/03/2023 ### Added + - Integrate EcoCode functionalities : https://www.ecocode.io/. -EcoCode is a SonarQube plugin developed by a French Open-Source Community `Green Code Initiative` (https://github.com/green-code-initiative) that will add new code smells related to Ecodesign when realizing a SonarQbe audit. Languages covered now are Java, PHP and Python. + EcoCode is a SonarQube plugin developed by a French Open-Source Community `Green Code Initiative` (https://github.com/green-code-initiative) that will add new code smells related to Ecodesign when realizing a SonarQbe audit. Languages covered now are Java, PHP and Python. - EcoSonar audit can now be exported into an Excel File to be able to share with external people the current status of the website - Ability to retrieve EcoSonar current Scores: EcoIndex, Lighthouse Performance & Accessibility and W3C Validator - - Request can be called in a CI/CD Pipeline to prevent production deployment if one of the scores is below a threshold + - Request can be called in a CI/CD Pipeline to prevent production deployment if one of the scores is below a threshold - Ability to sort EcoSonar Recommandation for EcoDesign Part following 3 different configurations: - - `scoreImpact` : best practices will be sorted by descending order of implementation (best practices not implemented returned first) - - `quickWins` : best practices will be sorted by ascending order of difficulty (best practices easy to implement returned first) - - `highestImpact` : best practices will be sorted by order of impact to improve EcoSonar scores (best practices most efficient returned first) + - `scoreImpact` : best practices will be sorted by descending order of implementation (best practices not implemented returned first) + - `quickWins` : best practices will be sorted by ascending order of difficulty (best practices easy to implement returned first) + - `highestImpact` : best practices will be sorted by order of impact to improve EcoSonar scores (best practices most efficient returned first) Goal of this feature is to help delivery teams tackle recommendations according to their priorities. ### Removed ### Changed + - BUG FIX: When an analysis from one of our tool failed, best practices were saved with default value (0) that could lead to reduce the effective score from the website for that best practice. - BUG FIX : App should not crashed if an invalid url has been inserted into the user flow configuration in the `navigate` step - BUG FIX : Getting User flow should be made with parameters : url and projectName if either the same url has been saved severed times into several EcoSonar projects. - Update EcoSonar dependencies - Improve EcoSonar Ecodesign and Accessibily Rate - --- + --- ## Version 3.0 , 09/12/2022 ### Added + - W3C Validator Audit available for public pages: - - Retrieve all errors to improve ecodesign and accessibility levels of web application - - Scoring methodology: if an error has been resolved, it will increase your w3c score + - Retrieve all errors to improve ecodesign and accessibility levels of web application + - Scoring methodology: if an error has been resolved, it will increase your w3c score - Environment Configuration For Sonarqube Plugin to ease deployments - API Configuration of Login Credentials, dedicated Credentials per project and possibility to save them into database (if security allows it) - API Configuration of Proxy Configuration per project - API Configuration of User Flow Configuration, saved into the database (instead of yaml files) - ### Removed ### Changed + - Best Practices is divided into 2 seperated sections : Ecodesign and accessibility (previously it was by audit tool) - BUG FIX: set a default browser viewport in case of unresponsive website to have the right user flow - BUG FIX: inserting the analysis to the wrong url if one url of the batch fails - BUG FIX: possiiblity to create a browser for one url audit if user flow is enabled to allow a better cookie management (however performance of the API will decrease - more time to audit all pages) --- + --- + ## Version 2.3 , 04/10/2022 ### Added @@ -96,9 +125,11 @@ EcoCode is a SonarQube plugin developed by a French Open-Source Community `Green - Retrieve best practices per URL and per project ### Removed + - Removing greenhouse gas emissions and water consumption because calculation may not be accurate to some IT Systems ### Changed + - Upgrade EcoIndex Calculation : https://github.com/cnumr/GreenIT-Analysis/issues/61 - Upgrading EcoSonar URL Configuration and Best practices pages to resolve some accessibility issues - Resolve bug fix on "Optimize Bitmap Images" @@ -106,7 +137,9 @@ EcoCode is a SonarQube plugin developed by a French Open-Source Community `Green - Resolve bug fix on "Image Downloaded and not displayed" --- + --- + ## Version 2.2 , 03/08/2022 ### Added @@ -115,11 +148,12 @@ EcoCode is a SonarQube plugin developed by a French Open-Source Community `Green ### Removed - ### Changed --- + --- + ## Version 2.1 , 26/07/2022 ### Added @@ -128,11 +162,12 @@ EcoCode is a SonarQube plugin developed by a French Open-Source Community `Green ### Removed - ### Changed + - we have updated the way to register Lighthouse analysis : /!\ new version is not compatible with previous one, you should delete all your analysis before adding this new version. --- + ## Version 2.0 , 13/07/2022 ### Added @@ -146,16 +181,16 @@ EcoCode is a SonarQube plugin developed by a French Open-Source Community `Green - Fixing some bugs - Keep an history of every GreenIt and Lighthouse audits made - ### Removed - ### Changed -- /!\ V2 Data Model is no longer compatible with V1 version, sorry about that ... -You will need to remove analysis saved under bestPractices collection in order to have a working API. + +- /!\ V2 Data Model is no longer compatible with V1 version, sorry about that ... + You will need to remove analysis saved under bestPractices collection in order to have a working API. - A New Sonarqube Plugin Version has been set (2.0.0), please make sure to delete previous one (1.0.0) before launching your Sonarqube instance --- + ## Version 1.0 , 12/04/2022 ### Added @@ -168,8 +203,6 @@ You will need to remove analysis saved under bestPractices collection in order t ### Removed - ### Changed - --- diff --git a/EcoSonar-API/README.md b/EcoSonar-API/README.md index e652e1b..abf217a 100644 --- a/EcoSonar-API/README.md +++ b/EcoSonar-API/README.md @@ -1,25 +1,21 @@ # EcoSonar API EcoSonar API is an audit aggregator that will use the following open-source audit tools: + - GreenIT-Analysis CLI (https://github.com/cnumr/GreenIT-Analysis-cli) -- Google Lighthouse with a npm package (https://github.com/GoogleChrome/lighthouse/blob/HEAD/docs/readme.md#using-programmatically) +- Google Lighthouse with a npm package (https://github.com/GoogleChrome/lighthouse/blob/HEAD/docs/readme.md#using-programmatically) - W3C Validator with a npm package (https://www.npmjs.com/package/html-validator). This Audit is using right now an external API to audit websites thus can only audit public pages. By default, W3C Validator is disabled for those reasons. However, if you agree to use this external API, please check this section [Enable W3C validator Analysis](#w3c-validator) -Once the EcoSonar audit is triggered, it will launch the three analysis and store them into a MongoDB Database. -Then, the API can allow you to retrieve pre-formatted audit results using json format. A custom Sonarque Plugin has been created to display the audit directly within the Sonarqube instance. The API can also be used with any other interface that can handle json formats. - -API Documentation : https://github.com/Accenture/EcoSonar/blob/main/API.md - -Swagger User Interface available at the link : `[ECOSONAR-API-URL]/swagger/` - -Locally, available at this address : `http://localhost:3002/swagger/` +Once the EcoSonar audit is triggered, it will launch the three analysis and store them into a MongoDB Database. +Then, the API can allow you to retrieve pre-formatted audit results using json format. A custom SonarQube Plugin has been created to display the audit directly within the Sonarqube instance. The API can also be used with any other interface that can handle json formats. # Summary + - [To start with](#to-start-with) - [MongoDB Database](#mongodb-database) - [Installation](#installation) - [Create a MongoDB Database](#mongodb-creation) - - [Create a MongoDB Community Server](#mongodb-server) + - [Create a MongoDB Community Server](#mongodb-server) - [Create a MongoDB Atlas Database](#mongodb-atlas) - [Create MongoDB Collections](#mongodb-collections) - [Node.js](#nodejs) @@ -29,56 +25,44 @@ Locally, available at this address : `http://localhost:3002/swagger/` - [Prerequisites](#prerequisites-docker) - [Installation](#installation-api) - [Our advice for Server Deployment](#docker-deployment) - - [Add Environment setup](#mongo-setup) + - [Add Environment setup](#env-setup) - [Database configuration](#database-env-var) - [CORS Setup](#cors) - [Enable W3C validator Analysis](#w3c-validator) - [Setup User flow](#user-flow) - [API Endpoints](#api-endpoints) -- [Authentication Configuration](#auth) - - [When you have a simple login flow](#simple-login) - - [EcoSonar V2.3 and below](#old-version-login) - - [CSS Selectors](#css-slectors) - - [EcoSonar V3.0 and above](#new-version-login) - - [More complicated Login flows](#complicated-login) - - [EcoSonar V2.3 and below](#old-version-login-complicated) - - [EcoSonar V3.0 and above](#new-version-login-complicated) -- [Proxy Configuration](#proxy) - - [EcoSonar V2.3 and below](#old-version-proxy) - - [EcoSonar V3.0 and above](#new-version-proxy) -- [User Flow](#user-flow) - - [User Flow Creation](#creation) - - [First method : using Chrome Recorder](#chrome-recorder) - - [Second method : creating your own User Flow JSON](#custom-user-flow) - - [User Flow Integration](#integration) - - [EcoSonar V2.3 and below](#old-version-user-flow) - - [EcoSonar V3.0 and above](#new-version-user-flow) - - [User Flow Verification](#verification) - [Usage Rights](#usage-rights) + # To start with To use the tool, you must first check the prerequisites and complete the installation steps. For this, two different ways to use it: + - Either through a manual installation of Node.js - Either through Docker In both cases, it will be necessary to set up a new MongoDB database. + ## MongoDB Database + ### Installation If the MongoDB database is already created, you can skip this step and retrieve the relevant information to connect to the database (username, password, cluster, database name). + #### Create a MongoDB Database + You will need to choose the most adequate MongoDB database according to your infrastructure. -By default, we have implemented connection with +By default, we have implemented connection with + - MongoDB Community Server : https://www.mongodb.com/try/download/community - MongoDB Atlas : https://www.mongodb.com/atlas - Azure CosmosDB : https://azure.microsoft.com/en-us/products/cosmos-db/#overview @@ -86,77 +70,94 @@ By default, we have implemented connection with For any other MongoDB Database, you will need to set up a new database connection in the file `EcoSonar-API/configuration/database.js`. + ##### Create a MongoDB Community Server 1. First you need to install MongoDB Server Community and it is recommended also to install MongoDB Compass for visualization purposes. You can select the following default setup: - ![MongoDB Server Installation](../images/mongodb-install.webp) +![MongoDB Server Installation](../images/mongodb-install.webp) 2. Once installation on your laptop is over, you can open MongoDB Compass. You can create a new connection with the default settings: - ![MongoDB Database Creation](../images/mongodb-connstring.webp) +![MongoDB Database Creation](../images/mongodb-connstring.webp) 3. Once you are connected, create a database called ‘EcoSonar’. You might also be required to set at least one collection during database initialization. If so, create collection called ‘bestpractices’. The other collections will be created automatically when you will first launch the API connected to the database. - ![MongoDB Database Creation](../images/mongodb-dbcreate.webp) +![MongoDB Database Creation](../images/mongodb-dbcreate.webp) + ##### Create a MongoDB Atlas Database 1. Open MongoDB Cloud : https://www.mongodb.com/fr-fr/cloud 2. Create an account 3. Click on "build a database" --> choose free one - - In "cloud provider & region" choose the closest region in which EcoSonar API is deployed - - In "cluster" put the name of our database (here "EcoSonar") + - In "cloud provider & region" choose the closest region in which EcoSonar API is deployed + - In "cluster" put the name of our database (here "EcoSonar") 4. Click on "Create cluster" 5. Click on "connect" 6. Authorize access 7. Create a username and a password 8. Create a connection with application - - node.js - - version 4.0 or later - - close + - node.js + - version 4.0 or later + - close + ##### Create MongoDB Collections -EcoSonar database will contain the following MongoDB collections: +EcoSonar database will contain the following MongoDB collections: + - bestpractices - greenits - lighthouses - projects - urlsprojects - w3cs +- tempurlsprojects Collections are created automatically when the project is first launched. However, if you chose Azure CosmoDB for MongoDB Database as database, then you will need to create the following collections with related indexes before starting the project otherwise it will fail. Please find below the different indexes that needs to be added for each collection: + 1. bestpractices : `_id`, `idAnalysisBestPractices`, `dateAnalysisBestPractices` 2. greenits : `_id`, `idGreenAnalysis`, `dateGreenAnalysis` 3. lighthouses : `_id`, `idLighthouseAnalysis`, `dateLighthouseAnalysis` 4. projects : `_id` 5. urlsprojects : `_id`, `idKey` 6. w3cs : `_id`, `idW3cAnalysis`, `dateW3cAnalysis` +7. tempurlsprojects: `_id`, `idKey` -## Node.js + +## Option 1 : launch Node.js server + ### Prerequisites - - Node.js https://nodejs.org/fr/ (at least v16) + +- Node.js https://nodejs.org/fr/ (at least v16) + ### Installation -1. Retrieve source code : + +1. Retrieve source code : + ``` git clone https://github.com/Accenture/EcoSonar ``` + 2. Go into the Folder EcoSonar-API 3. Install npm packages : + ``` npm install ``` + 4. Launch the API + ``` npm start ``` @@ -164,26 +165,34 @@ npm start API can be reached at: http://localhost:3000 -## Docker + +## Option 2 : launch a Docker container + ### Prerequisites - - Docker Desktop for Windows (Note : a licence is now required if you need to use Docker Desktop at an Enterprise Level) - - Docker Installed if you are using Mac or Linux + +- Docker (Note : for Windows, a licence is now required if you need to use Docker Desktop at an Enterprise Level) + ### Installation -1. Retrieve source code : - ``` - git clone https://github.com/Accenture/EcoSonar - ``` +1. Retrieve source code : + +``` +git clone https://github.com/Accenture/EcoSonar +``` + 2. Go into the Folder EcoSonar-API -3. Build Docker image : - ``` - docker build -t imageName . - ``` +3. Build Docker image : + +``` +docker build -t imageName . +``` + 4. Launch a Docker Server : + ``` docker container run -d -p 3000:3000 imageName ``` @@ -191,24 +200,31 @@ docker container run -d -p 3000:3000 imageName API can be reached at: http://localhost:3000 + #### Our advice for Server Deployment + Instead, we recommend setting up a CI/CD pipeline with the following steps: + 1. Build the Docker image 2. Push the Docker image into the Docker Registry 3. Stop the server 4. Deploy the server using the newly imported image and correct API configuration 5. Start the server - + + ### Add Environment setup -If you want to run locally the EcoSonar API, you can add an `.env` file at the root of the project, it will contain the local environment variables of the project. -Then choose among the variables below the ones required and add it into `.env` file. +You will need to set up some environment variables to run the API. +Locally, you can add an `.env` file in the folder `EcoSonar-API`, it will contain the local environment variables of the project. +Then choose among the variables below the ones required and add it into `.env` file or to the application settings of your deployed server. + #### Database configuration ##### MongoDB Community Server + ``` ECOSONAR_ENV_DB_TYPE = 'MongoDB' ECOSONAR_ENV_CLUSTER = 'localhost' or '127.0.0.1' @@ -217,59 +233,78 @@ ECOSONAR_ENV_DB_NAME = 'EcoSonar' ``` ##### MongoDB Atlas + ``` ECOSONAR_ENV_DB_TYPE= 'MongoDB_Atlas' ECOSONAR_ENV_CLUSTER = #cluster ECOSONAR_ENV_DB_NAME = 'EcoSonar' ECOSONAR_ENV_USER = #user -ECOSONAR_ENV_CLOUD_PROVIDER= 'local' (the password will be retrieved from the environment variables) +ECOSONAR_ENV_CLOUD_PROVIDER= 'local' (the database password will be retrieved from the environment variables) ECOSONAR_ENV_PASSWORD = #password ``` ###### Azure CosmosDB + ``` ECOSONAR_ENV_DB_TYPE= 'CosmosDB' ECOSONAR_ENV_CLUSTER = #cluster ECOSONAR_ENV_DB_PORT = #port ECOSONAR_ENV_DB_NAME = 'EcoSonar' ECOSONAR_ENV_USER = #user -ECOSONAR_ENV_CLOUD_PROVIDER= 'AZURE' (the password will be retrieved from the Azure Key Vault) or ‘local’ (the password will be retrieved from the environment variables) -ECOSONAR_ENV_PASSWORD = #password (if ECOSONAR_ENV_CLOUD_PROVIDER=’local’) -ECOSONAR_ENV_KEY_VAULT_NAME= #keyVaultName (if ECOSONAR_ENV_CLOUD_PROVIDER=’AZURE’) -ECOSONAR_ENV_SECRET_NAME = #keyVaultSecretName (if ECOSONAR_ENV_CLOUD_PROVIDER=’AZURE’) +ECOSONAR_ENV_CLOUD_PROVIDER= 'AZURE' (the database password will be retrieved from the Azure Key Vault) or ‘local’ (the database password will be retrieved from the environment variables) +ECOSONAR_ENV_PASSWORD = #password (required only if ECOSONAR_ENV_CLOUD_PROVIDER=’local’) +ECOSONAR_ENV_KEY_VAULT_NAME= #keyVaultName (required only if ECOSONAR_ENV_CLOUD_PROVIDER=’AZURE’) +ECOSONAR_ENV_SECRET_NAME = #keyVaultSecretName (required only if ECOSONAR_ENV_CLOUD_PROVIDER=’AZURE’) ``` -##### Other database configuration possible + +##### Other database or password manager configuration possible If you are not using the same MongoDB database than us, you can develop your own. Please check to the `EcoSonar-API/configuration/database.js` to set up a different connection string to your database and `EcoSonar-API/configuration/retrieveDatabasePasswordFromCloud.js` for another password manager solution. We would be very happy if you want to share this new set up in a Pull Request in the Github Repository to enrich the community. + #### CORS Setup + To improve API Security, CORS options need to be configured to allow any other application to send requests to the API. To configure it, you can add the following environment variable in your Application Configuration to allow requests coming from your frontend interface: + +``` +ECOSONAR_ENV_SONARQUBE_SERVER_URL = url of the Sonarqube Server instantiated or any other frontend interface used to retrieve the audits ``` -ECOSONAR_ENV_SONARQUBE_SERVER_URL = url of the Sonarqube Server instantiated or any other frontend interface + +For local development purposes only, you can add additional URL authorize to reach out to the API using the variable `ECOSONAR_ENV_LOCAL_DEV_SERVER_URL`. You can declare several urls but you have to add `;` between each. + +``` +ECOSONAR_ENV_LOCAL_DEV_SERVER_URL = #URL1;#URL2 ``` + #### Enable W3C validator Analysis + W3C Validator needs to make a request to an external API to audit your url. It means that only 'public' pages can be audited right now. We have raised an issue to the team in charge of W3C Auditor to be able to audit also pages protected by authentication. To be continued... In the environment variable, you can set the following parameter to request an audit through the external API or not: + ``` -ECOSONAR_ENV_ALLOW_EXTERNAL_API = take `true`or `false` +ECOSONAR_ENV_ALLOW_EXTERNAL_API = `true`or `false` ``` -#### Setup User flow + +#### Setup User flow + If your projects require to set up a user flow to access some of your web pages, you should then enable this parameter to run audits on dedicated browser to ensure cookies are correctly configured. However, it will increase the audit time of your project. + ``` -ECOSONAR_ENV_USER_JOURNEY_ENABLED = take `true`or `false` +ECOSONAR_ENV_USER_JOURNEY_ENABLED = `true`or `false` ``` + # API Endpoints 1. With Postman @@ -282,327 +317,12 @@ For Swagger User Interface : `[ECOSONAR-API-URL]/swagger/` Locally, available at this address : `http://localhost:3002/swagger/` -3. Additional documentation +3. Additional API documentation https://github.com/Accenture/EcoSonar/blob/main/API.md - -# Authentication Configuration - -In order to audit pages that can be accessed only through an authentication service (intranet pages for example), -you need to add authentication credentials into EcoSonar API to allow auditing dedicated pages. - - -## When you have a simple login flow : username, password and click on a button - - -### EcoSonar V2.3 and below -To implement that, you can create a YAML file login.yaml at the root of the folder `EcoSonar-API` and use the following format -if the CSS selector of you input field is `input[name=username]` or `input[type=email]`, password field `input[name=password]`, `input[type=password]`, `input[id=password]` and button `button[type=submit]` : - -``` -authentication_url: authenticationPage -username: yourUsername -password: yourPassword -``` -or if one of the CSS Selector does not match the default CSS Selectors : - -``` -authentication_url:authenticationPage -username: yourUsername -password: yourPassword -loginButtonSelector: CSS_Selector_Button -usernameSelector: CSS_Selector_Login -passwordSelector: CSS_Selector_Password -``` - - -#### CSS Selectors - -CSS Selectors are patterns in HTML code to apply some style (doc ). For exemple, to find the css selector of  loginButtonSelector: -Go to the login page of your website -Right click on the login button -Select inspect -Choose css selectors you want (class, type, name, id, ....) - -More Information : - -documentation: https://github.com/cnumr/GreenIT-Analysis-cli/blob/072987f7d501790d1a6ccc4af6ec06937b52eb13/README.md#commande -code: https://github.com/cnumr/GreenIT-Analysis-cli/blob/072987f7d501790d1a6ccc4af6ec06937b52eb13/cli-core/analysis.js#L198 - - -### EcoSonar V3.0 and above - -You can directly configure your login credentials at a project level in the API. -Be careful your login credentials will then be saved into the database, please check with your security team if you are allowed to do so. - -You can use the Endpoint "Save Login and Proxy" and enter the following body: - -``` -{ - "login": { - "authentication_url": "authenticationPage", - "username": "yourUsername", - "password": "yourPassword" - } -} -``` -or - -``` -{ - "login": { - "authentication_url": "authenticationPage", - "username": "yourUsername", - "password": "yourPassword", - "loginButtonSelector": "CSS_Selector_Button", - "usernameSelector": "CSS_Selector_Login", - "passwordSelector": "CSS_Selector_Password" - } -} -``` - -## More complicated Login flows - -When the Username and password are not in the same page, or you need other user inputs to complete authentication - - -### EcoSonar V2.3 and below -If the authentication of the website required steps or a page change, you must follow these requirements: - -1. Create a YAML file login.yaml at the root of the repo -2. Add authentication_url key and value is required -3. Add steps key is required -4. Fill steps part as follow - -To choose you authentification_url, you can either set it to the page in which you need to perform the authentification steps or pick the page that can only be accessed after being authenticated. - -(To help you to create steps, you can use on Google Chrome Tool "Recorder". (inspector -> recorder -> start a new recording) and save json file, then you can extract steps type, target, selectors) - -Each step is a description of an action made by a regular user: -- "click" -> Click on a button for example: "submit" or "next" -type: "click" (required) -selector: CSS Selector of the field or button (required) -- "change" -> to fill a field like username or password -type: "change" (required) -selector: CSS Selector of the field or button (required) -value: value of the password or username (required) -/!\ CSS Selectors with "aria" label are not read by EcoSonar. - -Example of login.yaml file. to access into an account - -``` -authentication_url: authenticationPage -steps: -  -   type: "click" -      selectors: -          - "#input-email" -  -   type: "change" -      value: "my email" -      selectors: -          - "#input-email" -  -   type: "click" -      selectors: -        - "#lookup-btn" -  -   type: "change" -      value: "my password" -      selectors: -          - "#input-password" -  -   type: "click" -      selectors: -        - "#signin-button" -``` - - -### EcoSonar V3.0 and above - -You can use directly to configure your login credentials at a project level in the API. - -You can use the Endpoint "Save Login and Proxy" and enter the following body: - -``` -{ - "login": { - "authentication_url": "authenticationPage", - "steps" : [ ....] - } -} -``` - - -# Proxy Configuration - -For some websites, you may need to configure a proxy in order to access it. -You need to seperate the analysis that are made with or without a proxy into several EcoSonar projects. - - -## EcoSonar V2.3 and below -To implement that, you can create a YAML file proxy.yaml at the root of the repo. -Please find below the configuration format : - -``` -ipaddress: ipAddress -port: port -projectName: (optional) - - PROJECT_NAME_1 - - PROJECT_NAME_2 -``` - -ipaddress : IP Address of your proxy -port : port of your proxy - -projectName : list of EcoSonar Projects (corresponding to Sonarqube projectKey) that needs a proxy to audit pages registered. If no projectName has been added but proxy.yaml file exists, then proxy will be applied by default to all your projects. - - -## EcoSonar V3.0 and above - -You can directly configure your login credentials at a project level in the API. - -You can use the Endpoint "Save Login and Proxy" and enter the following body: - -``` -{ - "proxy": { - "ipAddress": "ipAddress", - "port" : "port" - } -} -``` - - -# User Flow - -In order to audit some pages, sometimes you may need to go through a user flow to get access to that page (for exemple fill in a form). Otherwise, if you don't have the context, the page can not be accessed. -We have added this functionality into EcoSonar. - - -## User Flow Creation - - -### First method : using Chrome Recorder - -If your business allows to use Chrome Browser, we hightly recommend you to use this method. -Chrome has a native panel called "Recorder" that allows you to record, replay and measure user flows (https://developer.chrome.com/docs/devtools/recorder/). - - ![Chrome Recorder](../images/chrome-recorder.webp) - - To access this panel, please click right on your browser, select Inspect, then choose Recorder in the DevTools Panel. - -To start recording a user flow, you can then click on button "Start new recording", choose a name then click on "Start a new recording". - - ![Start Chrome Recorder](../images/chrome-start-recorder.webp) - - Then the Chrome browser is going to register every interaction that is made with the page and save it into the user flow. - -For example, we want to audit this page : http://www.ecometer.org/job?url=https%3A%2F%2Fwww.accenture.com%2Ffr-fr. It is only accessible if you are launching an analysis of the website with Ecometer : -1. You need to navigate to the page : http://www.ecometer.org/ -2. You need to change the input to have your URL. -3. You need to click on the button "Analyse" to launch the analysis. - - ![Chrome Recorder User flow](../images/chrome-recorder-result.webp) - -Chrome Recorder is going to register the user flow by saving every step/interaction. - -To make sure your user flow is correct and can be used through Ecosonar, please use "Replay" button and start from initial page to make sure the User flow automation is set up correctly. You should have the result as your previous manual configuration. - -/!\ Be Careful "click" steps are not duplicated in your userflow (same element triggered) otherwise it could not have the expected behaviour. You can remove step in the Recorder by clicking on the 3 dots. - -Once you have validated your userflow, you can export this User Flow using the export button and choose JSON. - - ![Chrome Recorder User flow export](../images/save-chrome-recorder.webp) - - -### Second method : creating your own User Flow JSON - -If you are not allowed to use Chrome Browser, you can edit manually the user flow JSON file created by Chrome Recorder. -It should have the following format : -``` -{​​​​​​​​ - "steps": [ - {​​​​ - "type": "navigate", - "url": "http://www.ecometer.org/", - }​​​​​​​​​​​​​​​​​​, - {​​​​​​​​​​​​​​​​​​​​​​ - "type": "click", - "selectors": [ - [ - "body > div.container.begin > div > form > input.url" - ] - ], - }​​​​​​​​​​​​​​​​​​​​​​, - {​​​​​​​​​​​​​​​​​​​ - "type": "change", - "value": "https://www.accenture.com/fr-fr", - "selectors": [ - [ - "body > div.container.begin > div > form > input.url" - ] - ], - }​​​​​​​​​​​​​​​​​​​, - {​​​​​​​​​​​​​​​​​​​ - "type": "click", - "selectors": [ - [ - "body > div.container.begin > div > form > input.button" - ] - ], - ] - }​​​​​​​​​​​​​​​​​​​, - { - "type": "scroll", - "distancePercentage": 50 - }, - ] -}​​​​​​​​​​​​​​​​​​​​​​​​​​​​​ -``` - -We are handling into EcoSonar 4 kind of browser interactions : -1. Navigate to a URL -It should have "type" = "navigate" and "url" the url you want to go to -2. Change an input field -"type" = "change", "value" : value to be set in the input field, "selectors" : list of CSS Selectors to find the right input field -3. Click on a button -"type" = "click", "selectors" : list of CSS Selectors to find the right button -4. Scroll in the page and stop at a certain percentage at the page. -It will scroll down each 100px until the scroll limit has been reached. For example, the page is 1080px and we want to stop at the middle of the page (so distancePercentage = 50 %), it will iterate every 100 pixels until the windows has scrolled 540 px. -"type" = "scroll" and "distancePercentage" = value between 0 and 100 - - -## User Flow Integration - - -### EcoSonar v2.3 and below - -Once you have been able to define the JSON file matching to your user flow, you can followed instructions: - -1. Create a folder "userJourney" if it does not exists yet at the root of the folder `EcoSonar-API`. -2. Paste JSON file created in the folder "userJourney" and rename it with the URL you wish to audit. Please remove the following special character `:` `?` `:` `/` from the URL in order to save the JSON. To retrieve the user flow we are matching it with the URL registered through EcoSonar URL Configuration. This step is not to forget otherwise EcoSonar won't be auditing the right page. -3. Deploy EcoSonar-API with all relevant user flows. -4. Launch a new EcoSonar audit to verify there are no technical errors in the logs application. Correct them if needed. - - -### EcoSonar v3.0 and above - -With version 3.0, you can directly configure the user flow in the API provided (no longer need to reboot the instance) -You can use the Endpoint "Save User Flow" and enter the following body: - -``` -{ - "url": "urlToAudit, - "userFlow": { - "steps": [ ....] - } -} -``` - - -## User Flow Verification - -To verify pages you audit are the correct ones, we suggest you to use both Chrome extensions : Green-IT Analysis (https://chrome.google.com/webstore/detail/greenit-analysis/mofbfhffeklkbebfclfaiifefjflcpad?hl=fr) and Google Lighthouse (https://chrome.google.com/webstore/detail/lighthouse/blipmdconlkpinefehnmjammfjpmpbjk?hl=fr) and compare results from these extensions to the EcoSonar audits. There should be almost identical. -If that is not the case, do not hesitate to contact us to help you. - + # Usage Rights -This tool uses an API that does not allow its use for commercial purposes. \ No newline at end of file +This tool uses an API that does not allow its use for commercial purposes. diff --git a/EcoSonar-API/dataBase/bestPracticesRepository.js b/EcoSonar-API/dataBase/bestPracticesRepository.js index 6cf1c65..7ae9387 100644 --- a/EcoSonar-API/dataBase/bestPracticesRepository.js +++ b/EcoSonar-API/dataBase/bestPracticesRepository.js @@ -6,16 +6,14 @@ const BestPracticesRepository = function () { /** * Insert best practices * @param {Array} reports array containing the result of greenIt analysis (including metrics and best practices) - * @param {Array} urlIdList array of urls ID - * @param {String} projectName name of the project */ - this.insertBestPractices = async function (arrayToInsert) { - if (arrayToInsert.length > 0) { arrayToInsert = await checkValues(arrayToInsert) } + this.insertBestPractices = async function (reports) { + if (reports.length > 0) { reports = checkValues(reports) } return new Promise((resolve, reject) => { - if (arrayToInsert.length > 0) { + if (reports.length > 0) { bestpractices - .insertMany(arrayToInsert) + .insertMany(reports) .then(() => { resolve() }) @@ -33,8 +31,7 @@ const BestPracticesRepository = function () { /** * deletion of one or more analysis of best practices on the table bestPractices - * @param {name of the project} projectNameReq - * @returns + * @param {string} projectNameReq */ this.delete = async function (projectNameReq) { let empty = false @@ -73,8 +70,8 @@ const BestPracticesRepository = function () { /** * find All analysis of best practices for a project on the table bestPractices - * @param {name of the project} projectNameReq - * @returns + * @param {string} projectNameReq + * @returns {Array} best practices reports for the last analysis run on project */ this.findAll = async function (projectNameReq) { let hasNoUrl = false @@ -118,9 +115,9 @@ const BestPracticesRepository = function () { /** * find analysis of best practices for an URL on the table bestPractices - * @param {name of the project} projectName - * @param {url} urlName - * @returns + * @param {string} projectName + * @param {string} urlName + * @returns {Array} best practices reports for the last analysis run on URL */ this.find = async function (projectName, urlName) { let hasNoUrl = false @@ -153,24 +150,42 @@ const BestPracticesRepository = function () { } /** + * Deletion of all best practices analysis for a project + * @param {string} urlIdKeyList list of id key representing url saved + */ + this.deleteProject = async function (urlIdKeyList) { + return new Promise((resolve, reject) => { + bestpractices.deleteMany({ idUrl: { $in: urlIdKeyList } }) + .then((result) => { + console.log(`DELETE URLS PROJECT - On best practices ${result.deletedCount} objects removed`) + resolve() + }) + .catch((error) => { + console.error('\x1b[31m%s\x1b[0m', error) + reject(new SystemError()) + }) + }) + } +} + +/** * * @param {Array} arrayToInsert * @param {Array} urlIdList - * @param {String} projectName + * @param {string} projectName * @returns an array cleaned of analysis containing undefined and NaN to avoid mongoose rejecting every GreenIt Best Practices insertion * This function check if best practices exists for each url of the report (arrayToInsert), if true then also update urlIdList array to match */ - async function checkValues (arrayToInsert) { - const arrayToInsertSanitized = [] - for (const analysis of arrayToInsert) { - if (analysis.bestPractices) { - arrayToInsertSanitized.push(analysis) - } else { - console.log(`BEST PRACTICES INSERT - Best practices for url ${analysis.url} cannot be inserted due to presence of NaN or undefined values`) - } +function checkValues (arrayToInsert) { + const arrayToInsertSanitized = [] + for (const analysis of arrayToInsert) { + if (analysis.bestPractices) { + arrayToInsertSanitized.push(analysis) + } else { + console.log(`BEST PRACTICES INSERT - Best practices for url ${analysis.url} cannot be inserted due to presence of NaN or undefined values`) } - return arrayToInsertSanitized } + return arrayToInsertSanitized } const bestPracticesRepository = new BestPracticesRepository() diff --git a/EcoSonar-API/dataBase/greenItRepository.js b/EcoSonar-API/dataBase/greenItRepository.js index 7efd697..9e9676f 100644 --- a/EcoSonar-API/dataBase/greenItRepository.js +++ b/EcoSonar-API/dataBase/greenItRepository.js @@ -5,17 +5,16 @@ const formatGreenItAnalysis = require('../services/format/formatGreenItAnalysis' const GreenItRepository = function () { /** - * insertion of one or more analysis - * @param {arrayToInsert} reports - * @returns + * insertion of one or more greenit analysis + * @param {Array} reports reports to add */ - this.insertAll = async function (arrayToInsert) { - if (arrayToInsert.length > 0) { arrayToInsert = await checkValues(arrayToInsert) } + this.insertAll = async function (reports) { + if (reports.length > 0) { reports = await checkValues(reports) } return new Promise((resolve, reject) => { - if (arrayToInsert.length > 0) { + if (reports.length > 0) { greenits - .insertMany(arrayToInsert) + .insertMany(reports) .then(() => { resolve() }) @@ -33,8 +32,8 @@ const GreenItRepository = function () { } /** - * find all EcoIndex analysis - * @returns + * find all GreenIT analysis saved in EcoSonar + * @returns greenit reports */ this.findAllAnalysis = async function () { return new Promise((resolve, reject) => { @@ -42,17 +41,18 @@ const GreenItRepository = function () { .then((res) => { resolve(res) }) - .catch(() => { + .catch((error) => { + console.error('\x1b[31m%s\x1b[0m', error) reject(new SystemError()) }) }) } /** - * find analysis for one url : OK - * @param {project Name} projectNameReq - * @param {url Name} urlNameReq - * @returns + * find last greenit analysis for one url + * @param {string} projectNameReq project name + * @param {string} urlNameReq URL of the page analyzed + * @returns last greenit analysis of a url */ this.findAnalysisUrl = async function (projectNameReq, urlNameReq) { let res @@ -112,10 +112,9 @@ const GreenItRepository = function () { } /** - * find analysis for one Project - * @param {project Name} projectNameReq - * @param {all deployment = true} alldeployment - * @returns + * find last greenit analysis for one Project + * @param {string} projectNameReq name of the project + * @returns last greenit analysis of a project */ this.findAnalysisProject = async function (projectNameReq) { let stringErr = null @@ -160,9 +159,9 @@ const GreenItRepository = function () { } /** - * find EcoIndex from last analysis for one Project - * @param {project Name} projectNameReq - * @returns + * find scores from last analysis for one Project + * @param {string} projectNameReq name of the project + * @returns scores of last analysis */ this.findScoreProject = async function (projectNameReq) { let stringErr = null @@ -206,6 +205,24 @@ const GreenItRepository = function () { } }) } + + /** + * Deletion of all greenIt analysis for a project + * @param {string} urlIdKeyList list of id key representing url saved + */ + this.deleteProject = async function (urlIdKeyList) { + return new Promise((resolve, reject) => { + greenits.deleteMany({ idUrlGreen: { $in: urlIdKeyList } }) + .then((result) => { + console.log(`DELETE URLS PROJECT - On GreenIt ${result.deletedCount} objects removed`) + resolve() + }) + .catch((error) => { + console.error('\x1b[31m%s\x1b[0m', error) + reject(new SystemError()) + }) + }) + } } /** @@ -219,8 +236,13 @@ async function checkValues (arrayToInsert) { if (!Object.values(analysis).includes(undefined) || !Object.values(analysis).includes(NaN)) { arrayToInsertSanitized.push(analysis) } else { - const urlInfos = await urlsprojects.find({ idKey: analysis.idUrlGreen }) - console.log(`GREENIT INSERT - Url ${urlInfos[0].urlName} cannot be inserted due to presence of NaN or undefined values`) + await urlsprojects.find({ idKey: analysis.idUrlGreen }) + .then((result) => { + console.warn(`GREENIT INSERT - Url ${result[0].urlName} cannot be inserted due to presence of NaN or undefined values`) + }) + .catch((error) => { + console.error(error) + }) } } return arrayToInsertSanitized diff --git a/EcoSonar-API/dataBase/lighthouseRepository.js b/EcoSonar-API/dataBase/lighthouseRepository.js index 9961776..30f9ae7 100644 --- a/EcoSonar-API/dataBase/lighthouseRepository.js +++ b/EcoSonar-API/dataBase/lighthouseRepository.js @@ -5,9 +5,8 @@ const formatLighthouseAnalysis = require('../services/format/formatLighthouseAna const LighthouseRepository = function () { /** - * insertion of one or more analysis on the table lighthouses - * @param {list of url analysis} lighthouseMetricsReports - * @returns + * insertion of one or more lighthouse analysis on the table lighthouses + * @param {Array} lighthouseMetricsReports lightouse reports */ this.insertAll = function (lighthouseMetricsReports) { return new Promise((resolve, reject) => { @@ -33,8 +32,8 @@ const LighthouseRepository = function () { } /** - * find all Lighthouse analysis - * @returns + * find all Lighthouse analysis saved in EcoSonar + * @returns all ligthouse reports */ this.findAllAnalysis = async function () { return new Promise((resolve, reject) => { @@ -42,17 +41,18 @@ const LighthouseRepository = function () { .then((res) => { resolve(res) }) - .catch(() => { + .catch((error) => { + console.error('\x1b[31m%s\x1b[0m', error.message) reject(new SystemError()) }) }) } /** - * find analysis for one url in a project - * @param {project Name} projectNameReq - * @param {url Name} urlNameReq - * @returns + * find last analysis for one url in a project + * @param {string} projectNameReq name of the project + * @param {string} urlNameReq url id key representing the url saved in database + * @returns last ligthouse analysis for url */ this.findAnalysisUrl = async function (projectNameReq, urlNameReq) { let urlMatching @@ -144,9 +144,9 @@ const LighthouseRepository = function () { } /** - * find analysis for one Project - * @param {project Name} projectNameReq - * @returns + * find last lighthouse analysis for one Project + * @param {string} projectNameReq project name + * @returns last lighthouse analysis for the project */ this.findAnalysisProject = async function (projectNameReq) { let stringErr = null @@ -222,8 +222,8 @@ const LighthouseRepository = function () { /** * find Lighthouse Scores for one Project - * @param {project Name} projectNameReq - * @returns + * @param {string} projectNameReq project name + * @returns ligthouse score for last analysis in the project */ this.findScoreProject = async function (projectNameReq) { let stringErr = null @@ -284,6 +284,24 @@ const LighthouseRepository = function () { } }) } + + /** + * Deletion of all lighthouses analysis for a project + * @param {Array} urlIdKeyList list of id key representing urls saved + */ + this.deleteProject = async function (urlIdKeyList) { + return new Promise((resolve, reject) => { + lighthouses.deleteMany({ idUrlLighthouse: { $in: urlIdKeyList } }) + .then((result) => { + console.log(`DELETE URLS PROJECT - On Lighthouse ${result.deletedCount} objects removed`) + resolve() + }) + .catch((error) => { + console.error('\x1b[31m%s\x1b[0m', error) + reject(new SystemError()) + }) + }) + } } const lighthouseRepository = new LighthouseRepository() diff --git a/EcoSonar-API/dataBase/models/tempurlsproject.js b/EcoSonar-API/dataBase/models/tempurlsproject.js new file mode 100644 index 0000000..079a84a --- /dev/null +++ b/EcoSonar-API/dataBase/models/tempurlsproject.js @@ -0,0 +1,19 @@ +const mongoose = require('mongoose') +const Schema = mongoose.Schema + +const tempUrlsProjectSchema = new Schema({ + idKey: { + type: String, + required: true, + unique: true + }, + projectName: { + type: String, + required: true, + unique: true + }, + urlsList: [String] +}) + +const tempurlsProject = mongoose.model('tempurlsprojects', tempUrlsProjectSchema) +module.exports = tempurlsProject diff --git a/EcoSonar-API/dataBase/projectsRepository.js b/EcoSonar-API/dataBase/projectsRepository.js index 951ae5f..8f1f0c5 100644 --- a/EcoSonar-API/dataBase/projectsRepository.js +++ b/EcoSonar-API/dataBase/projectsRepository.js @@ -4,8 +4,9 @@ const urlsProject = require('./models/urlsprojects') const ProjectsRepository = function () { /** - * get all projects in database - * @returns an array with the projectName for all projects founded + * get all projects in database that match a regexp + * @param {string} filterName regexp for the project name + * @returns an array with the projectName for all projects found */ this.findAllProjectsNames = async function (filterName) { let query = {} @@ -17,7 +18,8 @@ const ProjectsRepository = function () { .then((res) => { resolve(res) }) - .catch(() => { + .catch((error) => { + console.error('\x1b[31m%s\x1b[0m', error.message) reject(new SystemError()) }) }) @@ -25,8 +27,8 @@ const ProjectsRepository = function () { /** * add a new procedure for a project - * @param {projectName} : the name of the project - * @param {procedure} : the procedure to add + * @param {string} projectName the name of the project + * @param {string} procedure the procedure to add */ this.createProcedure = function (projectName, procedure) { return new Promise((resolve, reject) => { @@ -45,10 +47,8 @@ const ProjectsRepository = function () { /** * update the procedure of a project - * @param {projectName} : the name of the project - * @param {selectedProcedure} : the new procedure to update - * @param {loginCredentials} : the login credentials to be set when analysing the project - * @returns + * @param {string} projectName the name of the project + * @param {string} selectedProcedure the new procedure to update */ this.updateProjectProcedure = async function (projectName, selectedProcedure) { return new Promise((resolve, reject) => { @@ -69,16 +69,13 @@ const ProjectsRepository = function () { /** * Create login Configuration to be saved in the project - * @param {projectName} projectName is the name of the project - * @param {procedure} procedure is the procedure to be saved in a specified enumeration - * @param {loginCredentials} loginCredentials is the login credentials to be set when analysing the project - * @param {proxy} proxy is the proxy configuration to be set when analysing the project - * @returns + * @param {string} projectName is the name of the project + * @param {JSON} loginCredentials is the login credentials to be set when analysing the project */ - this.createLoginConfiguration = async function (projectName, loginCredentials, proxy) { + this.createLoginConfiguration = async function (projectName, loginCredentials) { const loginMap = (loginCredentials !== undefined && loginCredentials !== null) ? new Map(Object.entries(loginCredentials)) : {} return new Promise((resolve, reject) => { - projects.create({ projectName, login: loginMap, proxy }) + projects.create({ projectName, login: loginMap }) .then(() => { resolve() }) .catch((error) => { console.error('PROJECTS REPOSITORY - login creation failed') @@ -89,18 +86,34 @@ const ProjectsRepository = function () { }) } + /** + * Create proxy configuration to be saved in the project + * @param {string} projectName is the name of the project + * @param {string} proxy is the proxy configuration to be set when analysing the project + */ + this.createProxyConfiguration = async function (projectName, proxy) { + return new Promise((resolve, reject) => { + projects.create({ projectName, proxy }) + .then(() => { resolve() }) + .catch((error) => { + console.error('PROJECTS REPOSITORY - proxy creation failed') + console.error('\x1b[31m%s\x1b[0m', error) + const systemError = new SystemError() + reject(systemError) + }) + }) + } + /** * Update login Configuration to be saved in the project - * @param {projectName} projectName is the name of the project - * @param {procedure} procedure is the procedure to be saved in a specified enumeration - * @param {loginCredentials} loginCredentials is the login credentials to be set when analysing the project - * @param {proxy} proxy is the proxy configuration to be set when analysing the project - * @returns + * @param {string} projectName is the name of the project + * @param {string} procedure is the procedure to be saved in a specified enumeration + * @param {JSON} loginCredentials is the login credentials to be set when analysing the project */ - this.updateLoginConfiguration = async function (projectName, procedure, loginCredentials, proxy) { + this.updateLoginConfiguration = async function (projectName, procedure, loginCredentials) { const loginMap = new Map(Object.entries(loginCredentials)) return new Promise((resolve, reject) => { - projects.updateOne({ projectName }, { login: loginMap, proxy, procedure }) + projects.updateOne({ projectName }, { login: loginMap, procedure }) .then(() => { resolve() }) .catch((error) => { console.error('PROJECTS REPOSITORY - login update failed') @@ -111,10 +124,29 @@ const ProjectsRepository = function () { }) } + /** + * Update proxy configuration to be saved in the project + * @param {string} projectName is the name of the project + * @param {string} procedure is the procedure to be saved in a specified enumeration + * @param {JSON} proxy is the proxy configuration to be set when analysing the project + */ + this.updateProxyConfiguration = async function (projectName, procedure, proxy) { + return new Promise((resolve, reject) => { + projects.updateOne({ projectName }, { proxy, procedure }) + .then(() => { resolve() }) + .catch((error) => { + console.error('PROJECTS REPOSITORY - proxy update failed') + console.error('\x1b[31m%s\x1b[0m', error) + const systemError = new SystemError() + reject(systemError) + }) + }) + } + /** * find project settings in the table projects - * @param {projectName} projectName - * @returns + * @param {string} projectNameReq name of the project + * @returns project settings */ this.getProjectSettings = async function (projectName) { let systemError = null @@ -139,8 +171,9 @@ const ProjectsRepository = function () { /** * Deletion of login credentials for project - * @param {name of the project} projectNameReq - * @returns + * @param {string} projectNameReq name of the project + * @param {string} procedureRegistered procedure registered for the project + * @param {JSON} proxyRegistered proxy registered for the project */ this.deleteLoginCredentials = async function (projectNameReq, procedureRegistered, proxyRegistered) { let systemError = null @@ -166,8 +199,9 @@ const ProjectsRepository = function () { /** * Deletion of proxy configuration for project - * @param {name of the project} projectNameReq - * @returns + * @param {string} projectNameReq name of the project + * @param {string} procedureRegistered procedure registered for the project + * @param {JSON} loginRegistered login registered for the project */ this.deleteProxyConfiguration = async function (projectNameReq, procedureRegistered, loginRegistered) { let systemError = null @@ -190,6 +224,23 @@ const ProjectsRepository = function () { } }) } + + /** + * Deletion of one project based on his name + * @param {string} projectNameReq name of the project + */ + this.deleteProjectPerProjectName = async function (projectNameReq) { + return new Promise((resolve, reject) => { + projects.deleteOne({ projectName: projectNameReq }) + .then(() => { + console.log(`DELETE URLS PROJECT - project ${projectNameReq} deleted`) + resolve() + }).catch((error) => { + console.error('\x1b[31m%s\x1b[0m', error) + reject(new SystemError()) + }) + }) + } } const projectsRepository = new ProjectsRepository() diff --git a/EcoSonar-API/dataBase/tempurlsProjectRepository.js b/EcoSonar-API/dataBase/tempurlsProjectRepository.js new file mode 100644 index 0000000..7dfcda3 --- /dev/null +++ b/EcoSonar-API/dataBase/tempurlsProjectRepository.js @@ -0,0 +1,79 @@ +const uniqid = require('uniqid') +const tempurlsproject = require('./models/tempurlsproject') +const SystemError = require('../utils/SystemError') + +const TempUrlsProjectRepository = function () { + /** + * insertion of urls crawled for the project in the collection temporaryurlsProject + * @param {string} projectName project name + * @param {Array} urls urls crawled to be saved + */ + this.create = async function (projectName, urls) { + return new Promise((resolve, reject) => { + tempurlsproject.create({ + idKey: uniqid(), + projectName, + urlsList: urls + }) + .then(() => { resolve() }) + .catch((err) => { + console.error('\x1b[31m%s\x1b[0m', err) + reject(new SystemError()) + }) + }) + } + + /** + * update of urls crawled for the project in the collection temporaryurlsProject + * @param {string} projectName project name + * @param {Array} urls urls crawled to be saved + */ + this.updateUrls = async function (projectName, urls) { + return new Promise((resolve, reject) => { + tempurlsproject.updateOne({ projectName }, { urlsList: urls }) + .then(() => { resolve() }) + .catch((err) => { + console.error('\x1b[31m%s\x1b[0m', err) + reject(new SystemError()) + }) + }) + } + + /** + * get urls crawled for the project in the collection temporaryurlsProject + * @param {string} projectName project name + * @param {Array} urls urls crawled to be saved + * @returns list of urls crawled + */ + this.findUrls = async function (name) { + return new Promise((resolve, reject) => { + tempurlsproject.findOne({ projectName: name }) + .then((result) => { resolve(result) }) + .catch((err) => { + console.error('\x1b[31m%s\x1b[0m', err) + reject(new SystemError()) + }) + }) + } + + /** + * deletion of all temporary urls for the project + * @param {string} projectName name of the project + */ + this.deleteProject = async function (projectName) { + return new Promise((resolve, reject) => { + tempurlsproject.deleteOne({ projectName }) + .then((result) => { + console.log(`DELETE URLS PROJECT - On tempurlsproject project ${projectName} removed`) + resolve() + }) + .catch((error) => { + console.error('\x1b[31m%s\x1b[0m', error) + reject(new SystemError()) + }) + }) + } +} + +const tempurlsProjectRepository = new TempUrlsProjectRepository() +module.exports = tempurlsProjectRepository diff --git a/EcoSonar-API/dataBase/urlsProjectRepository.js b/EcoSonar-API/dataBase/urlsProjectRepository.js index 212c22c..81fca3a 100644 --- a/EcoSonar-API/dataBase/urlsProjectRepository.js +++ b/EcoSonar-API/dataBase/urlsProjectRepository.js @@ -8,9 +8,9 @@ const SystemError = require('../utils/SystemError') const UrlsProjectRepository = function () { /** - * insertion of one or more url on the table urlsProject : OK - * @param {*} values - * @returns + * insertion of one or more url on the table urlsProject + * @param {string} projectName project Name + * @param {Array} urlList urls to be saved */ this.insertAll = async function (projectName, urlList) { const urlsProjects = [] @@ -48,7 +48,7 @@ const UrlsProjectRepository = function () { } /** - * deletion on the table urlsProject : OK + * deletion on the table urlsProject * @param {id url} key */ this.delete = async function (projectNameReq, urlNameReq) { @@ -84,14 +84,33 @@ const UrlsProjectRepository = function () { } /** - * display all urls of a project : OK - * @param {name of the project} projectName + * deletion of all urls of a project + * @param {Array} urlIdKeyList list of id key representing url saved */ - this.findAll = async function (projectNameReq, insert) { + this.deleteProject = async function (urlIdKeyList) { + return new Promise((resolve, reject) => { + urlsprojects.deleteMany({ idKey: { $in: urlIdKeyList } }) + .then((result) => { + console.log(`DELETE URLS PROJECT - On urlsprojects ${result.deletedCount} objects removed`) + resolve() + }) + .catch((error) => { + console.error('\x1b[31m%s\x1b[0m', error) + reject(new SystemError()) + }) + }) + } + + /** + * list all urls of a project + * @param {string} projectName name of the project + * @param {boolean} getUrlNameOnly retrieve only parameter url from the collection + */ + this.findAll = async function (projectNameReq, getUrlNameOnly) { return new Promise((resolve, reject) => { let res try { - if (insert) { + if (getUrlNameOnly) { res = urlsprojects.find({ projectName: projectNameReq }) } else { res = urlsprojects.find({ projectName: projectNameReq }, { urlName: 1 }) @@ -107,9 +126,8 @@ const UrlsProjectRepository = function () { /** * Insert or Update user flow for a specific url - * @param {urlObject} urlsProject previously registered - * @param {userFlow} user flow to be saved - * @returns + * @param {JSON} urlObject urlProject previously registered + * @param {JSON} userFlow user flow to be saved */ this.insertUserFlow = async function (urlObject, userFlow) { const userflowMap = new Map(Object.entries(userFlow)) @@ -126,8 +144,9 @@ const UrlsProjectRepository = function () { /** * find user flow for url to be audited - * @param {urlName} url to find user flow - * @returns + * @param {string} projectName project name + * @param {string} url url name + * @returns user flow for the project and url defined */ this.getUserFlow = async function (projectName, urlName) { let systemError = null @@ -150,8 +169,7 @@ const UrlsProjectRepository = function () { /** * Deletion of user flow for a specified url - * @param {urlName} url to delete user flow - * @returns + * @param {string} urlName url to delete user flow */ this.deleteUserFlow = async function (projectName, urlName) { let systemError = null diff --git a/EcoSonar-API/dataBase/w3cRepository.js b/EcoSonar-API/dataBase/w3cRepository.js index cb31c21..9264acc 100644 --- a/EcoSonar-API/dataBase/w3cRepository.js +++ b/EcoSonar-API/dataBase/w3cRepository.js @@ -7,8 +7,7 @@ const formatW3cAnalysis = require('../services/format/formatW3cAnalysis') const W3cRepository = function () { /** * Insert the w3c analysis for a project - * @param {reportsW3c} reportW3c is a list a the report for the w3c analysis - * @returns + * @param {reportsW3c} reportW3c is a list of the report for the w3c analysis */ this.insertAll = function (reportsW3c) { return new Promise((resolve, reject) => { @@ -34,8 +33,8 @@ const W3cRepository = function () { } /** - * find all w3c analysis - * @returns + * find all w3c analysis saved in EcoSonar + * @returns list of w3c analysis */ this.findAllAnalysis = async function () { return new Promise((resolve, reject) => { @@ -43,17 +42,18 @@ const W3cRepository = function () { .then((res) => { resolve(res) }) - .catch(() => { + .catch((error) => { + console.error('\x1b[31m%s\x1b[0m', error.message) reject(new SystemError()) }) }) } /** - * find analysis for one url in a project - * @param {project Name} projectNameReq - * @param {url Name} urlNameReq - * @returns + * find last w3c analysis for one url in a project + * @param {string} projectNameReq project Name + * @param {string} urlNameReq url Name + * @returns last w3c analysis for the URL */ this.findAnalysisUrl = async function (projectNameReq, urlNameReq) { let urlMatching @@ -129,9 +129,9 @@ const W3cRepository = function () { } /** - * find w3c analysis for one Project - * @param {project Name} projectName - * @returns + * find last w3c analysis for one Project + * @param {string} projectName project Name + * @returns last w3c analysis for the project */ this.findAnalysisProject = async function (projectName) { let error = null @@ -203,10 +203,10 @@ const W3cRepository = function () { } /** - * find analysis of w3c best practices for an URL on the table w3cs - * @param {name of the project} projectName - * @param {url} urlName - * @returns + * find last analysis of w3c best practices for an URL on the table w3cs + * @param {string} projectName name of the project + * @param {string} urlName url + * @returns last w3c analysis */ this.find = async function (projectName, urlName) { let hasNoUrl = false @@ -245,8 +245,7 @@ const W3cRepository = function () { /** * Deletion of one or more w3c analysis on the w3cs collection - * @param {name of the project} projectNameReq - * @returns + * @param {string} projectNameReq name of the project */ this.delete = async function (projectNameReq) { let empty = false @@ -282,6 +281,24 @@ const W3cRepository = function () { } }) } + + /** + * Deletion of all w3c analysis for a project + * @param {string} urlIdKeyList list of id key representing url saved + */ + this.deleteProject = async function (urlIdKeyList) { + return new Promise((resolve, reject) => { + w3cs.deleteMany({ idUrlW3c: { $in: urlIdKeyList } }) + .then((result) => { + console.log(`DELETE URLS PROJECT - On W3C ${result.deletedCount} objects removed`) + resolve() + }) + .catch((error) => { + console.error('\x1b[31m%s\x1b[0m', error.message) + reject(new SystemError()) + }) + }) + } } const w3cRepository = new W3cRepository() diff --git a/EcoSonar-API/package.json b/EcoSonar-API/package.json index dbaa9dc..e75d895 100644 --- a/EcoSonar-API/package.json +++ b/EcoSonar-API/package.json @@ -1,6 +1,6 @@ { "name": "ecosonar-api", - "version": "3.2", + "version": "3.4", "description": "Ecodesign and accessibility tool to help developpers minimize carbon footprint of their web-application", "repository": { "type": "git", diff --git a/EcoSonar-API/routes/app.js b/EcoSonar-API/routes/app.js index 625fe8c..671524b 100644 --- a/EcoSonar-API/routes/app.js +++ b/EcoSonar-API/routes/app.js @@ -15,6 +15,8 @@ const asyncMiddleware = require('../utils/AsyncMiddleware') const swaggerUi = require('swagger-ui-express') const swaggerSpec = require('../swagger') const projectService = require('../services/projectService') +const packageJson = require('../package.json') +const bestPracticesServices = require('../services/bestPracticesService') dotenv.config() @@ -32,8 +34,10 @@ const sonarqubeServerUrl = process.env.ECOSONAR_ENV_SONARQUBE_SERVER_URL || '' const whitelist = [sonarqubeServerUrl] if (process.env.ECOSONAR_ENV_CLOUD_PROVIDER === 'local') { - const localServer = process.env.ECOSONAR_ENV_LOCAL_DEV_SERVER_URL || '' - whitelist.push(localServer) + const localServers = process.env.ECOSONAR_ENV_LOCAL_DEV_SERVER_URL?.split(';') || [] + for (const localServer of localServers) { + whitelist.push(localServer) + } } const corsOptions = { @@ -130,7 +134,7 @@ app.get('/api/all', asyncMiddleware(async (req, res, _next) => { app.post('/api/insert', asyncMiddleware(async (req, res, _next) => { const projectName = req.body.projectName const urlsList = req.body.urlName - console.log('INSERT URLS PROJECT - insert urls into project ' + projectName) + console.log(`INSERT URLS PROJECT - insert urls into project ${projectName}`) urlConfigurationService.insert(projectName, urlsList) .then(() => { console.log('INSERT URLS PROJECT - insert succeeded') @@ -198,17 +202,17 @@ app.delete('/api/delete', asyncMiddleware(async (req, res, _next) => { * post: * tags: * - "Login Configuration" - * summary: "Save Login and Proxy For Project" - * description: Insert login credentials and proxy configuration for a project. + * summary: "Save Login For Project" + * description: Insert login credentials for a project. * parameters: * - name: projectName * in: query * description: The name of the project * required: true * type: string - * - name: login and proxy + * - name: login * in: body - * description: The login credentials and proxy settings + * description: The login credentials settings * required: true * schema: * type: object @@ -222,6 +226,52 @@ app.delete('/api/delete', asyncMiddleware(async (req, res, _next) => { * type: array * items: * type: object + * responses: + * 201: + * description: Success. + * 500: + * description: System error. + */ +app.post('/api/login/insert', asyncMiddleware(async (req, res, _next) => { + const projectName = req.query.projectName + const loginCredentials = req.body.login + console.log('INSERT LOGIN CREDENTIALS - insert credentials into project ' + projectName) + loginProxyConfigurationService.insertLoginCredentials(projectName, loginCredentials) + .then(() => { + console.log('INSERT LOGIN CREDENTIALS - insert succeeded') + return res.status(201).send() + }) + .catch((error) => { + if (error instanceof SystemError) { + return res.status(500).send() + } + console.log('INSERT LOGIN CREDENTIALS - insertion failed') + return res.status(400).json({ error }) + }) +})) + +// API CRUD PROXY Configuration +/** + * @swagger + * /api/proxy/insert: + * post: + * tags: + * - "Proxy Configuration" + * summary: "Save Proxy For Project" + * description: Insert proxy configuration for a project. + * parameters: + * - name: projectName + * in: query + * description: The name of the project + * required: true + * type: string + * - name: proxy + * in: body + * description: The proxy settings + * required: true + * schema: + * type: object + * properties: * proxy: * type: object * properties: @@ -232,26 +282,23 @@ app.delete('/api/delete', asyncMiddleware(async (req, res, _next) => { * responses: * 201: * description: Success. - * 400: - * description: Insertion failed. * 500: * description: System error. */ -app.post('/api/login/insert', asyncMiddleware(async (req, res, _next) => { +app.post('/api/proxy/insert', asyncMiddleware(async (req, res, _next) => { const projectName = req.query.projectName - const loginCredentials = req.body.login const proxyConfiguration = req.body.proxy - console.log('INSERT LOGIN - PROXY CREDENTIALS - insert credentials into project ' + projectName) - loginProxyConfigurationService.insert(projectName, loginCredentials, proxyConfiguration) + console.log('INSERT PROXY - insert proxy credentials into project ' + projectName) + loginProxyConfigurationService.insertProxyConfiguration(projectName, proxyConfiguration) .then(() => { - console.log('INSERT LOGIN CREDENTIALS - insert succeeded') + console.log('INSERT PROXY CREDENTIALS - insert succeeded') return res.status(201).send() }) .catch((error) => { if (error instanceof SystemError) { return res.status(500).send() } - console.log('INSERT LOGIN CREDENTIALS - insertion failed') + console.log('INSERT PROXY CREDENTIALS - insertion failed') return res.status(400).json({ error }) }) })) @@ -300,7 +347,7 @@ app.get('/api/login/find', asyncMiddleware(async (req, res, _next) => { * /api/proxy/find: * get: * tags: - * - "Login Configuration" + * - "Proxy Configuration" * summary: "Get Proxy For Project" * description: Find proxy configuration for a project. * parameters: @@ -340,7 +387,7 @@ app.get('/api/proxy/find', asyncMiddleware(async (req, res, _next) => { * delete: * tags: * - "Login Configuration" - * summary: "Delete Login for Project" + * summary: "Delete Login For Project" * description: Delete login credentials for a project. * parameters: * - name: projectName @@ -378,8 +425,8 @@ app.delete('/api/login', asyncMiddleware(async (req, res, _next) => { * /api/proxy: * delete: * tags: - * - "Login Configuration" - * summary: "Delete Proxy for Project" + * - "Proxy Configuration" + * summary: "Delete Proxy For Project" * description: Delete proxy configuration for a project. * parameters: * - name: projectName @@ -419,7 +466,7 @@ app.delete('/api/proxy', asyncMiddleware(async (req, res, _next) => { * post: * tags: * - "User Flow Configuration" - * summary: "Save User Flow for URL" + * summary: "Save User Flow For URL" * description: Insert new user flow for a url in a project. * parameters: * - name: userFlow @@ -473,7 +520,7 @@ app.post('/api/user-flow/insert', asyncMiddleware(async (req, res, _next) => { * post: * tags: * - "User Flow Configuration" - * summary: "Get User Flow for URL" + * summary: "Get User Flow For URL" * description: Find user flow for a URL. * parameters: * - name: userFlow @@ -518,7 +565,7 @@ app.post('/api/user-flow/find', asyncMiddleware(async (req, res, _next) => { * delete: * tags: * - "User Flow Configuration" - * summary: "Delete User Flow for URL" + * summary: "Delete User Flow For URL" * description: Delete user flow for a URL * parameters: * - name: userFlow @@ -938,7 +985,7 @@ app.post('/api/bestPractices/url', asyncMiddleware(async (req, res, _next) => { * post: * tags: * - "URL Configuration" - * summary: "Get Crawler Result" + * summary: Launch crawling website * description: Crawl the given website to find all pages related. * parameters: * - name: crawledUrl @@ -952,24 +999,59 @@ app.post('/api/bestPractices/url', asyncMiddleware(async (req, res, _next) => { * type: string * mainUrl: * type: string + * saveUrls: + * type: boolean * responses: - * 200: - * description: Success. - * 500: - * description: System error. + * 202: + * description: Crawler started. */ app.post('/api/crawl', asyncMiddleware(async (req, res, _next) => { const projectName = req.body.projectName const mainUrl = req.body.mainUrl + const saveUrls = req.body.saveUrls console.log(`CRAWLER - Running crawler from ${mainUrl}`) - crawlerService.crawl(projectName, mainUrl) + crawlerService.launchCrawl(projectName, mainUrl, saveUrls) + console.log('CRAWLER - Crawler started') + return res.status(202).send() +})) + +/** + * @swagger + * /api/crawl: + * get: + * tags: + * - "URL Configuration" + * summary: "Get URLs crawled" + * description: Get all URLs already crawled for the project + * parameters: + * - name: projectName + * in: query + * description: project name + * required: true + * type: string + * responses: + * 200: + * description: Success. + * 400: + * description: No urls crawled saved. + * 500: + * description: System error. + */ +app.get('/api/crawl', asyncMiddleware(async (req, res, _next) => { + const projectName = req.query.projectName + console.log(`CRAWLER - Retrieve all urls crawled for ${projectName}`) + crawlerService.retrieveCrawledUrl(projectName) .then((results) => { - console.log(`CRAWLER - ${results.length} URL retrieved`) + console.log(`CRAWLER - ${results.length} URLs retrieved for project ${projectName}`) return res.status(200).json(results) }) - .catch(() => { - console.log('CRAWLER - Crawler has encountered an error') - return res.status(500).send() + .catch((error) => { + if (error instanceof SystemError) { + console.log(`CRAWLER - Urls for ${projectName} retrieving has encountered an error`) + return res.status(500).send() + } + console.log(`CRAWLER - No Urls saved for ${projectName}`) + return res.status(400).json(error.message) }) })) @@ -1076,4 +1158,91 @@ app.post('/api/export', asyncMiddleware(async (req, res, _next) => { return res.status(400).json({ error: error.message }) }) })) + +/** + * @swagger + * /api/version: + * get: + * tags: + * - "EcoSonar Infos" + * summary: "Get version of Ecosonar" + * description: Retrieve the version of Ecosonar used. + * responses: + * 200: + * description: Success. + * 400: + * description: EcoSonar version could not be retrieved. + */ +app.get('/api/version', asyncMiddleware(async (_req, res, _next) => { + try { + console.log('GET VERSION - Version of Ecosonar retrieved') + return res.status(200).json({ version: packageJson.version }) + } catch (error) { + console.log('GET VERSION - Version of Ecosonar could not be retrieved') + return res.status(400).json({ error: error.message }) + } +})) + +/** + * @swagger + * /api/best-practices-rules: + * get: + * tags: + * - "EcoSonar Infos" + * summary: "Get all practices documentation" + * description: Retrieve documentation for all best practices in EcoSonar. + * responses: + * 200: + * description: Success. + * 400: + * description: Documentation could not be retrieved. + */ +app.get('/api/best-practices-rules', asyncMiddleware(async (req, res, _next) => { + console.log('GET BEST PRACTICES - Best practices rules to be retrieved') + + bestPracticesServices.getAllBestPracticesRules() + .then((bestPracticesRules) => { + console.log('GET BEST PRACTICES - Best practices rules has been retrieved') + return res.status(200).send(bestPracticesRules) + }) + .catch((error) => { + console.log('GET BEST PRACTICES - Best practices rules could not be retrieved') + return res.status(400).json({ error: error.message }) + }) +})) + +/** + * @swagger + * /api/project: + * delete: + * tags: + * - "URL Configuration" + * summary: "Delete Project " + * description: Delete project and all related urls & analysis + * parameters: + * - name: projectName + * in: query + * description: The name of the project + * required: true + * type: string + * responses: + * 200: + * description: Success. + * 500: + * description: System error. + */ +app.delete('/api/project', asyncMiddleware(async (req, res, _next) => { + const projectName = req.query.projectName + console.log(`DELETE PROJECT - Delete project ${projectName}`) + projectService.deleteProject(projectName) + .then(() => { + console.log(`DELETE PROJECT - Project ${projectName} deletion succeeded`) + return res.status(200).send() + }) + .catch(() => { + console.log(`DELETE PROJECT - Project ${projectName} deletion failed`) + return res.status(500).send() + }) +})) + module.exports = app diff --git a/EcoSonar-API/services/bestPracticesService.js b/EcoSonar-API/services/bestPracticesService.js new file mode 100644 index 0000000..637cf1f --- /dev/null +++ b/EcoSonar-API/services/bestPracticesService.js @@ -0,0 +1,24 @@ +const greenItData = require('../utils/bestPractices/greenItData.json') +const lighthouseAccessibilityData = require('../utils/bestPractices/lighthouseAccessibilityData.json') +const lighthousePerformanceData = require('../utils/bestPractices/lighthousePerformanceData.json') + +class BestPracticesServices { } + +BestPracticesServices.prototype.getAllBestPracticesRules = async function () { + const allBestPracticesRules = { + greenitDocs: {}, + lighthousePerformanceDocs: {}, + lighthouseAccessbilityDocs: {} + } + try { + allBestPracticesRules.greenitDocs = greenItData + allBestPracticesRules.lighthousePerformanceDocs = lighthousePerformanceData + allBestPracticesRules.lighthouseAccessbilityDocs = lighthouseAccessibilityData + return allBestPracticesRules + } catch (error) { + return error + } +} + +const bestPracticesServices = new BestPracticesServices() +module.exports = bestPracticesServices diff --git a/EcoSonar-API/services/crawler/crawlerService.js b/EcoSonar-API/services/crawler/crawlerService.js index 5c34b57..344ae00 100644 --- a/EcoSonar-API/services/crawler/crawlerService.js +++ b/EcoSonar-API/services/crawler/crawlerService.js @@ -2,8 +2,9 @@ const cheerio = require('cheerio') const puppeteer = require('puppeteer') const authenticationService = require('../authenticationService') const urlConfigurationService = require('../urlConfigurationService') +const tempUrlsProjectRepository = require('../../dataBase/tempurlsProjectRepository') -class CrawlerService {} +class CrawlerService { } /** * VARIABLES @@ -18,8 +19,10 @@ let seenUrls * * @param {*} projectName the name of the project * @param {*} mainUrl the main url used to start crawling + * @param {*} savedAsPermanent boolean value that mentions if urls crawled should be saved permanently or temporary + * launch crawling of the website and save the urls crawled according to context */ -CrawlerService.prototype.crawl = async function (projectName, mainUrl) { +CrawlerService.prototype.launchCrawl = async function (projectName, mainUrl, savedAsPermanent) { let crawledUrls = [] let projectUrls = [] seenUrls = [] @@ -49,7 +52,7 @@ CrawlerService.prototype.crawl = async function (projectName, mainUrl) { await authenticationService.loginIfNeeded(browser) await recursiveCrawl(mainUrl, browser, crawledUrls) } catch (error) { - console.log(error) + console.error(error) } finally { browser.close() } // Get all the URL already registered in the project to avoid crawling them again @@ -57,7 +60,7 @@ CrawlerService.prototype.crawl = async function (projectName, mainUrl) { .then((result) => { projectUrls = result }).catch(() => { - console.log(`CRAWLER - Project ${projectName} has 0 url`) + console.log('An error occured when retrieving urls saved to be audited for the project or no urls were saved') }) // Removing mainUrl and aliases from return list if already exist in the project if (projectUrls.includes(mainUrl) || projectUrls.includes(mainUrl + '/') || projectUrls.includes(mainUrl.slice(0, -1)) || crawledUrls.includes(mainUrl + '/')) { @@ -71,7 +74,7 @@ CrawlerService.prototype.crawl = async function (projectName, mainUrl) { crawledUrls = crawledUrls.filter((url) => (!projectUrls.includes(url) && !projectUrls.includes(url + '/') && !projectUrls.includes(url.slice(0, -1)))) - return crawledUrls + saveUrlsCrawled(projectName, crawledUrls, savedAsPermanent) } /** @@ -144,14 +147,66 @@ async function recursiveCrawl (url, browser, crawledUrls) { /** * - * @param {string} link any link found by the scrawler + * @param {string} projectName project name + * @param {string} urlsList list of urls crawled + * @param {string} savedAsPermanent boolean if urls crawled should be saved as temporary or permanent + * Save the urls crawled as temporary or permanent + */ +async function saveUrlsCrawled (projectName, urlsList, savedAsPermanent) { + if (savedAsPermanent) { + urlConfigurationService.insert(projectName, urlsList) + .then(() => { + console.log('CRAWLER - Crawled URLs are saved and added to the project') + }) + .catch((error) => { + console.error(error) + console.error('CRAWLER - Crawled URLs could not be saved') + }) + } else { + let temporaryUrlsAlreadySaved = null + await tempUrlsProjectRepository.findUrls(projectName) + .then((result) => { + temporaryUrlsAlreadySaved = result + }) + .catch((error) => { + console.error(error) + console.error('CRAWLER - Crawled URLs could not be saved') + }) + + if (temporaryUrlsAlreadySaved === null) { + await tempUrlsProjectRepository.create(projectName, urlsList) + .then(() => { + console.log('CRAWLER - Crawled URLs are saved temporary') + }) + .catch((error) => { + console.error(error) + console.error('CRAWLER - Crawled URLs could not be saved temporary') + }) + } else { + temporaryUrlsAlreadySaved = temporaryUrlsAlreadySaved.urlsList + const crawledNotSavedUrls = urlsList.filter(e => !temporaryUrlsAlreadySaved.includes(e)) + const urlsToUpdate = crawledNotSavedUrls.concat(temporaryUrlsAlreadySaved) + await tempUrlsProjectRepository.updateUrls(projectName, urlsToUpdate) + .then(() => { + console.log('CRAWLER - Crawled URLs temporary are updated') + }) + .catch((error) => { + console.error(error.message) + console.error('CRAWLER - Crawled URLs could not be updated temporary') + }) + } + } +} + +/** + * + * @param {string} link any link found by the crawler * @returns a formatted link * Avoid issue with relatives URL by formatting links to be crawled. Ex : given '/about' when crawling, function will construct an usable URL with websiteProtocol and websitePrefix to be : 'https://nameofthewebsite.com/about' */ - CrawlerService.prototype.getUrl = function (link) { // Exclude links that are outside website - if ((link.includes(websiteProtocol) || link.includes(alternativeProtocol)) && link.slice(0, webSitePrefixWithProtocol.length) !== webSitePrefixWithProtocol) { + if ((link.includes(websiteProtocol) || link.includes(alternativeProtocol)) && link.startsWith(webSitePrefixWithProtocol)) { return undefined } else { // If the link is part of the website @@ -183,5 +238,26 @@ CrawlerService.prototype.checkUrl = function (url) { } else return true } +/** + * + * @param {string} projectName project name + * retrieve the temporary urls saved from last crawling in the database for this project + * @returns a list of urls crawled saved + */ +CrawlerService.prototype.retrieveCrawledUrl = async function (projectName) { + return new Promise((resolve, reject) => { + tempUrlsProjectRepository.findUrls(projectName) + .then((result) => { + if (result && result.urlsList.length > 0) { + resolve(result.urlsList) + } else { + reject(new Error('No crawled urls were saved for this project')) + } + }).catch((error) => { + reject(error) + }) + }) +} + const crawlerService = new CrawlerService() module.exports = crawlerService diff --git a/EcoSonar-API/services/loginProxyConfigurationService.js b/EcoSonar-API/services/loginProxyConfigurationService.js index ec88871..ba7bf71 100644 --- a/EcoSonar-API/services/loginProxyConfigurationService.js +++ b/EcoSonar-API/services/loginProxyConfigurationService.js @@ -4,9 +4,10 @@ const retrieveLoginProxyYamlConfigurationService = require('./yamlConfiguration/ class LoginProxyConfigurationService {} -LoginProxyConfigurationService.prototype.insert = async function (projectName, loginCredentials, proxy) { +LoginProxyConfigurationService.prototype.insertLoginCredentials = async function (projectName, loginCredentials) { let projectSettingsRegistered = null let systemError = null + const succesMessage = 'INSERT LOGIN CONFIGURATION - Success' await projectsRepository.getProjectSettings(projectName) .then((projectSettings) => { projectSettingsRegistered = projectSettings @@ -16,17 +17,55 @@ LoginProxyConfigurationService.prototype.insert = async function (projectName, l } }) if (projectSettingsRegistered === null) { - await projectsRepository.createLoginConfiguration(projectName, loginCredentials, proxy) + await projectsRepository.createLoginConfiguration(projectName, loginCredentials) .then(() => { - console.log('INSERT LOGIN - PROXY CONFIGURATION - Success') + console.log(succesMessage) }) .catch(() => { systemError = new SystemError() }) } else { - await projectsRepository.updateLoginConfiguration(projectName, projectSettingsRegistered.procedure, loginCredentials, proxy) + await projectsRepository.updateLoginConfiguration(projectName, projectSettingsRegistered.procedure, loginCredentials) .then(() => { - console.log('UPDATE LOGIN - PROXY CONFIGURATION - Success') + console.log(succesMessage) + }) + .catch(() => { + systemError = new SystemError() + }) + } + return new Promise((resolve, reject) => { + if (systemError !== null) { + reject(systemError) + } else { + resolve() + } + }) +} + +LoginProxyConfigurationService.prototype.insertProxyConfiguration = async function (projectName, proxy) { + let projectSettingsRegistered = null + let systemError = null + const succesMessage = 'INSERT PROXY CONFIGURATION - Success' + await projectsRepository.getProjectSettings(projectName) + .then((projectSettings) => { + projectSettingsRegistered = projectSettings + }).catch((error) => { + if (error instanceof SystemError) { + systemError = new SystemError() + } + }) + if (projectSettingsRegistered === null) { + await projectsRepository.createProxyConfiguration(projectName, proxy) + .then(() => { + console.log(succesMessage) + }) + .catch(() => { + systemError = new SystemError() + }) + } else { + await projectsRepository.updateProxyConfiguration(projectName, projectSettingsRegistered.procedure, proxy) + .then(() => { + console.log(succesMessage) }) .catch(() => { systemError = new SystemError() diff --git a/EcoSonar-API/services/projectService.js b/EcoSonar-API/services/projectService.js index afee04a..bb1d3fe 100644 --- a/EcoSonar-API/services/projectService.js +++ b/EcoSonar-API/services/projectService.js @@ -1,9 +1,15 @@ const SystemError = require('../utils/SystemError') const retrieveAnalysisService = require('../services/retrieveAnalysisService') +const projectsRepository = require('../dataBase/projectsRepository') +const w3cRepository = require('../dataBase/w3cRepository') +const lighthouseRepository = require('../dataBase/lighthouseRepository') +const greenItRepository = require('../dataBase/greenItRepository') +const bestPracticesRepository = require('../dataBase/bestPracticesRepository') +const urlsProjectRepository = require('../dataBase/urlsProjectRepository') +const tempurlsProjectRepository = require('../dataBase/tempurlsProjectRepository') const scores = ['ecoIndex', 'perfScore', 'accessScore', 'w3cScore'] -class ProjectService { -} +class ProjectService { } /** * get an average of all score for all projects of the database of last analysis @@ -23,11 +29,9 @@ ProjectService.prototype.getAllInformationsAverage = async function (date) { resultformatted[scoreType] += result.projects[project][scoreType] scoreNbProject[scoreType] += 1 } - } else { - if (result.projects[project][scoreType] !== null) { - resultformatted[scoreType] = result.projects[project][scoreType] - scoreNbProject[scoreType] = 1 - } + } else if (result.projects[project][scoreType] !== null) { + resultformatted[scoreType] = result.projects[project][scoreType] + scoreNbProject[scoreType] = 1 } } }) @@ -50,9 +54,9 @@ function selectRightAnalysisByDateAndUrl (searchDate, projectsAnalysis, urlField acc[obj[urlFieldName]].push(obj) return acc }, {}) - Object.keys(groupedAnalysisByIdKeys).forEach(UrlAnalysisId => { - const retainedAnalysis = filterPerDate(searchDate, groupedAnalysisByIdKeys[UrlAnalysisId]) - allAnalysisPerUrl[UrlAnalysisId] = retainedAnalysis + Object.keys(groupedAnalysisByIdKeys).forEach(id => { + const retainedAnalysis = filterPerDate(searchDate, groupedAnalysisByIdKeys[id]) + allAnalysisPerUrl[id] = retainedAnalysis }) return allAnalysisPerUrl } @@ -247,16 +251,52 @@ ProjectService.prototype.getAllProjectInformations = async function (date, sortB } }) } else { - return new Promise((_resolve, reject) => { - reject(new Error(error)) - }) + return Promise.reject(new Error(error)) } } else { - return new Promise((_resolve, reject) => { - reject(new Error(error)) - }) + return Promise.reject(new Error(error)) } } +/** + * Delete all part the project (project, urls and analysis) + * @param {string} projectName name of the project to delete + */ +ProjectService.prototype.deleteProject = async function (projectName) { + let urlsProjects = [] + let systemError = false + try { + await urlsProjectRepository.findAll(projectName, true) + .then((result) => { + urlsProjects = result.map((e) => e.idKey) + }) + } catch (error) { + console.error('\x1b[31m%s\x1b[0m', error.message) + systemError = true + } + if (systemError) { + Promise.reject(new SystemError()) + } + try { + await lighthouseRepository.deleteProject(urlsProjects) + await greenItRepository.deleteProject(urlsProjects) + await w3cRepository.deleteProject(urlsProjects) + await bestPracticesRepository.deleteProject(urlsProjects) + await urlsProjectRepository.deleteProject(urlsProjects) + await tempurlsProjectRepository.deleteProject(projectName) + await projectsRepository.deleteProjectPerProjectName(projectName) + } catch (error) { + console.error('\x1b[31m%s\x1b[0m', error.message) + systemError = true + } + return new Promise((resolve, reject) => { + if (systemError) { + reject(new SystemError()) + } else { + resolve() + } + }) +} + const projectService = new ProjectService() module.exports = projectService diff --git a/EcoSonar-API/services/urlConfigurationService.js b/EcoSonar-API/services/urlConfigurationService.js index a12c299..037a1c9 100644 --- a/EcoSonar-API/services/urlConfigurationService.js +++ b/EcoSonar-API/services/urlConfigurationService.js @@ -1,17 +1,29 @@ +const tempUrlsProjectRepository = require('../dataBase/tempurlsProjectRepository') const urlsProjectRepository = require('../dataBase/urlsProjectRepository') const SystemError = require('../utils/SystemError') class UrlConfigurationService { } + +/** + * @param {String} projectName is the name of the project + * Retrieve the urls saved for the project (those who will be audited when running an analysis) + * @return list of urls saved + * @return list of errors (duplication or validation) + */ UrlConfigurationService.prototype.getAll = function (projectName) { return new Promise((resolve, reject) => { - urlsProjectRepository.findAll(projectName, false).then((resultats) => { - if (resultats.length === 0) { - reject(new Error('Your project has no url assigned into EcoSonar. You must at least add one url if you want to analyse ecodesign practices.')) - } - const resultatsFormatted = resultats.map((res) => res.urlName) - resolve(resultatsFormatted) - }) + urlsProjectRepository.findAll(projectName, false) + .then((results) => { + if (results.length === 0) { + reject(new Error('Your project has no url assigned into EcoSonar. You must at least add one url if you want to analyse ecodesign practices.')) + } + const resultatsFormatted = results.map((res) => res.urlName) + resolve(resultatsFormatted) + }) + .catch((error) => { + reject(error) + }) } ) } @@ -22,17 +34,18 @@ UrlConfigurationService.prototype.getAll = function (projectName) { * This function will do 2 checks : * 1 - Verify into database if URL isn't already registered * 2- Verify that every URLs in the list is different + * 3- Insert into database + * 4- Remove crawled urls that have been saved * Later a check about syntax is made (using REGEX) * URLs are trimmed to avoid issues with copy-paste adding whitespace and tab charactes * @reject in case of error, the function reject error type and description */ - UrlConfigurationService.prototype.insert = async function (projectName, urlList) { // Initializing parameters - const notInsertedArray = [] - const errorArray = [] + let systemError = false - let urlAlreadyAddedInProject + let urlAlreadyAddedInProject = [] + let errorRegexp = [] // Retrieving URLs in database for project await urlsProjectRepository.findAll(projectName, true) .then((urlListResult) => { urlAlreadyAddedInProject = urlListResult.map((res) => res.urlName) }) @@ -42,6 +55,41 @@ UrlConfigurationService.prototype.insert = async function (projectName, urlList) } }) + const { errorArray, notInsertedArray } = verifyNoDuplication(urlList, urlAlreadyAddedInProject) + + if (notInsertedArray.length === 0 && !systemError) { + urlsProjectRepository.insertAll(projectName, urlList) + .catch((error) => { + if (error instanceof SystemError) { + systemError = true + } + errorRegexp = error + }) + } + + if (notInsertedArray.length === 0 && !systemError && errorRegexp.length === 0) { + systemError = await removeTemporaryUrlsThatWereSaved(projectName, urlList) + } + + return new Promise((resolve, reject) => { + if (notInsertedArray.length > 0) { + console.log('URL CONFIGURATION SERVICE - Some urls are duplicated') + reject(errorArray) + } else if (errorRegexp.length > 0) { + console.log('URL CONFIGURATION SERVICE - Some urls are invalid') + reject(errorRegexp) + } else if (systemError) { + console.log('URL CONFIGURATION SERVICE - An error occured when reaching the database') + reject(new SystemError()) + } else { + resolve() + } + }) +} + +function verifyNoDuplication (urlList, urlAlreadyAddedInProject) { + const errorArray = [] + const notInsertedArray = [] let index = 0 while (index < urlList.length) { const newList = urlList.filter((url) => url.trim() === urlList[index].trim()) @@ -53,20 +101,35 @@ UrlConfigurationService.prototype.insert = async function (projectName, urlList) } index++ } + return { errorArray, notInsertedArray } +} - return new Promise((resolve, reject) => { - if (notInsertedArray.length === 0 && !systemError) { - urlsProjectRepository.insertAll(projectName, urlList) - .then(() => resolve()) - .catch((error) => { reject(error) }) - } else if (systemError) { - reject(new SystemError()) - } else { - reject(errorArray) - } - }) +async function removeTemporaryUrlsThatWereSaved (projectName, urlList) { + // Retrieved all urls crawled to remove saved urls + let systemError = false + await tempUrlsProjectRepository.findUrls(projectName) + .then((crawledList) => { + const urlsCrawledList = crawledList ? crawledList.urlsList : [] + if (urlsCrawledList.length > 0) { + // remove urls that were saved previously in the temporary url list + const crawledNotSaved = urlsCrawledList.filter(e => !urlList.includes(e)) + tempUrlsProjectRepository.updateUrls(projectName, crawledNotSaved) + .catch(() => { + systemError = true + }) + } + }) + .catch(() => { + systemError = true + }) + return systemError } +/** + * @param {String} projectName is the name of the project + * @param {String} urlName is the url in the project to be deleted + * Delete a url into a project + */ UrlConfigurationService.prototype.delete = async function (projectName, urlName) { return new Promise((resolve, reject) => { urlsProjectRepository.delete(projectName, urlName) diff --git a/EcoSonar-API/utils/bestPractices/greenItData.json b/EcoSonar-API/utils/bestPractices/greenItData.json new file mode 100644 index 0000000..80e8b45 --- /dev/null +++ b/EcoSonar-API/utils/bestPractices/greenItData.json @@ -0,0 +1,146 @@ +{ + "addExpiresOrCacheControlHeaders": { + "title": "Add Expires or Cache-Control HTTP Headers", + "description": "You should reach 100% of resources cached.", + "correction": "The Expires and Cache-Control headers determine how long a browser should keep a resource in its cache. You should therefore use them, and configure them correctly for CSS style sheets, JavaScript scripts and images. Ideally, these elements should be kept as long as possible so that the browser does not request them again from the server. This saves HTTP requests, bandwidth and CPU power server-side.Here is a configuration example for Expires and Cache-Control headers for the Apache web server:
<IfModule mod_headers.c>
    <FilesMatch "\.(ico|jpe?g|png|gif|swf|css|gz)$">
        Header set Cache-Control "max-age=2592000, public"
    </FilesMatch>
    <FilesMatch  "\.(html|htm)$">
       Header set Cache-Control "max-age=7200, public"
    </FilesMatch>
 </IfModule>
Government Regulation: RGESN 6.3 : Does the digital service use caching mechanisms for all transferred content under its control? See : Cache Header Cache-Control HeadersExpires Headers", + "titleData": "{0}% of resources cached" + }, + "compressHttp": { + "title": "Compress ressources", + "description": "To get an A score, reach 100 % of compression ratio.", + "correction": "You can compress the content of HTML pages to minimize bandwidth consumption between the client and the server. All modern browsers (for smartphones, tablets, notebook and desktop computers) accept HTML compressed via gzip or Deflate. The easiest way to do so is to configure the web server so that it compresses the HTML data stream, either on-the-fly or automatically, as it leaves the server. This practice (on-the-fly compression) is only beneficial for a HTML data stream as it is constantly evolving. When possible, we recommend that you manually compress static resources (e.g. CSS and JavaScript libraries) all in one go. With Apache, the Deflate and gzip compression methods offer considerable savings. A typical 26 KB HTML file is reduced to 6 KB after being compressed with gzip. If your frontend framework is one of the following: React / Angular / Vue.js If your front-end framework is React Government Regulation; RGESN 6.4 : Has the digital service implemented compression techniques on all transferred resources under its control? See : Http Compress How to compress HTML code ?", + "titleData": "{0}% of resources compressed" + }, + "domainsNumber": { + "title": "Limit the number of domains", + "description": "You should limit the number of domains to 3 per page.", + "correction": " When a website or online service hosts a web page's components across several domains, the browser must establish an HTTP connection with every single one. Once the HTML page has been retrieved, the browser calls the sources as it traverses the DOM (Document Object Model). Some resources are essential for the page to work. If they are hosted on another domain which is slow, it may increase the page's render time. You should therefore, when possible, group all resources on a single domain. The only exception to this is for static resources (style sheets, images, etc.), which should be hosted on a separate domain to avoid sending one or multiple cookies for each browser GET HTTP request. This reduces response time and unnecessary bandwidth consumption. For a corporate website with heavy traffic, it is better to have two domains: - the application server at www.domain.tld - the cookieless media server at media.domain.tld By doing so, you minimize the number of domains while also avoiding unnecessarily sending a cookie for each GET HTTP request for a static resource. Best practices n°82 from '115 bonnes pratiques d'écoconception web v4' See : What is a domain number and how does it works Minimize the number of domains ", + "titleData": "{0} domain(s) found per page in average" + }, + "dontResizeImageInBrowser": { + "title": "Don't resize image in browser", + "description": "There should be no image resized in browser in your web application. You are resizing an image if you are using the attributes HEIGHT and WIDTH in the HTML tag of the image.", + "correction": "Do not resize images using HTML height and width attributes. Doing so sends images in their original size, wasting bandwidth and CPU power. A PNG-24 350 x 300 px image is 41 KB. If you resized the same image file using HTML and displayed it as a 70 x 60 px thumbnail, it would still be 41 KB, when it should be no more than 3 KB! Meaning 38 KB downloaded for nothing. The best solution is to resize images using software such as Photoshop, without using HTML. When content added by the website's users has no specific added value, it is best to prevent them from being able to insert images using a WYSIWYG editor e.g., CKEditor. Non Compliant : ”loading Compliant : ”loading Government Regulation: RGESN 5.2 Does the digital service offer image content whose level of compression is appropriate for the content and viewing context?See : How to resize image outside the browser ", + "titleData": "{0} image(s) resized in browser found in the whole project" + }, + "emptySrcTag": { + "title": "Avoid empty src tag", + "description": "You should have no empty src tags.", + "correction": "If there is an image tag with an empty src attribute, the browser will call the directory in which the page is located, generating unnecessary, additional HTTP requests.The following image tag will request the foo directory's index file from the server: ”” for a page located at: http://domain.tld/foo/bar.htmlSee : Delete image tags with empty src attributes", + "titleData": "{0} empty src tags found in the whole project" + }, + "externalizeCss": { + "title": "Externalize css", + "description": "You should reach 0 inline stylesheets.", + "correction": "Ensure that CSS files and JavaScript code are separate from the page's HTML code, except for any configuration variables for JavaScript objects. If you include CSS or JavaScript code in the body of the HTML file, and it is used for several pages (or even the whole website), then the code must be sent for each page requested by the user, therefore increasing the volume of data sent. However, if the CSS and JavaScript code are in their own separate files, the browser can avoid requesting them again by storing them in its local cache.
Non compliant :
<style type=\"text/css\" media=\"screen\"> p { color: #333, margin: 2px 0 }/* All the website's CSS declarations */ </style>
Compliant :
<link href=\"css/styles.css\" rel=\"stylesheet\">Best practices n°42 from '115 bonnes pratiques d'écoconception web v4' See : Externalize CSS files How to create a css external stylesheet", + "titleData": "{0} inline stylesheet(s) found in the whole project" + }, + "externalizeJs": { + "title": "Externalize js", + "description": "You should have no inline JavaScript script in HTML code.", + "correction": "Ensure that JavaScript code is separate from the page's HTML code, except for any configuration variables for JavaScript objects. If you include JavaScript code in the body of the HTML file, and it is used for several pages (or even the whole website), then the code must be sent for each page requested by the user, therefore increasing the volume of data sent. However, if the JavaScript code is in his own separate file, the browser can avoid requesting them again by storing them in its local cache.
Non Compliant :
File 1 Avoid using script directly into HTML : <script type=\"\"text\/javascript\"\"> alert(\"\"Hello Jean ! \"\") <\/script><button onclick=alert('Hello Jeanne')>Say Hello Jeanne</button>
Compliant :
Instead use a JavaScript file where the function is defined : script: function sayHello(name) { alert(\"\"Hello\"\" + name +\"\" ! \"\")}<script type=\"\"text\/javascript\"\">sayHello(Jean)<\/script>Best practices n°42 from '115 bonnes pratiques d'écoconception web v4'See : Externalize JS Files Externalize JavaScript Files", + "titleData": "{0} inline javascripts found in the whole project" + }, + "httpError": { + "title": "Avoid HTTP request errors", + "description": "You should not have HTTP errors when loading your pages.", + "correction": "Requests with HTTP errors consume resources unnecessarily.Best practices n°89 from '115 bonnes pratiques d'écoconception web v4' See : How to troubleshoot common http error code", + "titleData": "{0} HTTP error(s) in the whole project" + }, + "httpRequests": { + "title": "Limit the number of HTTP requests", + "description": "A page's download time client-side directly correlates to the number and size of files the browser must download. You should not have more than 25 requests to load one page of your application.", + "correction": "For each file, the browser sends a GET HTTP to the server. It waits for the response, and then downloads the resource as soon as it is available. Depending on the type of web server you use, the more requests per page there are, the fewer pages the server can handle. Reducing the number of requests per page is key to reducing the number of HTTP servers needed to run the website, and consequently its environmental impact.There are several ways to reduce the number of requests per page: - Combine static files e.g., CSS and JavaScript libraries - Use a CSS sprite to group the interface's images - Favor glyphs over images and, in general, vectors over bitmaps. - Fill in the browser cache as much as possible.Potential saving: reduced server load, thus minimizing the economic and environmental footprint by reducing the amount of equipment needed (from HTTP servers to application servers and RDBMS).Best practices n°47 from '115 bonnes pratiques d'écoconception web v4'Government Regulation: RGESN 6.2 : Does the digital service have a limit of requests per screen? See : Limit HTTP Requests", + "titleData": "{0} HTTP request(s) on average" + }, + "imageDownloadedNotDisplayed": { + "title": "Do not download unecessary image", + "description": "You should not request images from the server if they are not going to be displayed in your web application.", + "correction": "Downloading images that will not necessarily be visible consumes resources unnecessarily. For example, images that are displayed only after a user action.Government Regulation: RGESN 5.2 Does the digital service offer image content whose level of compression is appropriate for the content and viewing context?", + "titleData": "{0} image(s) downloaded but not displayed in the whole project" + }, + "jsValidate": { + "title": "Validate js", + "description": "You shouldn't have JavaScript errors when launching your web application.", + "correction": "JSLint is a JavaScript code quality tool that checks that the JavaScript syntax used will be understood by all browsers. The code produced thus complies with coding rules which enables interpreters to quickly and easily run the code. The CPU is therefore used for a shorter time.Install eslint to analyse your code npm install eslint --save-dev or yarn add -D eslintOnce installed, you can launch eslint project configuration npx eslint --initThe command prompt will guide you through the linter configuration adapted to your projet. The file name .eslintrc defines the linter configuration and can be modified according to your requirement.To launch the linter analysis : eslint --ext .js .To let the linter fix issues automatically :eslint --fix --ext .js .Best practices n°82 from '115 bonnes pratiques d'écoconception web v4'See : Check JavaScript code", + "titleData": "{0} JavaScript error(s) found in the whole project" + }, + "maxCookiesLength": { + "title": "Max cookies length", + "description": "Maximum size of your cookies should be the smallest possible as it is sent with each request. Your cookies should not be longer than 512 bytes.", + "correction": "A cookie makes it possible to maintain a state between the internet user's browser and the remote web server thanks to identifiers. This text file is transferred in each http request. It is therefore necessary to optimize its size as much as possible and delete it as soon as its presence is no longer mandatory. You can automatically delete a cookie when it is no longer useful, by specifying an expiry date, as follows: Set-Cookie: user_myvariable=myvalue; expires=Wed, 12 Dec 2012 07:40:20 UTC See : Using HTTP cookies ", + "titleData": "Max cookies length = {0} Bytes, in the whole project" + }, + "minifiedCss": { + "title": "Minified css", + "description": "You should reach 100% of your CSS files minified.", + "correction": "You can use the Yahoo's YUI Compressor specialized filters to :- remove comments and white spaces - remove the last semi-colon - remove extra semi-colons - remove empty declarations - remove units of measure when using 0 values and reduce multiple 0s into one - remove 0 for values less than 1 - convert RGB colors into hex values and reduce 6-digit hex values to 3-digit values - remove extra charsets - optimize the alpha layer's opacity values in Internet Explorer - replace none with 0Government Regulation: RGESN 6.4 : Has the digital service implemented compression techniques on all transferred resources under its control? See : CSS Minification ", + "titleData": "{0}% of minified stylesheet" + }, + "minifiedJs": { + "title": "Minified js", + "description": "You should reach 100% of your JS files minified.", + "correction": "Use a tool such as YUI Compressor to :- remove unnecessary white spaces - remove unnecessary line breaks - remove unnecessary semi-colons - shorten local variable names This operation can be automated using Google Apache speed moduleA standard 248 KB JavaScript file will be 97KB after being minifiedGovernment Regulation: RGESN 6.4 : Has the digital service implemented compression techniques on all transferred resources under its control?See : JavaScript minification ", + "titleData": "{0}% of minified JavaScript" + }, + "noCookieForStaticRessources": { + "title": "No cookie for static ressources", + "description": "You should have 0 static resources with cookies.", + "correction": "Images, CSS stylesheets, and JavaScript files must be hosted on a cookie-free domain. This prevents the browser from sending a cookie for each resource ... when it is unnecessary. Indeed, although transferred in each http request, the cookie is useless for static content, since it is used to maintain a state between the Internet user's browser and the remote application server thanks to the identifiers contained in the text file.. It is therefore preferable to store this type of content on a specific domain name, for example static.domainname.com. For static resources, a cookie is unnecessary, so it unnecessarily consumes bandwidth. To avoid this, we can use a different domain for static resources or restrict the scope of cookies created. Web Giants are using a dedicated domain to serve static ressources which does not require cookies. For example, Yahoo! uses the domain called yimg.com, Youtube ytimg.com and Amaon images-amazon.comGovernment Regulation: RGESN 6.11 : Does the digital service host the transferred static resources of which it is the issuer on the same domain?See : Serve static content from a cookieless domain. Why do you need a cookie-less domain", + "titleData": "{0} static ressource(s) with cookie in the whole project" + }, + "noRedirect": { + "title": "Avoid redirect", + "description": "Redirections should be avoided as much as possible as they slow down response and drain resources unnecessarily.", + "correction": "These redirections can take place on various levels: HTML code, JavaScript code, HTTP server and application server. Best practices n°112 from '115 bonnes pratiques d'écoconception web v4' See : Avoid redirections Avoid multiple page redirects", + "titleData": "{0} redirect in the whole project" + }, + "optimizeBitmapImages": { + "title": "Optimize bitmap images", + "description": "You should optimize all your bitmap images.", + "correction": "The first step is to choose the correct format between bitmap (e.g., JPEG, PNG & GIF) and vector (SVG). Bitmaps should only be used for photos and interface elements that are not possible though icons or CSS styling.The choice of bitmap format depends on the image's characteristics: black and white or color, color palette, need for transparency, etc. For these characteristics, the ability to use lossy compression on the image is more suited to JPEG and WebP (Google); while the need for transparency and/or lossless compression is more suited to GIF or PNG.Tools such as pngcrush, ImageMagick and jpegtran will help you reduce the size of images as much as possible.Potential saving: At least 25% saved by fine-tuning the color palette and the compression ratio, and up to over 80% compared to a uncompressed bitmap. WebP is on average 30% smaller than JPEG.Government Regulation: RGESN 5.2 Does the digital service offer image content whose level of compression is appropriate for the content and viewing context? See : Optimize Bitmap images", + "titleData": "{0} bitmap image to optimize in the whole project" + }, + "optimizeSvg": { + "title": "Optimize svg images", + "description": "All SVG images added into your web application should be optimized.", + "correction": "Svg images are less heavy than bitmap images, nevertheless they can be optimized and minified via tools (for example, svgo).Government Regulation: RGESN 5.2 Does the digital service offer image content whose level of compression is appropriate for the content and viewing context? See : Tools for optimizing SVG", + "titleData": "{0} images to optimize in the whole project" + }, + "plugins": { + "title": "Do not use plugins", + "description": "You should use no plugin in your web application if possible.", + "correction": "Avoid using plugins (Flash Player, Java and Silverlight virtual machines, etc.) because they can be a heavy drain on resources (CPU and RAM).This is especially true with Adobe's Flash Player, to such an extent that Apple decided to not install the technology on its mobile devices to maximize battery life. Favor standard technology such as HTML5 and ECMAScript. See : Limit plugins ", + "titleData": "{0} plugin found in the whole project" + }, + "printStyleSheet": { + "title": "Provide print stylesheet", + "description": "Each of your pages should have at least one print style sheet to get an A Score.", + "correction": "In addition to the benefits for the user, this style sheet reduces the number of pages printed, and therefore indirectly minimizes the website's ecological footprint. It should be as streamlined as possible and employ an ink-light typeface e.g., Century Gothic. Also consider hiding the header, footer, menu and sidebar, as well as deleting all images except those needed for content. This print style sheet makes for a cleaner print by trimming down what is displayed on the screen. Compliant : Best practices n°31 from '115 bonnes pratiques d'écoconception web v4' See : Print Stylesheet CSS Printer Friendly Pages. How to set up a print stylesheet Print stylesheet guide", + "titleData": "{0} print stylesheet found in the whole project" + }, + "socialNetworkButton": { + "title": "Do not use standards social button", + "description": "You should not use social media buttons.", + "correction": "Social Network like Facebook, Twitter, Pinterest gives plugins to install on web page to get a share button and a like counter. These plugins consume unnecessary resources, it's better to put direct links.Best practices n°59 from '115 bonnes pratiques d'écoconception web v4'", + "titleData": "{0} standard(s) social button(s) found in the whole project" + }, + "styleSheets": { + "title": "Limit Stylesheet files", + "description": "You should have at most 2 stylesheets per page.", + "correction": "Minimize the number of CSS files to reduce the number of HTTP requests. If several style sheets are used on all the website's pages, concatenate them into one single file.Some CMS and frameworks offer ways to do such optimization automatically. The HTTP server can also be configured to compress and reduce the size of style sheets.With the Apache web server, simply add the following line in the .htaccess configuration file:# compress css:AddOutputFilterByType DEFLATE text/cssThis instruction activates the Deflate mode which compresses all the style sheets between the server and the HTTP client. Learn more about DeflateBest practices n°35 from '115 bonnes pratiques d'écoconception web v4'", + "titleData": "{0} stylesheet(s) found on average" + }, + "useETags": { + "title": "Use ETags", + "description": "ETags limit the number of server requests and avoid unnecessary use of bandwidth. At least 95 % of your resources should have ETags to have a B Score.", + "correction": "An ETag is a signature attached to a server response. If the client requests a URL (HTML page, image, style sheet, etc.) whose ETag is identical to the one it already has, the web server will reply that it does not need to download the resource and that it should use the one it already possesses. Using ETags saves huge amounts of bandwidth.Refer to the File Etag documentation for Apache: Apache documentation on EtagSee : ETags Use ETags Header", + "titleData": "{0}% of resources with ETags " + }, + "useStandardTypefaces": { + "title": "Use Standard Typefaces", + "description": "You should reduce the size of custom fonts used.", + "correction": "Use standard typefaces as they already exist on the user's computer, and therefore do not need to be downloaded. This saves bandwidth and improves the website's render time. When possible, use typefaces such as : Courrier New Georgia Arial Comic Impact Tahoma Trebuchet MS Times New Roman Verdana Segoe UI Best practices n°32 from '115 bonnes pratiques d'écoconception web v4' See : Use standard typefaces List of typeface included with MacOS X Revised Font Stack", + "titleData": "{0} KB custom fonts found in the whole project" + } +} \ No newline at end of file diff --git a/EcoSonar-API/utils/bestPractices/lighthouseAccessibilityData.json b/EcoSonar-API/utils/bestPractices/lighthouseAccessibilityData.json new file mode 100644 index 0000000..070391e --- /dev/null +++ b/EcoSonar-API/utils/bestPractices/lighthouseAccessibilityData.json @@ -0,0 +1,272 @@ +{ + "ariaAllowedAttr": { + "title": "`[aria-*]` attributes match their roles", + "description": "Lighthouse flags mismatches between ARIA roles and aria-* attributes.", + "correction": "Each ARIA `role` supports a specific subset of `aria-*` attributes. Mismatching these invalidates the `aria-*` attributes. An ARIA role attribute can be added to an element to instruct assistive technologies to treat the element as something other than its native HTML element type. For example, an < a > element with role='button' is to be treated as a button, not a link.Some ARIA property and state attributes are allowed only for certain ARIA roles. When an assistive technology encounters a mismatch between an element's role and its state or property attributes, it might ignore attributes or respond in an unexpected way. As a result, people who use assistive technologies might find the element difficult or impossible to use. See : [aria-*] attributes do not match their roles aria-allowed-attr", + "titleData": "{0} attribute(s) do not match their roles" + }, + "ariaCommandName": { + "title": "`button`, `link`, and `menuitem` elements have accessible names", + "description": "Lighthouse flags custom ARIA items whose names aren't accessible to assistive technologies.", + "correction": "When an element doesn't have an accessible name, screen readers announce it with a generic name, making it unusable for users who rely on screen readers. ARIA buttons, links, and menuitems are custom controls corresponding respectively to HTML < button >, < a >, and < menuitem > elements. An accessible name is a word or phrase coded in a way that assistive technologies can associate it with a specific user interface object. Assistive technologies can then refer to the object by name, not just by type. When an ARIA button, link, or menuitem doesn't an accessible name, people who use assistive technologies have no way of knowing its purpose. See :ARIA items do not have accessible names", + "titleData": "{0} element(s) have no accessible name" + }, + "ariaHiddenBody": { + "title": "`[aria-hidden=\"true\"]` is not present on the document ``", + "description": "Lighthouse flags pages whose element has an aria-hidden='true' attribute.", + "correction": "Assistive technologies, like screen readers, work inconsistently when `aria-hidden='true'` is set on the document `< body >`. In some browsers, the attribute aria-hidden='true' hides an element and all its children from assistive technologies. Users can still use the keyboard to navigate to any focusable child elements in the , but their content is inaccessible to people who use assistive technologies. For example, screen readers are silent. See :[aria-hidden='true'] is present on the document aria-hidden-body", + "titleData": "{0} element(s) have an hidden body" + }, + "ariaHiddenFocus": { + "title": "`[aria-hidden=\"true\"]` elements do not contain focusable descendents", + "description": "Lighthouse flags focusable elements that have parents with the aria-hidden='true' attribute.", + "correction": "Focusable descendents within an `[aria-hidden='true']` element prevent those interactive elements from being available to users of assistive technologies like screen readers. In some browsers, the attribute aria-hidden='true' hides an element and all its children from assistive technologies. Users can still use the keyboard to navigate to any focusable child elements, but their content is inaccessible to people who use assistive technologies. For example, screen readers are silent. (An element is focusable if it can receive input focus via scripting, mouse interaction, or keyboard tabbing.) See :[aria-hidden='true'] elements contain focusable descendants aria-hidden-focus", + "titleData": "{0} element(s) contain focusable descendents" + }, + "ariaRequiredAttr": { + "title": "`[role]`s have all required `[aria-*]` attributes", + "description": "Lighthouse flags ARIA roles that don't have the required states and properties.", + "correction": " Some ARIA roles have required attributes that describe the state of the element to screen readers. See : [role]s do not have all required [aria-*] attributes aria-required-attr", + "titleData": "{0} element(s) have no required attribute" + }, + "ariaRoles": { + "title": "`[role]` values are valid", + "description": "Lighthouse flags ARIA roles with invalid values.", + "correction":"An ARIA role attribute can be added to an element to instruct assistive technologies to treat the element as something other than its native HTML element type. For example, an < a > element with role='button' will be treated as a button, not as a link.When an assistive technology encounters an element whose role attribute has an invalid value, it might ignore the element or respond to it in an unexpected way. As a result, people who use assistive technologies might find the element difficult or impossible to detect or use.See : [role] values are not valid aria-roles", + "titleData": "{0} [role] value(s) are not valid" + }, + "ariaValidAttrValue": { + "title": "`[aria-*]` attributes have valid values", + "description": "Lighthouse flags ARIA attributes with invalid values.", + "correction": "When an assistive technology encounters an element with an invalid ARIA attribute value, it might ignore the attribute or respond to it in an unexpected way.As a result, people who use assistive technologies might find the element difficult or impossible to use.See : [aria-*] attributes do not have valid values aria-valid-attr-value", + "titleData": "{0} [aria-*] attribute(s) are not valid" + }, + "ariaValidAttr": { + "title": "`[aria-*]` attributes are valid and not misspelled", + "description": "Lighthouse flags invalid ARIA attributes.", + "correction": "When an assistive technology encounters an element with an invalid ARIA attribute name, it might ignore the attribute or respond to it in an unexpected way. As a result, people who use assistive technologies might find the element difficult or impossible to use.See : [aria-*] attributes are not valid or misspelled aria-valid-attr", + "titleData": "{0} [aria-*] attribute(s) are not valid or misspelled" + }, + "bypass": { + "title": "The page contains a heading, skip link, or landmark region", + "description": "Lighthouse flags pages that don't provide a way to skip repetitive content.", + "correction": "Web pages typically begin with blocks of content that repeat across multiple pages, such as banners and site navigation menus. A person who uses a mouse can visually skim past that repeated content and access a link or other control within the primary content with a single click.Similarly, a bypass mechanism allows keyboard users to navigate directly to the page's main content. Otherwise, reaching the primary content could require dozens of keystrokes. People with limited mobility could find this task difficult or painful, and people who use screen readers could find it tedious to listen as each repeated element is announced.See : The page does not contain a heading, skip link, or landmark region bypass", + "titleData": "At least one of the page does not contain a heading, skip link or landmark region", + "titleDataSuccess": "All pages contain a heading, skip line or landmark region" + }, + "colorContrast": { + "title": "Background and foreground colors don't have a sufficient contrast ratio.", + "description": "Lighthouse flags text whose background and foreground colors don't have a sufficiently high contrast ratio.", + "correction": "Most people find it easier to read text when it has a sufficiently high contrast against its background. People with visual disabilities, low vision, limited color perception, or presbyopia are likely to find text unreadable when contrast is too low.See : Background and foreground colors do not have a sufficient contrast ratio color-contrast", + "titleData": "At least one page has background and foreground colors do not have a sufficient contrast ratio", + "titleDataSuccess": "Background and foreground colors have a sufficient contrast ratio" + }, + "documentTitle": { + "title": "Document has a `` element", + "description": "Lighthouse flags pages without a <title> element in the page's <head>.", + "correction": "Typically, the first thing a user learns about a web page is its title. The title is displayed in the browser tab and in search engine results, and it's announced by assistive technologies as soon as a user navigates to a page. A descriptive page title helps everyone, especially users of assistive technologies, determine whether a page contains information relevant to their current needs.See : Document doesn't have a title element document-title", + "titleData": "{0} page(s) do not have a <title> element" + }, + "duplicateIdActive": { + "title": "`[id]` attributes on active, focusable elements are unique", + "description": "Lighthouse flags focusable elements that have duplicate ids.", + "correction": "When multiple active, focusable elements share the same id attribute, both scripting (such as JavaScript) and assistive technologies are likely to act only on the first and ignore the others. As a consequence, both functionality and accessibility can be degraded. (An element is focusable if it can receive input focus via scripting, mouse interaction, or keyboard tabbing. It's active if it is not marked as disabled.)See :[id] attributes on active, focusable elements are not unique duplicate-id-active", + "titleData": "{0} [id] attribute(s) on active, focusable elements are not unique" + }, + "duplicateIdAria": { + "title": "ARIA IDs are unique", + "description": "Lighthouse flags elements that share an ID referred to by another element's aria-labelledby attribute.", + "correction": "Labels and ARIA relationship attributes (such as aria-controls, aria-labelledby, and aria-owns) depend on unique id values to identify specific UI components. When multiple elements in a web page share the same id value, assistive technologies are likely to recognize only the first, and ignore others.See : ARIA IDs are not unique duplicate-id-aria", + "titleData": "{0} ARIA id(s) are not unique" + }, + "headingOrder": { + "title": "Heading elements appear in a sequentially-descending order", + "description": "Lighthouse flags pages whose headings skip one or more levels.", + "correction": "Properly ordered headings that do not skip levels convey the semantic structure of the page, making it easier to navigate and understand when using assistive technologies. See : Heading elements are not in a sequentially-descending order", + "titleData": "{0} heading element(s) are not in a sequentially-descending order" + }, + "htmlHasLang": { + "title": "`<html>` element has a `[lang]` attribute", + "description": "Lighthouse flags pages whose <html> element doesn't have a lang attribute.", + "correction": "When a web page's primary language is programmatically identified, browsers and assistive technologies can render the text more accurately; screen readers can use the correct pronunciation; visual browsers can display the correct characters; media players can show captions correctly; and automated translation is enabled.All users find it easier to understand the page's content.See : <html> element does not have a [lang] attribute html-has-lang", + "titleData": "{0} <html> element(s) does not have a [lang] attribute" + }, + "htmlLangValid": { + "title": "`<html>` element has a valid value for its `[lang]` attribute", + "description": "Lighthouse flags pages whose <html> element doesn't have a valid value for its lang attribute.", + "correction": "When a web page's primary language is programmatically identified, browsers and assistive technologies can render the text more accurately; screen readers can use the correct pronunciation; visual browsers can display the correct characters; media players can show captions correctly; and automated translation is enabled.All users find it easier to understand the page's content.See :<html> element does not have a valid value for its [lang] attribute html-lang-valid", + "titleData": "{0} <html> element(s) does not have a valid value for its [lang] attribute" + }, + "imageAlt": { + "title": "Image elements have `[alt]` attributes", + "description": "Lighthouse flags <img> elements that don't have alt attributes.", + "correction": "Because assistive technologies can't interpret an image directly, they rely on alternative text to communicate the image's meaning to users. If an image has (non-empty) alternative text, the image is identified as meaningful, and its alternative text is presented to the user. If an image has an empty alt attribute, the image is identified as decorative and ignored. If an image has no alternative text at all, the image is presumed to be meaningful, and its filename is likely to be presented to the user.See : Image elements do not have [alt] attributes image-alt", + "titleData": "{0} image element(s) do not have [alt] attributes" + }, + "label": { + "title": "Form elements have associated labels", + "description": "Lighthouse flags form elements that don't have associated labels.", + "correction": "A form control is an interactive HTML element used for user input. Form controls include buttons, checkboxes, text fields, color pickers, and more.An accessible name is a word or phrase coded in a way that assistive technologies can associate it with a specific user interface object. Assistive technologies can then refer to the object by its name, not just by type (role).When a form control doesn't have an accessible name, people who use assistive technologies have no way of knowing its specific purpose.See : Form elements do not have associated labels label", + "titleData": "{0} element(s) have no associated labels" + }, + "linkName": { + "title": "Links have a discernible name", + "description": "Lighthouse flags links that don't have discernible names.", + "correction": "An accessible name is a word or phrase coded in a way that assistive technologies can associate it with a specific user interface object. Assistive technologies can then refer to the object by name, not just by type. When a link doesn't have an accessible name, people who use assistive technologies have no way of knowing its purpose.See : Links do not have a discernible name link-name", + "titleData": "{0} link(s) do not have a discernible name" + }, + "list": { + "title": "Lists contain only `<li>` elements and script supporting elements", + "description": "Lighthouse flags lists that contain content elements that shouldn't be in a list.", + "correction": "In a properly structured list, all content is contained within list items. Content includes text and other HTML elements. Certain non-content elements are also allowed.When an assistive technology encounters a list that's poorly structured or contains disallowed elements, it might respond in an unexpected way. As a result, people who use assistive technologies might find it difficult to interpret the list.See : Lists do not contain only < li > elements and script supporting elements (< script > and < template >) list", + "titleData": "{0} list(s) do not contain only <li> elements and script supporting elemnts (<script> and <template>) " + }, + "listItem": { + "title": "List items (`<li>`) are contained within `<ul>` or `<ol>` parent elements", + "description": "Lighthouse flags list items (<li>) that aren't contained in <ul> or <ol> parent elements.", + "correction": "In a properly structured list, all list items (< li > elements) are contained by a < ul >, < ol >, or < menu > parent element.When an assistive technology encounters a list that's poorly structured, it might respond in an unexpected way. As a result, people who use assistive technologies might find it difficult to interpret the list. See : List items (< li >) are not contained within < ul > or < ol > parent elements listitem", + "titleData": "{0} List item(s) <li> are not contained within <ul> or <ol> parent elements" + }, + "tabIndex": { + "title": "No element has a `[tabindex]` value greater than 0", + "description": "Lighthouse flags elements that have a tabindex value greater than 0.", + "correction": "A value greater than 0 implies an explicit navigation ordering. Although technically valid, this often creates frustrating experiences for users who rely on assistive technologies. See : Some elements have a [tabindex] value greater than 0", + "titleData": "{0} element(s) have a [tabindex] value greater than 0" + }, + "tdHeadersAttr": { + "title": "Td Headers Attributes", + "description": "Lighthouse flags tables that have more than one table header per column.", + "correction": "In a table, a header cell and a data cell are programmatically related if they are coded in a way that assistive technologies can accurately determine their relationship. When a data cell has a headers attribute that points to a cell in a different table, the programmatic relationship isn't defined in a way that assistive technologies can recognize. As a result, assistive technology users can't tell which header cell goes with a given data cell.See : Cells in a < table > element that use the [headers] attribute refer to an element ID not found within the same table td-headers-attr", + "titleData": "{0} cell(s) in a <table> element that use the [headers] attribute refer to an element id not found within the same table" + }, + "validLang": { + "title": "[lang] attributes have a valid value", + "description": "Lighthouse flags elements that have a lang attribute with an invalid value.", + "correction": "Sometimes a web page written in one language has a passage in a different language. When the language of such a passage is correctly identified (by a lang attribute on the containing element), browsers and assistive technologies can render the text more accurately; screen readers can use the correct pronunciation; visual browsers can display the correct characters; and media players can show captions correctly. All users find it easier to understand the content.See : [lang] attributes do not have a valid value valid-lang", + "titleData": "{0} element(s) do not have valid lang attribute" + }, + "ariaInputFieldName": { + "title": "ARIA input fields have accessible names", + "description": "Lighthouse flags custom ARIA items whose names aren't accessible to assistive technologies.", + "correction": "When an input field doesn't have an accessible name, screen readers announce it with a generic name, making it unusable for users who rely on screen readers. See : ARIA items do not have accessible names aria-input-field-name", + "titleData": "{0} ARIA input field(s) do not have accessible names" + }, + "ariaMeterName": { + "title": "ARIA `meter` elements have accessible names", + "description": "Lighthouse flags custom ARIA items whose names aren't accessible to assistive technologies", + "correction": "When an element doesn't have an accessible name, screen readers announce it with a generic name, making it unusable for users who rely on screen readers. An ARIA meter is a custom control corresponding to the HTML < meter > element. A meter represents either a scalar value within a known range, or a fractional value. For example, a meter might represent the unused portion of total storage capacity. An accessible name is a word or phrase coded in a way that assistive technologies can associate it with a specific user interface object. Assistive technologies can then refer to the object by name, not just by type. When an ARIA meter doesn't an accessible name, people who use assistive technologies have no way of knowing its purpose.See : ARIA items do not have accessible names aria-meter-name", + "titleData": "{0} ARIA meter element(s) do not have accessible names" + }, + "ariaProgressbarName": { + "title": "ARIA `progressbar` elements have accessible names", + "description": "Lighthouse flags custom ARIA items whose names aren't accessible to assistive technologies", + "correction": "When a `progressbar` element doesn't have an accessible name, screen readers announce it with a generic name, making it unusable for users who rely on screen readers. An ARIA progressbar is a custom control corresponding to the HTML < progress > element. A progressbar represents progress on a task that takes a long time to complete. An accessible name is a word or phrase coded in a way that assistive technologies can associate it with a specific user interface object. Assistive technologies can then refer to the object by name, not just by type. When an ARIA progressbar doesn't an accessible name, people who use assistive technologies have no way of knowing its purpose. See : ARIA items do not have accessible names aria-progress-bar-name", + "titleData": "{0} ARIA progressbar element(s) do not have accessible names" + }, + "ariaRequiredChildren": { + "title": "ARIA Required children", + "description": "Lighthouse flags ARIA roles that don't have the required child roles.", + "correction": "An ARIA role attribute can be added to an element to instruct assistive technologies to treat the element as something other than its native HTML element type. For example, a < ul > element with role='listbox' is to be treated as a listbox control, not as a static list.Some ARIA 'parent' roles identify composite controls that always include managed controls, identified by 'child' roles. For example, role='listbox' identifies a composite control that manages a set of managed controls identified by role='option'. People who use assistive technologies might find it difficult or impossible to use a composite control if its managed controls lack the required child role. See : Elements with an ARIA [role] that require children to contain a specific [role] are missing some or all of those required children aria-required-children", + "titleData": "{0} element(s) have missing child roles" + }, + "ariaRequiredParent": { + "title": "`[role]`s are contained by their required parent element", + "description": "Lighthouse flags ARIA child roles that aren't contained by the required parent", + "correction": "An ARIA role attribute can be added to an element to instruct assistive technologies to treat the element as something other than its native HTML element type. For example, an < li > element with role='option' is to be treated as a selectable option in a listbox control, not as a static list item.Some ARIA 'child' roles identify managed controls that are always part of a larger composite control, identified by a 'parent' role. For example, role='option' identifies a child control that is managed by a parent control identified by role='listbox'. People who use assistive technologies might find it difficult or impossible to use a child control if its managing control lacks the required parent role.See : [role]s are not contained by their required parent element aria-required-parent", + "titleData": "{0} element(s) have missing parent roles" + }, + "ariaToggleFieldName": { + "title": "ARIA toggle fields have accessible names", + "description": "Lighthouse flags custom ARIA items whose names aren't accessible to assistive technologies.", + "correction": "When a toggle field doesn't have an accessible name, screen readers announce it with a generic name, making it unusable for users who rely on screen readers. See :ARIA items do not have accessible names aria-toggle-field-name", + "titleData": "Not all ARIA toggle fields have accessible names", + "titleDataSuccess": "ARIA toggle fields have accessible names" + }, + "ariaTooltipName": { + "title": "ARIA `tooltip` elements have accessible names", + "description": "Lighthouse flags custom ARIA items whose names aren't accessible to assistive technologies.", + "correction": "An ARIA tooltip is a contextual popup with text describing an interface element. The tooltip typically becomes visible when the mouse hovers over, or focus is received by, the owning element. An accessible name is a word or phrase coded in a way that assistive technologies can associate it with a specific user interface object. Assistive technologies can then refer to the object by name, not just by type. When an ARIA tooltip doesn't an accessible name, people who use assistive technologies have no way of knowing its purpose.See : ARIA items do not have accessible names aria-tooltip-name", + "titleData": "Not all ARIA tooltip elements have accessible names", + "titleDataSuccess": "ARIA tooltip elements have accessible names" + }, + "ariaTreeitemName": { + "title": "ARIA `treeitem` elements have accessible names", + "description": "Lighthouse flags custom ARIA items whose names aren't accessible to assistive technologies.", + "correction": "When an element doesn't have an accessible name, screen readers announce it with a generic name, making it unusable for users who rely on screen readers.See : ARIA items do not have accessible names", + "titleData": "Not all ARIA treeitem elements have accessible names", + "titleDataSuccess": "ARIA treeitem elements have accessible names" + }, + "buttonName": { + "title": "Buttons have an accessible name", + "description": "Lighthouse flags buttons that don't have text content or an aria-label property.", + "correction": "An accessible name is a word or phrase coded in a way that assistive technologies can associate it with a specific user interface object. Assistive technologies can then refer to the object by name, not just by type. When a button doesn't have an accessible name, people who use assistive technologies have no way of knowing its purpose.See : Buttons do not have an accessible name button-name", + "titleData": "{0} button(s) do not have an accessible name" + }, + "definitionList": { + "title": "Definition List", + "description": "Lighthouse flags <dl> elements that don't contain properly ordered <dt> and <dd> groups, <script>, or <template> elements.", + "correction": "A definition list is a list of terms (words or phrases), and their definitions. A definition list can contain only certain element types, and it requires a specific structure.When an assistive technology encounters a definition list that's poorly structured or contains invalid elements, it might respond in an unexpected way. As a result, people who use assistive technologies might find it difficult to interpret the list.See : < dl > do not contain only properly ordered < dt > and < dd > groups, < script >, or < template > elements definition-list", + "titleData": " {0} `<dl>`'s don't contain only properly-ordered `<dt>` and `<dd>` groups, `<script>`, `<template>` or `<div>` elements " + }, + "dlItem": { + "title": "Definition list items are wrapped in `<dl>` elements", + "description": "Lighthouse reports when definition list items are not wrapped in <dl> elements.", + "correction": "A definition list is a list of terms (words or phrases), and their definitions. The < dt > and < dd > elements must be contained by a < dl > element.When an assistive technology encounters a definition list that's poorly structured, it might respond in an unexpected way. As a result, people who use assistive technologies might find it difficult to interpret the list.See :Definition list items are not wrapped in < dl > elements dlitem", + "titleData": "{0} definition list item(s) are not wrapped in <dl> elements" + }, + "formFieldMultipleLabels": { + "title": "No form fields have multiple labels", + "description": "Lighthouse flags form elements that have more than one label.", + "correction": "Form fields with multiple labels can be confusingly announced by assistive technologies like screen readers which use either the first, the last, or all of the labels. See : Form fields have multiple labels", + "titleData": "{0} Form Field(s) have multiple labels" + }, + "frameTitle": { + "title": "`<frame>` or `<iframe>` elements have a title", + "description": "Lighthouse flags <frame> and <iframe> elements that don't have titles.", + "correction": "A < frame > or < iframe > is used to embed one HTML document within another. An accessible name is a word or phrase coded in a way that assistive technologies can associate it with a specific user interface object. Assistive technologies can then refer to the object by name, not just by type.People with good vision can glance at a < frame > or < iframe > element to get a good idea of its content. People who use assistive technologies rely on the frame's accessible name to determine whether it contains information relevant to their current needs.See :< frame > or < iframe > elements do not have a title frame-title", + "titleData": "{0} <frame> or <iframe> element(s) do not have a title" + }, + "inputImageAlt": { + "title": "`<input type=\"image\">` elements have `[alt]` text", + "description": "Lighthouse flags < input type='image' > elements that don't have alt text", + "correction": "An image button is an < input > element with type='image'. Alternative text is a word or phrase that (1) is coded in a way that assistive technologies can associate it with a specific non-text object, and (2) conveys the same information as the non-text object.Because assistive technologies can't interpret an image directly, they rely on alternative text to communicate the image button's purpose. When an image button doesn't have alternative text, people who use assistive technologies have no way of knowing its purpose.See :< input type='image' > elements do not have [alt] text input-image-alt", + "titleData": "{0} < input type='image' > element(s) do not have [alt] text" + }, + "metaRefresh": { + "title": "The document does not use `<meta http-equiv=\"refresh\">`", + "description": "Lighthouse flags pages that contain a <meta> tag with the http-equiv='refresh' attribute.", + "correction": "Using http-equiv='refresh' in a < meta > element causes a web page to refresh automatically at a specified time interval.An automatic page refresh can be disorienting. If a refresh causes input focus to move unexpectedly back to its original state, it can be especially frustrating for people who use screen readers and other keyboard users.See : The document uses < meta http-equiv='refresh' > meta-refresh", + "titleData": "At least one document uses <meta http-equiv='refresh'>", + "titleDataSuccess": "All documents do not use <meta http-equiv='refresh'>" + }, + "metaViewport": { + "title": "Meta Viewport", + "description": "Lighthouse flags pages that disable browser zooming.", + "correction": "Using content='user-scalable=no' in a < meta name='viewport' > element disables zooming in some browsers. Users are forced to view the text at the specified size.Most people find it easier to read text when it is sufficiently large. People with visual disabilities, low vision, or limited color perception are likely to find text unreadable when it's too small.See : [user-scalable='no'] is used in the < meta name='viewport' > element or the [maximum-scale] attribute is less than 5 meta-viewport", + "titleData": "{0} `[user-scalable=\"no\"]` is used in the `<meta name=\"viewport\">` element and the `[maximum-scale]` attribute is not less than 5. " + }, + "objectAlt": { + "title": "`<object>` elements have `[alt]` text", + "description": "Lighthouse flags <object> elements that don't have alternative text.", + "correction": "An < object > element is used to embed multimedia content in a web page. It can also be used to embed one web page inside another.Alternative text is a word or phrase that (1) is coded in a way that assistive technologies can associate it with a specific non-text object, and (2) conveys the same information as the non-text object.Because assistive technologies can't interpret objects directly, they rely on alternative text to communicate the meaning of non-text content to users.See : < object > elements do not have alt text object-alt", + "titleData": "{0} <object> element(s) do not have [alt] text" + }, + "thHasDataCells": { + "title": "<th> elements have data cells they describe.", + "description": "Lighthouse flags <th> elements and elements with [role='columnheader'/'rowheader'] that don't have the data cells they describe.", + "correction": "When people with good vision see a table with a row or column header that has no associated data cells, they can tell at a glance that the data is missing. People who use assistive technologies must explore a table deliberately to discover its contents; they are likely to have difficulty interpreting a table with missing data cells.See : < th > elements and elements with [role='columnheader'/'rowheader'] do not have data cells they describe th-has-data-cells", + "titleData": "{0} <th> elements and elements with [role='columnheader'/'rowheader'] do not have the data cells they describe" + }, + "videoCaption": { + "title": "Video Caption", + "description": "Lighthouse flags <video> elements that are missing a <track> element with the attribute kind='captions'.", + "correction": "When a video provides a caption it is easier for deaf and hearing impaired users to access its information. See :< video > elements do not contain a < track > element with [kind=\"captions\"]", + "titleData": "{0} <video> element(s) have missing <track> element with the attribute kind='captions'" + }, + "accessKeys": { + "title": "`[accesskey]` values are unique", + "description": "Lighthouse flags pages with duplicate access keys.", + "correction": "Access keys let users quickly focus a part of the page. For proper navigation, each access key must be unique. See :[accesskey] values are not unique", + "titleData": "{0} value(s) are not unique" + } +} \ No newline at end of file diff --git a/EcoSonar-API/utils/bestPractices/lighthousePerformanceData.json b/EcoSonar-API/utils/bestPractices/lighthousePerformanceData.json new file mode 100644 index 0000000..c6e9052 --- /dev/null +++ b/EcoSonar-API/utils/bestPractices/lighthousePerformanceData.json @@ -0,0 +1,169 @@ +{ + "viewport": { + "title": "Has a Viewport meta tag", + "description": "Lighthouse flags pages without a viewport meta tag.", + "correction": "A `< meta name=\"viewport\" >` not only optimizes your app for mobile screen sizes, but also prevents a 300 millisecond delay to user inputGovernment Regulation: RGESN 1.6 : Does the digital service adapt to different types of terminals display ? See Does not have a < meta name=\"viewport\" > tag with width or initial-scaleViewport meta tag Lighthouse: Use a < meta name=\"viewport\" > tag with width or initial-scale", + "titleData": "have missing `<meta name=\"viewport\">` tag", + "titleDataSuccess": "have viewport meta tag" + }, + "serverResponseTime": { + "title": "Initial server response time was short", + "description": "This audit fails when the browser waits more than 600 ms for the server to respond to the main document request.", + "correction": "Keep the server response time for the main document short because all other requests depend on it. Government Regulation: RGESN 6.3 : Does the digital service use caching mechanisms for all transferred content under its control? RGESN 7.1 : Does the digital service use a server caching system for the most used data? See : Reduce server response times (TTFB) Lighthouse: Reduce initial server response time 7 Ways to Reduce Server Response Time 8 Ways to Effectively Reduce Server Response Time", + "titleData": "Root document took {0}ms on average" + }, + "mainthreadWorkBreakdown": { + "title": "Minimize main-thread work", + "description": "Lighthouse flags pages that keep the main thread busy for longer than 4 seconds during load.", + "correction": "Consider reducing the time spent parsing, compiling and executing JS. You may find delivering smaller JS payloads helps with this.Government Regulation: RGESN 6.8 : Does the digital service avoid triggering the loading of unused assets and content for each feature? See : Minimize main thread work Lighthouse: Minimize main-thread work How do I minimize main thread work? How to minimize main thread work in React Component", + "titleData": "{0}s on average" + }, + "bootupTime": { + "title": "Reduce JavaScript execution time", + "description": "Lighthouse shows a warning when JavaScript execution takes longer than 2 seconds. The audit fails when execution takes longer than 3.5 seconds.", + "correction": "Consider reducing the time spent parsing, compiling and executing JS. You may find delivering smaller JS payloads helps with this.Government Regulation: RGESN 6.8 : Does the digital service avoid triggering the loading of unused assets and content for each feature? See : Reduce JavaScript execution time Lighthouse: Reduce JavaScript execution time How to Reduce Javascript Execution Time Reduce script evaluation time in 4 steps", + "titleData": "{0}s on average" + }, + "fontDisplay": { + "title": "Ensure text remains visible during webfont load", + "description": "Lighthouse flags any font URLs that may flash invisible text.", + "correction": "Leverage the font-display CSS feature to ensure text is user-visible while webfonts are loading. See : Ensure text remains visible during webfont load Lighthouse: Ensure text remains visible during webfont load How to Ensure Text Remains Visible During Webfont Load", + "titleData": "text are invisible during one of pages load", + "titleDataSuccess": "no text are invisible" + }, + "thirdPartySummary": { + "title": "Minimize third-party usage", + "description": "Reduce the presence of third-party code.", + "correction": "Third-party code can significantly impact load performance. Limit the number of redundant third-party providers and try to load third-party code after your page has primarily finished loading. Best practices n°82 from '115 bonnes pratiques d'écoconception web v4' See : Loading Third-Party JavaScript Lighthouse: Reduce the impact of third-party code Reduce the Impact of Third-Party Code", + "titleData": "Third-party code blocked the main thread for {0}ms on average" + }, + "thirdPartyFacades": { + "title": "Some third-party resources can be lazy loaded with a facade", + "description": "Some third-party embeds can be lazy loaded. Consider replacing them with a facade until they are required.", + "correction": "Some third-party embeds can be lazy loaded. Consider replacing them with a facade until they are required.Government Regulation: RGESN 6.8 : Does the digital service avoid triggering the loading of unused assets and content for each feature? See : Lazy load third-party resources with facades Lighthouse: Lazy load third-party resources with facades Lazy load third-party resources with facades", + "titleData": "{0} facade alternative(s) available" + }, + "lcpLazyLoaded": { + "title": "Don't lazy load Largest Contentful Paint image", + "description": "Above-the-fold images that are lazily loaded render later in the page lifecycle, which can delay the largest contentful paint.", + "correction": "Lazy-loading is a technique to defer downloading a resource until it's needed, which conserves data and reduces network contention for critical assets. It became a web standard in 2019 and today loading='lazy' for images is supported by most major browsers. That sounds great, but is there such a thing as too much lazy loading? What we found is that lazy-loading can be an amazingly effective tool for reducing unneeded image bytes, but overuse can negatively affect performance. Concretely, our analysis shows that more eagerly loading images within the initial viewport—while liberally lazy-loading the rest—can give us the best of both worlds: fewer bytes loaded and improved Core Web Vitals.Government Regulation: RGESN 6.6 : Does the digital service provide a progressive loading mechanism for graphics and media that require it? See : The performance effects of too much lazy-loading Lighthouse: Don't lazy load Largest Contentful Paint image", + "titleData": "At least one largest contentful image was lazy loaded", + "titleDataSuccess": "No largest contentful image was lazy loaded" + }, + "nonCompositedAnimations": { + "title": "Avoid non-composited animations", + "description": "Animations which are not composited can be janky and increase Cumulative Layout Shift.", + "correction": "Animations which are not composited can be janky and increase CLS. See :Avoid non-composited animations Lighthouse: Avoid non-composited animations Non-composited animations", + "titleData": "{0} animated elements found" + }, + "domSize": { + "title": "Avoids an excessive DOM size", + "description": "Lighthouse flags pages with DOM trees that: Warns when the body element has more than ~800 nodes. Errors when the body element has more than ~1,400 nodes. Be careful EcoSonar rules are more strict : you should have less than 475 nodes to reach a B Score.", + "correction": "A large DOM will increase memory usage, cause longer style calculations, and produce costly layout reflows. Best practices n°12 from '115 bonnes pratiques d'écoconception web v4' See : Avoid an excessive DOM size Reduce the scope and complexity of style calculations Minimizing browser reflow", + "titleData": "{0} elements in average" + }, + "usesLongCacheTtl": { + "title": "Serve static assets with an efficient cache policy", + "description": "Lighthouse flags all static resources that aren't cached.", + "correction": "A long cache lifetime can speed up repeat visits to your page.Government Regulation: RGESN 6.9 : Does the digital service use client-side storage of some resources to avoid unnecessary network exchanges? See : Serve static assets with an efficient cache policy Lighthouse: Serve static assets with an efficient cache policy How to Serve Assets With an Efficient Cache Policy on WordPress", + "titleData": "{0} resources found" + }, + "usesResponsiveImages": { + "title": "Properly size images", + "description": "The Opportunities section of your Lighthouse report lists all images in your page that aren't appropriately sized, along with the potential savings in kibibytes (KiB).", + "correction": "Serve images that are appropriately-sized to save cellular data and improve load time.Government Regulation: RGESN 5.2 Does the digital service offer image content whose level of compression is appropriate for the content and viewing context? See : Properly size images Optimize bitmaps How to properly size images", + "titleData": "Potential savings of {0} KiB" + }, + "offscreenImages": { + "title": "Defer offscreen images (or lazy-loading)", + "description": "The Opportunities section of your Lighthouse report lists all offscreen or hidden images in your page along with the potential savings in kibibytes (KiB). Consider lazy-loading these images after all critical resources have finished loading to lower Time to Interactive.", + "correction": "Consider lazy-loading offscreen and hidden images after all critical resources have finished loading to lower time to interactive.Government Regulation: RGESN 6.6 : Le service numérique propose-t-il un mécanisme de chargement progressif pour les éléments graphiques et les médias le nécessitant ? See : Defer offscreen images Learn how to fix 'defer offscreen images' Lighthouse: Defer offscreen images How to Defer Offscreen Images", + "titleData": "Potential savings of {0} KiB" + }, + "unusedCssRules": { + "title": "Reduce unused CSS", + "description": "The Opportunities section of your Lighthouse report lists all stylesheets with unused CSS with a potential savings of 2 KiB or more. Remove the unused CSS to reduce unnecessary bytes consumed by network activity.", + "correction": "Reduce unused rules from stylesheets and defer CSS not used for above-the-fold content to decrease bytes consumed by network activity.Government Regulation: RGESN 6.8 : Does the digital service avoid triggering the loading of unused assets and content for each feature? See : Remove unused CSS How Do You Remove Unused CSS From a Site? 4 Ways to Remove Unused CSS", + "titleData": "Potential savings of {0} KiB" + }, + "unusedJavascript": { + "title": "Reduce unused JavaScript", + "description": "Lighthouse flags every JavaScript file with more than 20 kibibytes of unused code.", + "correction": "Reduce unused JavaScript and defer loading scripts until they are required to decrease bytes consumed by network activity. Government Regulation: RGESN 6.8 : Does the digital service avoid triggering the loading of unused assets and content for each feature? See :Remove unused JavaScript A Lifehack for removing unused JS/CSS.. or just unminify How to Remove Unused JavaScript", + "titleData": "Potential savings of {0} KiB" + }, + "usesOptimizedImages": { + "title": "Efficiently encode images", + "description": "The Opportunities section of your Lighthouse report lists all unoptimized images, with potential savings in kibibytes (KiB).", + "correction": "Optimized images load faster and consume less cellular data.Government Regulation: RGESN 5.2 Does the digital service offer image content whose level of compression is appropriate for the content and viewing context? See : Efficiently encode images Lighthouse: Efficiently encode images", + "titleData": "Potential savings of {0} KiB" + }, + "modernImageFormats": { + "title": "Serve images in modern formats", + "description": "The Opportunities section of your Lighthouse report lists all images in older image formats, showing potential savings gained by serving AVIF versions of those images.", + "correction": "Image formats like WebP and AVIF often provide better compression than PNG or JPEG, which means faster downloads and less data consumption.Government Regulation: RGESN 5.1 : Does the digital service use a file format adapted to the content and viewing context of each image content? See : Serve images in modern formats How to Serve Next-Gen Image Formats in Modern Browsers Using Modern Image Formats: AVIF And WebP", + "titleData": "Potential savings of {0} KiB" + }, + "usesTextCompression": { + "title": "Enable text compression", + "description": "The Opportunities section of your Lighthouse report lists all text-based resources that aren't compressed.", + "correction": "Text-based resources should be served with compression (gzip, deflate or brotli) to minimize total network bytes.Government Regulation: RGESN 6.4 : Has the digital service implemented compression techniques on all transferred resources under its control? See :Enable text compression Lighthouse: Enable text compression How to Enable GZIP Compression for Faster Web Pages Enable Text Compression", + "titleData": "Potential savings of {0} KiB" + }, + "usesHttp2": { + "title": "Use HTTP/2", + "description": "Lighthouse lists all resources not served over HTTP/2.", + "correction": "HTTP/2 offers many benefits over HTTP/1.1, including binary headers and multiplexing.Regulation: Best practices n°83 from '115 bonnes pratiques d'écoconception web v4' See : Does not use HTTP/2 for all of its resources Lighthouse: Use HTTP/2 for all resources Use HTTP/2 for all of its resources", + "titleData": "{0} requests not served via HTTP/2" + }, + "efficientAnimatedContent": { + "title": "Use video formats for animated content", + "description": "The Opportunities section of your Lighthouse report lists all animated GIFs, along with estimated savings in seconds achieved by converting these GIFs to video.", + "correction": "Large GIFs are inefficient for delivering animated content. Consider using MPEG4/WebM videos for animations and PNG/WebP for static images instead of GIF to save network bytes. See : Use video formats for animated content Lighthouse: Use video formats for animated content", + "titleData": "Potential savings of {0} KiB" + }, + "legacyJavascript": { + "title": "Avoid serving legacy JavaScript to modern browsers", + "description": "Lighthouse identifies the polyfills and transforms that should not be present if using the module/nomodule pattern.", + "correction": "Polyfills and transforms enable legacy browsers to use new JavaScript features. However, many aren't necessary for modern browsers. For your bundled JavaScript, adopt a modern script deployment strategy using module/nomodule feature detection to reduce the amount of code shipped to modern browsers, while retaining support for legacy browsers. See : Lighthouse: Avoid serving legacy JavaScript to modern browsers Deploying ES2015+ Code in Production Today", + "titleData": "Potential savings of {0} KiB" + }, + "totalByteWeight": { + "title": "Avoid enormous network payloads", + "description": "Lighthouse shows the total size in kibibytes (KiB) of all resources requested by your page. The largest requests are presented first.", + "correction": "Large network payloads cost users real money and are highly correlated with long load times.Government Regulation: RGESN 6.4 : Has the digital service implemented compression techniques on all transferred resources under its control? See : Avoid enormous network payloads Lighthouse: Avoid enormous network payloads", + "titleData": "Total size was {0} KiB in average" + }, + "noDocumentWrite": { + "title": "Avoids document.write()", + "description": "Lighthouse flags calls to document.write() that weren't blocked by Chrome.", + "correction": "For users on slow connections, external scripts dynamically injected via `document.write()` can delay page load by tens of seconds.Government Regulation: RGESN 4.1 : Is the digital service usable via a low-speed connection? See : Uses document.write() Intervening against document.write()", + "titleData": "have at least one document.write()", + "titleDataSuccess": "have no document.write()" + }, + "layoutShiftElements": { + "title": "Avoid large layout shifts", + "description": "These DOM elements contribute most to the Cumulative Layout Shift of the page.", + "correction": "Large layout shifts can create a frustrating experience for your visitors as they make your page appear visually jarring, as page elements appear suddenly, move around, and affect how your visitors interact with the page. Avoiding large layout shifts is essential in creating a smooth and streamlined experience for your visitors. Regarding image dimensions, you should not be resizing image within your browser. Images should have by default the width and height that you want to set up. See : Lighthouse: Avoid large layout shifts Optimize Cumulative Layout Shift", + "titleData": "{0} elements found" + }, + "usesPassiveEventListeners": { + "title": "Does not use passive listeners to improve scrolling performance", + "description": "Consider marking your touch and wheel event listeners as `passive` to improve your page's scroll performance.", + "correction": "Consider marking your touch and wheel event listeners as `passive` to improve your page's scroll performance. See : Use passive listeners to improve scrolling performance Improving scroll performance with passive event listeners", + "titleData": "at least one page does not have passive listeners", + "titleDataSuccess": "have passive listeners" + }, + "duplicatedJavascript": { + "title": "Remove duplicate modules in JavaScript bundles", + "description": "If the wasted bandwidth exceeds 1 KB, this audit triggers.", + "correction": "Remove large, duplicate JavaScript modules from bundles to reduce unnecessary bytes consumed by network activity.Government Regulation: RGESN 6.8 : Does the digital service avoid triggering the loading of unused assets and content for each feature? See : Lighthouse: Remove duplicate modules in JavaScript bundles Reduce webpack bundle size by eliminating duplicated", + "titleData": "Potential savings of {0} KiB" + }, + "unminifiedJavascript": { + "title": "Minify JavaScript", + "description": "The Opportunities section of your Lighthouse report lists all unminified JavaScript files, along with the potential savings in kibibytes (KiB) when these files are minified.", + "correction": "Minifying JavaScript files can reduce payload sizes and script parse time.Best practices n°77 from '115 bonnes pratiques d'écoconception web v4' See : Minifiy Javascript Minify Javascript files Minification", + "titleData": "Potential savings of {0} KiB" + } +} \ No newline at end of file diff --git a/EcoSonar-SonarQube/README.md b/EcoSonar-SonarQube/README.md index 609d82a..5f7d26e 100644 --- a/EcoSonar-SonarQube/README.md +++ b/EcoSonar-SonarQube/README.md @@ -1,8 +1,10 @@ # Plugin SonarQube EcoSonar -## Introduction -This plugin aims to embed EcoSonar Audits, Recommendations as well as Configuration. +## Introduction + +This plugin aims to embed EcoSonar Audits, Recommendations as well as Configuration. It fulfills three purposes : + - enable automatic trigger of EcoSonar Analysis each time a Sonarqube analysis is done - static code analysis with green coding rules implemented by EcoCode project - add EcoSonar audit reports directly into Sonarqube projet User Interface @@ -10,29 +12,18 @@ It fulfills three purposes : ## Getting Started ### Prerequisites -- Sonarqube- minimum version 9.4 -https://docs.sonarqube.org/latest/setup/install-server/ -https://docs.sonarqube.org/latest/setup/install-cluster/ -No constraint on the edition type. Please check with your infrastructure team which edition are you allowed to use. -- If Sonarqube version is 9.9 or above, choose Java– version 17, otherwise Java – version 11 -- Maven - 3.8.3 - -### Build the SonarQube Plugin - -#### EcoSonar V2.3 and below -To trigger and retrieve EcoSonar audits, you need to set up in the plugin configuration the URL to reach the EcoSonar API. -Please change in both files `src/main/java/com/ls/api/GreenITAnalysis.java` and `src/main/js/config/axiosConfiguration.js`, the parameter called `baseUrlHosted` to set it with the EcoSonar API Server you use. - -To build the plugin JAR file: - -``` -mvn clean package -``` +- Sonarqube- minimum version 9.4 + https://docs.sonarqube.org/latest/setup/install-server/ + https://docs.sonarqube.org/latest/setup/install-cluster/ + No constraint on the edition type. Please check with your infrastructure team which edition are you allowed to use. +- Java : version 17 if Sonarqube version is 9.9 or above, otherwise version 11 +- Maven - 3.8.3 -#### EcoSonar V3.0 and above +### Build the SonarQube Plugin related to EcoSonar -To build the plugin JAR file: +To build the plugin JAR file, first you need to retrieve the URL of the deployed server for EcoSonar API. +Then run the following commands: For Windows: @@ -48,20 +39,20 @@ export REACT_APP_BASE_URL_ECOSONAR_API=#EcoSonar-API-URL mvn clean package -Durl=#EcoSonar-API-URL ``` -EcoSonar-API-URL should be replaced in local by `http://localhost:3000` and by the EcoSonar API URL for a deployed version. +If you are running EcoSonar locally, EcoSonar-API-URL should be by default `http://localhost:3000`. -### Install Sonarqube Plugins Manually +### Install Sonarqube Plugins (EcoSonar + Ecocode) manually -1. Copy the file located at the following path `target/ecosonar-X-SNAPSHOT.jar`. -2. Go to your Sonarqube folder `extensions/plugins/` and paste the JAR. -3. Retrieve all JAR files available in the `ecocode` folder (there should be 6, one by language): -4. Go to your Sonarqube folder `extensions/plugins/` and paste the JAR files to add the EcoCode Sonarqube plugins. +1. Copy the file located at the following path `EcoSonar-SonarQube/target/ecosonar-X-SNAPSHOT.jar`. +2. Go to your Sonarqube folder `extensions/plugins/` and paste the JAR. +3. Retrieve all JAR files available in the `EcoSonar-SonarQube/ecocode` folder (there should be 6, one by language): +4. Go to your Sonarqube folder `extensions/plugins/` and paste the JAR files to add the EcoCode Sonarqube plugins. To finally launch Sonarqube with the plugin, run the shell script: `bin/windows-x86-64/StartSonar.bat`. - ![Ecosonar Plugin Sonarqube](../images/ecosonar-plugin.webp) +![Ecosonar Plugin Sonarqube](../images/ecosonar-plugin.webp) -The Sonarqube instance startup logs are located in the file `logs/web.log` +The Sonarqube instance startup logs are located in the file `logs/web.log` Official documentation about installing a SonarQube plugin: https://docs.sonarqube.org/latest/setup/install-plugin/. @@ -73,4 +64,4 @@ Set up a CI/CD pipeline to build the executable and automatically add it in the Check this link : https://docs.sonarqube.org/latest/extend/developing-plugin/ -Otherwise feel free to use our code as example with respect of licence. \ No newline at end of file +Otherwise feel free to use our code as example with respect of licence. diff --git a/EcoSonar-SonarQube/package.json b/EcoSonar-SonarQube/package.json index 865c2a3..88257b1 100644 --- a/EcoSonar-SonarQube/package.json +++ b/EcoSonar-SonarQube/package.json @@ -1,6 +1,6 @@ { "name": "ecosonar-plugin", - "version": "3.3.0", + "version": "3.4", "description": "Ecodesign and accessibility tool to help developpers minimize carbon footprint of their web-application", "main": "index.js", "scripts": { @@ -13,7 +13,7 @@ "license": "GNU", "dependencies": { "apexcharts": "^3.37.0", - "axios": "^1.3.2", + "axios": "^1.6.2", "classnames": "^2.3.2", "file-saver": "^2.0.5", "focus-trap-react": "^10.0.2", diff --git a/EcoSonar-SonarQube/pom.xml b/EcoSonar-SonarQube/pom.xml index 5d6c7d0..c39ca7a 100644 --- a/EcoSonar-SonarQube/pom.xml +++ b/EcoSonar-SonarQube/pom.xml @@ -6,7 +6,7 @@ <groupId>com.ls</groupId> <artifactId>ecosonar</artifactId> - <version>3.3</version> + <version>3.4</version> <packaging>sonar-plugin</packaging> @@ -20,7 +20,7 @@ <dependency> <groupId>org.sonarsource.sonarqube</groupId> <artifactId>sonar-plugin-api</artifactId> - <version>8.0</version> + <version>9.4.0.54424</version> <scope>provided</scope> </dependency> </dependencies> diff --git a/EcoSonar-SonarQube/src/main/js/ecosonar_bestpractices_page/components/BestPracticesBody.js b/EcoSonar-SonarQube/src/main/js/ecosonar_bestpractices_page/components/BestPracticesBody.js index f4d8052..0efa9f8 100644 --- a/EcoSonar-SonarQube/src/main/js/ecosonar_bestpractices_page/components/BestPracticesBody.js +++ b/EcoSonar-SonarQube/src/main/js/ecosonar_bestpractices_page/components/BestPracticesBody.js @@ -1,7 +1,7 @@ import React, { useState } from 'react' import AccordionManager from './Accordion/AccordionManager' import BestPracticesFilters from './BestPracticesFilters/BestPracticesFilters' -import { allTools, auditTypes, defaultSelectedComplianceLevel, greenITTool, lighthouseAccessibility, lighthousePerformanceTool, w3cValidator, setTools } from './BestPracticesFilters/Filters' +import { allTools, auditTypes, defaultSelectedComplianceLevel, greenITTool, lighthouseAccessibility, lighthousePerformanceTool, setTools, w3cValidator } from './BestPracticesFilters/Filters' export default function BestPracticesBody (props) { const { diff --git a/EcoSonar-SonarQube/src/main/js/ecosonar_configuration_page/components/ConfigurationPage.js b/EcoSonar-SonarQube/src/main/js/ecosonar_configuration_page/components/ConfigurationPage.js index 4247f22..d0a9fd4 100644 --- a/EcoSonar-SonarQube/src/main/js/ecosonar_configuration_page/components/ConfigurationPage.js +++ b/EcoSonar-SonarQube/src/main/js/ecosonar_configuration_page/components/ConfigurationPage.js @@ -1,6 +1,5 @@ import React from 'react' import { getUrlsConfiguration } from '../../services/configUrlService' -import { crawl } from '../../services/crawlerService' import AddUrlForm from './AddUrlForm' import CrawlerPage from './Crawler/CrawlerPage' import DeleteUrlForm from './DeleteUrlForm' @@ -17,10 +16,7 @@ export default class ConfigurationPage extends React.PureComponent { error: '', indexToDelete: 0, urls: [], - crawledUrls: [], - crawlerLoading: false, - displayCrawler: false, - hasCrawled: false + displayCrawler: false } } @@ -30,17 +26,11 @@ export default class ConfigurationPage extends React.PureComponent { }) getUrlsConfiguration(this.props.project.key) .then((urls) => { - this.setState({ urls }) - this.setState({ - loading: false - }) + this.setState({ urls, loading: false }) }) .catch((result) => { if (result instanceof Error) { - this.setState({ error: result.message }) - this.setState({ - loading: false - }) + this.setState({ error: result.message, loading: false }) } }) } @@ -80,27 +70,15 @@ export default class ConfigurationPage extends React.PureComponent { addNewUrls = (urlsAdded) => { this.setState({ - urls: this.state.urls.concat(urlsAdded) - }) - this.setState({ crawledUrls: [] }) - this.setState({ displayCrawler: false }) - this.setState({ hasCrawled: false }) - this.setState({ error: '' }) - } - - setMainUrl = async (url) => { - this.setState({ crawlerLoading: true }) - await crawl(this.state.projectName, url.trim()).then((response) => { - this.setState({ crawlerLoading: false }) - this.setState({ crawledUrls: response }) - this.setState({ hasCrawled: true }) + urls: this.state.urls.concat(urlsAdded), + crawledUrls: [], + displayCrawler: false, + error: '' }) } setDisplayCrawler = () => { this.setState({ displayCrawler: !this.state.displayCrawler }) - this.setState({ crawledUrls: [] }) - this.setState({ hasCrawled: false }) } checkUrl = () => { @@ -114,12 +92,8 @@ export default class ConfigurationPage extends React.PureComponent { return ( <div className='boxed-group'> <CrawlerPage - setMainUrl={this.setMainUrl} - crawledUrls={this.state.crawledUrls} projectName={this.state.projectName} addNewUrls={this.addNewUrls} - crawlerLoading={this.state.crawlerLoading} - hasCrawled={this.state.hasCrawled} setDisplayCrawler={this.setDisplayCrawler} /> </div> @@ -131,30 +105,30 @@ export default class ConfigurationPage extends React.PureComponent { return ( <main role='main' aria-hidden='true'> - <div className='page' aria-hidden='true'> - <div className='page-header' role='banner' aria-label='configuration page presentation'> - <h1 className='page-title'>URL Configuration for project {this.state.projectName}</h1> - <div className='page-actions' aria-hidden={this.state.openCreate}> - <button - className='basic-button' - disabled={this.state.displayCrawler} - onClick={this.handleCreateOpen} - type='button' - aria-haspopup='dialog' - aria-label='add new urls' - aria-controls='dialog' - > - Add new URLs - </button> - {this.state.openCreate && <AddUrlForm isDisplayed={this.state.openCreate} projectName={this.state.projectName} onClose={this.handleCreateClose} onSubmitSuccess={this.addNewUrls} />} + <div className='page' aria-hidden='true'> + <div className='page-header' role='banner' aria-label='configuration page presentation'> + <h1 className='page-title'>URL Configuration for project {this.state.projectName}</h1> + <div className='page-actions' aria-hidden={this.state.openCreate}> + <button + className='basic-button' + disabled={this.state.displayCrawler} + onClick={this.handleCreateOpen} + type='button' + aria-haspopup='dialog' + aria-label='add new urls' + aria-controls='dialog' + > + Add new URLs + </button> + {this.state.openCreate && <AddUrlForm isDisplayed={this.state.openCreate} projectName={this.state.projectName} onClose={this.handleCreateClose} onSubmitSuccess={this.addNewUrls} />} + </div> + + <p className='page-description'> + In order to analyse your code and monitor key ecodesign metrics, you will need to set every route defined for your web application. + <br /> + EcoSonar will then analyse all pages of your web app and will guide you to set up practices optimizing ressources. + </p> </div> - - <p className='page-description'> - In order to analyse your code and monitor key ecodesign metrics, you will need to set every route defined for your web application. - <br /> - EcoSonar will then analyse all pages of your web app and will guide you to set up practices optimizing ressources. - </p> - </div> {!this.state.loading ? this.checkUrl() : <div className="loader"></div>} {this.state.deleting && ( @@ -166,9 +140,8 @@ export default class ConfigurationPage extends React.PureComponent { onCloseDelete={this.onCloseDelete} /> )} - </div> + </div> </main> - ) } } diff --git a/EcoSonar-SonarQube/src/main/js/ecosonar_configuration_page/components/Crawler/CrawlerPage.js b/EcoSonar-SonarQube/src/main/js/ecosonar_configuration_page/components/Crawler/CrawlerPage.js index 5bc7b37..80b8b97 100644 --- a/EcoSonar-SonarQube/src/main/js/ecosonar_configuration_page/components/Crawler/CrawlerPage.js +++ b/EcoSonar-SonarQube/src/main/js/ecosonar_configuration_page/components/Crawler/CrawlerPage.js @@ -1,13 +1,23 @@ import React from 'react' import { insertUrlsConfiguration } from '../../../services/configUrlService' import CrawledUrlItem from './CrawledUrlItem' +import { crawl, getCrawl } from '../../../services/crawlerService' export default function CrawlerPage (props) { - const { setMainUrl, crawledUrls, projectName, addNewUrls, crawlerLoading, hasCrawled, setDisplayCrawler } = props + const { + projectName, + addNewUrls, + setDisplayCrawler + } = props const [url, setUrl] = React.useState('') const [checkedUrls, setCheckedUrls] = React.useState([]) const [globalError, setGlobalError] = React.useState('') const [allChecked, setAllChecked] = React.useState(false) + const [autoSaveUrlsResult, setAutoSaveUrlsResult] = React.useState(false) + const [crawledUrls, setCrawledUrls] = React.useState([]) + const [crawlerLoading, setCrawlerLoading] = React.useState(false) + const [crawlerLaunched, setCrawlerLaunched] = React.useState(false) + const [crawlerErrorMessage, setCrawlerErrorMessage] = React.useState('') const handleChangeSetUrl = (event) => { setUrl(event.target.value) @@ -17,7 +27,9 @@ export default function CrawlerPage (props) { if (!checkedUrls.includes(checkedUrl)) { setCheckedUrls((checkedUrlList) => [...checkedUrlList, checkedUrl]) } else { - setCheckedUrls((checkedUrlList) => checkedUrlList.filter((urlObject) => urlObject !== checkedUrl)) + setCheckedUrls((checkedUrlList) => + checkedUrlList.filter((urlObject) => urlObject !== checkedUrl) + ) } } @@ -33,7 +45,7 @@ export default function CrawlerPage (props) { }) } - function compareArray (crawledUrlsObject, checkedUrlsObject) { + const compareArray = (crawledUrlsObject, checkedUrlsObject) => { for (let i = 0; i < crawledUrlsObject.length; i++) { if (crawledUrlsObject[i] !== checkedUrlsObject[i]) { return false @@ -53,89 +65,189 @@ export default function CrawlerPage (props) { } } - const checkCrawledAndNoUrl = () => { - return hasCrawled && crawledUrls.length === 0 + const handleChangeAutoSaveUrlsResult = () => { + setAutoSaveUrlsResult(!autoSaveUrlsResult) + } + + const launchCrawler = (url, autoSave) => { + setCrawlerLoading(true) + setCrawlerErrorMessage('') + crawl(projectName, url.trim(), autoSave).then(() => { + setCrawlerLoading(false) + setCrawlerLaunched(true) + }) + .catch((error) => { + setCrawlerLoading(false) + if (error instanceof Error) { + setCrawlerErrorMessage(error.message) + } + }) + } + + const getCrawlerResult = async () => { + setCrawlerLoading(true) + setCrawlerErrorMessage('') + await getCrawl(projectName).then((response) => { + setCrawlerLoading(false) + setCrawledUrls(response) + setCrawlerLaunched(false) + }).catch((error) => { + setCrawlerLoading(false) + if (error instanceof Error) { + setCrawlerErrorMessage(error.message) + } + }) } return ( <div> + <div className="url-list-button"> + <p className="crawler-message"> + I want to automatically search for all pages within my website + </p> + </div> + <div className="crawler-buttons"> + <input + className="input-crawler" + name="url" + type="text" + onChange={handleChangeSetUrl} + id="webhook-url" + placeholder="Add the homepage from my website" + aria-label="add the homepage from my website" + /> + <label + className="switch" + htmlFor="checkbox" + style={{ position: 'unset' }} + > + <input + type="checkbox" + checked={autoSaveUrlsResult} + aria-checked={autoSaveUrlsResult} + tabIndex={0} + aria-labelledby="checkbox" + onChange={() => handleChangeAutoSaveUrlsResult()} + id="checkbox" + /> + <div></div> + <p className="crawler-message"> + Save urls as to be audited by EcoSonar + </p> + </label> + <button + className="basic-button" + aria-label="launch-crawler" + onClick={() => launchCrawler(url, autoSaveUrlsResult)} + disabled={crawlerLoading || url === '' || crawledUrls.length > 0} + > + <span>Launch Crawler</span> + </button> + <button + className="basic-button" + aria-label="return to url list" + onClick={() => setDisplayCrawler()} + disabled={crawlerLoading} + > + <span>Return to url list</span> + </button> + </div> {crawledUrls.length === 0 && ( <div> - <div className='crawler-input'> - <p className='crawler-message'>I want to automatically search for all pages within my website</p> - <input - className='input' - name='url' - type='text' - onChange={handleChangeSetUrl} - id='webhook-url' - placeholder='add the homepage from my website' - aria-label='add the homepage from my website' - /> - - <div className='crawler-buttons'> - <button className='basic-button' aria-label='find pages' onClick={() => setMainUrl(url)} disabled={crawlerLoading}> - <span>Find pages</span> - </button> - <button className='basic-button' aria-label='return to url list' onClick={() => setDisplayCrawler()} disabled={crawlerLoading}> - <span>Return to url list</span> - </button> - </div> + <div> + <p className="crawler-message"> + If you previoulsy crawled your website, click directly on the button below. + </p> + <button + className="basic-button" + aria-label="return to url list" + onClick={() => getCrawlerResult()} + disabled={crawlerLoading} + > + <span>Get Crawled URLs</span> + </button> + </div> + <div> + {crawlerLaunched && ( + <div className="crawler-loading"> + <p> + Ecosonar crawler is running. Process can take several minutes + according to the size of the website. If you enabled the Save + option, URLS crawled will be saved automatically in the URL + Configuration list. Otherwise by default, the URLs crawled + will be saved in a temporary database and made available to + you by clicking on the button Get Crawler Result. + </p> + </div> + )} </div> - {crawlerLoading && ( - <div className='crawler-loading'> - <div className="loader"></div> - <p>Ecosonar crawler is running. Process can take several minutes according to the size of the website. Leave this page open.</p> - </div> - )} </div> )} - + <p className='text-danger' role='alert'> + {crawlerErrorMessage} + </p> {crawledUrls.length > 0 && ( - <div className='crawled-url-list'> - <table className='data-zebra' role='presentation'> + <div className="crawled-url-list"> + <table className="data-zebra" role="presentation"> <tbody> <tr> <td> - <p className='crawler-message'> - I want to automatically search for all pages within my website : <span className='url-name'>{url}</span> + <p className="crawler-message"> + Find below the URLs previously crawled for this project. Please select those you wish EcoSonar to audit. </p> </td> </tr> - <tr className='data-zebra-thead'> - <td className='head-url'>{'URL'}</td> + <tr className="data-zebra-thead"> + <td className="head-url">{'URL'}</td> <td> <input - type='checkbox' - onChange={() => { selectAll() }} + type="checkbox" + onChange={() => { + selectAll() + }} checked={allChecked} - aria-label='select all' + aria-label="select all" ></input> </td> </tr> {crawledUrls.map((crawledUrl, index) => { - return <CrawledUrlItem key={'url-' + index} index={index} url={crawledUrl} handleChangeCheckedUrls={handleChangeCheckedUrls} checkedUrls={checkedUrls} setAllChecked={setAllChecked} /> + return ( + <CrawledUrlItem + key={'url-' + index} + index={index} + url={crawledUrl} + handleChangeCheckedUrls={handleChangeCheckedUrls} + checkedUrls={checkedUrls} + setAllChecked={setAllChecked} + /> + ) })} </tbody> </table> - <div className='crawler-buttons'> - <button className='basic-button' aria-label='Cancel' onClick={() => setDisplayCrawler()}> + <div className="crawler-buttons"> + <button + className="basic-button" + aria-label="Cancel" + onClick={() => setDisplayCrawler()} + > <span>Cancel</span> </button> - <button className='basic-button' aria-label='Validate list' disabled={!checkedUrls.length} onClick={() => validateList()}> - <span>Validate list</span> + <button + className="basic-button" + aria-label="Validate list" + disabled={!checkedUrls.length} + onClick={() => validateList()} + > + <span>Validate</span> </button> </div> {globalError !== '' && ( - <p className='text-danger' role='alert'> + <p className="text-danger" role="alert"> {globalError} </p> )} </div> )} - {checkCrawledAndNoUrl() && ( - <p className='crawler-message-no-more-url'>No url detected</p> - )} </div> ) } diff --git a/EcoSonar-SonarQube/src/main/js/services/crawlerService.js b/EcoSonar-SonarQube/src/main/js/services/crawlerService.js index 8ddf233..8774f34 100644 --- a/EcoSonar-SonarQube/src/main/js/services/crawlerService.js +++ b/EcoSonar-SonarQube/src/main/js/services/crawlerService.js @@ -2,20 +2,35 @@ import { axiosInstance } from '../config/axiosConfiguration' import formatError from '../format/formatError' import errors from '../utils/errors.json' -export function crawl (projectName, mainUrl) { +export function crawl (projectName, mainUrl, saveUrls) { return new Promise((resolve, reject) => { - axiosInstance.post('/api/crawl', { projectName, mainUrl }, { timeout: 600000 }) + axiosInstance.post('/api/crawl', { projectName, mainUrl, saveUrls }, { timeout: 600000 }) + .then(() => { + resolve() + console.log('CRAWLER SERVICE - crawling started') + }) + .catch((error) => { + console.error(error) + console.error('CRAWLER SERVICE - unknown error occured : ', error.message) + reject(new Error(formatError(errors.errorCrawling, mainUrl))) + }) + }) +} + +export function getCrawl (projectNameReq) { + return new Promise((resolve, reject) => { + axiosInstance.get('/api/crawl', { params: { projectName: projectNameReq } }, { timeout: 600000 }) .then((response) => { - console.log('CRAWLER SERVICE - URL retrieved') + console.log(`CRAWLER SERVICE - ${response.data.length} URLs retrieved for project ${projectNameReq}`) resolve(response.data) }) .catch((error) => { if (error.response && error.response.status === 400) { - reject(new Error(formatError(errors.errorCrawling, mainUrl))) + reject(new Error(formatError(errors.errorCrawlingEmpty, projectNameReq))) } else { console.error(error) console.error('CRAWLER SERVICE - unknown error occured : ', error.message) - reject(new Error(formatError(errors.errorCrawling, mainUrl))) + reject(new Error(formatError(errors.errorGetCrawling, projectNameReq))) } }) }) diff --git a/EcoSonar-SonarQube/src/main/js/styles/_settings.scss b/EcoSonar-SonarQube/src/main/js/styles/_settings.scss index 4acf8d9..3649dd3 100644 --- a/EcoSonar-SonarQube/src/main/js/styles/_settings.scss +++ b/EcoSonar-SonarQube/src/main/js/styles/_settings.scss @@ -97,7 +97,6 @@ body { .basic-button { display: inline-flex; align-items: center; - overflow: hidden; white-space: nowrap; text-overflow: ellipsis; justify-content: center; @@ -164,6 +163,10 @@ body { cursor: not-allowed; box-shadow: none; } + + span { + padding: 3px 3px; + } } .boxed-group { border: 1px solid #e6e6e6; diff --git a/EcoSonar-SonarQube/src/main/js/styles/components/_urlConfig.scss b/EcoSonar-SonarQube/src/main/js/styles/components/_urlConfig.scss index c90a6ca..0c4dbb6 100644 --- a/EcoSonar-SonarQube/src/main/js/styles/components/_urlConfig.scss +++ b/EcoSonar-SonarQube/src/main/js/styles/components/_urlConfig.scss @@ -16,6 +16,7 @@ .modal-header-config { padding: 32px 32px 0; + .modal-title-config { margin: 0; font-size: 16px; @@ -24,9 +25,11 @@ overflow-wrap: break-word; } } + .modal-body-config { padding: 20px 32px; } + .modal-footer-config { padding: 20px 32px; border-top: 1px solid $medium-grey; @@ -45,35 +48,43 @@ margin-right: 2%; margin-bottom: 1%; } + .input { max-width: 30%; margin-right: 2%; margin-bottom: 4%; } + .basic-button { margin-bottom: 1%; } } + .crawler-loading { text-align: center; } + .crawled-url-list { display: flex; flex-direction: column; + .basic-button { max-width: 10%; margin-top: 3%; margin-left: auto; margin-right: 5%; text-align: right; + span { overflow: hidden; white-space: nowrap; text-overflow: ellipsis; } } + .crawler-message { margin-bottom: 1%; + span { text-decoration: underline; } @@ -83,6 +94,7 @@ .crawler-message-no-more-url { text-align: center; } + .crawler-input-no-url-assigned { display: flex; justify-content: space-around; @@ -91,6 +103,7 @@ .url-list-button { display: flex; align-items: center; + .basic-button { margin-left: 3%; } @@ -99,10 +112,17 @@ .crawler-buttons { display: flex; justify-content: right; - margin-bottom: 1%; + margin-bottom: 5%; + flex-direction: row; + align-items: center; .basic-button { margin-left: 5%; } + .crawler-message { + font-size: $small-font; + margin-right: 2%; + margin-bottom: 1%; + } } .button-delete { @@ -125,3 +145,20 @@ border-color: $red-error; color: $red-error; } + +.unset { + position: 'unset' +} + +.input-crawler { + margin-right: 8px; + width: calc(100% - 54px); + height: 24px; + padding: 0 6px; + border: 1px solid $light-grey; + box-sizing: border-box; + border-radius: 2px; + background: $white; + color: $dark-grey; + transition: border-color 0.2s ease; +} \ No newline at end of file diff --git a/EcoSonar-SonarQube/src/main/js/utils/errors.json b/EcoSonar-SonarQube/src/main/js/utils/errors.json index 7989bee..c4e6a97 100644 --- a/EcoSonar-SonarQube/src/main/js/utils/errors.json +++ b/EcoSonar-SonarQube/src/main/js/utils/errors.json @@ -15,6 +15,8 @@ "errorRetrievingAnalysisforURL": "An error occured while retrieving analysis for {1} in project {0}, please try again.", "errorRetrievingBestPractices": "An error occured while retrieving best practices for project {0}, please try again.", "errorCrawling": "An error occured while crawling from url {0}, please try again", + "errorGetCrawling": "An error occured while retrieving url crawled from project {0}, please try again", + "errorCrawlingEmpty": "No crawled urls were saved for project {0}", "errorW3cAnalysisNotFound": "The W3C Analysis could not be processed for project {0}, check with technical team to resolve this issue", "errorW3cLastAnalysisNotFoundForURL": "The W3C Analysis could not be processed for {0} in project {1}, check with technical team to resolve this issue", "errorSystemAddProcedure": "An error occured while adding procedure in project {0}, please try again.", diff --git a/README.md b/README.md index bcf0c62..fddfc7f 100644 --- a/README.md +++ b/README.md @@ -4,88 +4,98 @@ Our official website : https://ecosonar.org -User guide: https://github.com/Accenture/EcoSonar/blob/main/USER_GUIDE.md +User guide: https://github.com/Accenture/EcoSonar/blob/main/USER_GUIDE.md ## Main objectives of EcoSonar: -- Raising the awareness of delivery teams to environmental issues: enabling development teams to consider the environmental impact of digital technology during development and to promote knowledge of best eco-design and accessibility practices. -- Helping developers to implement best eco-design and accessibility practices with: - - Static Code Analysis with SonarQube, and dedicated green coding rules with the addition of Plugin EcoCode (https://www.ecocode.io/) - - Dynamic Code Analysis with EcoSonar API using three open-source tools to analyze the application as it is rendered on a web browser (Green-IT Analysis/EcoIndex, Google Lighthouse and W3C Validator). -- Get an environmental & performance monitoring solution to allow continuous improvement of delivery teams. +- Raising the awareness of delivery teams to environmental issues: enabling development teams to consider the environmental impact of digital technology during development and to promote knowledge of best eco-design and accessibility practices. +- Helping developers to implement best eco-design and accessibility practices with: + - Static Code Analysis with SonarQube, and dedicated green coding rules with the addition of Plugin EcoCode (https://www.ecocode.io/) + - Dynamic Code Analysis with EcoSonar API using three open-source tools to analyze the application as it is rendered on a web browser (Green-IT Analysis/EcoIndex, Google Lighthouse and W3C Validator). +- Get an environmental & performance monitoring solution to allow continuous improvement of delivery teams. # Summary + - [EcoSonar Architecture ](#archi) - [Prerequisites](#prerequisites) - - [Infrastructure Requirements](#infra) -- [EcoSonar Configuration](#configuration) + - [Infrastructure Requirements](#infra) +- [EcoSonar Local Installation](#installation) - [EcoCode Configuration](#ecocode-config) - [Audit Tools](#audit) - - [GreenIT-Analysis/EcoIndex](#greenit-cnumr) - - [Google Lighthouse](#ligthhouse) - - [W3C Validator](#w3c) - - [Ecocode](#ecocode) + - [GreenIT-Analysis/EcoIndex](#greenit-cnumr) + - [Google Lighthouse](#ligthhouse) + - [W3C Validator](#w3c) + - [Ecocode](#ecocode) - [About](#about) <a name="archi"></a> + ## EcoSonar Architecture The EcoSonar tool consists of: -- A containerized Node.js API - - run a GreenIT-Analysis/EcoIndex, Google Lighthouse and W3C Validator analysis for a project containing a list of predefined URLs. - - store audits in MongoDB Database - - retrieve audits through API calls. +- A containerized Node.js API + + - run a GreenIT-Analysis/EcoIndex, Google Lighthouse and W3C Validator analysis for a project containing a list of predefined URLs. + - store audits in MongoDB Database + - retrieve audits through API calls. -- Sonarqube plugins - - Able to configure and retrieve EcoSonar audit reports on dynamic rendering analysis. - - Launch an EcoSonar analysis by calling the API when a Sonarqube analysis is triggered. - - Add new eco-design coding rules in Sonarqube default configuration with EcoCode plugins. +- Sonarqube plugins + - Able to configure and retrieve EcoSonar audit reports on dynamic rendering analysis. + - Launch an EcoSonar analysis by calling the API when a Sonarqube analysis is triggered. + - Add new eco-design coding rules in Sonarqube default configuration with EcoCode plugins. - ![Architecture](./images/ecosonar-architecture.webp) Example of Architecture deployed on Azure: - ![Ecosonar Architecture Azure](./images/ecosonar-architecture-azure.webp) - -<a name="nodeprerequisitesjs"></a> -## Prerequisites -- Node.js (minimum version 16) - -For Sonarqube plugin only: -- Sonarqube- minimum version 9.4 -https://docs.sonarqube.org/latest/setup/install-server/ -https://docs.sonarqube.org/latest/setup/install-cluster/ -No constraint on the edition type. Please check with your infrastructure team which edition are you allowed to use. -- If Sonarqube version is 9.9 or above, choose Java– version 17, otherwise Java – version 11 -- Maven - 3.8.3 +![Ecosonar Architecture Azure](./images/ecosonar-architecture-azure.webp) <a name="infra"></a> + ### Infrastructure Requirements -- Docker Registry: storage of the Ecosonar API Docker image + +- Docker Registry: storage of the Ecosonar API Docker image. You can directly use our Github Package which host a Docker image of EcoSonar - Docker server with RAM > 4Gb necessary for the analysis by Google Lighthouse - MongoDB database - Private network: protects the data stored in the database and makes it only accessible to the specified services. - Subnet associated with the private network: connection between the database and the API - Password Manager: store the password to access the database from the API and credentials used to audits pages requiring authentication -<a name="configuration"></a> -## EcoSonar Configuration +<a name="installation"></a> + +## EcoSonar Local Installation + +To install EcoSonar locally, you have two options: + +1. Use Docker +Run the following commands: +``` +cd EcoSonar-SonarQube +export REACT_APP_BASE_URL_ECOSONAR_API=http://localhost:3000 +mvn clean package -Durl=http://localhost:3000 + +cd .. +docker-compose build +docker-compose up +``` -To setup the EcoSonar-API, follow the instructions available here: https://github.com/Accenture/EcoSonar/blob/main/EcoSonar-API/README.md +2. Launch each component seperately. +Follow instructions in both Readme file: +https://github.com/Accenture/EcoSonar/blob/main/EcoSonar-API/README.md +https://github.com/Accenture/EcoSonar/blob/main/EcoSonar-SonarQube/README.md -For EcoSonar Sonarqube plugin : https://github.com/Accenture/EcoSonar/blob/main/EcoSonar-SonarQube/README.md <a name="ecocode-config"></a> + ## Ecocode Configuration For specific details on Ecocode, please look at their GitHub repository: https://github.com/green-code-initiative/ecoCode . -You will find here https://github.com/Accenture/EcoSonar/tree/main/EcoSonar-SonarQube/ecocode the EcoCode Sonarqube plugin that needs to be imported into your Sonarqube instance. -To install plugins, you can follow the same instructions provided for EcoSonar Sonarqube plugin https://github.com/Accenture/EcoSonar/tree/main/EcoSonar-SonarQube#install-sonarqube-plugins and copy/paste the jar files into the same `extensions/plugins/` folder. - +You will find here `https://github.com/Accenture/EcoSonar/tree/main/EcoSonar-SonarQube/ecocode` the EcoCode Sonarqube plugin that needs to be imported into your Sonarqube instance. +To install the ecocode plugins, please follow instruction from EcoSonar SonarQube plugin : https://github.com/Accenture/EcoSonar/blob/main/EcoSonar-SonarQube/README.md When using Sonarqube as code analysis, a default Quality Profile is set up for each language. If you want to use EcoCode rules related to eco-design, you will have to: + - create a new Quality Profile based on the default one : click on the Setting icon for the languge you wish to extend and then Click on `Extend` and create the new Quality Profile ![EcoSonar Quality Profile Creation](./images/java-quality-profile.webp) @@ -102,56 +112,64 @@ When using Sonarqube as code analysis, a default Quality Profile is set up for e ![EcoSonar Default Quality Profile](./images/ecosonar-default-quality-profile.webp) +Do the same setup for each languague you wish to use with Ecocode rules. <a name="audit"></a> + ## Audit Tools <a name="greenit-cnumr"></a> + ### GreenIT-Analysis/EcoIndex EcoIndex makes it possible to become aware of the environmental impact of the Internet and to propose concrete solutions. You enter a URL into the EcoIndex, which then calculates the performance and environmental footprint of the tested page represented by a score out of 100 and a rating from A to G (the higher the rating, the better!). Several criteria are taken into account by our calculation method: -- The complexity of the page: the DOM (Document Object Model) represents the structure and the elements of an HTML web page. The more elements the DOM contains, the more complex the page is to decipher, and therefore to display for the browser. Concretely, all this means a greater effort to provide on the part of the processor of your computer to display the page, which reduces the life of your equipment. -- The weight of data transferred: before appearing on your screen, a web page is a set of data stored on a server. When you access a page, your browser sends a request to the server to communicate this data to it, in order to format it and display it on your screen. Only here: the transport of this data, more or less heavy, from the server to the browser requires energy. -- The number of HTTP requests: this criterion makes it possible to take into account the effort made by the servers to display the tested page. The greater the number of requests for the same page, the more servers will be needed to serve this page. -Official website: https://www.ecoindex.fr/ +- The complexity of the page: the DOM (Document Object Model) represents the structure and the elements of an HTML web page. The more elements the DOM contains, the more complex the page is to decipher, and therefore to display for the browser. Concretely, all this means a greater effort to provide on the part of the processor of your computer to display the page, which reduces the life of your equipment. +- The weight of data transferred: before appearing on your screen, a web page is a set of data stored on a server. When you access a page, your browser sends a request to the server to communicate this data to it, in order to format it and display it on your screen. Only here: the transport of this data, more or less heavy, from the server to the browser requires energy. +- The number of HTTP requests: this criterion makes it possible to take into account the effort made by the servers to display the tested page. The greater the number of requests for the same page, the more servers will be needed to serve this page. + +Official website: https://www.ecoindex.fr/ Chrome extension: https://chrome.google.com/webstore/detail/greenit-analysis/mofbfhffeklkbebfclfaiifefjflcpad?hl=fr -GitHub Link: https://github.com/cnumr/GreenIT-Analysis-cli +GitHub Link: https://github.com/cnumr/GreenIT-Analysis-cli <a name="ligthhouse"></a> + ### Google Lighthouse Lighthouse is an open-source, automated tool for improving the quality of web pages. You can run it against any web page, public or requiring authentication. It has audits for performance, accessibility and more. By default, Lighthouse produces a report in JSON or HTML. We will store the JSON report provided in the database to be able to monitor the various performances afterwards. It is also possible to customize this report to obtain only the desired metrics. -Official website: https://developer.chrome.com/docs/lighthouse/overview/ +Official website: https://developer.chrome.com/docs/lighthouse/overview/ -Chrome extension: https://chrome.google.com/webstore/detail/lighthouse/blipmdconlkpinefehnmjammfjpmpbjk +Chrome extension: https://chrome.google.com/webstore/detail/lighthouse/blipmdconlkpinefehnmjammfjpmpbjk -GitHub Link: https://github.com/GoogleChrome/lighthouse +GitHub Link: https://github.com/GoogleChrome/lighthouse <a name="w3c"></a> + ### W3C Validator The Markup Validator is a free service by W3C that helps check the validity of Web documents. Validating Web documents is an important step which can dramatically help improving and ensuring their quality, and it can save a lot of time and money. Validating Web Pages is also an important accessibility best practices to resolve (RGAA, criteria 8.2). If the HTML code is not well formatted, the browser will dynamically correct a certain number of elements to best display the pages causing problems. These dynamic corrections consume resources unnecessarily each time the pages concerned are loaded. -Official website: https://validator.w3.org/ +Official website: https://validator.w3.org/ -GitHub Link: https://github.com/zrrrzzt/html-validator +GitHub Link: https://github.com/zrrrzzt/html-validator <a name="ecocode"></a> + ### EcoCode -EcoCode is a SonarQube plugin developed by a french open-source community called Green Code Initiative. Their goal is to share best practices of development, be aware of environmental responsibility when programming, and together construct rules and metrics for assigning to mobile and web applications an "environmental label". They have defined a list of green coding rules to be checked through a Sonarqube analysis to reduce RAM or CPU usage of software application. +EcoCode is a SonarQube plugin developed by a french open-source community called Green Code Initiative. Their goal is to share best practices of development, be aware of environmental responsibility when programming, and together construct rules and metrics for assigning to mobile and web applications an "environmental label". They have defined a list of green coding rules to be checked through a Sonarqube analysis to reduce RAM or CPU usage of software application. Official website: https://www.ecocode.io/ -GitHub Link: https://github.com/green-code-initiative +GitHub Link: https://github.com/green-code-initiative <a name="about"></a> + ## About To get more info on EcoSonar, you can contact ecosonar-team@accenture.com and have a look at our new website : https://ecosonar.org. @@ -172,4 +190,4 @@ To know more on ecodesign best practices, EcoIndex Calculator and how an ecodesi https://blog.octo.com/sous-le-capot-de-la-mesure-ecoindex/ -https://blog.octo.com/une-bonne-pratique-vers-un-numerique-plus-responsable-mesurer-le-ressenti-des-internautes/ \ No newline at end of file +https://blog.octo.com/une-bonne-pratique-vers-un-numerique-plus-responsable-mesurer-le-ressenti-des-internautes/ diff --git a/ROADMAP.md b/ROADMAP.md deleted file mode 100644 index 9e84433..0000000 --- a/ROADMAP.md +++ /dev/null @@ -1,7 +0,0 @@ -# Roadmap - -1) GHG Emissions Calculation using SCI Methodology (https://github.com/Green-Software-Foundation/sci/blob/main/Software_Carbon_Intensity/Software_Carbon_Intensity_Specification.md) - -2) Integration of WebSite Analytics : weighted-average of EcoSonar scores according to page frequency, detection of pages not visited that could be decomissionned, etc. - -3) More green coding rules diff --git a/USER_GUIDE.md b/USER_GUIDE.md index 241db61..f6f4d37 100644 --- a/USER_GUIDE.md +++ b/USER_GUIDE.md @@ -2,24 +2,46 @@ # EcoSonar, the eco-design audit tool - USER GUIDE +## Summary + +- [Project Configuration](#project-config) +- [[OPTIONAL] Configure Authentication for your project](#auth) +- [[OPTIONAL] Configure Proxy for your project](#proxy) +- [[OPTIONAL] Configure User flow for each URL](#user-flow) +- [Launching an EcoSonar Analysis](#launch) +- [Retrieve an EcoSonar Analysis of your project](#get-analysis) +- [Retrieve EcoSonar recommendations](#get-recos) +- [Retrieve Green Coding Rules to implement](#get-green-code-smells) + +<a name="project-config"></a> + ## Project Configuration To realize an EcoSonar audit on a web-based application, you will need first to configure which URLs you want to audit. We recommend you to choose the Sonarqube project linked to your frontend code repository if you wish to launch EcoSonar audits directly in your CI/CD pipeline. Once Sonarqube project chosen to embed your future reports, you will need to go into the page called "EcoSonar URL Configuration". ![EcoSonar Configuration Page Access](./images/ecosonar-configuration-page.webp) +![EcoSonar URL Page](./images/ecosonar-url-page.webp) You will have two options to enter the pages you want to audit. 1. Automatically with a crawler -We have implemented a crawler that will detect automatically all pages from you website. It will be looking for "href" attributes to detect all redirections in your website. We suggest you to use this crawler when you want for the first time deploy to EcoSonar within your project. You will only need to enter the homepage of your website to retrieve all pages that can be accessible. - ![EcoSonar URL Configuration](./images/ecosonar-url-configuration.webp) + +We have implemented a crawler that will detect automatically all pages from you website. It will be looking for "href" attributes to detect all redirections in your website. We suggest you to use this crawler when you want for the first time deploy to EcoSonar within your project. + +You will need to enter the homepage of your website to retrieve all pages that can be accessible. +Then you have two options: + +- save the results in a temporary database you will retrieve by clicking on the button `Get crawled URLs`. Then you will be able to choose which one you want EcoSonar to audit. This option is enabled by default. +- save the results in database so that EcoSonar will audit them once analysis is triggered. This option is enabled by selecting `Save urls as to be audited by EcoSonar`. + ![EcoSonar URL Crawler Setup Configuration](./images/ecosonar-url-crawler-setup.webp) -![EcoSonar URL Crawler Result Configuration](./images/ecosonar-url-crawler-result.webp) -Once you have retrieved all pages detected automatically, you can choose the ones you wish to audit and validate the list. +After waiting a few minutes until the crawler found all pages within the website, you can retrieve them by clicking on the button `Get crawled URLs` (for option 1 only). Then, select the different pages you wish EcoSonar to audit. You will get them after in the initial URL Configuration page. + +![EcoSonar URL Crawler Result Configuration](./images/ecosonar-url-crawler-result.webp) 2. Manually @@ -29,6 +51,321 @@ Thanks to a configuration popup, you can enter manually the pages to audit. This ![EcoSonar Configuration Page](./images/ecosonar-configure-urls.webp) +<a name="auth"></a> + +## [OPTIONAL] Configure Authentication for your project + +In order to audit pages that can be accessed only through an authentication service (intranet pages for example), +you need to add authentication credentials into EcoSonar API to allow auditing dedicated pages. + +### When you have a simple login flow : username, password and click on a button + +#### EcoSonar V2.3 and below + +To implement that, you can create a YAML file login.yaml at the root of the folder `EcoSonar-API` and use the following format +if the CSS selector of you input field is `input[name=username]` or `input[type=email]`, password field `input[name=password]`, `input[type=password]`, `input[id=password]` and button `button[type=submit]` : + +``` +authentication_url: authenticationPage +username: yourUsername +password: yourPassword +``` + +or if one of the CSS Selector does not match the default CSS Selectors : + +``` +authentication_url:authenticationPage +username: yourUsername +password: yourPassword +loginButtonSelector: CSS_Selector_Button +usernameSelector: CSS_Selector_Login +passwordSelector: CSS_Selector_Password +``` + +##### CSS Selectors + +CSS Selectors are patterns in HTML code to apply some style (doc ). For exemple, to find the css selector of  loginButtonSelector: +Go to the login page of your website +Right click on the login button +Select inspect +Choose css selectors you want (class, type, name, id, ....) + +More Information : + +documentation: https://github.com/cnumr/GreenIT-Analysis-cli/blob/072987f7d501790d1a6ccc4af6ec06937b52eb13/README.md#commande +code: https://github.com/cnumr/GreenIT-Analysis-cli/blob/072987f7d501790d1a6ccc4af6ec06937b52eb13/cli-core/analysis.js#L198 + +#### EcoSonar V3.0 and above + +You can directly configure your login credentials at a project level in the API. +Be careful your login credentials will then be saved into the database, please check with your security team if you are allowed to do so. + +You can use the Endpoint "Save Login and Proxy" and enter the following body: + +``` +{ + "login": { + "authentication_url": "authenticationPage", + "username": "yourUsername", + "password": "yourPassword" + } +} +``` + +or + +``` +{ + "login": { + "authentication_url": "authenticationPage", + "username": "yourUsername", + "password": "yourPassword", + "loginButtonSelector": "CSS_Selector_Button", + "usernameSelector": "CSS_Selector_Login", + "passwordSelector": "CSS_Selector_Password" + } +} +``` + +### More complicated Login flows + +When the Username and password are not in the same page, or you need other user inputs to complete authentication + +#### EcoSonar V2.3 and below + +If the authentication of the website required steps or a page change, you must follow these requirements: + +1. Create a YAML file login.yaml at the root of the repo +2. Add authentication_url key and value is required +3. Add steps key is required +4. Fill steps part as follow + +To choose you authentification_url, you can either set it to the page in which you need to perform the authentification steps or pick the page that can only be accessed after being authenticated. + +(To help you to create steps, you can use on Google Chrome Tool "Recorder". (inspector -> recorder -> start a new recording) and save json file, then you can extract steps type, target, selectors) + +Each step is a description of an action made by a regular user: + +- "click" -> Click on a button for example: "submit" or "next" + type: "click" (required) + selector: CSS Selector of the field or button (required) +- "change" -> to fill a field like username or password + type: "change" (required) + selector: CSS Selector of the field or button (required) + value: value of the password or username (required) + /!\ CSS Selectors with "aria" label are not read by EcoSonar. + +Example of login.yaml file. to access into an account + +``` +authentication_url: authenticationPage +steps: +  -   type: "click" +      selectors: +          - "#input-email" +  -   type: "change" +      value: "my email" +      selectors: +          - "#input-email" +  -   type: "click" +      selectors: +        - "#lookup-btn" +  -   type: "change" +      value: "my password" +      selectors: +          - "#input-password" +  -   type: "click" +      selectors: +        - "#signin-button" +``` + +#### EcoSonar V3.0 and above + +You can use directly to configure your login credentials at a project level in the API. + +You can use the Endpoint "Save Login and Proxy" and enter the following body: + +``` +{ + "login": { + "authentication_url": "authenticationPage", + "steps" : [ ....] + } +} +``` + +<a name="proxy"></a> + +## [OPTIONAL] Configure Proxy for your project + +For some websites, you may need to configure a proxy in order to access it. +You need to seperate the analysis that are made with or without a proxy into several EcoSonar projects. + +### EcoSonar V2.3 and below + +To implement that, you can create a YAML file proxy.yaml at the root of the repo. +Please find below the configuration format : + +``` +ipaddress: ipAddress +port: port +projectName: (optional) + - PROJECT_NAME_1 + - PROJECT_NAME_2 +``` + +ipaddress : IP Address of your proxy +port : port of your proxy + +projectName : list of EcoSonar Projects (corresponding to Sonarqube projectKey) that needs a proxy to audit pages registered. If no projectName has been added but proxy.yaml file exists, then proxy will be applied by default to all your projects. + +### EcoSonar V3.0 and above + +You can directly configure your login credentials at a project level in the API. + +You can use the Endpoint "Save Login and Proxy" and enter the following body: + +``` +{ + "proxy": { + "ipAddress": "ipAddress", + "port" : "port" + } +} +``` + +<a name="user-flow"></a> + +## [OPTIONAL] Configure User flow for each URL + +In order to audit some pages, sometimes you may need to go through a user flow to get access to that page (for exemple fill in a form). Otherwise, if you don't have the context, the page can not be accessed. +We have added this functionality into EcoSonar. + +### User Flow Creation + +#### First method : using Chrome Recorder + +If your business allows to use Chrome Browser, we hightly recommend you to use this method. +Chrome has a native panel called "Recorder" that allows you to record, replay and measure user flows (https://developer.chrome.com/docs/devtools/recorder/). + +![Chrome Recorder](./images/chrome-recorder.webp) + +To access this panel, please click right on your browser, select Inspect, then choose Recorder in the DevTools Panel. + +To start recording a user flow, you can then click on button "Start new recording", choose a name then click on "Start a new recording". + +![Start Chrome Recorder](./images/chrome-start-recorder.webp) + +Then the Chrome browser is going to register every interaction that is made with the page and save it into the user flow. + +For example, we want to audit this page : http://www.ecometer.org/job?url=https%3A%2F%2Fwww.accenture.com%2Ffr-fr. It is only accessible if you are launching an analysis of the website with Ecometer : + +1. You need to navigate to the page : http://www.ecometer.org/ +2. You need to change the input to have your URL. +3. You need to click on the button "Analyse" to launch the analysis. + +![Chrome Recorder User flow](./images/chrome-recorder-result.webp) + +Chrome Recorder is going to register the user flow by saving every step/interaction. + +To make sure your user flow is correct and can be used through Ecosonar, please use "Replay" button and start from initial page to make sure the User flow automation is set up correctly. You should have the result as your previous manual configuration. + +/!\ Be Careful "click" steps are not duplicated in your userflow (same element triggered) otherwise it could not have the expected behaviour. You can remove step in the Recorder by clicking on the 3 dots. + +Once you have validated your userflow, you can export this User Flow using the export button and choose JSON. + +![Chrome Recorder User flow export](./images/save-chrome-recorder.webp) + +#### Second method : creating your own User Flow JSON + +If you are not allowed to use Chrome Browser, you can edit manually the user flow JSON file created by Chrome Recorder. +It should have the following format : + +``` +{​​​​​​​​ + "steps": [ + {​​​​ + "type": "navigate", + "url": "http://www.ecometer.org/", + }​​​​​​​​​​​​​​​​​​, + {​​​​​​​​​​​​​​​​​​​​​​ + "type": "click", + "selectors": [ + [ + "body > div.container.begin > div > form > input.url" + ] + ], + }​​​​​​​​​​​​​​​​​​​​​​, + {​​​​​​​​​​​​​​​​​​​ + "type": "change", + "value": "https://www.accenture.com/fr-fr", + "selectors": [ + [ + "body > div.container.begin > div > form > input.url" + ] + ], + }​​​​​​​​​​​​​​​​​​​, + {​​​​​​​​​​​​​​​​​​​ + "type": "click", + "selectors": [ + [ + "body > div.container.begin > div > form > input.button" + ] + ], + ] + }​​​​​​​​​​​​​​​​​​​, + { + "type": "scroll", + "distancePercentage": 50 + }, + ] +}​​​​​​​​​​​​​​​​​​​​​​​​​​​​​ +``` + +We are handling into EcoSonar 4 kind of browser interactions : + +1. Navigate to a URL + It should have "type" = "navigate" and "url" the url you want to go to +2. Change an input field + "type" = "change", "value" : value to be set in the input field, "selectors" : list of CSS Selectors to find the right input field +3. Click on a button + "type" = "click", "selectors" : list of CSS Selectors to find the right button +4. Scroll in the page and stop at a certain percentage at the page. + It will scroll down each 100px until the scroll limit has been reached. For example, the page is 1080px and we want to stop at the middle of the page (so distancePercentage = 50 %), it will iterate every 100 pixels until the windows has scrolled 540 px. + "type" = "scroll" and "distancePercentage" = value between 0 and 100 + +### User Flow Integration + +#### EcoSonar v2.3 and below + +Once you have been able to define the JSON file matching to your user flow, you can followed instructions: + +1. Create a folder "userJourney" if it does not exists yet at the root of the folder `EcoSonar-API`. +2. Paste JSON file created in the folder "userJourney" and rename it with the URL you wish to audit. Please remove the following special character `:` `?` `:` `/` from the URL in order to save the JSON. To retrieve the user flow we are matching it with the URL registered through EcoSonar URL Configuration. This step is not to forget otherwise EcoSonar won't be auditing the right page. +3. Deploy EcoSonar-API with all relevant user flows. +4. Launch a new EcoSonar audit to verify there are no technical errors in the logs application. Correct them if needed. + +#### EcoSonar v3.0 and above + +With version 3.0, you can directly configure the user flow in the API provided (no longer need to reboot the instance) +You can use the Endpoint "Save User Flow" and enter the following body: + +``` +{ + "url": "urlToAudit, + "userFlow": { + "steps": [ ....] + } +} +``` + +### User Flow Verification + +To verify pages you audit are the correct ones, we suggest you to use both Chrome extensions : Green-IT Analysis (https://chrome.google.com/webstore/detail/greenit-analysis/mofbfhffeklkbebfclfaiifefjflcpad?hl=fr) and Google Lighthouse (https://chrome.google.com/webstore/detail/lighthouse/blipmdconlkpinefehnmjammfjpmpbjk?hl=fr) and compare results from these extensions to the EcoSonar audits. There should be almost identical. +If that is not the case, do not hesitate to contact us to help you. + +<a name="launch"></a> + ## Launching an EcoSonar Analysis If your Sonarqube project is linked to a Code Repository with the Continuous and Integration Pipeline, then the EcoSonar analysis will be launched at the same time of Sonarqube analyis and will audit the pages you have registered. After the analysis has ended, you will be able to see the dashboard representing the scores of your application. @@ -38,6 +375,10 @@ If you do not wish to correlate a Sonarqube analysis and an EcoSonar audit, you Check for the Request called `Launch an EcoSonar Analysis` +Or go to the Swagger User interface available at `[ECOSONAR-API-URL]/swagger/` and then choose the endpoint `Launch an EcoSonar Analysis` + +<a name="get-analysis"></a> + ## Retrieve an EcoSonar Analysis of your project ![EcoSonar Analysis Page](./images/ecosonar-analyis-access.webp) @@ -59,7 +400,6 @@ In the central panel, you will find all the metrics used to calculate the 3 scor ![EcoSonar Analysis Page charts](./images/ecosonar-analyis-charts.webp) - In this first panel, you will find an average of all metrics from your website (sum of all pages). But you can be more precise in your analysis by retrieving the audit page per page with the same amount of details. ![EcoSonar Audit per page](./images/ecosonar-audit-per-page.webp) @@ -76,13 +416,16 @@ And then, each sheet will summarize audit results for each page of your website ![EcoSonar Export Project](./images/ecosonar-export-url.webp) -## Retrieve EcoSonar recommendations +<a name="get-recos"></a> + +## Retrieve EcoSonar recommendations The last page in the EcoSonar tool is the EcoSonar Best Practices. ![EcoSonar Best Practices Page Access](./images/ecosonar-best-practices-access.webp) EcoSonar lists now audits from ecodesign and accessibility best practices coming from : + - Green-IT Analysis and Google Lighthouse Performance for ecodesign purposes - Google Lighthouse Accessibility & W3C Validator for accessibility purposes @@ -91,6 +434,7 @@ EcoSonar lists now audits from ecodesign and accessibility best practices coming ![EcoSonar Best Practices Page Accessibility](./images/ecosonar-best-practices-accessibility.webp) For each recommendation, you can find the following information: + - Title of the Best Practice - Level of implementation (a letter from A to G) : represents if the best practice has been implemented or not in your project (a score from 0 to 100 is also available through the API) - Measured metric in your project/page related to the best practice. The level of implementation has been set by comparing this value to ecodesign standards. @@ -104,6 +448,7 @@ For each recommendation, you can find the following information: When first arriving to this page, you will have the choose the right Procedure. A procedure in EcoSonar is a sorting algorithm that will sort your ecodesign best practices according the 3 different configuration: + - `Score Impact` : best practices will be sorted by descending order of implementation (best practices not implemented returned first) - `Highest Impact` : best practices will be sorted by order of impact to improve EcoSonar scores (best practices most efficient returned first) - `Quick Wins` : best practices will be sorted by ascending order of difficulty (best practices easy to implement returned first) @@ -113,6 +458,7 @@ Choose the one that will better fit with your priorities. We suggest you if you ![EcoSonar Procedure Page](./images/ecosonar-procedure-page.webp) Once your procedure chosen, feel free to use and discover the several audits made for your website with the available filters: + - Type of audit : `ecodesign` or `accessibility` - Audit Tool : `Green-IT Analysis`, `Google Lighthouse Performance`, `Google Lighthouse Accessibility` or `W3C Validator` - Levels : `A`, `B`, `C`, `D`, `E`, `F`, `G` and `N.A` (by default `A` and `N.A` best practices will not be displayed) @@ -120,9 +466,11 @@ Once your procedure chosen, feel free to use and discover the several audits mad ![EcoSonar Audit Filters](./images/ecosonar-audit-filters.webp) +<a name="get-green-code-smells"></a> + ## Retrieve Green Coding Rules to implement -EcoSonar now integrates Ecocode green coding rules to help you code greener. This functionality comes in addition to default coding rules audited through a SonarQube analysis. Right now, 3 languages are supportes : Java, PHP and Python. +EcoSonar now integrates Ecocode green coding rules to help you code greener. This functionality comes in addition to default coding rules audited through a SonarQube analysis. Right now, 7 languages are supported : Java, PHP, Python, JavaScript, TypeScript, Android and iOS/Swift. Let's take as example a Java project. @@ -142,4 +490,4 @@ When you want to resolve a code smell, you can click directly into it and it wil To get some documentation on how to solve the code smell, you can click on the link `Why is this an issue ?` and a pop up will be displayed to explain why is this issue an ecodesign best practice and example of compliant and non-compliant code to help you in your implementation. -![EcoSonar Code Smell Correction](./images/ecosonar-code-smell-correction.webp) \ No newline at end of file +![EcoSonar Code Smell Correction](./images/ecosonar-code-smell-correction.webp) diff --git a/images/delete-project.webp b/images/delete-project.webp new file mode 100644 index 0000000000000000000000000000000000000000..ca414a1d8ff1ba3bd33d11bfdb071681b878d3ca GIT binary patch literal 10202 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 I!XP03248YK`Tzg` literal 0 HcmV?d00001 diff --git a/images/ecosonar-url-configuration.webp b/images/ecosonar-url-configuration.webp index c2efafe84b85d78739783381a572020d399fbd08..4576c4b74a4472e2b399d79c4f882d43654b5440 100644 GIT binary patch literal 19108 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 H!T<mOgmA_6 literal 27026 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 diff --git a/images/ecosonar-url-crawler-result.webp b/images/ecosonar-url-crawler-result.webp index f33c17adecd82eecfceaf59579c771bd5e6647a9..971a5d13c86047c959ea551b4913de55e4bdbd70 100644 GIT binary patch literal 24334 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 U8e+PjU4G~|>@OU27#Ns;1Jmg0p8x;= literal 28992 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 QtyijZQh8`UzUp%S3sCqVzW@LL diff --git a/images/ecosonar-url-crawler-setup.webp b/images/ecosonar-url-crawler-setup.webp index d93d361a4e35620322dc3a15bbd80eb1f142b25e..62fbc8d5588887ff3ca69821928b8feba9e61594 100644 GIT binary patch literal 17354 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 literal 13358 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 diff --git a/images/ecosonar-url-page.webp b/images/ecosonar-url-page.webp new file mode 100644 index 0000000000000000000000000000000000000000..9d3e7d196b371adee5d8395f2877d109e0470384 GIT binary patch literal 17870 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 Q5HVV{t5{Bnypym10B0)$zyJUM literal 0 HcmV?d00001 diff --git a/images/get-best-practices-documentation.webp b/images/get-best-practices-documentation.webp new file mode 100644 index 0000000000000000000000000000000000000000..a6ef2d627141b63eb056b76cc5a66ecb81666c94 GIT binary patch literal 9190 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 literal 0 HcmV?d00001 diff --git a/images/get-crawler-result.webp b/images/get-crawler-result.webp index 9de78ae43cd4bc265a4f4b860b2b01f0e502bc3c..003af81bb44cb8f96e84615703c0fbab0f6c91f7 100644 GIT binary patch literal 14792 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 literal 13674 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 L+0~ff!NC3xg%IvM diff --git a/images/get-version.webp b/images/get-version.webp new file mode 100644 index 0000000000000000000000000000000000000000..75867c4994d500e1c91e20c9c22693544bc7c410 GIT binary patch literal 8426 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 literal 0 HcmV?d00001 diff --git a/images/launch-crawler.webp b/images/launch-crawler.webp new file mode 100644 index 0000000000000000000000000000000000000000..c675737224c7f8459ea1d751247bce260f27dfaf GIT binary patch literal 17634 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 literal 0 HcmV?d00001 diff --git a/images/save-login-and-proxy-for-project.webp b/images/save-login-and-proxy-for-project.webp deleted file mode 100644 index f1df744467b7b80ab860704ee55556ece7fb66f5..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 15660 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 be|asf_jDn}Kw|Wvz_1~X6e<Bz3k3ULcy@}! diff --git a/images/save-login-for-project.webp b/images/save-login-for-project.webp new file mode 100644 index 0000000000000000000000000000000000000000..338d8c4ab17fe912673639499f30caeb75f59b50 GIT binary patch literal 15552 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 literal 0 HcmV?d00001 diff --git a/images/save-proxy-for-project.webp b/images/save-proxy-for-project.webp new file mode 100644 index 0000000000000000000000000000000000000000..661c1cd7e43724c9c762529094acd92458acf540 GIT binary patch literal 14830 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 literal 0 HcmV?d00001