Commit cad8e212 authored by Clement Brizard's avatar Clement Brizard
Browse files

Merge branch 'master' into 36-verifications-a-faire-avec-simapro-valeurs-restant-a-mesurer

parents 41302cd1 1e784825
......@@ -2,6 +2,7 @@ image: node:latest
before_script:
- npm install --save-dev eslint eslint-config-standard eslint-plugin-standard eslint-plugin-promise eslint-plugin-import eslint-plugin-node
- npm install --save-dev stylelint stylelint-scss stylelint-config-recommended-scss
- npm i
stages:
- lint
......@@ -14,6 +15,13 @@ eslint:
tags:
- docker
stylelint:
stage: lint
script:
- npx stylelint ./sass --config .stylelintrc.yml
tags:
- docker
unit-tests:
stage: test
script:
......
{
"extends": [
"stylelint-config-recommended-scss"
],
"plugins": [
"stylelint-scss"
],
"rules": {
"indentation": [ 2, {
"except": ["block"],
"message": "Please use 2 spaces for indentation.",
"severity": "warning"
} ],
"max-empty-lines": 2,
"rule-empty-line-before": [ "always", {
"except": ["first-nested"],
"ignore": ["after-comment"]
} ],
"declaration-block-semicolon-newline-after": "always",
"block-opening-brace-newline-after": "always",
"block-closing-brace-newline-before": "always",
"block-closing-brace-newline-after": "always",
"no-empty-source": [ true, {
"severity": "warning"
} ],
"unit-whitelist": ["em", "rem", "%", "s"]
}
}
\ No newline at end of file
......@@ -28,4 +28,4 @@ $ npm test
```
## Wiki
Voir le [wiki](https://gitlab.utc.fr/tx-techno-num/impactometre/wikis/home) pour détails sur certains aspects du projet, notamment des définitions sur les données manipulées, et des guides sur les technos utilisées.
Voir le [wiki](https://gitlab.utc.fr/tx-techno-num/impactometre/wikis/Accueil) pour détails sur certains aspects du projet, notamment des définitions sur les données manipulées, et des guides sur les technos utilisées.
......@@ -2,6 +2,9 @@
const createError = require('http-errors')
const express = require('express')
const sassMiddleware = require('node-sass-middleware')
const postcssMiddleware = require('postcss-middleware')
const autoprefixer = require('autoprefixer')
const path = require('path')
const cookieParser = require('cookie-parser')
const logger = require('morgan')
......@@ -17,6 +20,31 @@ app.set('view engine', 'ejs')
app.use(logger('dev'))
app.use(express.json())
app.use(express.urlencoded({ extended: false }))
// add the sass middleware
app.use(
sassMiddleware({
src: path.join(__dirname, 'sass'),
dest: path.join(__dirname, 'public/stylesheets'),
prefix: '/stylesheets',
/* outputStyle: 'compressed', */ // will be used at production
debug: true
})
)
// add the autoprefixer via postcss middleware
app.use(
'/stylesheets', postcssMiddleware({
src: function (req) {
return path.join(__dirname, 'public', 'stylesheets', req.path)
},
plugins: [
autoprefixer({
Browserslist: ['last 4 versions']
})
]
})
)
app.use(cookieParser())
app.use(express.static(path.join(__dirname, 'public')))
......
......@@ -65,6 +65,35 @@ const hardwareOperatingTimePerDay = {
LOGITECH_KIT: 3 / workedDaysByWeek
}
/**
* Components that a meeting can be composed of.
*/
const meetingComponents = {
HARDWARE: 'HARDWARE',
SOFTWARE: 'SOFTWARE',
JOURNEY: 'JOURNEY'
}
/**
* Transportation mean sub categories
*/
const transportationMeanSubCategories = {
CAR: 'CAR',
PLANE: 'PLANE',
TRAIN: 'TRAIN',
BUS: 'BUS',
BIKE: 'BIKE'
}
/**
* Damage categories for meetings
*/
const meetingCategoryDamage = {
HARDWARE: 'HARDWARE',
SOFTWARE: 'SOFTWARE',
JOURNEY: 'JOURNEY'
}
exports.hourToMinutes = hourToMinutes
exports.dayToHours = dayToHours
exports.minuteToSeconds = minuteToSeconds
......@@ -81,3 +110,7 @@ exports.hardwareDamageTypes = hardwareDamageTypes
exports.hardwareLifetime = hardwareLifetime
exports.knownOperatingTimeOverLife = knownOperatingTimeOverLife
exports.hardwareOperatingTimePerDay = hardwareOperatingTimePerDay
exports.meetingComponents = meetingComponents
exports.transportationMeanSubCategories = transportationMeanSubCategories
exports.meetingCategoryDamage = meetingCategoryDamage
'use strict'
var uniqid = require('uniqid')
/**
* A journey has a mean of transportation,
* a distance and a number of people.
*/
export default class Journey {
/**
* The Journey class constructor.
* @param {TransportationMean} mean The mean of transportation.
* @param {Float} distance The distance of the journey.
* @param {Integer} numberOfPeople The number of people of the journey.
*/
constructor (mean, distance, numberOfPeople) {
this._id = uniqid()
this._mean = mean
this._distance = distance
this._numberOfPeople = numberOfPeople
}
// Getters
/**
* Getter of the journey id.
*/
get id () {
return this._id
}
/**
* Getter of the journey transportation mean.
*/
get mean () {
return this._mean
}
/**
* Getter of the journey distance.
*/
get distance () {
return this._distance
}
/**
* Getter of the journey number of people.
*/
get numberOfPeople () {
return this._numberOfPeople
}
// Setters
/**
* Setter of the journey transportation mean.
* @param {TransportationMean} transportationMean - The new journey transportation mean.
*/
set mean (transportationMean) {
this._mean = transportationMean
}
/**
* Setter of the journey distance.
* @param {Float} distance - The new journey distance.
*/
set distance (distance) {
this._distance = distance
}
/**
* Setter of the journey number of people.
* @param {Integer} numberOfPeople - The new journey number of people.
*/
set numberOfPeople (numberOfPeople) {
this._numberOfPeople = numberOfPeople
}
// Other methods
/**
* Computes the damage caused by a journey.
* @returns {ComponentDamage} The damage caused by journey, for each damage sphere.
*/
computeEmbodiedDamage () {
// Get the transportation mean damage for one personKm or one kilometer
const transportationMeanDamage = new ComponentDamage(this.mean.embodied)
// Initialize the returned damage
const embodiedDamage = new ComponentDamage()
// Compute damage for each sphere (calculation mode is by personKm or by kilometer)
if (this.mean.isComputedByPersonKm) {
// Compute the personKilometers amount
const personKmAmount = this.distance * this.numberOfPeople
embodiedDamage.mutate(category => {
return transportationMeanDamage[category] * personKmAmount
})
} else {
embodiedDamage.mutate(category => {
return transportationMeanDamage[category] * this.distance
})
}
// Return the journey embodied damage
return embodiedDamage
}
/**
* Compute the total damage of the journey.
* There is a method with the same name for Software class and Hardware class.
* @returns {CompenentDamage} The total damage caused by the journey.
*/
computeDamage () {
return this.computeEmbodiedDamage()
}
}
module.exports = Journey
'use strict'
const Hardware = require('./Hardware')
const Damage = require('../shared/Damage')
const Journey = require('./Journey')
const Software = require('./Software')
const {
meetingCategoryDamage
} = require('../../../constants/meeting')
class CategoryDamage {
/**
* Create a damage synthesis for all meeting components from the same category (hardware, software or transport).
* It's composed of a total damage that is the sum of each component damage
* and of an array that contains all the component damages.
* @param {Object[]} components - An array of JSON objects that contains all necessary data to create the components of the category.
* @param {String} category - The category of the given components.
*/
constructor ({ components, category }) {
this._category = category
// Create a hashmap that contains components and their id
this._components = this.arrayToMapComponents(components, category)
}
// Getters
/**
* Getter of the total category damage.
*/
get totalDamage () {
return this._totalDamage
}
/**
* Getter of the hasmhap that contains all the components indexed by a their id.
*/
get components () {
return this._components
}
/**
* Getter of The category of the components wich caused the damage.
*/
get category () {
return this._category
}
// Setters
/**
* Setter of the total category damage.
*/
set totalDamage (totalDamage) {
this._totalDamage = totalDamage
}
/**
* setter of the hasmhap that contains all the components indexed by a their id.
*/
set components (components) {
this._components = components
}
/**
* Setter of The category of the components wich caused the damage.
*/
set category (category) {
this._category = category
}
// Other methods
/**
* From an array that contains all necessary data,
* Create a hashmap of components (hardware, software or journeys) indexed by their id
* @param {Object[]} components - An array of JSON objects that contain all necessary data to create the components of the meeting.
* @param {String} category - The category of the components that caused the damage.
*/
arrayToMapComponents (components, category) {
// The hashmap that will contain components indexed by their id
const componentsMap = new Map()
switch (category) {
case meetingCategoryDamage.HARDWARE:
components.forEach(c => {
const component = new Hardware(c)
componentsMap.set(component.id, component)
})
break
case meetingCategoryDamage.SOFTWARE:
components.forEach(c => {
const component = new Software(c)
componentsMap.set(component.id, component)
})
break
case meetingCategoryDamage.JOURNEY:
components.forEach(c => {
const component = new Journey(c)
componentsMap.set(component.id, component)
})
break
}
return componentsMap
}
/**
* Compute the damage caused by each component of the categoryDamage object and
* initialize the total damage caused by all these components.
* @param payload - A JSON object that contains all necessary data to compute
* the damage caused by each component of the categoryDamage (hardware, software, journeys).
*/
computeDamage (payload = {}) {
this.totalDamage = new Damage()
// Compute the damage caused by each component of the categoryDamage object
// and add it to the totalDamage caused by the components of the categoryDamage object.
this.components.forEach(c => {
c.computeDamage(payload)
this.totalDamage = this.totalDamage.add(c.damage)
})
}
}
module.exports = CategoryDamage
'use strict'
export default class DistributedDamage {
/**
* Create a damage synthesis for a given damage category
* shared among the three meeting impact categories.
* @param {Number} total - The total damage value (transport share + hardware share + software share).
* @param {Number} transportShare - The transport damage share.
* @param {Number} hardwareShare - The hardware damage share.
* @param {Number} softwareShare - The software damage share.
*/
constructor (total, transportShare, hardwareShare, softwareShare) {
this._total = total
this._transportShare = transportShare
this._hardwareShare = hardwareShare
this._softwareShare = softwareShare
}
// Getters
/**
* Getter of the total damage value (transport share + hardware share + software share).
*/
get total () {
return this._total
}
/**
* Getter of the transport damage share.
*/
get transportShare () {
return this._transportShare
}
/**
* Getter of the hardware damage share.
*/
get hardwareShare () {
return this._hardwareShare
}
/**
* Getter of the software damage share.
*/
get softwareShare () {
return this._softwareShare
}
// Setters
/**
* Setter of the total damage value (transport share + hardware share + software share).
*/
set total (total) {
this._total = total
}
/**
* Setter of the transport damage share.
*/
set transportShare (transportShare) {
this._transportShare = transportShare
}
/**
* Setter of the hardware damage share.
*/
set hardwareShare (hardwareShare) {
this._hardwareShare = hardwareShare
}
/**
* Setter of the software damage share.
*/
set softwareShare (softwareShare) {
this._softwareShare = softwareShare
}
// Other methods
}
......@@ -10,9 +10,10 @@ const {
} = require('../../../constants/meeting')
const hardwareDatabase = require('../../database/meeting/hardware')
const Damage = require('./Damage')
const Damage = require('../shared/Damage')
const Component = require('../shared/Component')
class Hardware {
class Hardware extends Component {
/**
* Create a hardware.
* @param {String} name - The key of an entry from the hardware database.
......@@ -26,9 +27,12 @@ class Hardware {
* @param {Array} componentsPayload - Optional components constructor parameters indexed by component name.
*/
constructor ({ name, quantity = 1, size = 1, shareForVisio = 1, componentsPayload = {} }) {
// Get the corresponding JSON object
const json = hardwareDatabase[name]
super({ french: json.french, category: json.category })
this._name = json.name
this._french = json.french
this._quantity = quantity
this._size = size
this._shareForVisio = shareForVisio
......@@ -60,6 +64,8 @@ class Hardware {
}
}
// Getters
get name () {
return this._name
}
......@@ -167,6 +173,19 @@ class Hardware {
return this._components
}
/**
* Getter of the total damage caused by the hardware.
*/
get damage () {
return this._damage
}
// Setters
set damage (damage) {
this._damage = damage
}
set quantity (quantity) {
this._quantity = quantity
}
......@@ -179,16 +198,17 @@ class Hardware {
this._shareForVisio = shareForVisio
}
// Other methods
/**
* Compute the total damage of the object by adding together
* Compute and initialize the total damage of the object by adding together
* the four types of damage of the hardware.
* @param {String} bound - The optional bound.
* If equals to 'UPPER', we will use the upper values
* of the damages if available, and the contrary if
* bound equals to 'LOWER'.
* @returns {Damage} The total damage.
*/
computeDamage (meetingDuration, bound = null) {
computeDamage ({ meetingDuration, bound = null }) {
let damage
// Hardware may be composed of other hardwares
......@@ -197,8 +217,8 @@ class Hardware {
/* For each component, compute its damage
and add it to composite hardware damage */
Object.values(this.components).forEach(component => {
const componentDamage = component.computeDamage(meetingDuration, bound)
damage.add(componentDamage)
component.computeDamage({ meetingDuration, bound })
damage.add(component.damage)
})
} else {
const operatingVisio = this.computeTypedDamage(hardwareDamageTypes.OPERATING_VISIO, meetingDuration, bound)
......@@ -210,10 +230,10 @@ class Hardware {
}
damage.mutate(category => {
return damage[category] * this.quantity
damage[category] *= this.quantity
})
return damage
this.damage = damage
}
/**
......@@ -229,12 +249,12 @@ class Hardware {
// Hardware may not have any value for the required damage
if (!this.getTypedDamage(damageType, bound)) {
damage = new Damage()
damage = new Damage({ component: this })
return damage
}
damage = new Damage(this.getTypedDamage(damageType, bound))
damage = new Damage({ component: this, ...this.getTypedDamage(damageType, bound) })
if (
damageType === hardwareDamageTypes.OPERATING_STANDBY ||
damageType === hardwareDamageTypes.OPERATING_VISIO
......@@ -243,12 +263,12 @@ class Hardware {
// Hardware damage may depends on its size
if (this.isSizeDependent) {
damage.mutate(category => {
return damage[category] * this.shareForVisio * this.size * this.getVisioOrStandbyDuration(damageType, meetingDuration)
damage[category] *= this.shareForVisio * this.size * this.getVisioOrStandbyDuration(damageType, meetingDuration)
})
} else {
damage = new Damage(this.getTypedDamage(damageType, bound))
damage = new Damage({ component: this, ...this.getTypedDamage(damageType, bound) })
damage.mutate(category => {
return damage[category] * this.shareForVisio * this.getVisioOrStandbyDuration(damageType, meetingDuration)
damage[category] *= this.shareForVisio * this.getVisioOrStandbyDuration(damageType, meetingDuration)
})
}
......@@ -269,8 +289,6 @@ class Hardware {
// Embodied damage for the meeting
damage[category] *= this.getVisioOrStandbyDuration(damageType, meetingDuration)
return damage[category]
})
} else {
damage.mutate(category => {
......@@ -278,8 +296,6 @@ class Hardware {