Skip to content
Open
Show file tree
Hide file tree
Changes from all 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
4 changes: 2 additions & 2 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ on:
- next-major
- beta
- alpha
- "[0-9]*.[0-9x]*.x"
- '[0-9]*.[0-9x]*.x'

concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
Expand Down Expand Up @@ -71,4 +71,4 @@ jobs:
uses: actions/upload-artifact@v3
with:
name: deploy_coverage
path: coverage
path: coverage
4 changes: 2 additions & 2 deletions .github/workflows/deploy.yml
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ jobs:
update_deployment_status:
name: Update Deployment Status ✅
runs-on: ubuntu-latest
needs:
needs:
- create_deployment
- deploy
if: always()
Expand All @@ -81,4 +81,4 @@ jobs:
token: '${{ github.token }}'
environment-url: ${{ needs.create_deployment.outputs.environment_url }}
deployment-id: ${{ needs.create_deployment.outputs.deployment_id }}
state: 'failure'
state: 'failure'
8 changes: 4 additions & 4 deletions .jira/config.yml
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
deployments:
environmentMapping:
development:
- "DEV-*"
- 'DEV-*'
testing:
- "TST-*"
- 'TST-*'
staging:
- "STG-*"
- 'STG-*'
production:
- "PROD-*"
- 'PROD-*'
6 changes: 3 additions & 3 deletions .prettierrc
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
{
"singleQuote": true,
"useTabs": false,
"tabWidth": 2
"singleQuote": true,
"useTabs": false,
"tabWidth": 2
}
2 changes: 1 addition & 1 deletion .scripts/check-i18n.js
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ const updateFile = (lang, json) => {
JSON.stringify(json, null, '\t'),
(err) => {
if (err) {
throw(err);
throw err;
}
// else success
}
Expand Down
2 changes: 1 addition & 1 deletion .vscode/extensions.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,4 +9,4 @@
"esbenp.prettier-vscode",
"ms-azuretools.vscode-docker"
]
}
}
4 changes: 1 addition & 3 deletions .vscode/settings.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,4 @@
{
"i18n-ally.localesPaths": [
"src/i18n"
],
"i18n-ally.localesPaths": ["src/i18n"],
"i18n-ally.keystyle": "nested"
}
901 changes: 412 additions & 489 deletions CHANGELOG.md

Large diffs are not rendered by default.

196 changes: 94 additions & 102 deletions CHANGELOG/CHANGELOG_alpha.md

Large diffs are not rendered by default.

13 changes: 7 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
OORT Back-end
=======
# OORT Back-end

