Skip to content

Commit

Permalink
feat: improved scopes selection auto-complete component(#743)
Browse files Browse the repository at this point in the history
Closes #729
  • Loading branch information
adrians5j committed Mar 9, 2020
1 parent 68e2533 commit f3acbc5
Show file tree
Hide file tree
Showing 25 changed files with 500 additions and 82 deletions.
11 changes: 6 additions & 5 deletions cypress.json
Expand Up @@ -4,11 +4,12 @@
"baseUrl": "http://localhost:3001",
"defaultCommandTimeout": 10000,
"env": {
"AWS_COGNITO_USER_POOL_ID": "eu-central-1_LGh6br2ix",
"AWS_COGNITO_CLIENT_ID": "561rp7m88m81t4jgdvq1j5eobf",
"API_URL": "https://d1cfsi9llzrdlf.cloudfront.net",
"DEFAULT_ADMIN_USER_USERNAME": "asd@net.hr",
"SITE_URL": "http://localhost:3000",
"AWS_COGNITO_USER_POOL_ID": "eu-central-1_4rzqiPNHm",
"AWS_COGNITO_CLIENT_ID": "1agul1e3ge3afpb4a0vsrqtuhb",
"API_URL": "https://d2sj4ukj5xxt5i.cloudfront.net",
"DEFAULT_ADMIN_USER_USERNAME": "admin@webiny.com",
"DEFAULT_ADMIN_USER_PASSWORD": "12345678",
"GRAPHQL_API_URL": "https://d1cfsi9llzrdlf.cloudfront.net/graphql"
"GRAPHQL_API_URL": "https://d2sj4ukj5xxt5i.cloudfront.net/graphql"
}
}
91 changes: 91 additions & 0 deletions cypress/integration/admin/security/roles/createGroup.spec.js
@@ -0,0 +1,91 @@
import uniqid from "uniqid";

context("Groups Module", () => {
beforeEach(() => cy.login());

it("should be able to create, edit, and immediately delete a group", () => {
const id = uniqid();
cy.visit("/groups")
.findByLabelText("Name")
.type(`Test Group ${id}`)
.findByText("Save group")
.click()
.findByText("Value is required.")
.should("exist")
.findByLabelText("Slug")
.type(`test-group-${id}`)
.findByLabelText("Description")
.type("This is a test test.")
.findByText("Save group")
.click();

cy.wait(500)
.findByText("Record saved successfully.")
.should("exist");

cy.findByLabelText("Slug")
.type("-edited")
.findByLabelText("Description")
.type(" Test test.")
.findByText("Save group")
.click();

cy.wait(500)
.findByTestId("default-data-list")
.within(() => {
cy.get("div")
.first()
.within(() => {
cy.findByText(`Test Group ${id}`)
.should("exist")
.findByText("This is a test test. Test test.")
.should("exist");
cy.get("button").click({ force: true });
});
});

cy.get('[role="alertdialog"] :visible').within(() => {
cy.contains("Are you sure you want to continue?")
.next()
.within(() => cy.findByText("Confirm").click());
});

cy.findByText("Record deleted successfully.").should("exist");
cy.findByTestId("default-data-list").within(() => {
cy.findByText(`Test Group ${id}`).should("not.exist");
});
});

it("groups with the same slug should not be allowed - an error message must be shown", () => {
const id = uniqid();
cy.visit("/groups")
.findByLabelText("Name")
.type(`Test Group ${id}`)
.findByText("Save group")
.findByLabelText("Slug")
.type(`test-group-${id}`)
.findByLabelText("Description")
.type("This is a test test.")
.findByText("Save group")
.click()
.wait(1500);

cy.findByTestId("new-record-button")
.click()
.findByLabelText("Name")
.type(`Test Group ${id}`)
.findByText("Save group")
.findByLabelText("Slug")
.type(`test-group-${id}`)
.findByLabelText("Description")
.type("This is a test test.")
.findByText("Save group")
.click();

cy.wait(500)
.get('[role="alertdialog"] :visible')
.within(() => {
cy.findByText(`Group with slug "test-group-${id}" already exists.`).should("exist");
});
});
});
132 changes: 132 additions & 0 deletions cypress/integration/admin/security/roles/createRole.spec.js
@@ -0,0 +1,132 @@
import uniqid from "uniqid";

