Source

services/rights-service.js

/**
 * @namespace Services
 * @category Services
 * @module rights-service
 * */

import store from '../store'
import envService from '@/services/env-service.js'
import { getQueryStringValue } from '@/utils/querystring'
const R = require('ramda')

export const rightsTable = {
  location_access: 'GEOV3_LOCALISATION_ACCESS',
  location_history_mode: 'GEOV3_LOCALISATION_HISTO_ACCESS',
  location_history: 'GEOV3_LOCALISATION_HISTO_VIEW_ROUTES_DONE',
  location_circuit: 'GEOV3_LOCALISATION_HISTO_VIEW_ROUTE_SECTIONS',
  location_circuit_filter_ignored:
    'GEOV3_LOCALISATION_HISTO_VIEW_IGNORED_ROUTE_SECTIO',
  location_messages: 'GEOV3_MESSAGES_VIEW_LIST',
  location_messages_can_send: 'GEOV3_MESSAGES_SENDED',
  location_alerts: 'GEOV3_ALERTS_ACCESS',
  location_events: 'GEOV3_EVENTS_ACCESS',
  location_chrono: 'GEOV3_LOCALISATION_HISTO_TACHO_SEARCH',
  location_identification: 'GEOV3_IDENTIFICATION_ACCESS',
  location_position_analysis: 'GEOV3_LOCALISATION_HISTO_VIEW_ROUTES_DONE',
  location_search_realtime_driver: 'GEOV3_LOCALISATION_REALTIME_DRIVER_SEARCH',
  location_search_realtime_circuit:
    'GEOV3_LOCALISATION_REALTIME_CIRCUIT_SEARCH',
  location_search_realtime_vehicle:
    'GEOV3_LOCALISATION_REALTIME_VEHICULE_SEARCH',
  location_search_history_driver: 'GEOV3_LOCALISATION_HISTO_DRIVER_SEARCH',
  location_search_history_circuit: 'GEOV3_LOCALISATION_HISTO_CIRCUIT_SEARCH',
  location_search_history_vehicle: 'GEOV3_LOCALISATION_HISTO_VEHICLE_SEARCH',

  identification_access: 'GEOV3_IDENTIFICATION_ACCESS',
  identification_search_circuit: 'GEOV3_IDENTIFICATION_CIRCUIT_SEARCH',
  identification_search_vehicle: 'GEOV3_IDENTIFICATION_VEHICLE_SEARCH',

  common_login_as_access: 'acceuilselectclient',
  common_login_as_user: 'seconnecter',

  geocoding_access: 'GEOV3_MAP_SEARCH_ACCESS',
  geocoding_address: 'GEOV3_MAP_SEARCH_LOCATE_ADDRESS',
  geocoding_address_natural: 'GEOV3_MAP_SEARCH_NATURAL_GEOCODING',
  geocoding_address_reverse: 'GEOV3_MAP_SEARCH_REVERSE_GEOCODING',
  geocoding_routing: 'GEOV3_MAP_SEARCH_ROUTING',

  ecoconduite_access: 'GEOV3_ECOCONDUITE_ACCESS',

  circuit_access: 'GEOV3_CIRCUIT_ACCESS',

  dashboard_access: 'GEOV3_DASHBOARD_ACCESS',

  objects_access: 'GEOV3_OBJECTS_ACCESS',

  zones_access: 'GEOV3_ZONES_ACCESS',

  diagnostics_access: 'GEOV3_DIAGNOSTIC_ACCESS',

  alerts_access: 'GEOV3_ALERTS_ACCESS',

  help_access: 'GEOV3_HELP_ACCESS',

  events_access: 'GEOV3_EVENTS_ACCESS',
  events_search_vehicle: 'GEOV3_EVENTS_VEHICLE_SEARCH',
  events_search_circuit: 'GEOV3_EVENTS_CIRCUIT_SEARCH',

  diagnostics_chart_chrono: 'GEOV3_LOCALISATION_HISTO_TACHO_SEARCH',

  map_predefined_view_list: 'GEOV3_MAPPREDEFINEDVIEW_ACCESS',
  map_predefined_view_create: 'GEOV3_MAPPREDEFINEDVIEW_CREATE',
  map_predefined_view_edit: 'GEOV3_MAPPREDEFINEDVIEW_EDIT',
  map_predefined_view_remove: 'GEOV3_MAPPREDEFINEDVIEW_REMOVE',

  nearby_vehicles_feature: 'GEOV3_MAP_SEARCH_NEARBY_VEHICLES',
  nearby_vehicles_map_menu_context: 'GEOV3_MAP_MENU_NEARBY_VEHICLES',

  map_menu_access: 'GEOV3_MAP_MENU_ACCESS',
}

