Skip to content
Open
Show file tree
Hide file tree
Changes from 5 commits
Commits
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
146 changes: 146 additions & 0 deletions src/schema/query/fieldDetails.query.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,146 @@
import { GraphQLNonNull, GraphQLError, GraphQLID } from 'graphql';
import { Record } from '@models';
import extendAbilityForRecords from '@security/extendAbilityForRecords';
import { logger } from '@services/logger.service';
import { graphQLAuthCheck } from '@schema/shared';
import { Context } from '@server/apollo/context';
import { subject } from '@casl/ability';
import GraphQLJSON from 'graphql-type-json';
import { Types } from 'mongoose';

/**
* Return record from id if available for the logged user.
* Throw GraphQL error if not logged.
*/
export default {
type: GraphQLJSON,
args: {
resource: { type: new GraphQLNonNull(GraphQLID) },
field: { type: new GraphQLNonNull(GraphQLJSON) },
},
async resolve(parent, args, context: Context) {
graphQLAuthCheck(context);
try {
const user = context.user;
// Check ability
const ability = await extendAbilityForRecords(user);
const field = args.field;

let min, max: Record[];
switch (field.type) {
case 'numeric':
max = await Record.find({ resource: args.resource })
.sort({ [`data.${field.name}`]: -1 })
.limit(1);
min = await Record.find({ resource: args.resource })
.sort({ [`data.${field.name}`]: 1 })
.limit(1);
if (max.length == 0) {
//if there is a max, there is a min
return [];
}
if (
ability.cannot(
'read',
subject('Record', max[0]),
`data.${field.name}`
)
) {
throw new GraphQLError(
context.i18next.t('common.errors.permissionNotGranted')
);
}
return [min[0].data[field.name], max[0].data[field.name]];
case 'time':
max = await Record.find({ resource: args.resource })
.sort({ [`data.${field.name}`]: -1 })
.limit(1);
min = await Record.find({ resource: args.resource })
.sort({ [`data.${field.name}`]: 1 })
.limit(1);
if (max.length == 0) {
//if there is a max, there is a min
return [];
}
if (
ability.cannot(
'read',
subject('Record', max[0]),
`data.${field.name}`
)
) {
throw new GraphQLError(
context.i18next.t('common.errors.permissionNotGranted')
);
}
return [min[0].data[field.name], max[0].data[field.name]];
case 'date':
max = await Record.find({ resource: args.resource })
.sort({ [`data.${field.name}`]: -1 })
.limit(1);

min = await Record.find({ resource: args.resource })
.sort({ [`data.${field.name}`]: 1 })
.limit(1);

if (max.length == 0) {
//if there is a max, there is a min
return [];
}
if (
ability.cannot(
'read',
subject('Record', max[0]),
`data.${field.name}`
)
) {
throw new GraphQLError(
context.i18next.t('common.errors.permissionNotGranted')
);
}
return [
new Date(min[0].data[field.name]),
new Date(max[0].data[field.name]),
];
case 'text':
//We get the 5 most common values from the database
const mostFrequentValues = await Record.aggregate([
{ $match: { resource: new Types.ObjectId(args.resource) } },
{
$group: {
_id: `$data.${field.name}`,
count: { $sum: 1 },
},
},
{ $sort: { count: -1 } },
{ $limit: 5 },
]);
if (mostFrequentValues.length == 0) {
return [];
}
if (
ability.cannot(
'read',
subject('Record', mostFrequentValues[0]),
'_id'
)
) {
throw new GraphQLError(
context.i18next.t('common.errors.permissionNotGranted')
);
}
return mostFrequentValues.map((item) => item._id);
default:
return new GraphQLError('Unsupported type');
}
} catch (err) {
logger.error(err.message, { stack: err.stack });
if (err instanceof GraphQLError) {
throw new GraphQLError(err.message);
}
throw new GraphQLError(
context.i18next.t('common.errors.internalServerError')
);
}
},
};
2 changes: 2 additions & 0 deletions src/schema/query/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { GraphQLObjectType } from 'graphql';
import resources from './resources.query';
import resource from './resource.query';
import notifications from './notifications.query';
import fieldDetails from './fieldDetails.query';
import forms from './forms.query';
import form from './form.query';
import records from './records.query';
Expand Down Expand Up @@ -49,6 +50,7 @@ const Query = new GraphQLObjectType({
channels,
dashboard,
dashboards,
fieldDetails,
form,
forms,
group,
Expand Down