[![GitHub version](https://img.shields.io/github/v/release/ReliefApplications/ems-backend)](https://img.shields.io/github/v/release/ReliefApplications/ems-backend)
[![CodeQL](https://github.com/ReliefApplications/ems-backend/actions/workflows/codeql-analysis.yml/badge.svg)](https://github.com/ReliefApplications/ems-backend/actions/workflows/codeql-analysis.yml)

Expand All @@ -11,25 +11,27 @@ It was made for a Proof of Concept of a UI Builder for WHO.

To read more about the project, and how to setup the back-end, please refer to the [documentation of the project](https://gitlab.com/who-ems/ui-doc).

* [Setup](https://gitlab.com/who-ems/ui-doc#how-to-setup)
* [Deployment](https://gitlab.com/who-ems/ui-doc#how-to-deploy)
- [Setup](https://gitlab.com/who-ems/ui-doc#how-to-setup)
- [Deployment](https://gitlab.com/who-ems/ui-doc#how-to-deploy)

# Utilities

Docker-compose executes nodemon command, which provides an inspector tool.

9229 port is allocated to back-end inspection. You can use inspector with browser tools.

For Chrome, go to **chrome://inspect)** and click on *inspect* below the remote target.
For Chrome, go to **chrome://inspect)** and click on _inspect_ below the remote target.

## Testing

In order to execute tests locally, you can execute the command:

```
docker-compose -f docker-compose.test.yml run test-server npm run test
```

It is also possible to run tests on a single file, by passing it as a parameter:

```
docker-compose -f docker-compose.test.yml run test-server npm run test -- <path_to_file>
```
Expand All @@ -45,7 +47,6 @@ On deployed environments, you should enter the container to run the script.

Explanations about each script should be written in the script itself.


# RabbitMQ

If management platform is not reachable at 15672, you can use this command ( while containers are running ):
Expand Down
2 changes: 1 addition & 1 deletion docker-compose.test.yml
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
version: "3.7"
version: '3.7'

services:
test-server:
Expand Down
2 changes: 1 addition & 1 deletion src/assets/emails/i18n/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -25,4 +25,4 @@
"createAccountToApp.accessSteps.3": "Access the application page <a href=\"{{url}}\">here</a>. We recommend saving it in your favorites for easy access.",
"createAccountToApp.noteContent": "You can only create your account during the 7 days following the reception of this email. If the invitation has expired, please ask the owner of the application to send you another invitation.",
"createAccountToApp.registerDirectly": "You can also register at: "
}
}
7 changes: 7 additions & 0 deletions src/models/form.model.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ interface FormDocument extends Document {
structure?: any;
core?: boolean;
status?: string;
disableCascadingUpdates?: boolean;
permissions?: {
canSee?: any[];
canUpdate?: any[];
Expand Down Expand Up @@ -106,6 +107,12 @@ const schema = new Schema<Form>(
graphQLTypeName: String,
structure: mongoose.Schema.Types.Mixed,
core: Boolean,
disableCascadingUpdates: {
type: Boolean,
default: true,
description:
'When true, this form will not receive updates from sibling forms, but will still receive updates from parent forms.',
},
status: {
type: String,
enum: Object.values(status),
Expand Down
2 changes: 2 additions & 0 deletions src/models/page.model.ts
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ export interface Page extends Document {
visible: boolean;
archived: boolean;
archivedAt?: Date;
redirectTo?: string;
}

/** Mongoose page schema declaration */
Expand Down Expand Up @@ -122,6 +123,7 @@ const pageSchema = new Schema<Page>(
type: Date,
expires: 2592000,
},
redirectTo: { type: String, default: null },
},
{
timestamps: { createdAt: 'createdAt', updatedAt: 'modifiedAt' },
Expand Down
6 changes: 6 additions & 0 deletions src/schema/mutation/addForm.mutation.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import {
GraphQLString,
GraphQLID,
GraphQLError,
GraphQLBoolean,
} from 'graphql';
import { validateGraphQLTypeName } from '@utils/validators';
import {
Expand Down Expand Up @@ -37,6 +38,7 @@ type AddFormArgs = {
template?: string | Types.ObjectId;
apiConfiguration?: string | Types.ObjectId;
kobo?: string;
disableCascadingUpdates?: boolean;
};

/**
Expand All @@ -51,6 +53,7 @@ export default {
template: { type: GraphQLID },
apiConfiguration: { type: GraphQLID },
kobo: { type: GraphQLString },
disableCascadingUpdates: { type: GraphQLBoolean },
},
async resolve(parent, args: AddFormArgs, context: Context) {
graphQLAuthCheck(context);
Expand Down Expand Up @@ -167,6 +170,7 @@ export default {
structure,
fields,
versions: [version._id],
disableCascadingUpdates: args.disableCascadingUpdates !== false,
kobo: {
id: args.kobo,
deployedVersionId,
Expand Down Expand Up @@ -205,6 +209,7 @@ export default {
resource,
core: true,
permissions: defaultFormPermissions,
disableCascadingUpdates: args.disableCascadingUpdates !== false,
});
await form.save();
return form;
Expand Down Expand Up @@ -234,6 +239,7 @@ export default {
structure,
fields,
permissions: defaultFormPermissions,
disableCascadingUpdates: args.disableCascadingUpdates !== false,
});
await form.save();
return form;
Expand Down
21 changes: 20 additions & 1 deletion src/schema/mutation/editForm.mutation.ts
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,7 @@ type EditFormArgs = {
cronSchedule?: string;
permissions?: any;
dataFromDeployedVersion?: boolean;
disableCascadingUpdates?: boolean;
};

/**
Expand All @@ -94,6 +95,7 @@ export default {
cronSchedule: { type: GraphQLString },
permissions: { type: GraphQLJSON },
dataFromDeployedVersion: { type: GraphQLBoolean },
disableCascadingUpdates: { type: GraphQLBoolean },
},
async resolve(parent, args: EditFormArgs, context: Context) {
graphQLAuthCheck(context);
Expand Down Expand Up @@ -225,6 +227,12 @@ export default {
};
}

// Update disableCascadingUpdates setting
if (args.disableCascadingUpdates !== undefined) {
// When true, this form will not receive updates from sibling forms, but will still receive updates from parent forms
update.disableCascadingUpdates = args.disableCascadingUpdates;
}

// Update fields and structure, check that structure is different
if (args.structure && !isEqual(form.structure, args.structure)) {
update.structure = args.structure;
Expand Down Expand Up @@ -300,7 +308,7 @@ export default {
const templates = await Form.find({
resource: form.resource,
_id: { $ne: new mongoose.Types.ObjectId(args.id) },
}).select('_id structure fields');
}).select('_id structure fields disableCascadingUpdates');
const oldFields: any[] = resource.fields
? JSON.parse(JSON.stringify(resource.fields))
: [];
Expand Down Expand Up @@ -347,6 +355,11 @@ export default {
}
for (const template of templates) {
// For each form that inherits from the same resource
// Skip updates only for non-core forms when disableCascadingUpdates=true
// If this is a core form (parent) updating child forms, always apply updates regardless of flag
if (!form.core && template.disableCascadingUpdates === true) {
continue;
}
if (storedFieldChanged) {
template.fields = template.fields.map((x) => {
// For each field of the childForm
Expand Down Expand Up @@ -443,6 +456,12 @@ export default {

// Loop on templates
for (const template of templates) {
// Skip updates only for non-core forms when disableCascadingUpdates=true
// If this is a core form (parent) updating child forms, always apply updates regardless of flag
if (!form.core && template.disableCascadingUpdates === true) {
continue;
}

// === REFLECT DELETION ===
// For each old field from core form which is not anymore in the current core form fields
for (const field of deletedFields) {
Expand Down
11 changes: 6 additions & 5 deletions src/schema/mutation/editPage.mutation.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ type EditPageArgs = {
permissions?: any;
icon?: string;
visible?: boolean;
redirectTo?: string;
};

/**
Expand All @@ -51,6 +52,7 @@ export default {
id: { type: new GraphQLNonNull(GraphQLID) },
name: { type: GraphQLString },
icon: { type: GraphQLString },
redirectTo: { type: GraphQLString },
permissions: { type: GraphQLJSON },
visible: { type: GraphQLBoolean },
},
Expand Down Expand Up @@ -83,9 +85,11 @@ export default {
}

// Create update
const update = {
const update: any = {
...(args.name && { name: args.name }),
...(!isNil(args.icon) && { icon: args.icon }),
...(!isNil(args.redirectTo) && { redirectTo: args.redirectTo }),
...(!isNil(args.visible) && { visible: args.visible }),
};

// Updating permissions
Expand Down Expand Up @@ -122,12 +126,9 @@ export default {
}
}

// Update visibility
Object.assign(update, !isNil(args.visible) && { visible: args.visible });

// apply the update
page = await Page.findByIdAndUpdate(
page._id,
args.id,
{ ...update, ...permissionsUpdate },
{ new: true }
);
Expand Down
29 changes: 27 additions & 2 deletions src/schema/query/pages.query.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,34 @@ import { logger } from '@lib/logger';
import { accessibleBy } from '@casl/mongoose';
import { graphQLAuthCheck } from '@schema/shared';
import { Context } from '@server/apollo/context';
import GraphQLJSON from 'graphql-type-json';
import getFilter from '@utils/filter/getFilter';

/** Default filter fields */
const FILTER_FIELDS: { name: string; type: string }[] = [
{
name: 'name',
type: 'text',
},
{
name: 'type',
type: 'text',
},
{
name: 'visible',
type: 'boolean',
},
];

/**
* List all pages available for the logged user.
* Throw GraphQL error if not logged.
*/
export default {
type: new GraphQLList(PageType),
args: {
filter: { type: GraphQLJSON },
},
async resolve(parent, args, context: Context) {
graphQLAuthCheck(context);
try {
Expand All @@ -27,8 +48,12 @@ export default {
ability = await extendAbilityForPage(user, application, ability);
}

// return the pages
return await Page.find(accessibleBy(ability, 'read'));
const abilityFilters = Page.find(accessibleBy(ability, 'read')).getFilter();
const queryFilters = getFilter(args.filter, FILTER_FIELDS);
const filters = [queryFilters, abilityFilters];

// return the pages with filters applied
return await Page.find({ $and: filters });
} catch (err) {
logger.error(err.message, { stack: err.stack });
if (err instanceof GraphQLError) {
Expand Down
6 changes: 6 additions & 0 deletions src/schema/types/form.type.ts
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,12 @@ export const FormType = new GraphQLObjectType({
return parent.core ? parent.core : false;
},
},
disableCascadingUpdates: {
type: GraphQLBoolean,
resolve(parent) {
return parent.disableCascadingUpdates || false;
},
},
records: {
type: RecordConnectionType,
args: {
Expand Down
Loading