/**
 * Given a list of vue routes (vue-router), returns the first route available for the current user (based access rights loaded on memory)
 *
 * Note: Routes are sorted by meta.weight ASC. (i.g Location could have priority over Ecoconduite)
 * Note: Login route is skip
 * Note: Routes with meta.allowRedirect=false are skip
 * @todo Add unit-test (router.spec.js)
 * @todo Parameter should be a list of non-vue-object routes
 * @todo Use a sort polyfill (sort behaves differently in firefox)
 * @returns
 */
export function getFirstGrantedRouteFromVueRoutes(vueRoutes) {
  return (
    vueRoutes
      .filter(
        (r) =>
          r.name !== 'login_as' &&
          !(r.meta && r.meta.isTestingRoute === true) &&
          (r.meta || {}).allowRedirect !== false &&
          !['login_screen', 'login_as'].includes(r.name)
      )
      .sort((a, b) => {
        return (a.meta || { weight: 999 }).weight <
          (b.meta || { weight: 999 }).weight
          ? 1
          : -1
      })
      .find(
        (r) =>
          ((r.meta || {}).requiredRights || [])
            .map((rightCode) => {
              return store.getters['auth/rightsList'].includes(rightCode)
                ? '1'
                : '0'
            })
            .join('')
            .indexOf('0') === -1
      ) || null
  )
}

/**
 * Given a vue route (vue-router), returns TRUE/FALSE if the user has the required access rights.
 * @param {*} vueRoute
 * @returns
 */
export function isVueRouteGranted(vueRoute) {
  return !![vueRoute].find(
    (r) =>
      ((r.meta || {}).requiredRights || [])
        .map((rightCode) => {
          return store.getters['auth/rightsList'].includes(rightCode)
            ? '1'
            : '0'
        })
        .join('')
        .indexOf('0') === -1
  )
}

/**
 * Given a list of rights codes and a right code, decide whenever the logged user has the right or not.
 * - sabadmin skip validation
 * - url?rights=0 skip validation on non production environments
 * - url?add_rights=XX add rights (during evaluation) on non production environments
 * - url?remove_rights=xx remove rights (during evaluation) on non production environments
 * - comparision is case insensitive
 * @param {Array} rights List of rights codes
 * @param {String} code Right code
 * @param {String} loggedUsername Username of the logged user
 * @param {String} options.startsWith (Optional) Match rights partially
 */
export function hasRight(rights, code, loggedUsername, options = {}) {
  //Non production environments: Can bypass right checking
  if (!envService.isProduction() && getQueryStringValue('rights') === '0') {
    return true
  }

  //Non production: Can add rights
  if (!envService.isProduction() && getQueryStringValue('add_rights')) {
    let addRights = getQueryStringValue('add_rights')
      .trim()
      .split(',')
      .map((code) => code.trim())
    rights = R.uniq([...rights, ...addRights])
  }

  //Non production: Can remove rights
  if (!envService.isProduction() && getQueryStringValue('remove_rights')) {
    let removeRights = getQueryStringValue('remove_rights')
      .trim()
      .split(',')
      .map((code) => code.trim())
    rights = R.difference(rights, removeRights)
  }

  //Bypass if sabadmin
  if (
    !!loggedUsername &&
    loggedUsername.toLowerCase() === 'sabadmin' &&
    (envService.isProduction() ||
      (!envService.isProduction() &&
        getQueryStringValue('rights_ignore_sabadmin') === '0'))
  ) {
    return true
  }

  //Bypass if env
  if (envService.getEnvValue('VUE_APP_DISABLE_RIGHTS_CHECK', '0') === '1') {
    return true
  }

  //Normalize right code
  code = rightsTable[code] !== undefined ? rightsTable[code] : code

  //Optional: Returns true if some rights match the code partially
  if (options.startsWith) {
    return (
      rights.findIndex(
        (c) => c.toUpperCase().indexOf(code.toUpperCase()) === 0
      ) !== -1
    )
  }

  return rights.map((c) => c.toUpperCase()).indexOf(code.toUpperCase()) !== -1
}