Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat/AB#74292 People picker #725

Open
wants to merge 35 commits into
base: 2.x.x
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 25 commits
Commits
Show all changes
35 commits
Select commit Hold shift + click to select a range
a164834
mock data
TaiKamilla Sep 4, 2023
8c5d92a
Merge branch '2.1.x' into feat/AB#74292_ABC-Create-people-picker-ques…
NathanHGit Sep 6, 2023
d486e03
Merge branch 'beta' into feat/AB#74292_ABC-Create-people-picker-question
MwanPygmay Sep 26, 2023
3647e3a
type not supported anymore, changed
MwanPygmay Sep 26, 2023
d93b78b
add support for people question: get type and metadata correctly, ali…
MwanPygmay Sep 27, 2023
54937ce
Merge branch 'beta' into feat/AB#74292_ABC-Create-people-picker-question
TaiKamilla Oct 3, 2023
a84fecf
Merge remote-tracking branch 'origin/beta' into feat/AB#74292_ABC-Cre…
TaiKamilla Oct 4, 2023
189c5a1
type
TaiKamilla Oct 5, 2023
2115ffb
missing resolver change
TaiKamilla Oct 5, 2023
3c3e00c
it works
TaiKamilla Oct 6, 2023
52ae447
compact the code a bit
TaiKamilla Oct 6, 2023
6602426
Clean 🧼 🧽
TaiKamilla Oct 9, 2023
21522f0
Merge branch '2.x.x' into feat/AB#74292_ABC-Create-people-picker-ques…
NathanHGit Mar 20, 2024
ae83129
feat: added people type
NathanHGit Mar 20, 2024
d5f2cea
feat: add get people
NathanHGit Mar 22, 2024
17c52d8
feat: handle people filtering and add people resolver
NathanHGit Mar 25, 2024
2c5088c
review people filter format + unique ids
NathanHGit Mar 25, 2024
05c65cd
add context to resolvers
NathanHGit Mar 26, 2024
8e5b164
fix people resolver
NathanHGit Mar 27, 2024
e3c999a
delete field.resource
NathanHGit Mar 27, 2024
0ea3ab0
fix empty value
NathanHGit Mar 27, 2024
716011b
Merge branch '2.x.x' into feat/AB#74292_ABC-Create-people-picker-ques…
AntoineRelief Apr 24, 2024
fe3d1fc
now getting people ten by ten
MwanPygmay Apr 30, 2024
f5d146e
update meta, and correct export
MwanPygmay May 3, 2024
d4ea0f5
add support for summary cards and text editor
MwanPygmay May 3, 2024
089a94d
avoid getting a back-to-back query
MwanPygmay May 21, 2024
acc3dee
Merge branch '2.x.x' into feat/AB#74292_ABC-Create-people-picker-ques…
AntoineRelief Jun 3, 2024
09be020
update config
AntoineRelief Jun 4, 2024
8f6eed0
Merge branch '2.x.x' into feat/AB#74292_ABC-Create-people-picker-ques…
AntoineRelief Jun 14, 2024
df67577
optimize people query
AntoineRelief Jun 14, 2024
0c7dc32
add support for graphs
MwanPygmay Jun 18, 2024
6906094
remove console log
MwanPygmay Jun 19, 2024
dcf1c7a
Merge branch '2.x.x' into feat/AB#74292_ABC-Create-people-picker-ques…
AntoineRelief Jun 26, 2024
7893c10
add support for filter, record history. Sorting does not work yet
MwanPygmay Jun 27, 2024
2031d43
add sorting for layouts
MwanPygmay Jun 28, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions config/custom-environment-variables.js
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,8 @@ module.exports = {
clientId: 'COMMON_SERVICES_CLIENT_ID',
clientSecret: 'COMMON_SERVICES_CLIENT_SECRET',
scope: 'COMMON_SERVICES_SCOPE',
authUrl: 'COMMON_SERVICES_AUTH_URL',
url: 'COMMON_SERVICES_URL',
},
microsoftGraph: {
tokenEndpoint: 'MICROSOFT_GRAPH_TOKEN_ENDPOINT',
Expand Down
1 change: 1 addition & 0 deletions src/const/fieldTypes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ export const MULTISELECT_TYPES: string[] = [
'tagbox',
'owner',
'users',
'people',
];

/** List of date field types */
Expand Down
27 changes: 27 additions & 0 deletions src/routes/proxy/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -171,6 +171,33 @@ router.post('/ping/**', async (req: Request, res: Response) => {
}
});

