/* * SonarQube * Copyright (C) 2009-2017 SonarSource SA * mailto:info AT sonarsource DOT com * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 3 of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program; if not, write to the Free Software Foundation, * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ // @flow import { isNil, omitBy } from 'lodash'; import { searchMembers } from '../../api/organizations'; import { searchUsers } from '../../api/users'; export type RawQuery = { [string]: string }; export type Query = {| assigned: boolean, assignees: Array, authors: Array, createdAfter: string, createdAt: string, createdBefore: string, createdInLast: string, directories: Array, facetMode: string, files: Array, issues: Array, languages: Array, modules: Array, projects: Array, resolved: boolean, resolutions: Array, rules: Array, severities: Array, sinceLeakPeriod: boolean, statuses: Array, tags: Array, types: Array |}; export type Paging = { pageIndex: number, pageSize: number, total: number }; const parseAsBoolean = (value: ?string, defaultValue: boolean = true): boolean => value === 'false' ? false : value === 'true' ? true : defaultValue; const parseAsString = (value: ?string): string => value || ''; const parseAsStringArray = (value: ?string): Array => value ? value.split(',') : []; const parseAsFacetMode = (facetMode: string) => facetMode === 'debt' || facetMode === 'effort' ? 'effort' : 'count'; export const parseQuery = (query: RawQuery): Query => ({ assigned: parseAsBoolean(query.assigned), assignees: parseAsStringArray(query.assignees), authors: parseAsStringArray(query.authors), createdAfter: parseAsString(query.createdAfter), createdAt: parseAsString(query.createdAt), createdBefore: parseAsString(query.createdBefore), createdInLast: parseAsString(query.createdInLast), directories: parseAsStringArray(query.directories), facetMode: parseAsFacetMode(query.facetMode), files: parseAsStringArray(query.fileUuids), issues: parseAsStringArray(query.issues), languages: parseAsStringArray(query.languages), modules: parseAsStringArray(query.moduleUuids), projects: parseAsStringArray(query.projectUuids), resolved: parseAsBoolean(query.resolved), resolutions: parseAsStringArray(query.resolutions), rules: parseAsStringArray(query.rules), severities: parseAsStringArray(query.severities), sinceLeakPeriod: parseAsBoolean(query.sinceLeakPeriod, false), statuses: parseAsStringArray(query.statuses), tags: parseAsStringArray(query.tags), types: parseAsStringArray(query.types) }); export const getOpen = (query: RawQuery) => query.open; export const areMyIssuesSelected = (query: RawQuery): boolean => query.myIssues === 'true'; const serializeString = (value: string): ?string => value || undefined; const serializeValue = (value: Array): ?string => value.length ? value.join() : undefined; export const serializeQuery = (query: Query): RawQuery => { const filter = { assigned: query.assigned ? undefined : 'false', assignees: serializeValue(query.assignees), authors: serializeValue(query.authors), createdAfter: serializeString(query.createdAfter), createdAt: serializeString(query.createdAt), createdBefore: serializeString(query.createdBefore), createdInLast: serializeString(query.createdInLast), directories: serializeValue(query.directories), facetMode: query.facetMode === 'effort' ? serializeString(query.facetMode) : undefined, fileUuids: serializeValue(query.files), issues: serializeValue(query.issues), languages: serializeValue(query.languages), moduleUuids: serializeValue(query.modules), projectUuids: serializeValue(query.projects), resolved: query.resolved ? undefined : 'false', resolutions: serializeValue(query.resolutions), severities: serializeValue(query.severities), sinceLeakPeriod: query.sinceLeakPeriod ? 'true' : undefined, statuses: serializeValue(query.statuses), rules: serializeValue(query.rules), tags: serializeValue(query.tags), types: serializeValue(query.types) }; return omitBy(filter, isNil); }; const areArraysEqual = (a: Array, b: Array) => { if (a.length !== b.length) { return false; } for (let i = 0; i < a.length; i++) { if (a[i] !== b[i]) { return false; } } return true; }; export const areQueriesEqual = (a: RawQuery, b: RawQuery) => { const parsedA: Query = parseQuery(a); const parsedB: Query = parseQuery(b); const keysA = Object.keys(parsedA); const keysB = Object.keys(parsedB); if (keysA.length !== keysB.length) { return false; } return keysA.every( key => Array.isArray(parsedA[key]) && Array.isArray(parsedB[key]) ? areArraysEqual(parsedA[key], parsedB[key]) : parsedA[key] === parsedB[key] ); }; type RawFacet = { property: string, values: Array<{ val: string, count: number }> }; export type Facet = { [string]: number }; export const parseFacets = (facets: Array): { [string]: Facet } => { // for readability purpose const propertyMapping = { fileUuids: 'files', moduleUuids: 'modules', projectUuids: 'projects' }; const result = {}; facets.forEach(facet => { const values = {}; facet.values.forEach(value => { values[value.val] = value.count; }); const finalProperty = propertyMapping[facet.property] || facet.property; result[finalProperty] = values; }); return result; }; export type ReferencedComponent = { key: string, name: string, organization: string, path: string }; export type ReferencedUser = { avatar: string, name: string }; export type ReferencedLanguage = { name: string }; export type Component = { key: string, organization: string, qualifier: string }; export type CurrentUser = | { isLoggedIn: false } | { isLoggedIn: true, email?: string, login: string, name: string }; export const searchAssignees = (query: string, component?: Component) => { return component ? searchMembers({ organization: component.organization, ps: 50, q: query }).then(response => response.users.map(user => ({ avatar: user.avatar, label: user.name, value: user.login }))) : searchUsers(query, 50).then(response => response.users.map(user => ({ // TODO this WS returns no avatar avatar: user.avatar, email: user.email, label: user.name, value: user.login }))); };