context("Roles Module", () => {
beforeEach(() => cy.login());

it("should be able to create, edit, and immediately delete a role", () => {
const id = uniqid();
cy.visit("/roles")
.findByLabelText("Name")
.type(`Test Role ${id}`)
.findByText("Save role")
.click()
.findByText("Value is required.")
.should("exist")
.findByLabelText("Slug")
.type(`test-role-${id}`)
.findByLabelText("Description")
.type("This is a test test.")
.findByText("Save role")
.click();

cy.wait(500)
.findByText("Record saved successfully.")
.should("exist");

cy.findByLabelText("Slug")
.type("-edited")
.findByLabelText("Description")
.type(" Test test.");

// Check if the scopes auto-complete is working.
cy.findByLabelText("Scopes")
.type(`revi`)
.findByText("Publish form revisions")
.click()
.findByLabelText("Scopes")
.type(`revi`)
.findByText("Unpublish form revisions")
.click();

cy.findByText("Save role").click();

cy.wait(500)
.findByTestId("default-data-list")
.within(() => {
cy.get("div")
.first()
.within(() => {
cy.findByText(`Test Role ${id}`)
.should("exist")
.findByText("This is a test test. Test test.")
.should("exist");
cy.get("button").click({ force: true });
});
});

cy.get('[role="alertdialog"] :visible').within(() => {
cy.contains("Are you sure you want to continue?")
.next()
.within(() => cy.findByText("Confirm").click());
});

cy.findByText("Record deleted successfully.").should("exist");
cy.findByTestId("default-data-list").within(() => {
cy.findByText(`Test Role ${id}`).should("not.exist");
});
});

it("roles with the same slug should not be allowed - an error message must be shown", () => {
const id = uniqid();
cy.visit("/roles")
.findByLabelText("Name")
.type(`Test Role ${id}`)
.findByText("Save role")
.findByLabelText("Slug")
.type(`test-role-${id}`)
.findByLabelText("Description")
.type("This is a test test.")
.findByText("Save role")
.click()
.wait(1500);

cy.findByTestId("new-record-button")
.click()
.findByLabelText("Name")
.type(`Test Role ${id}`)
.findByText("Save role")
.findByLabelText("Slug")
.type(`test-role-${id}`)
.findByLabelText("Description")
.type("This is a test test.")
.findByText("Save role")
.click();

cy.wait(500)
.get('[role="alertdialog"] :visible')
.within(() => {
cy.findByText(`Role with slug "test-role-${id}" already exists.`).should("exist");
});
});

it("should save scopes correctly", () => {
const id = uniqid();
cy.visit("/roles")
.findByLabelText("Name")
.type(`Test Role ${id}`)
.findByLabelText("Slug")
.type(`test-role-${id}`)
.findByLabelText("Description")
.type("This is a test test.")
.findByLabelText("Scopes")
.type(`revi`)
.findByText("Publish form revisions")
.click()
.findByLabelText("Scopes")
.type(`revi`)
.findByText("Unpublish form revisions")
.click()
.findByText("Save role")
.click();

cy.wait(2500)
.reload()
.findByTestId("default-form")
.within(() => {
cy.findByText("forms:form:revision:publish")
.should("exist")
.findByText("forms:form:revision:unpublish")
.should("exist");
});
});
});
12 changes: 6 additions & 6 deletions packages/api-form-builder/src/plugins/graphql.ts
Expand Up @@ -93,23 +93,23 @@ const plugin: GraphQLSchemaPlugin = {
security: {
shield: {
FormsQuery: {
getSettings: hasScope("cms:settings"),
getSettings: hasScope("forms:settings"),
getForm: hasScope("forms:form:crud"),
listForms: hasScope("forms:form:crud"),
listFormSubmissions: hasScope("forms:form:crud")
// listPublishedForms: hasScope("forms:form:crud") // Expose publicly.
// getPublishedForms: hasScope("forms:form:crud") // Expose publicly.
},
FormsMutation: {
updateSettings: hasScope("cms:settings"),
updateSettings: hasScope("forms:settings"),
createForm: hasScope("forms:form:crud"),
deleteForm: hasScope("forms:form:crud"),
createRevisionFrom: hasScope("forms:form:revision:create"),
updateRevision: hasScope("forms:form:revision:update"),
createRevisionFrom: hasScope("forms:form:crud"),
updateRevision: hasScope("forms:form:crud"),
publishRevision: hasScope("forms:form:revision:publish"),
unpublishRevision: hasScope("forms:form:revision:unpublish"),
deleteRevision: hasScope("forms:form:revision:delete"),
exportFormSubmissions: hasScope("forms:form:submission:export")
deleteRevision: hasScope("forms:form:crud"),
exportFormSubmissions: hasScope("forms:form:submissions:export")
// saveFormView: hasScope("forms:form:revision:delete") // Expose publicly.
// createFormSubmission: hasScope("forms:form:revision:delete") // Expose publicly.
}
Expand Down
8 changes: 4 additions & 4 deletions packages/api-page-builder/src/plugins/graphql.ts
Expand Up @@ -110,10 +110,10 @@ export default {
createPage: hasScope("pb:page:crud"),
deletePage: hasScope("pb:page:crud"),

createRevisionFrom: hasScope("pb:page:revision:create"),
updateRevision: hasScope("pb:page:revision:update"),
publishRevision: hasScope("pb:page:revision:publish"),
deleteRevision: hasScope("pb:page:revision:delete"),
createRevisionFrom: hasScope("pb:page:crud"),
updateRevision: hasScope("pb:page:crud"),
publishRevision: hasScope("pb:page:crud"),
deleteRevision: hasScope("pb:page:crud"),

createElement: hasScope("pb:element:crud"),
updateElement: hasScope("pb:element:crud"),
Expand Down
8 changes: 2 additions & 6 deletions packages/api-security/src/plugins/graphql.ts
Expand Up @@ -2,7 +2,7 @@ import { merge } from "lodash";
import gql from "graphql-tag";
import { emptyResolver } from "@webiny/commodo-graphql";
import { GraphQLSchemaPlugin } from "@webiny/api/types";
import { getRegisteredScopes, hasScope } from "@webiny/api-security";
import { hasScope } from "@webiny/api-security";

import role from "./graphql/Role";
import group from "./graphql/Group";
Expand All @@ -19,8 +19,7 @@ const plugin: GraphQLSchemaPlugin = {
}
type SecurityQuery {
# Returns all scopes that were registered throughout the schema.
scopes: [String]
_empty: String
}
type SecurityMutation {
Expand Down Expand Up @@ -59,9 +58,6 @@ const plugin: GraphQLSchemaPlugin = {
Mutation: {
security: emptyResolver
},
SecurityQuery: {
scopes: getRegisteredScopes
}
},
install.resolvers,
role.resolvers,
Expand Down
18 changes: 0 additions & 18 deletions packages/api-security/src/scopes.ts
@@ -1,24 +1,6 @@
import { rule } from "graphql-shield";
/**
* Contains a list of all registered scopes throughout GraphQL Schema.
* @type {Array}
*/
export const __scopes = {
registered: []
};

export const registerScopes = (...scopes: Array<string>) => {
scopes.forEach(scope => {
__scopes.registered.includes(scope) === false && __scopes.registered.push(scope);
});
};

export const getRegisteredScopes = () => {
return __scopes.registered;
};

export const hasScope = (scope: string) => {
registerScopes(scope);
return rule()(async (parent, args, ctx) => {
if (!ctx.user) {
return false;
Expand Down
2 changes: 2 additions & 0 deletions packages/app-form-builder/src/admin/plugins/index.ts
Expand Up @@ -12,6 +12,7 @@ import previewContent from "./formDetails/previewContent";
import formRevisions from "./formDetails/formRevisions";
import formSubmissions from "./formDetails/formSubmissions";
import install from "./install";
import scopesList from "./scopesList";

export default [
install,
Expand All @@ -21,6 +22,7 @@ export default [
formSubmissions,
previewContent,
formRevisions,
scopesList,

// Editor
fields,
Expand Down
38 changes: 38 additions & 0 deletions packages/app-form-builder/src/admin/plugins/scopesList.ts
@@ -0,0 +1,38 @@
import { i18n } from "@webiny/app/i18n";
import { SecurityScopesListPlugin } from "@webiny/app-security/types";

const t = i18n.ns("app-form-builder/admin/scopesList");

export default [
{
name: "security-scopes-list-form-builder",
type: "security-scopes-list",
scopes: [
{
scope: "forms:form:crud",
title: t`Forms CRUD`,
description: t`Allows basic CRUD operations on all forms.`
},
{
scope: "forms:settings",
title: t`Form Builder Settings`,
description: t`Allows updating Form Builder's settings.`
},
{
scope: "forms:form:revision:publish",
title: t`Publish form revisions`,
description: t`Allows publishing form revision.`
},
{
scope: "forms:form:revision:unpublish",
title: t`Unpublish form revisions`,
description: t`Allows unpublishing form revisions.`
},
{
scope: "forms:form:submissions:export",
title: t`Export form submissions`,
description: t`Allows creating form submission exports.`
}
]
} as SecurityScopesListPlugin
];

0 comments on commit f3acbc5

Please sign in to comment.