diff --git a/docs/assets/changelog-service.png b/docs/assets/changelog-service.png new file mode 100644 index 0000000000000000000000000000000000000000..cdc1c41841189f3899449ebbe349d3e728427ec7 Binary files /dev/null and b/docs/assets/changelog-service.png differ diff --git a/docs/assets/credits-service.png b/docs/assets/credits-service.png new file mode 100644 index 0000000000000000000000000000000000000000..5f308487208091c10899f5687377c3d062d75681 Binary files /dev/null and b/docs/assets/credits-service.png differ diff --git a/docs/assets/media-library-service.png b/docs/assets/media-library-service.png index b13811342853ec729e33b309c3349d09b7f8fae9..f8a513fe2aed9347a7a34dcb8c26704bb16585a6 100644 Binary files a/docs/assets/media-library-service.png and b/docs/assets/media-library-service.png differ diff --git a/docs/assets/resources-service.png b/docs/assets/resources-service.png new file mode 100644 index 0000000000000000000000000000000000000000..5f308487208091c10899f5687377c3d062d75681 Binary files /dev/null and b/docs/assets/resources-service.png differ diff --git a/docs/assets/reuses-service.png b/docs/assets/reuses-service.png new file mode 100644 index 0000000000000000000000000000000000000000..cdc1c41841189f3899449ebbe349d3e728427ec7 Binary files /dev/null and b/docs/assets/reuses-service.png differ diff --git a/docs/assets/social-media-share-helper.png b/docs/assets/social-media-share-helper.png new file mode 100644 index 0000000000000000000000000000000000000000..cfa7d84dde107be2fafae0dcb966589dc44e907c Binary files /dev/null and b/docs/assets/social-media-share-helper.png differ diff --git a/docs/assets/webapp/changelog.png b/docs/assets/webapp/changelog.png new file mode 100644 index 0000000000000000000000000000000000000000..579505932f507bddcbf7b67f2986d7663af0de2e Binary files /dev/null and b/docs/assets/webapp/changelog.png differ diff --git a/docs/assets/webapp/contact.png b/docs/assets/webapp/contact.png new file mode 100644 index 0000000000000000000000000000000000000000..2ee4a3896be6e2812d58e5094ac32e1860f14cbb Binary files /dev/null and b/docs/assets/webapp/contact.png differ diff --git a/docs/assets/webapp/credits.png b/docs/assets/webapp/credits.png new file mode 100644 index 0000000000000000000000000000000000000000..88bd1c4abff0dae33c70b0ed5f98f5e7e09fcbfd Binary files /dev/null and b/docs/assets/webapp/credits.png differ diff --git a/docs/assets/webapp/data.png b/docs/assets/webapp/data.png new file mode 100644 index 0000000000000000000000000000000000000000..9b1aac582f2c8c366cf6cc297edd2461f905f63c Binary files /dev/null and b/docs/assets/webapp/data.png differ diff --git a/docs/assets/webapp/dataset-detail.png b/docs/assets/webapp/dataset-detail.png new file mode 100644 index 0000000000000000000000000000000000000000..cbe9a73f31eca823ab2275737b484bdaca4238a3 Binary files /dev/null and b/docs/assets/webapp/dataset-detail.png differ diff --git a/docs/assets/webapp/download-resources.png b/docs/assets/webapp/download-resources.png new file mode 100644 index 0000000000000000000000000000000000000000..13d9a03cdef25b5af70bc157f0694091989243e8 Binary files /dev/null and b/docs/assets/webapp/download-resources.png differ diff --git a/docs/assets/webapp/downloads-2.png b/docs/assets/webapp/downloads-2.png new file mode 100644 index 0000000000000000000000000000000000000000..48711eea4edf648af078f3c430e548cecbd58fc7 Binary files /dev/null and b/docs/assets/webapp/downloads-2.png differ diff --git a/docs/assets/webapp/downloads.png b/docs/assets/webapp/downloads.png new file mode 100644 index 0000000000000000000000000000000000000000..80bdb73709859c667d0da3ac71cdce34fdf5a883 Binary files /dev/null and b/docs/assets/webapp/downloads.png differ diff --git a/docs/assets/webapp/feedback.png b/docs/assets/webapp/feedback.png new file mode 100644 index 0000000000000000000000000000000000000000..db1b5f321bed58b0bdccfcafa32c0a7180e61784 Binary files /dev/null and b/docs/assets/webapp/feedback.png differ diff --git a/docs/assets/webapp/filters.png b/docs/assets/webapp/filters.png new file mode 100644 index 0000000000000000000000000000000000000000..4e2bb710d3b340b1d325e0a79a683cf7621afb4b Binary files /dev/null and b/docs/assets/webapp/filters.png differ diff --git a/docs/assets/webapp/footer.png b/docs/assets/webapp/footer.png new file mode 100644 index 0000000000000000000000000000000000000000..21297f99e9dd849ad4ae5821246e420a6436ee57 Binary files /dev/null and b/docs/assets/webapp/footer.png differ diff --git a/docs/assets/webapp/geo-resources.png b/docs/assets/webapp/geo-resources.png new file mode 100644 index 0000000000000000000000000000000000000000..d87d4073cc62069d381e44e6a5ae00dd251bc09f Binary files /dev/null and b/docs/assets/webapp/geo-resources.png differ diff --git a/docs/assets/webapp/header.png b/docs/assets/webapp/header.png new file mode 100644 index 0000000000000000000000000000000000000000..dc5920ce782c436bcddc128090958c7ec6f1a8a6 Binary files /dev/null and b/docs/assets/webapp/header.png differ diff --git a/docs/assets/webapp/homepage.png b/docs/assets/webapp/homepage.png new file mode 100644 index 0000000000000000000000000000000000000000..cba949b302e2246283ed2de9015aeeada455121d Binary files /dev/null and b/docs/assets/webapp/homepage.png differ diff --git a/docs/assets/webapp/info-contact.png b/docs/assets/webapp/info-contact.png new file mode 100644 index 0000000000000000000000000000000000000000..46bf0187c05dc756b95fcbd0616dd7e3179c44f4 Binary files /dev/null and b/docs/assets/webapp/info-contact.png differ diff --git a/docs/assets/webapp/info.png b/docs/assets/webapp/info.png new file mode 100644 index 0000000000000000000000000000000000000000..800f8c8b5cae07d678951d8ccce110f1c1f78666 Binary files /dev/null and b/docs/assets/webapp/info.png differ diff --git a/docs/assets/webapp/other-resources.png b/docs/assets/webapp/other-resources.png new file mode 100644 index 0000000000000000000000000000000000000000..b6e9fe93b1684679807e8d8ab8e6fd5972db8c58 Binary files /dev/null and b/docs/assets/webapp/other-resources.png differ diff --git a/docs/assets/webapp/partners.png b/docs/assets/webapp/partners.png new file mode 100644 index 0000000000000000000000000000000000000000..b455d4096762b68a2acde9a33e1413e7c1c91445 Binary files /dev/null and b/docs/assets/webapp/partners.png differ diff --git a/docs/assets/webapp/reuses.png b/docs/assets/webapp/reuses.png new file mode 100644 index 0000000000000000000000000000000000000000..1792a83ea58baeb98fbb2379d07eea3eb211bd1e Binary files /dev/null and b/docs/assets/webapp/reuses.png differ diff --git a/docs/assets/webapp/search.png b/docs/assets/webapp/search.png new file mode 100644 index 0000000000000000000000000000000000000000..2a9782ba67530cc06c710b666575e6546dfdf578 Binary files /dev/null and b/docs/assets/webapp/search.png differ diff --git a/docs/assets/webapp/sidemenu.png b/docs/assets/webapp/sidemenu.png new file mode 100644 index 0000000000000000000000000000000000000000..ca686eae2cce4b9682133db390a6aaa41a99def7 Binary files /dev/null and b/docs/assets/webapp/sidemenu.png differ diff --git a/docs/assets/webapp/suggestion.png b/docs/assets/webapp/suggestion.png new file mode 100644 index 0000000000000000000000000000000000000000..908fd64d50868e3e0ee7877d9593792997981fb4 Binary files /dev/null and b/docs/assets/webapp/suggestion.png differ diff --git a/docs/assets/web-app-project-structure.png b/docs/assets/webapp/web-app-project-structure.png similarity index 100% rename from docs/assets/web-app-project-structure.png rename to docs/assets/webapp/web-app-project-structure.png diff --git a/docs/components/custom-apps/admin-gui.md b/docs/components/custom-apps/admin-gui.md index 4422a95b1a6c2e2de9544ebeb1fc69c791e0eb30..a41306a7940d7b224e61c28c0956670c24d547ca 100644 --- a/docs/components/custom-apps/admin-gui.md +++ b/docs/components/custom-apps/admin-gui.md @@ -14,7 +14,7 @@ The interface has been developed with the Angular framework, so you need to have Once you have Node.js installed you need to install the Angular CLI. Open a command line and run: -``` +```bash npm install -g @angular/cli ``` @@ -24,17 +24,17 @@ Open the `/src/assets/config/config.json` file and update the configuration in o For more explainations on how the configuration system works refer to the dedicated [section](../../miscellaneous/multi-environments-docker-build-for-angular.md). - - ### Start the web application Using the Angular CLI: -``` + +```bash ng serve ``` or the npm script (which use the Angular CLI) -``` + +```bash npm run start ``` @@ -45,43 +45,47 @@ We defined in the package.json two scripts that can build the application. One t Those two scripts contain an option `--max_old_space_size=<nb of max RAM octets the node process can take>`. Make sure the number does not exceed your RAM capacity (you can simply remove the option, it will use the default value: 512mb on 32-bit systems and 1gb on 64-bit systems). By incrising the node process memory limit we decrease the build time. For development environment (not optimized) -``` + +```bash npm run build:dev ``` For production environment (optimized) -``` + +```bash npm run build:prod ``` ### Build and deploy with Docker The related files are: + - `docker-compose.yml` which indicates what Dockerfile should be used, what image is going to be build, volumes, exposed port... - `Dockerfile` which describe the steps to build the docker image. Some environment variables need to be set before building or running the image. Use the appropriate command to set those variables: `SET` on Windows, `export` on Linux. -``` +```bash export TAG=<version> export APP_PORT=<port the application should be running on> export CONFIG_FILE_PATH=<path to your config file> ``` Then to build the image run (you can change prod to dev if you don't want an optimized build): -``` + +```bash docker-compose build --build-arg conf=prod admin-gui ``` Once the image is built on your machine, run the following command to start a container: -``` + +```bash docker-compose --project-name admin-gui up ``` ## Authentication -It uses the same authentication methods as the portail data web app, so if you have an account you will be able to log in. However only a user belongging to the admin group will be able to create, modify and delete entities. The groups are managed by the api gateway, for more information refer to the [Authentication and Authorization](../../miscellaneous/authentication&authorization.md) section. - +It uses the same authentication methods as the portail data web app, so if you have an account you will be able to log in. However only a user belonging to the admin group will be able to create, modify and delete entities. The groups are managed by the api gateway, for more information refer to the [Authentication and Authorization](../../miscellaneous/authentication&authorization.md) section. ## TO DEVELOP diff --git a/docs/components/custom-apps/web-app/changelog.md b/docs/components/custom-apps/web-app/changelog.md index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..2751e94512cab3a2013a5b1743ea610f54bf1fba 100644 --- a/docs/components/custom-apps/web-app/changelog.md +++ b/docs/components/custom-apps/web-app/changelog.md @@ -0,0 +1,7 @@ +# Changelog + + + +The main role of the changelog page consists in keeping users posted about the latest developments and bugfixes. Content is retrieved from a dedicated [back-end service](../../services/changelog.md) and displayed in descending order of publication date. Depending on the current language of the Web Application, either the French or the English version is shown. + +As a side role, the changelog page allows users to contact the back-office team, via the [dedicated form](./contact.md). diff --git a/docs/components/custom-apps/web-app/contact.md b/docs/components/custom-apps/web-app/contact.md index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..13a454234197d16f7cb56900c76d6da4a3fcd21e 100644 --- a/docs/components/custom-apps/web-app/contact.md +++ b/docs/components/custom-apps/web-app/contact.md @@ -0,0 +1,13 @@ +# Contact + + + +The contact page allow a user to send mails to the support team (cf. [email service](../../services/mailer.md)). + +User information (firstname, lastname, email) is automatically filled whenever the user is logged in. Otherwise, the task is left to the user. + +The message subject can be either chosen from a dropdown list or typed in (custom subject). + +The component can read the `subject` query parameter from the current url. If such a query parameter is not trivial, then the component uses its value to sets accordingly the `subject` value of the form. The `Contact Us` feature available on the information tab of each dataset page relies on this fonctionnality. Indeed, when the `Contact Us` button is clicked, the user is redirected to the contact page with a prefilled `subject`, equal to the name of the visited dataset. + +In order to activate the submit button, the user has to accept some terms, by checking the dedicated box at the bottom of the form. diff --git a/docs/components/custom-apps/web-app/credits.md b/docs/components/custom-apps/web-app/credits.md index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..f3c215fad6344aec78f7894432d27ca7a51c2b54 100644 --- a/docs/components/custom-apps/web-app/credits.md +++ b/docs/components/custom-apps/web-app/credits.md @@ -0,0 +1,7 @@ +# Credits + + + +This page showcases the Open Source initiatives powering the data.grandlyon.com Web platform. + +Content is fetched from the dedicated [credits service](../../services/credits.md). The logo, name and short description of each record are displayed. Each "card" is clickable and the click will open a new navigation tab, pointing at the address of the official website of the concerned record. diff --git a/docs/components/custom-apps/web-app/dataset/api.md b/docs/components/custom-apps/web-app/dataset/api.md new file mode 100644 index 0000000000000000000000000000000000000000..ac25123b6ca4e48169325939f7d7c2f34a8d00da --- /dev/null +++ b/docs/components/custom-apps/web-app/dataset/api.md @@ -0,0 +1,27 @@ +# API + +We define a resource a piece of information that is associated to a dataset. A resource can be classified in three categories: + +* queryable resources: this is provided by the geographical APIs available for the dataset. +* static resources: a file that can be downloaded directly. For example a PDF, a CSV. +* others: all other types. It might be for example an URL of a website providing more information about the dataset + +## Queryable resources + +For each geographical dataset, there is one or multiple interfaces to access geographical data. These interfaces are standards defined by the Open Geospatial Consortium (OGC). +We have one exception, the `WS` service. It is not a standard, and has been developped for specfic needs for the Métropole de Lyon. + +* WMS (Web Map Service): allows to get map as images +* WFS (Web Feature Service): manipulate geographical information with coordinates and properties +* WCS (Web Coverage Service): retrieves coverages data (geospatial information representing space/time-varying phenomena) +* KML (Keyhole Markup Service): get XML-based files for GIS softwares +* SOS (Sensor Observation Service): query observation and sensor metadata +* WS + +By the way, it is possible to select datasets with the services you want by using the [filters](../search.md#Filters) + +Here is an example of the page. + + +For each service you have the possibility to create a custom reequest (exception for the `SOS` service) and change the options such as the output formats, the projection system or the regions. From that you can copy the custom request, or download the resources that link will give you. +In the previous example in the picture, I would be able to download the image of the 'arbres d'alignement' dataset from the WMS (Web Map Service). diff --git a/docs/components/custom-apps/web-app/dataset/data.md b/docs/components/custom-apps/web-app/dataset/data.md index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..212ca6fe0265b90280af2ed853139754d5bf4408 100644 --- a/docs/components/custom-apps/web-app/dataset/data.md +++ b/docs/components/custom-apps/web-app/dataset/data.md @@ -0,0 +1,108 @@ +# Data + +The Data tab allows users to explore the records associated with a given dataset. The tab includes two main components: + +1. a data table; +2. a map, displayed only for geographical datasets (it makes sense, doesn't it?). + + + +The user can toggle the visibility of each of the two components by clicking on the dedicated buttons. The entire tab can also go fullscreen. + +## Data table + +Each entry of a given dataset is rendered as a line in a table. Data value having simple types (string, integer, float, ...) are fully displayed. Complex data values, such as JSON objects, are replaced by a placeholder signaling the presence of a complex property. Records are retrieved from the search engine in a paginated way (30 items per page), in order not to overload the browser. +To achieve this, we do not use the native scrolling feature of Elasticsearch, but the pagination. We retrieve records 30 by 30, changing the `from` property for each request. +A maximum limit of 10 000 records displayed has been set in the table. + +### Search within the data entries + +A dedicated text input allows the user to perform a full-text search within the entire dataset. The number of matching records is shown and visually illustrated in the guise of a progress bar. +To achieve this search, we concatenate each word in the input with the `&` character. This is done in order to have a very specific search, where each record contains all the terms. + +### Column visibility + +The visibility of each column can be toggled by clicking on a dedicated button and (de)selecting the various checkboxes. + +### User interaction with the data table + +* Each column can be sorted either alphabetically or numerically, according to the data type detected by the search engine. + +* Upon clicking on a given entry on the table, the entry gets fully displayed (including complex properties) on a dedicated viewer. If the map component is visible, then the map gets centered on the clicked entry. + +* Already visited entries are highlighted, on the table, with a different background color. + +## Map + +### Under the hood + +The map component is powered by the [Mapbox GL JS](https://github.com/mapbox/mapbox-gl-js) library. + +### Layers + +Three overlaid layers are used: + +1. a base layer, either vector or raster depending of the choice of the user. The raster layer is based on the [orthoimages](https://data.grandlyon.com/en/jeux-de-donnees/orthophotographie-2018-metropole-lyon-format-tiff/donnees) provided by the Métropole de Lyon with the addition of street labels coming from the vector base layer. + +2. A raster layer, displaying the entire (geographic) dataset by issuing requests against a Web Map Service (WMS). + +3. A transparent vector layer, fed by a Mapbox Vector Tiles (MVT) service, allowing users to interact with the raster features displayed by the WMS. Individual features get highlighted on hover and click events. + +#### Restricted-access datasets + +Some of the datasets hosted by data.grandlyon.com are only accessible to authorized users. For such datasets, two different behaviors were implemented: + +1. for **authorized users**: the very same behavior as for unrestriced datasets, in a seamless way; + +2. for **unauthorized users**: the raster layer, powered by the WMS, displays the full dataset; user interaction is limited to a small subset of geographical features and achieved by constructing a GeoJSON out of the sample returned by the search engine. + +This feature relies on a custom user-aware component, proxying requests to the Web Mapping Services hosted by the data.grandlyon.com Core. + +#### 3D emulation + +3D emulation for buildings is achieved thanks to the *ad hoc* styling of the polygones returned by the following dataset: https://data.grandlyon.com/jeux-de-donnees/volumes-toiture-3d-2015-bati-metropole-lyon/donnees. More specifically, the `fill-extrusion` property is used. + +### Search by address & geolocation + +Users can search for addresses and points of interest by typing terms in the dedicated form. This feature relies on a geocoding API which is powered by [Photon](https://github.com/komoot/photon) and hosted by data.grandlyon.com. + +Users can center the map on their current geolocation, as well. The feature relies on the native [Navigator API](https://developer.mozilla.org/en-US/docs/Web/API/Navigator/geolocation). + +### *Share* feature + +A button allows users to generate a share link, using the following pattern: `http://<hostName>#<zoom>/<latitude>/<longitude>/<bearing>/<pitch>/<selectedBaseLayerId>`. Such a link can be shared with other users in order to let the recipients land on the map with a given context: zoom, center, bearing, pitch and base layer. + +### User interaction with the map + +Upon clicking on a geographical feature, the latter gets fully displayed (including complex properties) on a dedicated viewer. At the same, the feature is highlighted on the data table and pushed to the first row. + +### Styling + +The OpenMapTiles basemap [Klokantech Basic](https://openmaptiles.org/styles/#klokantech-basic) has been used as a starting point to generate data.grandlyon.com's custom styles. Such styles are compliant with the the [Mapbox GL style specification](https://docs.mapbox.com/mapbox-gl-js/style-spec/) and publicly available (cf. https://openmaptiles.data.grandlyon.com/). + +#### Sprites + +The map component uses custom sprites (*e.g.* the grass in green spaces), generated via the following workflow: + +* download the [Mapbox icons](https://labs.mapbox.com/maki-icons/) (the Maki icons) +* add the custom SVG we want to use in our style (for example grass.svg and water.svg) +* clone and install [spritezero-cli](https://github.com/mapbox/spritezero-cli), a command-line interface for [spritezero](https://github.com/mapbox/spritezero) +* `spritezero [output filename] [input directory]` . It generates a JSON layout file and the associated PNG spritesheet. +Also generate it with the `--retina` option to have the @2x sprites +* Once the folder containing these files is hosted, we reference it in the style file: +`"sprites": 'path/to/the/sprites/folder/'` +* Finally we can style the custom grass in green area: + +```json +"paint": { + "fill-pattern": "grass" + } +``` + +#### Glyphs + +The map component uses the [Titillium Web](https://fonts.google.com/specimen/Titillium+Web) font, the same as the rest of the Web application. The Mapbox GL JS library uses the notion of "glyphs" instead of "fonts". Glyphs are rendered as SDFs (Signed Distance Fields) and are better suited than fonts to rotation and scaling. + +The [node-fontnik](https://github.com/mapbox/node-fontnik) tool can be used to convert `.ttf` files into protobuf-encoded SDF glyphs. Multiple fonts can be combined by using this other tool: [glyph-pbf-composite](https://github.com/mapbox/glyph-pbf-composite). + +**TO ADD: "bannière rouge"** diff --git a/docs/components/custom-apps/web-app/dataset/dataset-detail.md b/docs/components/custom-apps/web-app/dataset/dataset-detail.md new file mode 100644 index 0000000000000000000000000000000000000000..398a4f8d1f95f5191f706a037087828670307920 --- /dev/null +++ b/docs/components/custom-apps/web-app/dataset/dataset-detail.md @@ -0,0 +1,12 @@ +# Dataset detail + +This page gives all the detail concerning one dataset. + + + +It's cut into one to four tabs: + +* [Data tab](./data.md): only if geographical data. It displays the data into a table and a map. +* [Information](./info.md): always display. It presents the metadata and other important information of the dataset. +* [Downloads](./downloads.md): a list of files available to download +* [API](./api.md): access to the geographical services available for the dataset diff --git a/docs/components/custom-apps/web-app/dataset/downloads.md b/docs/components/custom-apps/web-app/dataset/downloads.md new file mode 100644 index 0000000000000000000000000000000000000000..ada412a0f06d2caf56e356bfeeba1900b15564e6 --- /dev/null +++ b/docs/components/custom-apps/web-app/dataset/downloads.md @@ -0,0 +1,15 @@ +# Downloads + +## From API + +In the first section, the files are created by using the API. + + + +For example a PNG file is created by querying the WMS service with specific paramameters. Then the response is converted into a `blob` to allow the browser launch the download. + +## Static and other resources + + + +Any other resources like static files (eg a `.csv` or `.tiff`) or an url are listed in two other sections as seen in the figure above. \ No newline at end of file diff --git a/docs/components/custom-apps/web-app/dataset/info.md b/docs/components/custom-apps/web-app/dataset/info.md index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..54d649e105483f4f50d4c71cbd2435135534bcfb 100644 --- a/docs/components/custom-apps/web-app/dataset/info.md +++ b/docs/components/custom-apps/web-app/dataset/info.md @@ -0,0 +1,35 @@ +# Information + +This tab shows metadata related to the visited dataset. + + + +Let us note that metadata: + +* are originally filled in by the back-office team via the [GeoNetwork](https://www.geonetwork-opensource.org/) off-the-shelf application; +* comply to two different templates: + * ISO19139 for geographical datasets; + * Dublin Core for non-geographical datesets; +* are indexed in Elasticsearch by a [custom indexer](https://forge.grandlyon.com/web-et-numerique/web-et-numerique-internet/data.grandlyon.com/web-portal/components/indexers/metadata-and-data), in order to enable full-text searches. + +This Web Application retrieves metadata from Elasticsearch, by applying a filter on the `slug` field. + +## Parent and children datasets + +Between datasets can exist a relationship of parents and children. It usually happens when many datasets share the same metadata, and then are separated in multiple datasets for the data. +From this information page it's possible to navigate throw this relationship as the parent or the children of the dataset are mentionned and linked. + +## Licence + +There is the possibility to download the licence from this page. +The way we retrieve it is a bit triclky, as there is no specific metadata properties for the licence. +We check in the `links` items, and if on of them contains in its name `"Licence"`, then we use the url associated to this `link`. +So when we click on the licence button in the information page, it uses this url we retrieved for the `link` metadata. + +## Contact us + +The contact from this page will redirect to the contact page, with a specific behavior. + + + +It fills in automatically the subject width the title of the dataset we come from. diff --git a/docs/components/custom-apps/web-app/dataset/resources.md b/docs/components/custom-apps/web-app/dataset/resources.md deleted file mode 100644 index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..0000000000000000000000000000000000000000 diff --git a/docs/components/custom-apps/web-app/drafts.md b/docs/components/custom-apps/web-app/drafts.md index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..47a1db68fffbad8e317017291a27669303420e74 100644 --- a/docs/components/custom-apps/web-app/drafts.md +++ b/docs/components/custom-apps/web-app/drafts.md @@ -0,0 +1,7 @@ +# Drafts + +This page presents a card per post in draft status. Such draft posts can be retrieved from the search engine by applying a filter (**which one**?). + +Each card includes the article cover image, title and the last modification date. The click on a card allows the user to navigate to a page where the concerned post is displayed as if it were actually published (cf. **TODO: link to the documentation of the article page**). + +This page is only accessible to the members of a dedicated user group. configured through the [API Gateway](../../off-the-shelf-apps/api-gateway.md) and its ACL plugin. We refer the reader to [this page](../../../miscellaneous/nestjs-micro-services.md) for further information about how user authorizations are implemented. diff --git a/docs/components/custom-apps/web-app/feedback.md b/docs/components/custom-apps/web-app/feedback.md index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..70c0ff5675ade7d9913e7a056654e6ea68da4067 100644 --- a/docs/components/custom-apps/web-app/feedback.md +++ b/docs/components/custom-apps/web-app/feedback.md @@ -0,0 +1,13 @@ +# Feedback + + + +The goal of this feature is to let end users provide feedback about their experience with the Web Application : bug reports, suggestions for improvement, etc. + +The feedback form is composed by : + +* a free text area; +* a set of buttons allowing the user to rate the website (`1 star`, `2 stars`, `3 stars`, `No opinion`); +* an optional email field, which the user can fill in if a reply from the support team is desired. + +In case the email address is provided, the user has to accept some terms for the submit button to be enabled. diff --git a/docs/components/custom-apps/web-app/footer.md b/docs/components/custom-apps/web-app/footer.md index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..e3de5c21e24a72050f2207a44bf375854a5d06c4 100644 --- a/docs/components/custom-apps/web-app/footer.md +++ b/docs/components/custom-apps/web-app/footer.md @@ -0,0 +1,11 @@ +# Footer + + + +The footer is devided in three sections. + +The left section comports links to the facebook and twitter pages of the Lyon Metropolitan Area as well as the link to the RSS feed of the platform. + +The middle section is composed of internal links to different pages of the web app. Besides it also has a `Download the catalog` link which triggers the download of a CSV export of the metadata catalog through the [CSV catalog downloader](../../services/csv-catalog-downloader.md) service. + +The right section only has a link to the official [website](https://grandlyon.com) of the *Grand Lyon*. diff --git a/docs/components/custom-apps/web-app/header.md b/docs/components/custom-apps/web-app/header.md index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..bbc6ae6ede5f654a5c97d9a6de7756484fbad2ad 100644 --- a/docs/components/custom-apps/web-app/header.md +++ b/docs/components/custom-apps/web-app/header.md @@ -0,0 +1,55 @@ +# Header + + + +The header of the application has different display and content depending on two factors: + +* the screen size (mobile, tablet or desktop) +* the current page, (homepage or any other pages) + +The header background is `transparent` on the homepage. + +The menu button which let the user hide or display the side menu always keep its left position. + +The platform logo is almost always displayed, unless the current page is the homepage. It has a different version on mobile and is centered on mobile and tablet. + +The search bar is hidden on the homepage that has its own search bar and on the mobile and tablet version because then it is located in the side menu. + +The user button is always present but as a text (`Sign in` or user's `firstname`) when current page is the homepage. + +The *Grand lyon* logo is only displayed on desktop version. + +The feedback button is integrated to the header on mobile version only. It is also positioned at the level of the header when not on the homepage and not on mobile but it is only an absolute position. + +## Search bar + +The search bar allow a user to perform a multi-word search over the datasets catalog. The search is performed over the metadata as well as the data. + +With the search bar comes an auto-complete functionality. As the user types, but with a debounce time of 500ms, a request is made to the elasticsearch service in order to retrieve a maximum of 5 possible completions for the text the user as typed so far. In each of those completions, the part matching the user's text is bolded. Each completion is clickable which will then replace the current text of the search bar and trigger the search action. + +In order to trigger a search the user can either type the `Enter` button of its keyboard when the input of the search bar is focused or click the magnifying glass icon. + +The trigger of a search will not only perform a request to the elasticsearch service but also redirect the app the the `research` page if it wasn't the current page. + +When the search bar has a value, it is possible to reset the search by clicking the cross icon. + +### Special characters + +The search bar supports advanced queries and some special characters + +* `-` if this character is used in front of a word, it will exclude it from the results. + +* `NOT ()`: it has the same use of `-`. +`-lyon` and `NOT (lyon)` are two different synthax with the same results. + +* `AND`: this logical operator is used for strict intersection. It filters the datasets that have the both words + +* `OR`: this is used for union. It is the default behavior of the search bar. + +## User button + +This button can have different behaviors. If the user is anonymous, a click will redirect to the login page. If the user is already authenticated, it opens a dropdown menu with three possible actions: + +* access to the user profil page +* access to the user data accesses page +* sign out diff --git a/docs/components/custom-apps/web-app/homepage.md b/docs/components/custom-apps/web-app/homepage.md index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..d3463a2b86d1d7e92df1ab3ee6238e55af9d2b3b 100644 --- a/docs/components/custom-apps/web-app/homepage.md +++ b/docs/components/custom-apps/web-app/homepage.md @@ -0,0 +1,12 @@ +# Homepage + + + +This is the landing page of the data.grandlyon.com Web portal. The main goal of this page is to encourage the user to discover the dataset catalog. Two entrypoints are provided: + +* The search bar, allowing the user to find datasets that match the typed search terms. For more information about the search bar, please refer to [this](./header.md#Search-bar) section of the documentation. +* The explore button, which redirects the user to the search results page, with no filter activated: all the datasets are returned. + +The homepage also highlights the three latest news, retrieved from the search engine. In case any post is tagged as "featured" - a fonctionnality provided by the [Ghost CMS](../../off-the-shelf-apps/cms.md) - such post occupies the leftmost position. *QUESTION*: *what if multiple posts are featured* ? + +Finally, the `All news` button allows one to land on the `News` tab of search results page. diff --git a/docs/components/custom-apps/web-app/overview.md b/docs/components/custom-apps/web-app/overview.md index e0180910a6302c6aaab7e009fe1f0077d4d95d67..b523cab9cffb6412e4b8a952a29181c4709115ed 100644 --- a/docs/components/custom-apps/web-app/overview.md +++ b/docs/components/custom-apps/web-app/overview.md @@ -1,174 +1,50 @@ -# Web app +# data.grandlyon.com's Main Web Application + +## Overview + +[...] + +## Routing + +By: + +* `slug` +* `uuid` + +Let's explain how routing works! + +[...] ## Files & Folders structure Organize a folders and files structure inside a project is never an easy task, and it exists many ways to do so. -We think that at the beginning we should just not overthink about it, choose one way to do it, keep to it, until a natural re-organization will happen if needed. +We think that at the beginning we should just not overthink about it, choose one way to do it, keep to it, until a natural re-organization will happen if needed. Here is our `/src` folder structure: - + * `src/app/`: where the Angular code is located. With time we organized this part in different modules each taking care of one main functionnality. Here is the list of the modules: * `core/`: constitutes the base of the application (layout, notifications, navigation history...) * `dataset-details/`: contains the components and logic allowing the display of a dataset information (metadata, data, map...) * `datasets/`: contains the components and some of the logic related to the research * `editorialisation/`: contains the components and logic related to the display of editorial content (static pages, articles) - * `elasticsearch/`: + * `elasticsearch/`: provides an interface to the elasticsearch service and contains all the logic needed to access the data indexed in elasticsearch (data sets, pages, articles) * `map/`: contains the components and logic allowing the display and manipulation of a map - * `shared/`: provides components, directives and others things that can be reused in different modules + * `shared/`: provides components, directives and others things that can be reused in any module of the application * `user/`: contains the components and logic related to the user management in the application (login, logout, user profil...) * `src/assets/`: contains all the images, favicon, svg, fonts, dynamic config file... * `src/environments/`: contains files with static configuration. * `src/i18n/`: this folder is dedicated to the translation. The are two types of files: - * `.xlf`: - * `.ts`: -* `src/scss/`: -* `src/app-routing.module.ts`: -* `src/app.component(.ts, .html, .scss)`: -* `src/app.module.ts`: -* `src/routes.ts`: - -Each module is organized in the following way: (not all the subfolders are required) - -* `<module-name>.module.ts`: -* `<module-name>-routing.module.ts`: -* `components/`: -* `directives/`: -* `guards/`: -* `handlers/`: -* `interceptors/`: -* `models/`: -* `pipes/`: -* `resolvers/`: -* `services/`: -* `validators/`: - -Inside one module each component has its own folder with one `.ts`, one `.scss` and one `html` file. + * `.xlf`: for static texts written in html files + * `.ts`: for dynamic texts retrieved by HTTP calls +* `src/scss/`: contains the main stylesheets of the application +* `src/routes.ts`: contains the translation of the different url fragments of all the application ## CSS integration with Bulma All the styling work has been done with [Bulma](https://bulma.io/), a free and open source CSS framework based on Flexbox. It is highlighy customizable and easy to integrate in a project. -To do so, a `variables.scss` file that contains our project variables, overrides the Bulma variables (color, padding, anything you want). Then Bulma is imported and added to our main `style.scss`. That's it, our style incorporate a personalized Bulma . - -## Features by pages - -### Home - -#### Explore - -#### News - -#### All news - -### Side menu - -#### Draft button - -#### App version number - -#### FR and EN buttons - -### Feedback - -### Static pages - -### Partners - -### Reuses - -### Draft page - -### Contact - -### Last changes - -### Download the catalogue - -### Credits - -### Sign In & Sign Up - -### User profil - -### User data - -### Research - -#### Filters - -#### Tabs - -#### Pagination - -#### Sort - -#### Suggestion - -#### Dataset result - -### Datset details (Data tab) - -#### Research in the data - -#### Properties display toggle - -#### Data table (sort properties & complex properties & hostory of the click elements) - -#### Map - -* plan vecto & satellite -* research by address -* geoloc -* copy map -* interactions -* detail of a data on map feature click - -For each geographical dataset it's possible to display the data on a map. Here is what have been done to make this happen. - -Mapbox GL JS - -On the client side, the library [Mapbox GL JS](https://github.com/mapbox/mapbox-gl-js) is used. This is a very interesting tool improving quickly. The only drawback using it with Angular is that we cannot always use its last version. Indeed as we are using Typescript, we need to wait until the @types are updated. - -### Styling - -Mapbox use the [Mapbox style specification](https://docs.mapbox.com/mapbox-gl-js/style-spec/) to define the visual appearance of a map. -In our project we have created different styles depending on how we want to display the map. For example when we display the aerial layer, we don't necessary want the names of, say the roads and the river, to have the same color than when we display the vectorial layer. -So when we change these layers, we load the appropriate style. - -### How is the data fetched ? - -Initially we were using Web Feature Service (WFS) and Web Map Service protocols to get the data (geojson or images). But for WFS we realized that when our needs became more complex and precise, this could sometimes be not so easy (filters are not the most funny thing to do). -So we used...Elasticsearch. It is super fast and even have geographical research. We fetch the data from ES, format it into a `.geojson` and voilà ! This will also allow us in the future to have more advanced features on the map (like filters). - - -#### Fullscreen - -#### Toggle Map/data - -### Datset details (Info tab) - -#### Parent and children datasets - -#### License - -#### Contact us - - - -## Research features - -This core feature is based on [Elasticsearch](https://www.elastic.co/fr/) (ES). Almost all the information in the portal (including datasets, articles, geographical data) is indexed in ES. This allows lot's of possibilities with the powerful features of this tool. -Here are the features existing on the portal: - -* *research*: thanks to ES great indexation, to go through millions of documents is super fast (millions because we are not only looking inside the metadata, but also inside the data) -* *autocompletion*: using the score based on some criteria, we provides an autocompletion feature that helps to give a context for some research keywords. -* *suggestion*: if a research didn't give good or no results (for example because of a typo), a word with more results will be suggested. - -Of course there is a plenty of room for improvements for these features (and for new ones). ES is very powerful but also very complex to master. It's in a constant improvement. - - -## API & Downloads feature +In order to override the default Bulma style, we added a `init_bulma.scss` file that redefines some of the Bulma variables (color, padding, anything you want). In this file, we also import a `variables.scss` file which contains our custom scss variables and Bulma scss files. Finally `init_bulma.scss` is imported in `styles.scss` which is the main scss file of the app. ## CI/CD diff --git a/docs/components/custom-apps/web-app/partners.md b/docs/components/custom-apps/web-app/partners.md index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..42db3200e93359d7332f0b3e2a09c32cc4a0e048 100644 --- a/docs/components/custom-apps/web-app/partners.md +++ b/docs/components/custom-apps/web-app/partners.md @@ -0,0 +1,13 @@ +# Partners + + + +The Lyon Metropolitan Area has opened its portal to all stakeholders in the region who wish to distribute their data, in open data or restricted access. This page list the current partners. + +Each partner is represented as a card with its logo, a description, its website and the number of datasets and services distributed. + +The logo of a partner is clickable and redirects to their official website. + +The `dataset` button of a partner redirects to the `Datasets` tab of the search page with the `Producers` filter activated with the corresponding partner. + +The `service` button of a partner redirects to the `Services` tab of the search page with the `Producers` filter activated with the corresponding partner. diff --git a/docs/components/custom-apps/web-app/reuses.md b/docs/components/custom-apps/web-app/reuses.md index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..702cfc88efe6e04f012895eed9b1c53420d70f69 100644 --- a/docs/components/custom-apps/web-app/reuses.md +++ b/docs/components/custom-apps/web-app/reuses.md @@ -0,0 +1,12 @@ +# Reuses + + + +The Lyon Metropolitan Area promotes the reuse of territorial data: analysis, map, site, service, application... This page lists thoses reuses. + +The reuses are displayed as a card with their logo, name, creator, type and the number of datasets they use. Each reuse is clickable and redirects to the detail page of the reuse in question. + +On the detail page two additional information can be found: + +* the official website of the reuse +* the list of the datasets being reused (each of them is clickable and redirects to the detail page of the dataset) diff --git a/docs/components/custom-apps/web-app/search.md b/docs/components/custom-apps/web-app/search.md index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..4bdc1d499cf5641f0d94a10f3f6e24b44a380719 100644 --- a/docs/components/custom-apps/web-app/search.md +++ b/docs/components/custom-apps/web-app/search.md @@ -0,0 +1,42 @@ +# Search + +This core feature is based on [Elasticsearch](https://www.elastic.co/fr/) (ES). Almost all the information in the portal (including datasets, articles, geographical data) is indexed in ES. This allows lot's of possibilities with the powerful features of this tool. +Here are the features existing on the portal: + +* *research*: thanks to ES great indexation, to go through millions of documents is super fast (millions because we are not only looking inside the metadata, but also inside the data) +* *autocompletion*: using the score based on some criteria, we provides an autocompletion feature that helps to give a context for some research keywords. +* *suggestion*: if a research didn't give good or no results (for example because of a typo), a word with more results will be suggested. + +Of course there is a plenty of room for improvements for these features (and for new ones). ES is very powerful but also very complex to master. It's in a constant improvement. + + + +## Datasets results + +As in many search tools the results are displayed in different tabs representing different results categories: `All`, `Data`, `Services` and the `News` (editorial content). +For each tab these results are paginate with 10 entries per page. + +It's possible to sort the results by relevance, date and alphabetically. + +## Research features + +See the [search bar](./header.md#Search-bar) documentation + +## Filters + + + +On the left side of the screen the user has the possibility to add filters and subfilters (depending the category) +These categories (e.g. producers, licences, formats) are based on the metadata properties. Then each value for these properties are aggregated. +Inside one filter category, the values are sorted by the number of datasets. + +### Behavior inside and between filters category + +If the user selects multiple values inside one filter category, they will behave as `OR` operators. It means that the datasets matching with one category **or** another one are displayed. +On another hand, if the user selects different filters in different filter categories; they will behave as `AND` operators. For example if we apply the filters `SYTRAL` in Producers and `WMS` in Services, it will display the datasets that are matching with these two conditions. + +## Suggestion + + + +This is a useful feature, especially for typo. If your research doesn't give you any result, Elasticsearch might find for you a word that is close of yours that would give more success in the results. diff --git a/docs/components/custom-apps/web-app/side-menu.md b/docs/components/custom-apps/web-app/side-menu.md index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..e4b5a16c4f7870e0c35fd7434892830de77b983a 100644 --- a/docs/components/custom-apps/web-app/side-menu.md +++ b/docs/components/custom-apps/web-app/side-menu.md @@ -0,0 +1,27 @@ +# Side menu + +The purpose of the side menu is to help the user to easily navigate through the main pages of the website without altering the user experience. Indeed, to avoid that it takes to much place on the left, a hide and show system as been developed. + + + +## Draft button + +The first section of the menu is constituted of internal links to the principal pages of the application. Though, there is one particular link, `Drafts`, that is only displayed when the user has access to articles that haven't been published yet. This is the case when the user belongs to the `ghost-editors` group. To verify that, a request is made to the elasticsearch service in order to get the drafts, if none are return it means the user doesn't have the appropriate rights and so the button is hidden. Please refer to [this]() section of the documentation to understand how the elasticsearch service can return different content depending on the user's groups. + +## App version number + +The bottom part of the menu includes the version number of the application. This helps us to keep track of what version is deployed on our different environments and to know on what particular version of the app a bug as been found. This version number is set in the `environment.ts` file with the value of the package.json version number. Here is the piece of code we implemented. + +```ts +import * as packageJson from '../../package.json'; + +export const environment = { + version: (<any>packageJson).version +} +``` + +Then the `environment` variable can be imported anywhere in our application. + +## FR and EN buttons + +The application is built in two languages: French and English. Both are served by the same Nginx server. The French version is served at the root `data.grandlyon.com/` while the English build is served at `data.grandlyon.com/en/`. The menu includes two buttons at its bottom part, `FR` and `EN` which respectively redirects to data.grandlyon.com and data.grandlyon.com/en. Notice that it also keeps the current path and arguments. For example: `https://data.grandlyon.com/contact?subject=question` would become `https://data.grandlyon.com/en/contact?subject=question`. diff --git a/docs/components/custom-apps/web-app/sign-up-in-out.md b/docs/components/custom-apps/web-app/sign-up-in-out.md deleted file mode 100644 index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..0000000000000000000000000000000000000000 diff --git a/docs/components/custom-apps/web-app/static-pages.md b/docs/components/custom-apps/web-app/static-pages.md index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..387cb5d4568d616d98183e293312b515630bbeb1 100644 --- a/docs/components/custom-apps/web-app/static-pages.md +++ b/docs/components/custom-apps/web-app/static-pages.md @@ -0,0 +1,9 @@ +# Static pages + +Some pages of the application such as `Accessibility` or `Approach` only contains editorial content. Our need was to be able to easily update the content of those pages and that this action could be realized by a non technical person. + +This is why we choosed to use a CMS ([Ghost](../../off-the-shelf-apps/cms.md)) that makes the entry of editorial content easy with a well designed interface. Each page is identified by a unique slug (ex: `mentions-legales`) that can be used to identify them. + +[Elasticsearch](../../off-the-shelf-apps/elasticsearch) is the entrypoint we use to retrieve datasets and articles, so we decided to homogenize the way we collect data and to have one unique entrypoint. Indeed, we decided to index the static pages as well in elasticsearch. Doing so we also anticipate a need that might come in the futur that would be the research in all the application. + +In the Angular application, there is one unique component that handles the display of those pages: `cms-page.component.ts`. We defined a different path for each page but all are associated with this component (see `editorialisation-routing.module.ts`). In order to retrieve the right content the component reads the path of the current url. Then it uses a particular property of the environment variable (see environment files) that contains the mapping between the angular paths of the pages and their slug in Ghost. Finally, a request is made to elasticsearch with the page's slug to retrieve its content and then display it. diff --git a/docs/components/custom-apps/web-app/user-management.md b/docs/components/custom-apps/web-app/user-management.md new file mode 100644 index 0000000000000000000000000000000000000000..c7cf39984741edf5829cd50c6a9057c42fe8fe3d --- /dev/null +++ b/docs/components/custom-apps/web-app/user-management.md @@ -0,0 +1,337 @@ +# User management + +## Sign up + +There are two steps to create an account on data.grandlyon.com. + +First of all the user must go to the sign up page accessible from the login page and fill the form. A few information are required such as the firstname, the lastname and the email. A password also has to be entered. It must: + +* have at least 6 characters +* contain at least one special character +* contain at least one uppercased character +* contain at least one lowercased character +* contain at least one number + +Passwords are always encrypted with a public key retrieved from the [legacy auth middleware](../../middlewares/legacy-auth.md) before they are sent accross the network. Only the legacy auth middleware knows the private key that allow the decryption of the password. + +Before being able to submit the form, the user has to accept the general terms of use and the processing of its information. + +When the form is submitted, the account is not directly created. In fact, a request is made to the [legacy auth middleware](../../middlewares/legacy-auth.md). The service stores temporarily the user account information in a Redis database and send an email to the user's email address through the [email service](../../services/mailer.md). The purpose of this email is to confirm the validity of the user's email address. Indeed the email contains a unique link which expires after 24h. + +The link is actually a link to the login page of our application that includes a `token` query param. When the `LoginComponent` of the Angular app detects a `token` param in the url, it sends an HTTP request to the [legacy auth middleware](../../middlewares/legacy-auth.md) including the token. If the token is still valid the user account associated with this token is created in the real user database of the [legacy auth service](../../core/legacy-auth.md). + +For more information about this process read [this](../../../miscellaneous/authentication&authorization.md) section of the documentation. + +## Sign in + +Obviously, on the sign in page the user can enter its credentials in order to authenticate himself/herself. For more details refer to [this](../../../miscellaneous/authentication&authorization.md) section of the documentation. + +A checkbox on the left of the password input allow one to display the content of the input. + +## Password forgotten + +A user that forgets its password can click the `Password forgotten` button from the sign in page. The application will then display a second form asking the user to enter its email address. When the form is submitted, the password is encrypted with the public key retrieved from the [legacy auth middleware](../../middlewares/legacy-auth.md). Then just as in the sign up process the app sends a request to the middleware that in its turn sends an email to the user address ,through the [mailer](../../services/mailer.md), containing a link valid for 24 hours. + +The link sends the user on the page dedicated to the reset of the password. This page first verifies that a token is indeed present in the query param of the current url. It also checks with the [legacy auth middleware](../../middlewares/legacy-auth.md) if the token is still valid. In the failing case a message ask the user to restart the password reset process from the beginning. When the token is valid, the user is asked to enter a new password. Finally the application sends the request to the middleware along with the token from the query param. The middleware checks again the validity of the token and then make an HTTP call to the `Legacy auth` service in order to apply the new password to the email associated to the user account. + +Here's a diagram that sums this up. + +```plantuml + +!define BLACK #333745 +!define RED #d5232a +!define GREEN #37A77C + +' Base Setting +skinparam BackgroundColor transparent + +skinparam Sequence { + ArrowThickness 1 + ArrowColor RED + LifeLineBorderColor GREEN + ParticipantBorderThickness 1 +} +skinparam Participant { + BackgroundColor #FFFFFF + BorderColor BLACK + FontColor BLACK +} + +skinparam note { + BackgroundColor #FFFFFF + BorderColor BLACK + FontColor BLACK +} + +participant "Front" as front +participant "Authentication Service" as auth +participant "Middleware Legacy Auth" as middle +participant "Legacy Auth (Neogeo)" as django +participant "Email Service" as email +participant "Kong" as kong +participant "OIDC Server" as oidc + +group Password forgotten + front -> middle : <b>POST</b> /passwordForgotten + note over middle: Set token in Redis with ttl 24h. + middle -> email : <b>POST</b> /email/send (body contains the link to the reset password form) + middle <-- email : void + front <-- middle : void +end + +group Verify Password reset token validity + front -> middle : <b>GET</b> /isPasswordResetTokenValid + note over middle: Look for token in Redis. + front <-- middle : boolean +end + +group Password reset + front -> middle : <b>GET</b> /publicKey + front <-- middle : { publicKey } + front -> middle : <b>PUT</b> /user/resetPassword + note over middle: Look for token in Redis. + middle -> django : <b>POST</b> /update_user_password/ + middle <-- django + note over middle: Delete token from Redis. + front <-- auth : void +end +``` + +## Sign out + +The sign out button is available in the dropdown menu that can be displayed with a click on the user button of the header of the app. + +Cookies are used to store the two authentication pieces and more particularily `HTTP only` cookie to store the JWT. It means the application cannot manipulate this cookie, the only way is to force it's expiration through our backend service. This is why the application makes a call to the [authentication service](../../services/authentication.md) which returns two new cookie with the same keys but with outdated expiration dates. Those cookies will replace the two existing ones in the user's browser, and as they are expired they will be removed and user signed out. + +```plantuml + +!define BLACK #333745 +!define RED #d5232a +!define GREEN #37A77C + +' Base Setting +skinparam BackgroundColor transparent + +skinparam Sequence { + ArrowThickness 1 + ArrowColor RED + LifeLineBorderColor GREEN + ParticipantBorderThickness 1 +} +skinparam Participant { + BackgroundColor #FFFFFF + BorderColor BLACK + FontColor BLACK +} + +skinparam note { + BackgroundColor #FFFFFF + BorderColor BLACK + FontColor BLACK +} + +participant "Front" as front +participant "Authentication Service" as auth + +group Logout + front -> auth : <b>GET</b> /logout + front <-- auth : [200] + cookies with outdated expiration dates +end +``` + +## User update + +A user can easily update its profil information from the user profil page. He needs to agree to the general term of use and the process of its information before sumitting any changes. To update the profil, the application calls the [authentication service](../../services/authentication.md). In its turn it makes the appropriate request to the [legacy auth middleware](../../middlewares/legacy-auth.md) and then generate a new JWT with the latest user information. Finally the [authentication service](../../services/authentication.md) replies to the application with two cookies to replace the older ones. + +Here's in bit more details the different exchanges that take place during the update of the user's profil. + +```plantuml + +!define BLACK #333745 +!define RED #d5232a +!define GREEN #37A77C + +' Base Setting +skinparam BackgroundColor transparent + +skinparam Sequence { + ArrowThickness 1 + ArrowColor RED + LifeLineBorderColor GREEN + ParticipantBorderThickness 1 +} +skinparam Participant { + BackgroundColor #FFFFFF + BorderColor BLACK + FontColor BLACK +} + +skinparam note { + BackgroundColor #FFFFFF + BorderColor BLACK + FontColor BLACK +} + +participant "Front" as front +participant "Authentication Service" as auth +participant "Middleware Legacy Auth" as middle +participant "Legacy Auth (Neogeo)" as django +participant "Kong" as kong + + +group User update + front -> auth : <b>PUT</b> /user/update + auth -> middle : <b>PUT</b> /user/update + middle -> django : <b>POST</b> /update_user/ + middle <-- django : Ok + middle -> django : <b>POST</b> /get_user/ + middle <-- django : { userInfo } + auth <-- middle : { userInfo with encrypted password as authzKey} + auth -> kong : <b>PUT</b> /consumers/:email + auth <-- kong : Ok + auth -> kong : <b>GET or POST</b> /consumers/:email/jwt (POST if no creadetials exist for this user) + auth <-- kong : { credentials } + front <-- auth : { token: jwt } +end +``` + +## Password update + +From its profile page a user can access to the password update tab. He/she can change its password by filling the dedicated inputs. However the current password must be reentered. + +The password update is done through a call to the [legacy auth middleware](../../middlewares/legacy-auth.md). If the request is successful the app will trigger a new login with the new credentials that will be transparent for the user. Doing so, the user wont be logged out on the next authenticated HTTP call (as the password would be outdated) and wont need to reconnect manualy while he/she just entered in the latter form. + +```plantuml + +!define BLACK #333745 +!define RED #d5232a +!define GREEN #37A77C + +' Base Setting +skinparam BackgroundColor transparent + +skinparam Sequence { + ArrowThickness 1 + ArrowColor RED + LifeLineBorderColor GREEN + ParticipantBorderThickness 1 +} +skinparam Participant { + BackgroundColor #FFFFFF + BorderColor BLACK + FontColor BLACK +} + +skinparam note { + BackgroundColor #FFFFFF + BorderColor BLACK + FontColor BLACK +} + +participant "Front" as front +participant "Authentication Service" as auth +participant "Middleware Legacy Auth" as middle +participant "Legacy Auth (Neogeo)" as django +participant "Email Service" as email +participant "Kong" as kong + +group Get Public Key + front -> middle : <b>GET</b> /publicKey + front <-- middle : { publicKey } +end + +group Password update + front -> middle : <b>PUT</b> /user/updatePassword + middle -> django : <b>GET</b> /get_user/ + middle <-- django : Ok + middle -> django : <b>PUT</b> /update_user_password/ + middle <-- django : Ok + front <-- middle : void +end + +group Legacy login + front -> auth : <b>POST</b> /login/legacy + auth -> middle : <b>POST</b> /user/login + middle -> django : <b>POST</b> /get_user/ + middle <-- django : { userInfo } + middle --> auth : { userInfo with encrypted password as authzKey} + auth -> kong : <b>PUT</b> /consumers/:email + auth <-- kong : Ok + auth -> kong : <b>GET or POST</b> /consumers/:email/jwt (POST if no creadetials exist for this user) + auth <-- kong : { credentials } + front <-- auth : { token: jwt } +end +``` + +## Account deletion + +From its profile page, one can also delete its account. A modal is asking for a confirmation in order to prevent that an unwanted click deletes the user account without any possible rollback. + +This diagrams shows the different exchanges made. + +```plantuml + +!define BLACK #333745 +!define RED #d5232a +!define GREEN #37A77C + +' Base Setting +skinparam BackgroundColor transparent + +skinparam Sequence { + ArrowThickness 1 + ArrowColor RED + LifeLineBorderColor GREEN + ParticipantBorderThickness 1 +} +skinparam Participant { + BackgroundColor #FFFFFF + BorderColor BLACK + FontColor BLACK +} + +skinparam note { + BackgroundColor #FFFFFF + BorderColor BLACK + FontColor BLACK +} + +participant "Front" as front +participant "Middleware Legacy Auth" as middle +participant "Legacy Auth (Neogeo)" as django + +group User account deletion + front -> middle : <b>DELETE</b> /user + middle -> django : <b>POST</b> /delete_user/ + middle <-- django : Ok + front <-- middle : void +end +``` + +## User accesses + +This page is composed of two tabs: + +* one for the restricted access datasets that the user can access +* one for the restricted access datasets that the user can require access to + +In both tab, a dataset's name is an internal link that redirects to the corresponding dataset detail page. + +### Request access to a new dataset + +Each dataset can have many different available services (WMS, WFS...). The user can request access to all the services for this particular dataset or chose to require access only to the services he/she is interested in. + +<!-- TO BE COMPLETED --> +<!-- At first the user is granted a one month access. He/she will receive an email asking for more details about the use he/she will do of the services. --> + +Once a service has been requested it will disapear from the available services list. Instead it will appear in the user accesses tab. + +### User accesses management + +A user access state can have three different values: + +* Pending, the user request hasn't been accepted yet +* Ok, the user request has been accepted and the expiration date has been reached +* Expired, the expiration date has been reached + +From this table, one can remove its access to a service but can also renew it if it has expired or if it is soon to be expired. The user and the dedicated team on our side will receive an email acknowledging the request. However, there is currently no way in the backend to change the state of the service to `renewal request pending` so there will be no change in the application until the request has been accepted. diff --git a/docs/components/off-the-shelf-apps/cms.md b/docs/components/off-the-shelf-apps/cms.md index 66ecf7c69ceca70f18a3d8037eac8171bca05b1d..2fd8b0085c69f01242dcd4cdf6acaf01bd252a20 100644 --- a/docs/components/off-the-shelf-apps/cms.md +++ b/docs/components/off-the-shelf-apps/cms.md @@ -9,11 +9,12 @@ For all the editorial content on the portal one CMS is used to offer the possibi The choice went for the open source CMS [Ghost](https://ghost.org/), replacing Wordpress as our first choice at the beginning of the project. Whereas it's not perfect and there is still room for improvement, this is a great tool to use to create content in a beautiful user interface. The API allows us to get all the information needed for the web application by a REST API. +## Hooks for indexing it inside Elasticsearch - ## Hooks for indexing it inside Elasticsearch The CMS offers a hooks functionnality. Put it simply, you can trigger any API call after some events. In our case, after saving a page or an article, the Elasticsearch (ES) indexer service will be called to re-index the article or the page which was just modified. In few seconds the modification will be visible inside the webapp without any manual manipulation. ## Integration into the webapp + After the content is indexed inside ES, very little work is needed to integrate it into the web application. The content actually retrieved as HTML, and the code is pretty clean, so very few CSS adjustment is needed to display a nice article. diff --git a/docs/components/proxies/web-mapping-services.md b/docs/components/proxies/web-mapping-services.md index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..7562108dcc7370ad3a50b7d0acd4c841dbda4cd8 100644 --- a/docs/components/proxies/web-mapping-services.md +++ b/docs/components/proxies/web-mapping-services.md @@ -0,0 +1,28 @@ +# Web mapping services + +## Features + +This service is the unique entrypoint of the map in the portal toward the geographical services of the datasets hosted on our platform. It proxifies two services: + +* `WMS` +* `MVT` + +Depending on the dataset's license, those services might be in open access or restricted access. Our goal is to display to a particular user exactly what it's access are allowing him to see. It wasn't possible to add the authentication pieces as the map services are expecting it (basic auth) directly from the web application this is why we created this proxy. + +In order for the map to work properly and to always be able to display the full data on the portal, it has been decided that WMS would always be opened even if the user doesn't have access to the dataset. + +## Dependencies + +This proxy has two dependencies: + +* `Elasticsearch` +* `MapServer` + +## Endpoints + +It provides two endpoints: + +* `/wms`: +* `/mvt`: + +## Implementation diff --git a/docs/components/services/authentication.md b/docs/components/services/authentication.md index 6ba6e8e2d213d3d49a83cddb98f75aba7a1c9ea6..fe60baf0dcf59615329635ef078cc97840d43d36 100644 --- a/docs/components/services/authentication.md +++ b/docs/components/services/authentication.md @@ -13,7 +13,6 @@ The service relies on  - ## Endpoints This service provides five **endpoints**: @@ -22,7 +21,6 @@ This service provides five **endpoints**: 1. an HTTP-only cookie including an **access token**, including in turn a JSON Web Token (JWT), signed by the API Gateway, namely Kong. 2. a cookie including an **XSRF token** (generated as a version 4 UUID). - Both the access token and the XSRF token are needed to issue authenticated requests. We refer the reader to a [dedicated page](../../miscellaneous/security.md) for further information about security. 2. A **logout** endpoint, `/logout`, which signs out the user by deprecating the cookie set by the login endpoint. @@ -35,7 +33,6 @@ This service provides five **endpoints**: * the [API Gateway](../off-the-shelf-apps/api-gateway.md) must be up; * the [Legacy AUTH Middleware](../middlewares/legacy-auth.md) must be up. - ## Implementation The service is implemented using the [NestJS](https://nestjs.com/) framework. We refer the reader to the [NestJS-based micro-services](../../miscellaneous/nestjs-micro-services.md) page for further details concerning the latter framework and the features it provides. diff --git a/docs/components/services/changelog.md b/docs/components/services/changelog.md index d81dd7b1a8af0035f0fd128cdc0962ad8df73ea7..9f23111bb00985a1ab475df53b944ab8fd84de9c 100644 --- a/docs/components/services/changelog.md +++ b/docs/components/services/changelog.md @@ -33,6 +33,9 @@ This service has no dependency on other components. This service exposes one single endpoint, `/changelog`, supporting all the CRUD methods in a RESTful fashion. An healthcheck endpoint is exposed as well, `/health`, returning a `200` HTTP code when all indicators are healthy, `503` in the opposite case. The service is considered to be healthy if the underlying database is up. ## Implementation + + + The service is implemented using the [NestJS](https://nestjs.com/) framework. We refer the reader to the [NestJS-based micro-services](../../miscellaneous/nestjs-micro-services.md) page for further details concerning the latter framework and the features it provides. [MongoDB](https://www.mongodb.com/) is used for data persistence. Data modeling as well as connections to MongoDB are performed with [Mongoose](https://github.com/Automattic/mongoose). diff --git a/docs/components/services/credits.md b/docs/components/services/credits.md index 7a3da9f4070448a347569a938a67de2869cf440a..68e5b421ee2f8fe094bdd2a5a88aeaa2e02ceaee 100644 --- a/docs/components/services/credits.md +++ b/docs/components/services/credits.md @@ -23,16 +23,17 @@ This service has no dependency on other components. The service provides two endpoints, 1. `/credits`; -2. `/links`, -allowing one to perform CRUD operations on credits and links in a RESTful manner. Moreover, an healtcheck endpoint is provided, +allowing one to perform CRUD operations on credits in a RESTful manner. Moreover, an healtcheck endpoint is provided, -3. `/health`, +2. `/health`, returning a `200` HTTP code if the API is healthy, `503` otherwise. For the service to be healthy, the underlying database must be up. ## Implementation + + The service is implemented using the [NestJS](https://nestjs.com/) framework. We refer the reader to the [NestJS-based micro-services](../../miscellaneous/nestjs-micro-services.md) page for further details concerning NestJS and the features it provides. Data persistence is achieved by using [PostgreSQL](https://www.postgresql.org/) and [TypeORM](https://github.com/typeorm/typeorm). diff --git a/docs/components/services/mailer.md b/docs/components/services/mailer.md index b4ec516fe43ec8f8e574a7908c47e0a413a9e291..bb3471d5ee5102947f4dead0054ba5bc61989233 100644 --- a/docs/components/services/mailer.md +++ b/docs/components/services/mailer.md @@ -4,7 +4,6 @@ This service allow to deliver mails to any email address from the address specified in the configuration. It also provides two particular endpoints, one for the user to give a feedback and another one for general contact purpose. Those endpoints will both send an email to the admin address specified in the configuration. - ## Dependencies ## Endpoints @@ -15,28 +14,51 @@ This service allow to deliver mails to any email address from the address specif `/send` - `/health` This service will return a `200` http status code when all indicators are healthy. Otherwise it will return a `503` http status code. For this service we declared an health indicator that verify that the connection to the SMTP Server is available. ## Implementation - -## How it works +The service is implemented using the [NestJS](https://nestjs.com/) framework. We refer the reader to the [NestJS-based micro-services](../../miscellaneous/nestjs-micro-services.md) page for further details concerning the latter framework and the features it provides.  -The entrypoint of the service is a REST API provided by a [NestJS](https://github.com/nestjs/nest) application. The service builds email bodies based on the information it receives and on the provided HTML templates. It then format a JSON with all the properties (to, from, body...) expected by an SMTP server to correctly send an email. +<!-- The entrypoint of the service is a REST API provided by a [NestJS](https://github.com/nestjs/nest) application. The service builds email bodies based on the information it receives and on the provided HTML templates. It then format a JSON with all the properties (to, from, body...) expected by an SMTP server to correctly send an email. -However the service does not send this JSON directly to the distant SMTP server. Indeed as a connection failure might occure, we chose to persist this object in a RabbitMQ queue. Then a small worker written in Node.js will consume the messages from the queue and send it to the SMTP server if correctly formatted. The messages will be removed (acknoledged) from the queue only if the SMTP received the message. +However the service does not send this JSON directly to the distant SMTP server. Indeed as a connection failure might occure, we chose to persist this object in a RabbitMQ queue. Then a small worker written in Node.js will consume the messages from the queue and send it to the SMTP server if correctly formatted. The messages will be removed (acknoledged) from the queue only if the SMTP received the message. --> -## API documentation +## Templates -NestJS provides a [swagger module](https://docs.nestjs.com/recipes/swagger) that can be easily integrated. Using specific annotations alongside your endpoints declaration, this module will automatically generates a swagger documentation, reachable at `/api-doc`. +In order to generate responsive (on most-popular email clients) email templates, we use the framework [MJML](https://mjml.io/). +There are different ways to install it, an easy one is with `npm`. +```bash +npm install -g mjml +``` -## Templates +It uses its own file extention (`.mjml`) and syntax that abstracts the whole layer of complexity related to responsive email design. Once the template done and the content updated we can convert the mjml syntax to html using the following command: + +```bash +mjml my-file.mjml -o my-file.html +``` + +As we needed to add some dynamic content in our mails, we used the power of template literals. Indeed when we want to add some dynamic content in the template, we used the following syntax: + +```ts +${myVariableName} +``` + +Once the html is generated, we copy it inside a template literal and put it inside a js function. This function is taking parameters which corresponds to the name of the variables inside the template. As the function also returns the email body as template literal the `${variableName}` will automatically replaced. Here is an example. + +```ts +export const buildFeedbackEmail = (myVariable) => { + const html = `<html>.... ${myVariable} ......</html>` + return html; +}; +``` + +So, everytime we need to use this template, a simple call to this function with the appropriate parameters will do the job. ## AUTHZ diff --git a/docs/components/services/media-library.md b/docs/components/services/media-library.md index 152c31f10de45d9ec14ee29701f407fb16126627..fd818a9cbd5ae97b834be7ac2cd9a53788a4a5ff 100644 --- a/docs/components/services/media-library.md +++ b/docs/components/services/media-library.md @@ -1,40 +1,25 @@ # Media library service -## What it does +## Features -This service allows you to upload a file on the [Minio](https://min.io/) instance (compatible with S3) of your choice. The file will be stored in the bucket defined in the configuration of the service. +This service allows you to upload a file on the [Minio](https://min.io/) instance (compatible with S3) of your choice. The file will be stored in the bucket defined in the configuration of the service. It also stores some metadataabout the file in a mongo database. -## How it works +## Dependencies - - -The entrypoint of the service is a REST API provided by a [NestJS](https://github.com/nestjs/nest) application. The service uses the [Javascript MinIO SDK](https://docs.min.io/docs/javascript-client-quickstart-guide.html) to interact with a running instance of Minio. - -Before uploading the file, it makes sure that the specified bucket is created. If this is not the case, it creates it with a `public read access`. - -The files are folded in sub-buckets as following `/<specified-bucket-name>/<year-YYYY>/<month-MM>/`. - -The uploaded file keep its original name but is prefixed by an md5 computed based on its content witch gives the following pattern for file names: `<md5>-<original-name>`. This means that if we upload twice the exact same file, with the same name there will be only one file stored in MinIO. +This service needs a running instance of Minio in order to work. -## API documentation +## Endpoints -NestJS provides a [swagger module](https://docs.nestjs.com/recipes/swagger) that can be easily integrated. Using specific annotations alongside your endpoints declaration, this module will automatically generates a swagger documentation, reachable at `/api-doc`. - -## Service health +For this service we implemented a custom health indicator that checks the connection to MinIO giving the total number of buckets when the connection is succesful. -NestJS provides a [health module](https://github.com/nestjs/terminus) based on Terminus, that gives you the opportunity to declare predefined or custom health indicators. It exposes the health status of the service at `/health`. -This service will return a `200` http status code when all indicators are healthy. Otherwise it will return a `503` http status code. +## Implementation -For this service we implemented a custom health indicator that checks the connection to MinIO giving the total number of buckets when the connection is succesful. + -## Stats +The entrypoint of the service is a REST API provided by a [NestJS](https://github.com/nestjs/nest) application. The service uses the [Javascript MinIO SDK](https://docs.min.io/docs/javascript-client-quickstart-guide.html) to interact with a running instance of Minio. -We are using a Node module called [swagger-stats](http://swaggerstats.io/). -It traces API calls, monitors API performance and usage statistics. It exposes the metrics in different formats, such as Prometheus format, so you may use Prometheus and Graphana for API monitoring and alerting. -Those metrics are available at `/swagger-stats/metrics`. +Before uploading the file, it makes sure that the specified bucket is created. If this is not the case, it creates it with a `public read access`. -For more information about this module, visit the [official swagger-stat page](http://swaggerstats.io/docs.html). +The files are folded in sub-buckets as following `/<specified-bucket-name>/<year-YYYY>/<month-MM>/`. -## Docker -It is possible to run this service using Docker containers, using the `docker-compose.yml` and `Dockerfile` files. -For more information, refer to the project [service-media-library][add a link] \ No newline at end of file +The uploaded file keeps its original name but is prefixed with the id of the corresponding entry in the mongo database. diff --git a/docs/components/services/organizations.md b/docs/components/services/organizations.md index 0637a0931ba5aeec7ff31ca162fa82c1bdfb6f5c..ef1f5a7f8abbe6df1953de35de3bee851b1d5df2 100644 --- a/docs/components/services/organizations.md +++ b/docs/components/services/organizations.md @@ -1,35 +1,41 @@ # Organizations service -## What it does +## Features + This service provides a list of organizations with different information about it (such as description, logo..etc). In our application, one organization is usually a provider of data, used in the Portal Open Data. It can be a public actor or a private one. -## How it works +Each record of the catalog includes the following information: - +* `id`: a technical unique identifier acting as primary key in the underlying database +* `uuid`: a business unique identifier +* `name`: the name of the credited initiative +* `description`: a short description of the credited initiative, in particular of the role the latter plays in this project +* `links`: a collection of URLs related to the organization, modeled as a One-To-Many relationship +* `logo`: the URL of the organization's logo +* `published`: a boolean flag, indicating whether the record is published or not (draft) +* `elasticSearchName`: name of the organization in elasticsearc, it can be found in the metadata of a dataset under `responsibleParty[0].organisationName`. -The entrypoint of the service is a REST API provided by a [NestJS](https://github.com/nestjs/nest) application. This backend application interacts with a PostgresSQL database through an ORM called [TypeORM](https://github.com/typeorm/typeorm). +## Dependencies +This service has no dependency on other components. -## API documentation +## Endpoints -NestJS provides a [swagger module](https://docs.nestjs.com/recipes/swagger) that can be easily integrated. Using specific annotations alongside your endpoints declaration, this module will automatically generates a swagger documentation, reachable at `/api-doc`. +The service provides two endpoints, -## Service health +1. `/organizations`; -NestJS provides a [health module](https://github.com/nestjs/terminus) based on Terminus, that gives you the opportunity to declare predefined or custom health indicators. It exposes the health status of the service at `/health`. -This service will return a `200` http status code when all indicators are healthy. Otherwise it will return a `503` http status code. +allowing one to perform CRUD operations on credits and links in a RESTful manner. Moreover, an healtcheck endpoint is provided, -For this service we declared an health indicator that verifies that it can connect to the database. +2. `/health`, -## Stats +returning a `200` HTTP code if the API is healthy, `503` otherwise. For the service to be healthy, the underlying database must be up. -We are using a Node module called [swagger-stats](http://swaggerstats.io/). -It traces API calls, monitors API performance and usage statistics. It exposes the metrics in different formats, such as Prometheus format, so you may use Prometheus and Graphana for API monitoring and alerting. -Those metrics are available at `/swagger-stats/metrics`. +## Implementation + + -For more information about this module, visit the [official swagger-stat page](http://swaggerstats.io/docs.html). +The service is implemented using the [NestJS](https://nestjs.com/) framework. We refer the reader to the [NestJS-based micro-services](../../miscellaneous/nestjs-micro-services.md) page for further details concerning NestJS and the features it provides. -## Docker -It is possible to run this service using Docker containers, using the `docker-compose.yml` and `Dockerfile` files. -For more information, refer to the project [organizations-service][add a link] \ No newline at end of file +Data persistence is achieved by using [PostgreSQL](https://www.postgresql.org/) and [TypeORM](https://github.com/typeorm/typeorm). diff --git a/docs/components/services/resources-helper.md b/docs/components/services/resources-helper.md index 8e7e2c51398aac245dffbeca5470cfcc8d4b2cf4..14c0a8c68ed59b664b364596eff0aa14425ad980 100644 --- a/docs/components/services/resources-helper.md +++ b/docs/components/services/resources-helper.md @@ -1,6 +1,7 @@ # Resources service -## What it does +## Features + This service can provide lists of resources and formats. A resource is an entity representing some information, usually geographic, that can be accessed by a query (for example Web Map Service) or by downloading a file. One resource can be considered standard (e.g WMS protocol) or not standard (a custom service). Each resource is associated with one or many formats. @@ -8,32 +9,29 @@ Each resource is associated with one or many formats. *Example:* the output of a Web Feature Service (WFS), standard service providing an interface for geographical features, is a resource. And it is associated with many formats as such Shapefile or JSON. -## How it works - - +## Dependencies -The entrypoint of the service is a REST API provided by a [NestJS](https://github.com/nestjs/nest) application. This backend application interacts with a PostgresSQL database through an ORM called [TypeORM](https://github.com/typeorm/typeorm). +This service has no dependency on other components. +## Endpoints -## API documentation +The service provides five endpoints, -NestJS provides a [swagger module](https://docs.nestjs.com/recipes/swagger) that can be easily integrated. Using specific annotations alongside your endpoints declaration, this module will automatically generates a swagger documentation, reachable at `/api-doc`. +1. `/resources`; +2. `/resourceformats`; +3. `/projections`; +4. `/formats`; -## Service health +allowing one to perform CRUD operations in a RESTful manner. Moreover, an healtcheck endpoint is provided, -NestJS provides a [health module](https://github.com/nestjs/terminus) based on Terminus, that gives you the opportunity to declare predefined or custom health indicators. It exposes the health status of the service at `/health`. -This service will return a `200` http status code when all indicators are healthy. Otherwise it will return a `503` http status code. +5. `/health`, -For this service we declared an health indicator that verifies that it can connect to the database. +returning a `200` HTTP code if the API is healthy, `503` otherwise. For the service to be healthy, the underlying database must be up. -## Stats +## Implementation -We are using a Node module called [swagger-stats](http://swaggerstats.io/). -It traces API calls, monitors API performance and usage statistics. It exposes the metrics in different formats, such as Prometheus format, so you may use Prometheus and Graphana for API monitoring and alerting. -Those metrics are available at `/swagger-stats/metrics`. + -For more information about this module, visit the [official swagger-stat page](http://swaggerstats.io/docs.html). +The service is implemented using the [NestJS](https://nestjs.com/) framework. We refer the reader to the [NestJS-based micro-services](../../miscellaneous/nestjs-micro-services.md) page for further details concerning NestJS and the features it provides. -## Docker -It is possible to run this service using Docker containers, using the `docker-compose.yml` and `Dockerfile` files. -For more information, refer to the project [organizations-service][add a link] \ No newline at end of file +Data persistence is achieved by using [PostgreSQL](https://www.postgresql.org/) and [TypeORM](https://github.com/typeorm/typeorm). diff --git a/docs/components/services/reuses.md b/docs/components/services/reuses.md index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..edcbb81fefa87c0a3edcfc88e6e1c3c6917dc95e 100644 --- a/docs/components/services/reuses.md +++ b/docs/components/services/reuses.md @@ -0,0 +1,35 @@ +# Reuses + +## Features + +The Metropolitan area of Lyon promotes the reuse of territorial data: analysis, map, site, service, application... This service provides a list of those reuses. + +A record in the underlying database includes the following information: + +* `_id`: a technical unique identifier (automatically generated); +* `name`: the name of the reuse; +* `uuid`: a business unique identifier (automatically generated if not provided); +* `creator`: the name of the entity that created the reuse; +* `logo`: the url of the reuse's logo; +* `website`: the website url of the reuse; +* `reuseTypes`: an array of the types of the reuse (mobile app, website, article); +* `datasetsUsed`: an array containing the `slugs` of the datasets being reused; +* `createDate`: the date on which the reuse has been created; +* `updateDate`: the date on which the reuse has been updated for the last time; +* `published`: a boolean flag, indicating whether the record is published or not (draft); + +## Dependencies + +This service has no dependency on other components. + +## Endpoints + +This service exposes one single endpoint, `/reuses`, supporting all the CRUD methods in a RESTful fashion. An healthcheck endpoint is exposed as well, `/health`, returning a `200` HTTP code when all indicators are healthy, `503` in the opposite case. The service is considered to be healthy if the underlying database is up. + +## Implementation + + + +The service is implemented using the [NestJS](https://nestjs.com/) framework. We refer the reader to the [NestJS-based micro-services](../../miscellaneous/nestjs-micro-services.md) page for further details concerning the latter framework and the features it provides. + +[MongoDB](https://www.mongodb.com/) is used for data persistence. Data modeling as well as connections to MongoDB are performed with [Mongoose](https://github.com/Automattic/mongoose). diff --git a/docs/components/services/social-media-share-helper.md b/docs/components/services/social-media-share-helper.md index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..0656e24bbb94135486568f53a072172ca8c201e5 100644 --- a/docs/components/services/social-media-share-helper.md +++ b/docs/components/services/social-media-share-helper.md @@ -0,0 +1,41 @@ +# Social media share helper + +## Features + +The data.grandlyon.com web portal has a functionality that let a user share articles on social media directly from the portal. It can be pretty challenging to have an appropriate preview of different pages of an Single Page Application when sharing it on social media. This service has been developed to address that problem and have a correct preview for each article. + +When Facebook's or Twitters' robots access a page, they look for [Open graph](https://ogp.me/) meta tags. Based on those tags they generate a preview of the page containing a title, a description, eventually an image... + +Here is the list of the meta tag read by the robots: + +* `og:locale`: The locale these tags are marked up in. +* `og:type`: The type of the object (ex: article, website...) +* `og:title`: The title of the object described (ex: title of the article) +* `og:description`: The description of the object (ex: abstract of the article) +* `og:image`: An image URL which should represent the object +* `og:url`: The canonical URL of your object that will be used as its permanent ID in the graph + +The problem when working with an SPA is that we serve only one `index.html` file with its own meta tags. Of course with Javascript it is possible to dynamically update the tags according to page current page of the app. A user will see the changes in its browser but a robot won't see any changes has it doesn't execute Javascript. + +The goal of this service is therefor to generate an HTML page with the right meta tags depending on the url parameter. + +## Dependencies + +This service depends on [Elasticsearch](../off-the-shelf-apps/elasticsearch.md) as it is where it collects information about the articles. + +## Endpoints + +This service has two endpoints: + +* `/articles/:slug`: returns an HTML page with the meta tags of the article associated to the `slug` parameter +* `/`: returns an HTML page with the default meta tags of the data.grandlyon.com portal + +## Implementation + + + +The logic here, is that instead of sharing directly the url of the web app, we will share the url of our dedicated service with the slug of the current article. When the service receives the request, it reads the slug from the url and query elasticsearch in order to retrieve more information about the article. Based on the collected information, it generates a very simple empty html page with the appropriates `meta tags` and finally returns the HTML page. Thereby the robot can read the correct meta tag instead of the default ones. + +To prevent the displaying of a blank page, in case of someone access this url from a browser, the page also include the `refresh` tag. This tag tells the browser to refresh the page after a certain time (directly if not specified). Also an url can be passed along to indicate on which url the browser should refresh the page. We use this to redirect the user on the actual data.grandlyon.com page of the article. + +The root url of the service `/` will return a page with the default mata tags of data.grandlyon.com. diff --git a/docs/deployment/beta-deployment.md b/docs/deployment/beta-deployment.md deleted file mode 100644 index d0fc9c5ebe0d14458523452e9e2ede3b79df974d..0000000000000000000000000000000000000000 --- a/docs/deployment/beta-deployment.md +++ /dev/null @@ -1,333 +0,0 @@ -# Deployment of the beta version - -The software is hosted on 5 machines, having the following hostnames and specs: - -* **front-web**: 7 GB RAM; 2 vCores; 50 GB SSD -* **back-office**: 15 GB RAM; 4 vCores; 100 GB SSD -* **es-1**: 30 GB RAM; 8 vCores; 200 GB SSD -* **es-2**: 30 GB RAM; 8 vCores; 200 GB SSD -* **es-3**: 30 GB RAM; 8 vCores; 200 GB SSD - -The above machines exchanges information through a private LAN: `192.168.0.0/24`; `front-web` is the only instance which is directly connected to the Internet, through its WAN interface `ens3` and public IP addresses : `51.83.13.51` (standard), `91.121.35.236` (failover). - -The following diagram provides a sketch of the various applications hosted by infrastructure:  - -Deployments are performed using Gitlab CI. Details on each machine's role and configuration are provided here-below. - -## front-web - -The **front-web** machine has the following roles: - -* router, firewall -* DNS server -* SMTP server -* Reverse Proxy - -Such roles are accomplished thanks to the configuration detailed here-below. - -### router, firewall - -The relevant configuration is stored within the file `/etc/iptables/rules.v4`: - -``` -*nat -:PREROUTING ACCEPT [541:33128] -:INPUT ACCEPT [333:20150] -:OUTPUT ACCEPT [683:49410] -:POSTROUTING ACCEPT [683:49410] --A POSTROUTING -s 192.168.0.0/24 -o ens3 -j MASQUERADE --A POSTROUTING -o ens3 -j SNAT --to-source 91.121.35.236 -COMMIT - -*filter -:INPUT DROP [173:7020] -:FORWARD ACCEPT [2218:856119] -:OUTPUT ACCEPT [5705:2627050] --A INPUT -s 192.168.0.0/24 -m comment --comment "FULL ACCESS LAN" -j ACCEPT --A INPUT -i lo -m comment --comment "FULL ACCESS LOOPBACK" -j ACCEPT --A INPUT -s 217.182.252.78/32 -p tcp -m tcp --dport 22 -m comment --comment "SSH neogeo-ansible" -j ACCEPT --A INPUT -s 80.12.88.99/32 -p tcp -m tcp --dport 22 -m comment --comment "SSH neogeo-bureau" -j ACCEPT --A INPUT -s 213.245.116.190/32 -p tcp -m tcp --dport 22 -m comment --comment "SSH erasmes" -j ACCEPT --A INPUT -m conntrack --ctstate RELATED,ESTABLISHED -m comment --comment "in order to receive responses to outgoing requests" -j ACCEPT --A INPUT -d 51.83.13.51/32 -i ens3 -p tcp -m tcp --dport 443 -j ACCEPT --A INPUT -d 51.83.13.51/32 -i ens3 -p tcp -m tcp --dport 80 -j ACCEPT --A INPUT -d 91.121.35.236/32 -i ens3 -p tcp -m tcp --dport 443 -j ACCEPT --A INPUT -d 91.121.35.236/32 -i ens3 -p tcp -m tcp --dport 80 -j ACCEPT -COMMIT -``` - -Moreover, the following line must appear in the `/etc/sysctl.conf` file: - -`net.ipv4.ip_forward=1` - -### DNS server - -We rely on the `dnsmasq` software, which was installed via `apt`. The relevant configuration is stored in `/etc/dnsmasq.conf` file, which reads as follows: -``` -domain-needed -bogus-priv -server=213.186.33.99 -listen-address=192.168.0.59 -no-dhcp-interface=ens4 -bind-interfaces -``` - -The following lines were appended to the `/etc/hosts` file, allowing the DNS to resolve the entire infrastructure: -``` -51.83.13.51 front-web.wan -192.168.0.59 front-web.lan - -51.83.15.2 back-office.wan -192.168.0.146 back-office.lan - -51.68.115.202 es-1.wan -192.168.0.74 es-1.lan - -51.77.229.85 es-2.wan -192.168.0.65 es-2.lan - -51.83.13.94 es-3.wan -192.168.0.236 es-3.lan - -``` - -The WAN interfaces were declared in spite of the fact that they are not actually used (except for the `front-web` instance). - -It is important to note that, by default, the `/etc/hosts` file is managed by the hosting service. In order to prevent user modifications from being reset at every reboot, a line has to be modified in the `/etc/cloud/cloud.cfg` file: - -`manage_etc_hosts: false` - - -### SMTP server - -`postfix` and `opendkim` were installed through `apt`. The latter was setup following the instructions found at [https://wiki.debian.org/opendkim](https://wiki.debian.org/opendkim). In particular, the following commands were issued as `root`: - -``` -mkdir /etc/postfix/dkim/ -opendkim-genkey -D /etc/postfix/dkim/ -d data.beta.grandlyon.com -s mail -chgrp opendkim /etc/postfix/dkim/* -chmod g+r /etc/postfix/dkim/* -chmod o= /etc/postfix/dkim/* -``` - -Moreover, - -* the line "Mode sv" was uncommented in `/etc/opendkim.conf` (for unknown reasons :-() -* the following lines were appended to the same file: - - ``` - # Specify the list of keys - KeyTable file:/etc/postfix/dkim/keytable - - # Match keys and domains. To use regular expressions in the file, use refile: instead of file: - SigningTable refile:/etc/postfix/dkim/signingtable - - # Match a list of hosts whose messages will be signed. By default, only localhost is considered as internal host. - InternalHosts refile:/etc/postfix/dkim/trustedhosts - ``` -* the line starting with `Socket` was modified as follows: - - ``` - Socket inet:8892@localhost - ``` - -Some other files were edited: - -* `/etc/postfix/dkim/keytable`: - - ```mail._domainkey.data.beta.grandlyon.com data.beta.grandlyon.com:mail:/etc/postfix/dkim/mail.private``` - -* `/etc/postfix/dkim/signingtable`: - - ```*@data.beta.grandlyon.com mail._domainkey.data.beta.grandlyon.com``` - -* `/etc/postfix/dkim/trustedhosts`: - - ``` - 127.0.0.1 - 192.168.0.0/24 - ``` - -The relevant lines in the `postfix` configuration file (`/etc/postfix/main.cf`) read as follows: - -``` -[...] -myhostname = data.beta.grandlyon.com -alias_maps = hash:/etc/aliases -alias_database = hash:/etc/aliases -myorigin = /etc/mailname -mydestination = $myhostname, data.beta.grandlyon.com, front-web.localdomain, localhost.localdomain, localhost -relayhost = -mynetworks = 127.0.0.0/8 [::ffff:127.0.0.0]/104 [::1]/128 192.168.0.0/24 -mailbox_size_limit = 0 -recipient_delimiter = + -inet_interfaces = all -inet_protocols = ipv4 -[...] -milter_default_action = accept -milter_protocol = 6 -smtpd_milters = inet:127.0.0.1:8892 -non_smtpd_milters = $smtpd_milters -[...] -``` - -The DNS records was updated as follows: -``` -data.beta.grandlyon.com. 86400 IN TXT "v=spf1 +ip4:51.83.13.51 ~all" -``` - -``` -mail._domainkey.data.beta.grandlyon.com. 86400 IN TXT "v=DKIM1; h=sha256; k=rsa; " "p=MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAzzoL8dvkfhm3xCpGxW8COUIgmw4r0PV/5GSUekCA8sLGPiqNh8//Jj4tFpLK6eUMacKYPbL4goUdRyTF5gqh/MdEWwafodZczELETRcp3a7mGdmM2nDhD6lk2Xtdf+nS+HWobYN18a3abNFchcF62LJWGTd4fwKV8gOIIuvTiakVxFuC7eIBUO+7m0JU0EnnivLUabphFSL3yV" "hEdpCD3csRGedSnG6+ocpZw25ll8/5f6WZnobU2d5KKqk7MVgOFXfuJMhdjmd6UvSGPaxR+/E+PsxQCU0f9vLG4R8fLPLh0ngNGGiyNYGHB5Sn8VxIrxqpH2pQKaJsfHLK/IgRJwIDAQAB" -``` - -in order to implement the Sender Policy Framework (SPF). The public key can be found in the file `/etc/postfix/dkim/mail.txt`. - -### Reverse Proxy - -`nginx` was installed through `apt`. The various "virtual host" configuration files can be found in the `/etc/nginx/sites-available` and `/etc/nginx/sites-enabled` folders. TLS certificates are stored in `/etc/nginx/ssl`. - -## back-office - -This instance hosts both custom and off-the-shelf applications, as illustrated by the diagram displayed at the beginning of this. These applications serve several purposes: - -* administration, configuration -* monitoring -* business - -The public network interface (`ens3`) was deactivated, by commenting out the line -`auto ens3` in the `/etc/network/interfaces.d/50-cloud-init.cfg`. In order for the modification to be persistent, we need to disable cloud-init's network configuration capabilities, by editing the file `/etc/cloud/cloud.cfg.d/99-disable-network-config.cfg` with the following content: -``` -network: {config: disabled} -``` - -The private network interface (`ens4`) was statically configured. Here's the relevant lines of the `/etc/network/interfaces` file: - -``` -[...] -auto ens4 -iface ens4 inet static - address 192.168.0.146 - netmask 255.255.255.0 - gateway 192.168.0.59 - dns-nameservers 192.168.0.59 -[...] -``` - -The `back-office` instance runs Docker and docker-compose, which were installed following the official documentation: - -* https://docs.docker.com/install/linux/docker-ce/debian/ -* https://docs.docker.com/compose/install/ - -The default configuration was tweaked in order to prevent Docker from messing up with virtual networks. Here's is the content of the `/etc/docker/daemon.json` file: -``` -{ - "default-address-pools": [ - { - "scope": "local", - "base": "172.17.0.0/16", - "size": 24 - }, - { - "scope": "global", - "base": "172.90.0.0/16", - "size": 24 - } - ] -} -``` - -Moreover, the content of the file `/etc/systemd/system/docker.service.d/startup_options.conf` was edited as follows, -``` -[Service] -ExecStart= -ExecStart=/usr/bin/dockerd -H fd:// -H tcp://192.168.0.146:2375 -``` -in order to make the Docker Daemon listen to a TCP socket, instead of the default Unix socket. This allows Portainer to connect to the Docker Daemons running on the various Docker-enabled instances of the infrastructure (cf. https://success.docker.com/article/how-do-i-enable-the-remote-api-for-dockerd). - -## es-1, es-2, es-3 - -These three instances host some distributed applications: - -* Elasticsearch -* Kong (backed by the Cassandra database) -* MinIO - -Moreover, - -* they collect and parse HTTP logs via Filebeat and Logstash, respectively, which are then sent to a "small" Elasticsearch instance which is running on the `back-office` machine for monitoring purposes; -* they store (cold) backups of the configuration of the entire infrastructure, as well as some of the relevant application data. Backups are performed by `rsnapshot`, which was installed via `apt`. Its setup requires the following steps: - -1. `rsync` needs be installed on all the instances of the infrastructure -2. a public SSH key owned by the `root` user of each `es-X` instance must be appended to the `/root/.ssh/authorized_keys` of all the other instances -3. a first SSH session from each `es-X` instance to all the others must be established, in order to answer "yes" to the question concerning the authenticity of the host we wish to connect to -4. the `/etc/rsnapshot.conf` file must be customized according to our needs. Here's the copy of the relevant lines that can be found on `es-1`: - - ``` - [...] - - cmd_ssh /usr/bin/ssh - - [...] - - retain hourly 6 - retain daily 7 - retain weekly 4 - retain monthly 3 - - [...] - - backup /home/ es-1/ - backup /etc/ es-1/ - backup /usr/local/ es-1/ - - backup root@es-2.lan:/etc/ es-2/ - backup root@es-2.lan:/home/ es-2/ - backup root@es-2.lan:/usr/local/ es-2/ - - backup root@es-3.lan:/etc/ es-3/ - backup root@es-3.lan:/home/ es-3/ - backup root@es-3.lan:/usr/local/ es-3/ - - backup root@back-office.lan:/etc/ back-office/ - backup root@back-office.lan:/home/ back-office/ - backup root@back-office.lan:/usr/local/ back-office/ - backup root@back-office.lan:/var/local/docker-apps/ back-office/ - - backup root@front-web.lan:/etc/ front-web/ - backup root@front-web.lan:/home/ front-web/ - backup root@front-web.lan:/usr/local/ front-web/ - ``` - - N.B.: `rsnapshot` loves (hates) tabs (blank spaces) - -**The `es-1`, `es-2`, `es-3` instances share the same network and Docker (+ docker-compose) configuration as the `back-office` instance.** - -## Additional notes - -The following software packages are installed on all the machines (via `apt`): - -* `resolvconf` -* `prometheus-node-exporter` - -On the `back-office` and `es-{1,2,3}` instances, `gitlab-runner` was installed following the [official documentation]( https://docs.gitlab.com/runner/install/linux-repository.html). Gitlab Runners were then registered as "group runners" associated with the following group: https://gitlab.alpha.grandlyon.com/groups/refonte-data/deployment-beta. The following tags were used -* data-beta-grandlyon-com-back-office -* data-beta-grandlyon-com-es-1 -* data-beta-grandlyon-com-es-2 -* data-beta-grandlyon-com-es-3 -in order to be able to trigger CI jobs only on selected machines. - - -## Critical points and potential improvements - -1. **The `front-web` instance is the SPOF of the infrastructure. How to cope with it? Shall we use an HA instance ? If not, how to set up an infrastructure with two routers??** -2. Despite the periodic backups that we let `rsnapshot` perform, in case of failure data/service restoration would take a non-negligible amount of time. Some applications are already deployed in High Availability mode: - * Kong, thanks to the Cassandra cluster - * Elasticsearch, which stores both the (meta)data related to datasets and the editorial content (edited from within the Ghost CMS application) - - Some others, hosted by the `back-office` instance are not yet distributed/replicated, but could be in the near future: - - * by deploying the stateless services (mail, AUTHN, CSV catalog download, single page app, ...) on `es-{1,2,3}`; - * by deploying PostgreSQL (needed by the "organizations" and "resources wizard" services) in master-slave mode, the slaves being hosted by `es-{1,2,3}` and the master by `back-office` (N.B.: writes to the database come from the "Admin GUI" service); - * by deploying Redis (needed by the "legacy AUTH middleware" service) in HA mode, cf. https://redis.io/topics/sentinel. - - N.B.: It's not such a big deal to leave the administration tools (Konga, Portainer, pgAdmin, Prometheus + Elasticsearch + Grafana) unreplicated. diff --git a/docs/extra.css b/docs/extra.css index 27e17f3396f8515eb10a02eeb56d1ba5e040ab6b..a9559f944662e28c3664723a9843a7fae33c0261 100644 --- a/docs/extra.css +++ b/docs/extra.css @@ -6,4 +6,8 @@ body { background: white; border: 1px solid #dcd9d9; margin-bottom: 2rem; +} + +.md-content a { + text-decoration: underline; } \ No newline at end of file diff --git a/docs/miscellaneous/accessibility.md b/docs/miscellaneous/accessibility.md index c8d3077d2d25da70e8d8b9d8c20d0b3f0de0c0eb..e5238072ebe413b96f5caf23e0147040623dbe13 100644 --- a/docs/miscellaneous/accessibility.md +++ b/docs/miscellaneous/accessibility.md @@ -2,23 +2,22 @@ This [resource](https://bitsofco.de/pa11y/) is a good start to create your own testing pipeline. - - ## Quick and simple overview -``` + +```bash npm install -g pa11y -``` -``` pa11y https://data.beta.grandlyon.com/fr/accueil ``` ## Display only critical errors -``` + +```bash pa11y https://data.beta.grandlyon.com/fr/accueil --ignore "warning;notice" ``` ## Using the pa11y-ci -``` + +```bash npm install -g pa11y-ci ``` @@ -30,12 +29,15 @@ Then create a **.pa11yci** json file. ] } ``` + To run the report on multiple URLs: -``` + +```bash pay11-ci ``` It is also possible to save the report as a json file: -``` + +```bash pay11-ci --json > report.json ``` diff --git a/docs/miscellaneous/authentication&authorization.md b/docs/miscellaneous/authentication&authorization.md index 2fae0bf7e3bceee53bc0b830bb25c34a3ee06c67..d5f5916246be9de1f84b65823fbdaf46ce597226 100644 --- a/docs/miscellaneous/authentication&authorization.md +++ b/docs/miscellaneous/authentication&authorization.md @@ -145,7 +145,7 @@ end @enduml ``` -When the user receives the "account validation" email, he/she/it is invited to click the link. This will open the web application that will get the Uuid4 token from the url and call a validate account endpoint of the middleware. +When the user receives the "account validation" email, he/she is invited to click the link. This will open the web application that will get the Uuid4 token from the url and call a validate account endpoint of the middleware. If the token is still in Redis, then the middleware can process with the account creation calling the legacy Auth service. diff --git a/docs/miscellaneous/nestjs-micro-services.md b/docs/miscellaneous/nestjs-micro-services.md index a4b48bc6d0a28e4bb7ea30061764fffddb4235e0..6ca28d4ecc68665a6d68452111d48a878eebe100 100644 --- a/docs/miscellaneous/nestjs-micro-services.md +++ b/docs/miscellaneous/nestjs-micro-services.md @@ -12,6 +12,17 @@ NestJS provides a [swagger module](https://docs.nestjs.com/recipes/swagger) that NestJS provides a health module based on [Terminus](https://github.com/nestjs/terminus), allowing developers to declare predefined and/or custom health indicators. By default, the health status of a given NestJS service is available through the `/health` endpoint. +A service will return a `200` http status code when all indicators are healthy. Otherwise it will return a `503` http status code. + ## Logging -## Guards or how to implement an AUTHZ layer +## Guards or: how to implement an AUTHZ layer + + +## TODO + +* Explain how the `validationPipe` works +* Explain why we need to expose the `Content-Range` header +* Is the order of NestJS decorations relevant? +* Explain how data can be exported and imported +* Explain why we need to use the `pgcrypto` extension diff --git a/docs/miscellaneous/sass-recommendation.md b/docs/miscellaneous/sass-recommendation.md index 05a2cc2d9758fb6c2e0d57d2184c831dab55fab0..5fcb1facc4d414c84d2c55e548f8a37e377f4472 100644 --- a/docs/miscellaneous/sass-recommendation.md +++ b/docs/miscellaneous/sass-recommendation.md @@ -1,10 +1,13 @@ # Good practices CSS/SASS ## Naming convention + Many exist, but we should look for [SUIT CSS](https://github.com/suitcss/suit/blob/master/doc/naming-conventions.md) ## Code formatting -Two tools are usually used for having a clean and nice organized code across all the applicaiton: + +Two tools are usually used for having a clean and nice organized code across all the application: + * a style linter: here the suggestion is [stylelint](https://stylelint.io/) * a code formatter: for example [Prettier](https://prettier.io/) @@ -13,32 +16,40 @@ The main issue here is that sometime is difficult to put settings between the li ## Responsiveness -#### Use REM instead pixel +### Use REM instead pixel + One popular technique (there is a lot of discussion about it. The choice is yours): It's all about changing the `font-size` for the html element to 62.5%. + ```css html { font-size: 62.5% } ``` + The reason is that the default `font-size` for browser is usually `16px`. It means now inside your application `1rem` will be equal to 10px. This will help for the readability and maintainability of your code. -#### For mobile +#### For mobile + * Increase the `font-size` on mobile * Decrease or remove the paddings and margins ## REM vs EM spacing -It has to be considered case by case. But *in general*: + +It has to be considered case by case. But *in general*: + * `rem` is more applied for **horizontal spacing** * `em` is more applied for **vertical spacing** ## Random things about SVG + * when you create a SVG, make it from the most small version you will use inside the website * one tool to optimize your SVGs: [SVGOMG](https://jakearchibald.github.io/svgomg/) * if your SVG has some blurry, probably your paths are not enough specifics ## Some questions + * animation on `height:auto` element: You are screwed :) . There is no miracle solution. Here you can find on this [CSS Tricks article](https://css-tricks.com/using-css-transitions-auto-dimensions/) @@ -47,5 +58,3 @@ here it's even worse. there is no suitable solution ! * `display:flex`: is it possible to use it everywhere ? This has changed the way to use CSS, so no hesitation. The Flex main bugs are listed in this [Github page](https://github.com/philipwalton/flexbugs) if you find yourself with some issues. - -* \ No newline at end of file diff --git a/docs/miscellaneous/vscode-settings.md b/docs/miscellaneous/vscode-settings.md index 24c8bd32b4f599465ad6e9606a7b307fedfee57b..872046f0719ad46bd5344bda1ec37456e116d532 100644 --- a/docs/miscellaneous/vscode-settings.md +++ b/docs/miscellaneous/vscode-settings.md @@ -1,7 +1,10 @@ -## User settings +# VS Code settings + +## User settings + To add in the **settings.json** of Vscode IDE: -``` +```json { "editor.snippetSuggestions": "top", "editor.tabSize": 2, @@ -22,12 +25,12 @@ To add in the **settings.json** of Vscode IDE: ``` ## Some important plugins to install + * stylelint * Beautify * TSLint * Angular Language Service ## Beautify (formatter) & stylelint (linter) settings -The rules of these are inside 2 files at the root of the project: .stylelintrc and .jsbeautifyrc. - +The rules of these are inside 2 files at the root of the project: .stylelintrc and .jsbeautifyrc. diff --git a/docs/miscellaneous/webapp-auth.md b/docs/miscellaneous/webapp-auth.md index b78d4a3bb62dffbab26800ae40a6f9260910ca92..363a88171aed0e11a54bf7e00f22028be99d720b 100644 --- a/docs/miscellaneous/webapp-auth.md +++ b/docs/miscellaneous/webapp-auth.md @@ -297,7 +297,7 @@ group Authorization with Django server front -> middle : <b>GET</b> /restrictedAccessDatasets middle -> django : <b>GET</b> /get_services/ middle <-- django : { datasets } - front <-- middle : { datsets with "RESTRICTED" access} + front <-- middle : { datasets with "RESTRICTED" access} end end -``` \ No newline at end of file +``` diff --git a/mkdocs.yml b/mkdocs.yml index e17d3244cc24c12daa2b339d30a0bc5b5f99b730..1f25d50eccdd1609c4f146467fb0011909e8bbe6 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -43,12 +43,12 @@ nav: - Dataset: - Data: components/custom-apps/web-app/dataset/data.md - Information: components/custom-apps/web-app/dataset/info.md - - API \& Downloads: components/custom-apps/web-app/dataset/resources.md + - API & Downloads: components/custom-apps/web-app/dataset/resources.md - Header: components/custom-apps/web-app/header.md - Footer: components/custom-apps/web-app/footer.md - Drafts: components/custom-apps/web-app/drafts.md - Side Menu: components/custom-apps/web-app/side-menu.md - - Sign Up, Sign In, Sign Out: components/custom-apps/web-app/sign-up-in-out.md + - User management: components/custom-apps/web-app/user-management.md - Contact: components/custom-apps/web-app/contact.md - Search: components/custom-apps/web-app/search.md - Admin GUI: components/custom-apps/admin-gui.md