Skip to content

Commit

Permalink
feat: organization admin support
Browse files Browse the repository at this point in the history
  • Loading branch information
shreddedbacon committed Jun 6, 2024
1 parent 67d9718 commit 1b2f074
Show file tree
Hide file tree
Showing 11 changed files with 219 additions and 10 deletions.
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@ A couple of environment variables are required:
- user_owner - user with owner role
- user_orguser - Organization user
- user_orgviewer - Organization viewer
- user_orgadmin - Organization admin
- user_orgowner - Organization owner
- user_platformowner - Platform owner

Expand Down
1 change: 1 addition & 0 deletions cypress/cypress.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ export default defineConfig({
// orgs
user_orguser: 'orguser@example.com',
user_orgviewer: 'orgviewer@example.com',
user_orgadmin: 'orgadmin@example.com',
user_orgowner: 'orgowner@example.com',
// top level user for all default tests
user_platformowner: 'platformowner@example.com',
Expand Down
170 changes: 170 additions & 0 deletions cypress/e2e/rbac/organizations/orgAdmin.cy.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,170 @@
import { testData } from 'cypress/fixtures/variables';
import GroupAction from 'cypress/support/actions/organizations/GroupsAction';
import NotificationsAction from 'cypress/support/actions/organizations/NotificationsAction';
import OverviewAction from 'cypress/support/actions/organizations/OverviewAction';
import ProjectsActions from 'cypress/support/actions/organizations/ProjectsActions';
import { aliasMutation, aliasQuery, registerIdleHandler } from 'cypress/utils/aliasQuery';

const overview = new OverviewAction();
const group = new GroupAction();
const project = new ProjectsActions();
const notifications = new NotificationsAction();

const orgAdmin = [Cypress.env('user_orgadmin')];

orgAdmin.forEach(admin => {
const desc = {
[Cypress.env('user_orgadmin')]: 'Org admin',
};

describe(`Organizations ${desc[admin]} journey`, () => {
beforeEach(() => {
// register interceptors/idle handler
cy.intercept('POST', Cypress.env('api'), req => {
aliasQuery(req, 'getOrganization');
aliasMutation(req, 'updateOrganizationFriendlyName');
aliasMutation(req, 'addUserToGroup');
aliasMutation(req, 'addGroupToOrganization');
});

registerIdleHandler('idle');

cy.login(admin, admin);
cy.visit(`${Cypress.env('url')}/organizations/lagoon-demo-organization`);
});

if (admin === Cypress.env('user_orgadmin')) {
it('Fails to change org name and desc - no permission for ORGADMIN', () => {
overview.doFailedChangeOrgFriendlyname(testData.organizations.overview.friendlyName);
overview.closeModal();
overview.doFailedChangeOrgDescription(testData.organizations.overview.description);
overview.closeModal();
});
} else {
it('Changes org name and desc', () => {
overview.changeOrgFriendlyname(testData.organizations.overview.friendlyName);
overview.changeOrgDescription(testData.organizations.overview.description);
});
}

it('Navigates to groups and creates', () => {
cy.waitForNetworkIdle('@idle', 500);

const group1 = testData.organizations.groups.newGroupName;
const group2 = testData.organizations.groups.newGroupName2;

cy.get('.groups').click();
cy.location('pathname').should('equal', '/organizations/lagoon-demo-organization/groups');

group.doAddGroup(group1, group2);
registerIdleHandler('groupQuery');
group.doAddMemberToGroup(testData.organizations.users.email, group1);
});

it('Navigates to projects and creates a new one', () => {
registerIdleHandler('projectsQuery');
cy.intercept('POST', Cypress.env('api'), req => {
aliasMutation(req, 'addProjectToOrganization');
});

cy.waitForNetworkIdle('@idle', 500);

cy.get('.projects').click();
cy.location('pathname').should('equal', '/organizations/lagoon-demo-organization/projects');
cy.waitForNetworkIdle('@projectsQuery', 1000);

project.doAddProject(testData.organizations.project);
});

it('Navigates to notifications and creates a couple', () => {
cy.intercept('POST', Cypress.env('api'), req => {
aliasMutation(req, 'addNotificationSlack');
aliasMutation(req, 'UpdateNotificationSlack');
aliasMutation(req, 'addNotificationRocketChat');
aliasMutation(req, 'addNotificationMicrosoftTeams');
aliasMutation(req, 'addNotificationEmail');
aliasMutation(req, 'addNotificationWebhook');
});

registerIdleHandler('notificationsQuery');

cy.waitForNetworkIdle('@idle', 500);
cy.get('.notifications').click();
cy.location('pathname').should('equal', '/organizations/lagoon-demo-organization/notifications');
cy.waitForNetworkIdle('@notificationsQuery', 1000);

const { slack: slackData, email: emailData, webhook: webhookData } = testData.organizations.notifications;

notifications.doAddNotification('slack', slackData);
notifications.doAddNotification('email', emailData);
notifications.doAddNotification('webhook', webhookData);
});

it('Navigates to a project, adds a group and notifications', () => {
cy.visit(
`${Cypress.env('url')}/organizations/lagoon-demo-organization/projects/${
testData.organizations.project.projectName
}`
);

cy.getBySel('addGroupToProject').click();

cy.get('.react-select__indicator').click({ force: true });
cy.get('#react-select-2-option-0').click();

cy.getBySel('addGroupToProjectConfirm').click();

cy.log('add notifications');

cy.getBySel('addNotificationToProject').click();

cy.get('[class$=control]').click({ force: true });
cy.get('#react-select-3-option-0').click();

cy.getBySel('addNotificationToProjectConfirm').click();
});

// cleanup
after(() => {
registerIdleHandler('projectsQuery');
registerIdleHandler('groupQuery');
cy.intercept('POST', Cypress.env('api'), req => {
aliasMutation(req, 'removeNotification');
aliasMutation(req, 'deleteGroup');
aliasMutation(req, 'deleteProject');
});

cy.waitForNetworkIdle('@idle', 500);
cy.get('.groups').click();

group.doDeleteGroup(testData.organizations.groups.newGroupName);
cy.wait('@gqldeleteGroupMutation');

group.doDeleteGroup(testData.organizations.groups.newGroupName2);
cy.wait('@gqldeleteGroupMutation');

cy.waitForNetworkIdle('@idle', 500);
cy.get('.projects').click();

cy.waitForNetworkIdle('@projectsQuery', 1000);

project.doDeleteProject(testData.organizations.project.projectName);

cy.get('.notifications').click();

cy.waitForNetworkIdle('@idle', 500);

const {
webhook: { name: webhooknName },
email: { name: emailName },
slack: { name: slackName },
} = testData.organizations.notifications;

notifications.doDeleteNotification(webhooknName);
cy.wait('@gqlremoveNotificationMutation'); // wait for a delete mutation instead
notifications.doDeleteNotification(emailName);
cy.wait('@gqlremoveNotificationMutation');
notifications.doDeleteNotification(slackName);
});
});
});
17 changes: 15 additions & 2 deletions src/components/Organizations/AddUserToOrganization/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,8 @@ import { Footer } from '../SharedStyles';
import { NewUser } from './Styles';

export const ADD_USER_MUTATION = gql`
mutation AddUserToOrganization($email: String!, $organization: Int!, $owner: Boolean) {
addUserToOrganization(input: { user: { email: $email }, organization: $organization, owner: $owner }) {
mutation AddUserToOrganization($email: String!, $organization: Int!, $owner: Boolean, $admin: Boolean) {
addUserToOrganization(input: { user: { email: $email }, organization: $organization, owner: $owner, admin: $admin }) {
id
}
}
Expand All @@ -28,6 +28,8 @@ export const AddUserToOrganization = ({
setInputValue,
checkboxValueOwner,
setCheckboxValueOwner,
checkboxValueAdmin,
setCheckboxValueAdmin,
onAddUser,
users,
}) => {
Expand Down Expand Up @@ -70,6 +72,16 @@ export const AddUserToOrganization = ({
onChange={setCheckboxValueOwner}
/>
</label>
<label>
Admin: <span style={{ color: '#E30000' }}>*</span>
<input
data-cy="manageAdmin"
className="inputCheckbox"
type="checkbox"
value={checkboxValueAdmin}
onChange={setCheckboxValueAdmin}
/>
</label>

<div>
<Footer>
Expand All @@ -83,6 +95,7 @@ export const AddUserToOrganization = ({
email: inputValueEmail,
organization: organization.id,
owner: checkboxValueOwner,
admin: checkboxValueAdmin,
},
});
}}
Expand Down
14 changes: 10 additions & 4 deletions src/components/Organizations/Manage/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,7 @@ const Manage = ({ users = [], organization, organizationName, refetch }) => {
{
width: '55%',
key: 'email',
render: ({ email, owner }) => {
render: ({ email, owner, admin }) => {
return (
<>
<div className="email" style={{ width: '60%' }}>
Expand All @@ -102,9 +102,15 @@ const Manage = ({ users = [], organization, organizationName, refetch }) => {
ORG OWNER
</Tag>
) : (
<Tag style={{ display: 'inline-block', marginLeft: '2.5rem' }} $background="#47D3FF">
ORG VIEWER
</Tag>
admin ? (
<Tag style={{ display: 'inline-block', marginLeft: '2.5rem' }} $background="#E69138">
ORG ADMIN
</Tag>
) : (
<Tag style={{ display: 'inline-block', marginLeft: '2.5rem' }} $background="#47D3FF">
ORG VIEWER
</Tag>
)
)}
</>
);
Expand Down
8 changes: 8 additions & 0 deletions src/components/Organizations/Organization/Styles.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,14 @@ export const StyledOrganization = styled.div`
border-radius: 4px;
box-shadow: 0px 4px 8px 0px rgba(0, 0, 0, 0.03);
}
.admin-label {
color: ${color.black};
background-color: ${color.lightBlue};
margin-left: 10px;
padding: 0px 5px 0px 5px;
border-radius: 4px;
box-shadow: 0px 4px 8px 0px rgba(0, 0, 0, 0.03);
}
.viewer-label {
color: ${color.black};
background-color: ${color.lightestBlue};
Expand Down
12 changes: 9 additions & 3 deletions src/components/Organizations/Organization/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -277,9 +277,15 @@ const Organization = ({ organization, refetch }) => {
ORG OWNER
</Tag>
) : (
<Tag style={{ display: 'inline-block', marginLeft: '1.5rem' }} $background="#47D3FF">
ORG VIEWER
</Tag>
owner.admin ? (
<Tag style={{ display: 'inline-block', marginLeft: '1.5rem' }} $background="#E69138">
ORG ADMIN
</Tag>
) : (
<Tag style={{ display: 'inline-block', marginLeft: '1.5rem' }} $background="#47D3FF">
ORG VIEWER
</Tag>
)
)}
</div>
</div>
Expand Down
1 change: 1 addition & 0 deletions src/lib/query/organizations/OrganizationByID.js
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ export default gql`
lastName
email
owner
admin
}
projects {
id
Expand Down
1 change: 1 addition & 0 deletions src/lib/query/organizations/OrganizationByName.js
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ export default gql`
lastName
email
owner
admin
}
projects {
id
Expand Down
2 changes: 2 additions & 0 deletions src/lib/query/organizations/UsersByOrganization.js
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ export const getOrganization = gql`
lastName
email
owner
admin
}
}
}
Expand All @@ -52,6 +53,7 @@ export const getOrganizationByName = gql`
lastName
email
owner
admin
}
}
}
Expand Down
2 changes: 1 addition & 1 deletion test/keycloak/configure-keycloak.sh
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ function is_keycloak_running {
function configure_user_passwords {

LAGOON_DEMO_USERS=("guest@example.com" "reporter@example.com" "developer@example.com" "maintainer@example.com" "owner@example.com")
LAGOON_DEMO_ORG_USERS=("orguser@example.com" "orgviewer@example.com" "orgowner@example.com" "platformowner@example.com")
LAGOON_DEMO_ORG_USERS=("orguser@example.com" "orgviewer@example.com" "orgadmin@example.com" "orgowner@example.com" "platformowner@example.com")

for i in ${LAGOON_DEMO_USERS[@]}
do
Expand Down

0 comments on commit 1b2f074

Please sign in to comment.