router.all('/common-services/**', async (req, res) => {
const commonServiceConfig = {
name: 'common-services',
status: 'active',
authType: 'service-to-service',
endpoint: config.get<string>('commonServices.url'),
settings: CryptoJS.AES.encrypt(
JSON.stringify({
authTargetUrl: config.get<string>('commonServices.authUrl'),
apiClientID: config.get<string>('commonServices.clientId'),
scope: config.get<string>('commonServices.scope'),
safeSecret: config.get<string>('commonServices.clientSecret'),
}),
config.get('encryption.key')
).toString(),
};

try {
const api = new ApiConfiguration(commonServiceConfig);
const path = req.originalUrl.split('common-services').pop().substring(1);
await proxyAPIRequest(req, res, api, path);
} catch (err) {
logger.error(err.message, { stack: err.stack });
return res.status(500).send(req.t('common.errors.internalServerError'));
}
});

/**
* Forward requests to actual API using the API Configuration
*/
Expand Down
2 changes: 2 additions & 0 deletions src/schema/query/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ import layer from './layer.query';
import draftRecords from './draftRecords.query';
import referenceDataAggregation from './referenceDataAggregation.query';
import types from './types.query';
import people from './people.query';

/** GraphQL query type definition */
const Query = new GraphQLObjectType({
Expand Down Expand Up @@ -84,6 +85,7 @@ const Query = new GraphQLObjectType({
layers,
layer,
draftRecords,
people,
},
});

Expand Down
67 changes: 67 additions & 0 deletions src/schema/query/people.query.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
import { GraphQLError, GraphQLInt, GraphQLList } from 'graphql';
import { logger } from '@services/logger.service';
import { Context } from '@server/apollo/context';
import GraphQLJSON from 'graphql-type-json';
import { PersonType } from '@schema/types/person.type';
import { getPeople } from '@utils/proxy';

/** Arguments for the people query */
type PeopleArgs = {
filter?: any;
offset?: number;
limitItems?: number | null;
};

/**
* Return distant users from common services
*/
export default {
type: new GraphQLList(PersonType),
args: {
filter: { type: GraphQLJSON },
offset: { type: GraphQLInt },
limitItems: { type: GraphQLInt },
},
async resolve(parent, args: PeopleArgs, context: Context) {
if (!args.filter) return [];
try {
// Formatted filter used by the API
const getFormattedFilter = (filter: any) => {
const formattedFilter = `{${filter.logic.toUpperCase()}:[
${filter.filters.map((el: any) => {
if (el.operator === 'like') {
el.value = `"%${el.value}%"`;
} else if (el.operator === 'in') {
el.value = el.value.map((e) => `"${e}"`);
el.value = `[${el.value}]`;
}
return `{ ${el.field}_${el.operator}: ${el.value} }`;
})}
]
}`;
return formattedFilter.replace(/\s/g, '');
};
const filter = getFormattedFilter(args.filter);
const people = await getPeople(
context.token,
filter,
args.offset,
args.limitItems
);
if (people) {
return people.map((person) => {
const updatedPerson = { ...person };
updatedPerson.id = updatedPerson.userid;
delete updatedPerson.userid;
return updatedPerson;
});
}
return [];
} catch (err) {
logger.error(err.message, { stack: err.stack });
throw new GraphQLError(
context.i18next.t('common.errors.internalServerError')
);
}
},
};
14 changes: 14 additions & 0 deletions src/schema/types/person.type.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import { GraphQLObjectType, GraphQLString } from 'graphql';

/**
* GraphQL Person type.
*/
export const PersonType = new GraphQLObjectType({
name: 'Person',
fields: () => ({
id: { type: GraphQLString },
firstname: { type: GraphQLString },
lastname: { type: GraphQLString },
emailaddress: { type: GraphQLString },
}),
});
14 changes: 4 additions & 10 deletions src/utils/files/getRowsFromMeta.ts
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,8 @@ export const getRowsFromMeta = (columns: any[], records: any[]): any[] => {
set(row, column.name, Array.isArray(value) ? value.join(',') : value);
break;
}
case 'people':
case 'singlepeople':
case 'users': {
let value: any = get(record, column.field);
const choices = column.meta.field.choices || [];
Expand Down Expand Up @@ -92,16 +94,8 @@ export const getRowsFromMeta = (columns: any[], records: any[]): any[] => {
set(row, column.name, Array.isArray(value) ? value.join(',') : value);
break;
}
case 'multipletext': {
const value = get(record, column.name);
set(row, column.name, value);
break;
}
case 'matrix': {
const value = get(record, column.name);
set(row, column.name, value);
break;
}
case 'multipletext':
case 'matrix':
case 'matrixdropdown': {
const value = get(record, column.name);
set(row, column.name, value);
Expand Down
4 changes: 4 additions & 0 deletions src/utils/form/getFieldType.ts
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,10 @@ export const getFieldType = async (question: {
return 'users';
case 'owner':
return 'owner';
case 'people':
return 'people';
case 'singlepeople':
return 'singlepeople';
case 'geospatial':
return 'geospatial';
default:
Expand Down
50 changes: 50 additions & 0 deletions src/utils/proxy/getPeople.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
import axios from 'axios';

/**
* Fetches the people
*
* @param token The authorization token
* @param filter The filter used for fetching the distant users
* @param offset offset to query users
* @param limitItems number of maximum items to fetch
* @returns the choices
*/
export const getPeople = async (
token: string,
filter: any,
offset = 0,
limitItems = null
): Promise<any[]> => {
const url = 'http://localhost:3000/proxy/common-services/graphql';
Matthis-M-ReliefApps marked this conversation as resolved.
Show resolved Hide resolved
Matthis-M-ReliefApps marked this conversation as resolved.
Show resolved Hide resolved
const query = `query {
users(
filter: ${filter}
offset: ${offset}
${limitItems ? `limitItems: ${limitItems}` : ''}
) {
userid
firstname
lastname
emailaddress
}
}`;
try {
let people: any[] = [];
await axios({
url,
method: 'post',
headers: {
Authorization: token,
'Content-Type': 'application/json',
},
data: {
query: query,
},
}).then(({ data }) => {
people = data?.data?.users;
});
return people;
} catch {
return [];
}
};
1 change: 1 addition & 0 deletions src/utils/proxy/index.ts
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
export * from './authManagement';
export * from './getChoices';
export * from './getPeople';
6 changes: 6 additions & 0 deletions src/utils/schema/introspection/getFieldType.ts
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,12 @@ const getFieldType = (
case 'owner': {
return GraphQLJSON;
}
case 'people': {
return GraphQLJSON;
}
case 'singlepeople': {
return GraphQLString;
}
case 'geospatial': {
return GraphQLJSON;
}
Expand Down
9 changes: 8 additions & 1 deletion src/utils/schema/resolvers/Meta/getMetaFieldResolver.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,17 @@ import getMetaOwnerResolver from './getMetaOwnerResolver';
import getMetaUsersResolver from './getMetaUsersResolver';
import getMetaRadioResolver from './getMetaRadiogroupResolver';
import getMetaTagboxResolver from './getMetaTagboxResolver';
import getMetaPeopleResolver from './getMetaPeopleResolver';
import { Context } from '@server/apollo/context';

/**
* Return GraphQL resolver of the field, based on its type.
*
* @param field field definition.
* @param context graphQL context.
* @returns resolver of the field.
*/
const getMetaFieldResolver = (field: any) => {
const getMetaFieldResolver = (field: any, context: Context) => {
switch (field.type) {
case 'dropdown': {
return getMetaDropdownResolver(field);
Expand All @@ -28,6 +31,10 @@ const getMetaFieldResolver = (field: any) => {
case 'users': {
return getMetaUsersResolver(field);
}
case 'people':
case 'singlepeople': {
return getMetaPeopleResolver(field, context);
}
case 'owner': {
return getMetaOwnerResolver(field);
}
Expand Down
60 changes: 60 additions & 0 deletions src/utils/schema/resolvers/Meta/getMetaPeopleResolver.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
import { Record } from '@models';
import { Context } from '@server/apollo/context';
import { getPeople } from '@utils/proxy';
import { isArray } from 'lodash';

/**
* Return people meta resolver.
*
* @param field field definition.
* @param context graphQL context.
* @returns People resolver.
*/
const getMetaPeopleResolver = async (field: any, context: Context) => {
const records = await Record.find({
resource: field.resource,
archived: false,
});
const peopleIds = [];
records.forEach((record) => {
const propertyValue = record.data[field.name];
if (isArray(propertyValue))
propertyValue?.flat().forEach((id: string) => {
if (!peopleIds.includes(id)) {
peopleIds.push(id);
}
});
else {
peopleIds.push(propertyValue);
}
});
const getFilter = (people: any) => {
const formattedFilter = `{
userid_in:
[${people.map((el: any) => `"${el}"`)}]
}`;
return formattedFilter.replace(/\s/g, '');
};
const filter = getFilter(peopleIds);
const people = await getPeople(context.token, filter);
if (!people) {
return [];
}

delete field.resource;

return Object.assign(field, {
choices: people.map((x: any) => {
const fullname =
x.firstname && x.lastname
? `${x.firstname}, ${x.lastname}`
: x.firstname || x.lastname;
return {
text: `${fullname} (${x.emailaddress})`,
value: x.userid,
};
}),
});
};

export default getMetaPeopleResolver;
7 changes: 5 additions & 2 deletions src/utils/schema/resolvers/Meta/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -161,7 +161,7 @@ export const getMetaResolver = (
.reduce(
(resolvers, fieldName) =>
Object.assign({}, resolvers, {
[fieldName]: (parent) => {
[fieldName]: (parent, args, context) => {
const field = relationshipFields.includes(fieldName)
? parent[
fieldName.slice(
Expand All @@ -170,7 +170,10 @@ export const getMetaResolver = (
)
]
: parent[fieldName];
return getMetaFieldResolver(field);
if (field.type === 'people' || 'singlepeople') {
field.resource = id;
}
return getMetaFieldResolver(field, context);
},
}),
{}
Expand Down
Loading