added create, modify, delete role actions in module

This commit is contained in:
Florian Scholdei
2019-05-15 09:50:20 +02:00
parent 4388efc2af
commit dfbc2e2cfd
2 changed files with 372 additions and 41 deletions

View File

@@ -16,17 +16,28 @@ export const FETCH_ROLE_PENDING = `${FETCH_ROLE}_${types.PENDING_SUFFIX}`;
export const FETCH_ROLE_SUCCESS = `${FETCH_ROLE}_${types.SUCCESS_SUFFIX}`;
export const FETCH_ROLE_FAILURE = `${FETCH_ROLE}_${types.FAILURE_SUFFIX}`;
export const FETCH_VERBS = "scm/roles/FETCH_VERBS";
export const FETCH_VERBS_PENDING = `${FETCH_VERBS}_${types.PENDING_SUFFIX}`;
export const FETCH_VERBS_SUCCESS = `${FETCH_VERBS}_${types.SUCCESS_SUFFIX}`;
export const FETCH_VERBS_FAILURE = `${FETCH_VERBS}_${types.FAILURE_SUFFIX}`;
export const CREATE_ROLE = "scm/roles/CREATE_ROLE";
export const CREATE_ROLE_PENDING = `${CREATE_ROLE}_${types.PENDING_SUFFIX}`;
export const CREATE_ROLE_SUCCESS = `${CREATE_ROLE}_${types.SUCCESS_SUFFIX}`;
export const CREATE_ROLE_FAILURE = `${CREATE_ROLE}_${types.FAILURE_SUFFIX}`;
export const CREATE_ROLE_RESET = `${CREATE_ROLE}_${types.RESET_SUFFIX}`;
export const MODIFY_ROLE = "scm/roles/MODIFY_ROLE";
export const MODIFY_ROLE_PENDING = `${MODIFY_ROLE}_${types.PENDING_SUFFIX}`;
export const MODIFY_ROLE_SUCCESS = `${MODIFY_ROLE}_${types.SUCCESS_SUFFIX}`;
export const MODIFY_ROLE_FAILURE = `${MODIFY_ROLE}_${types.FAILURE_SUFFIX}`;
export const MODIFY_ROLE_RESET = `${MODIFY_ROLE}_${types.RESET_SUFFIX}`;
export const DELETE_ROLE = "scm/roles/DELETE_ROLE";
export const DELETE_ROLE_PENDING = `${DELETE_ROLE}_${types.PENDING_SUFFIX}`;
export const DELETE_ROLE_SUCCESS = `${DELETE_ROLE}_${types.SUCCESS_SUFFIX}`;
export const DELETE_ROLE_FAILURE = `${DELETE_ROLE}_${types.FAILURE_SUFFIX}`;
export const FETCH_VERBS = "scm/roles/FETCH_VERBS";
export const FETCH_VERBS_PENDING = `${FETCH_VERBS}_${types.PENDING_SUFFIX}`;
export const FETCH_VERBS_SUCCESS = `${FETCH_VERBS}_${types.SUCCESS_SUFFIX}`;
export const FETCH_VERBS_FAILURE = `${FETCH_VERBS}_${types.FAILURE_SUFFIX}`;
const CONTENT_TYPE_ROLE = "application/vnd.scmm-repositoryRole+json;v=2";
// fetch roles
@@ -72,13 +83,8 @@ export function fetchRoles(link: string) {
return fetchRolesByLink(link);
}
export function fetchRolesByPage(link: string, page: number, filter?: string) {
export function fetchRolesByPage(link: string, page: number) {
// backend start counting by 0
if (filter) {
return fetchRolesByLink(
`${link}?page=${page - 1}&q=${decodeURIComponent(filter)}`
);
}
return fetchRolesByLink(`${link}?page=${page - 1}`);
}
@@ -226,24 +232,104 @@ function verbReducer(state: any = {}, action: any = {}) {
}
}
function listReducer(state: any = {}, action: any = {}) {
switch (action.type) {
case FETCH_ROLES_SUCCESS:
const roles = action.payload._embedded.repositoryRoles;
const roleNames = roles.map(role => role.name);
return {
...state,
entries: roleNames,
entry: {
roleCreatePermission: !!action.payload._links.create,
page: action.payload.page,
pageTotal: action.payload.pageTotal,
_links: action.payload._links
// modify role
export function modifyRolePending(role: Role): Action {
return {
type: MODIFY_ROLE_PENDING,
payload: role,
itemId: role.name
};
}
export function modifyRoleSuccess(role: Role): Action {
return {
type: MODIFY_ROLE_SUCCESS,
payload: role,
itemId: role.name
};
}
export function modifyRoleFailure(role: Role, error: Error): Action {
return {
type: MODIFY_ROLE_FAILURE,
payload: {
error,
role
},
itemId: role.name
};
}
export function modifyRoleReset(role: Role): Action {
return {
type: MODIFY_ROLE_RESET,
itemId: role.name
};
}
export function modifyRole(role: Role, callback?: () => void) {
return function(dispatch: Dispatch) {
dispatch(modifyRolePending(role));
return apiClient
.put(role._links.update.href, role, CONTENT_TYPE_ROLE)
.then(() => {
dispatch(modifyRoleSuccess(role));
if (callback) {
callback();
}
};
default:
return state;
}
})
.then(() => {
dispatch(fetchRoleByLink(role));
})
.catch(err => {
dispatch(modifyRoleFailure(role, err));
});
};
}
// delete role
export function deleteRolePending(role: Role): Action {
return {
type: DELETE_ROLE_PENDING,
payload: role,
itemId: role.name
};
}
export function deleteRoleSuccess(role: Role): Action {
return {
type: DELETE_ROLE_SUCCESS,
payload: role,
itemId: role.name
};
}
export function deleteRoleFailure(role: Role, error: Error): Action {
return {
type: DELETE_ROLE_FAILURE,
payload: {
error,
role
},
itemId: role.name
};
}
export function deleteRole(role: Role, callback?: () => void) {
return function(dispatch: any) {
dispatch(deleteRolePending(role));
return apiClient
.delete(role._links.delete.href)
.then(() => {
dispatch(deleteRoleSuccess(role));
if (callback) {
callback();
}
})
.catch(error => {
dispatch(deleteRoleFailure(role, error));
});
};
}
function extractRolesByNames(
@@ -263,6 +349,22 @@ function extractRolesByNames(
return rolesByNames;
}
function deleteRoleInRolesByNames(roles: {}, roleName: string) {
let newRoles = {};
for (let rolename in roles) {
if (rolename !== roleName) newRoles[rolename] = roles[rolename];
}
return newRoles;
}
function deleteRoleInEntries(roles: [], roleName: string) {
let newRoles = [];
for (let role of roles) {
if (role !== roleName) newRoles.push(role);
}
return newRoles;
}
const reducerByName = (state: any, rolename: string, newRoleState: any) => {
return {
...state,
@@ -270,6 +372,37 @@ const reducerByName = (state: any, rolename: string, newRoleState: any) => {
};
};
function listReducer(state: any = {}, action: any = {}) {
switch (action.type) {
case FETCH_ROLES_SUCCESS:
const roles = action.payload._embedded.repositoryRoles;
const roleNames = roles.map(role => role.name);
return {
...state,
entries: roleNames,
entry: {
roleCreatePermission: !!action.payload._links.create,
page: action.payload.page,
pageTotal: action.payload.pageTotal,
_links: action.payload._links
}
};
// Delete single role actions
case DELETE_ROLE_SUCCESS:
const newRoleEntries = deleteRoleInEntries(
state.entries,
action.payload.name
);
return {
...state,
entries: newRoleEntries
};
default:
return state;
}
}
function byNamesReducer(state: any = {}, action: any = {}) {
switch (action.type) {
// Fetch all roles actions
@@ -280,9 +413,14 @@ function byNamesReducer(state: any = {}, action: any = {}) {
return {
...byNames
};
// Fetch single role actions
case FETCH_ROLE_SUCCESS:
return reducerByName(state, action.payload.name, action.payload);
case DELETE_ROLE_SUCCESS:
return deleteRoleInRolesByNames(state, action.payload.name);
default:
return state;
}
@@ -301,7 +439,6 @@ const selectList = (state: Object) => {
}
return {};
};
const selectListEntry = (state: Object): Object => {
const list = selectList(state);
if (list.entry) {
@@ -344,14 +481,6 @@ export function getFetchRolesFailure(state: Object) {
return getFailure(state, FETCH_ROLES);
}
export function isCreateRolePending(state: Object) {
return isPending(state, CREATE_ROLE);
}
export function getCreateRoleFailure(state: Object) {
return getFailure(state, CREATE_ROLE);
}
export function isFetchVerbsPending(state: Object) {
return isPending(state, FETCH_VERBS);
}
@@ -360,6 +489,14 @@ export function getFetchVerbsFailure(state: Object) {
return getFailure(state, FETCH_VERBS);
}
export function isCreateRolePending(state: Object) {
return isPending(state, CREATE_ROLE);
}
export function getCreateRoleFailure(state: Object) {
return getFailure(state, CREATE_ROLE);
}
export function getRoleByName(state: Object, name: string) {
if (state.roles && state.roles.byNames) {
return state.roles.byNames[name];
@@ -373,3 +510,19 @@ export function isFetchRolePending(state: Object, name: string) {
export function getFetchRoleFailure(state: Object, name: string) {
return getFailure(state, FETCH_ROLE, name);
}
export function isModifyRolePending(state: Object, name: string) {
return isPending(state, MODIFY_ROLE, name);
}
export function getModifyRoleFailure(state: Object, name: string) {
return getFailure(state, MODIFY_ROLE, name);
}
export function isDeleteRolePending(state: Object, name: string) {
return isPending(state, DELETE_ROLE, name);
}
export function getDeleteRoleFailure(state: Object, name: string) {
return getFailure(state, DELETE_ROLE, name);
}

View File

@@ -16,6 +16,14 @@ import reducer, {
CREATE_ROLE_PENDING,
CREATE_ROLE_SUCCESS,
CREATE_ROLE_FAILURE,
MODIFY_ROLE,
MODIFY_ROLE_PENDING,
MODIFY_ROLE_SUCCESS,
MODIFY_ROLE_FAILURE,
DELETE_ROLE,
DELETE_ROLE_PENDING,
DELETE_ROLE_SUCCESS,
DELETE_ROLE_FAILURE,
fetchRoles,
getFetchRolesFailure,
getRolesFromState,
@@ -30,6 +38,13 @@ import reducer, {
isCreateRolePending,
getCreateRoleFailure,
getRoleByName,
modifyRole,
isModifyRolePending,
getModifyRoleFailure,
deleteRole,
isDeleteRolePending,
deleteRoleSuccess,
getDeleteRoleFailure,
selectListAsCollection,
isPermittedToCreateRoles
} from "./roles";
@@ -101,7 +116,8 @@ const response = {
const URL = "repositoryRoles";
const ROLES_URL = "/api/v2/repositoryRoles";
const ROLE1_URL = "http://localhost:8081/scm/api/v2/repositoryRoles/specialrole";
const ROLE1_URL =
"http://localhost:8081/scm/api/v2/repositoryRoles/specialrole";
const error = new Error("FEHLER!");
@@ -247,6 +263,99 @@ describe("repository roles fetch", () => {
expect(callMe).toBe("yeah");
});
});
it("successfully update role", () => {
fetchMock.putOnce(ROLE1_URL, {
status: 204
});
fetchMock.getOnce(ROLE1_URL, role1);
const store = mockStore({});
return store.dispatch(modifyRole(role1)).then(() => {
const actions = store.getActions();
expect(actions.length).toBe(3);
expect(actions[0].type).toEqual(MODIFY_ROLE_PENDING);
expect(actions[1].type).toEqual(MODIFY_ROLE_SUCCESS);
expect(actions[2].type).toEqual(FETCH_ROLE_PENDING);
});
});
it("should call callback, after successful modified role", () => {
fetchMock.putOnce(ROLE1_URL, {
status: 204
});
fetchMock.getOnce(ROLE1_URL, role1);
let called = false;
const callMe = () => {
called = true;
};
const store = mockStore({});
return store.dispatch(modifyRole(role1, callMe)).then(() => {
expect(called).toBeTruthy();
});
});
it("should fail updating role on HTTP 500", () => {
fetchMock.putOnce(ROLE1_URL, {
status: 500
});
const store = mockStore({});
return store.dispatch(modifyRole(role1)).then(() => {
const actions = store.getActions();
expect(actions[0].type).toEqual(MODIFY_ROLE_PENDING);
expect(actions[1].type).toEqual(MODIFY_ROLE_FAILURE);
expect(actions[1].payload).toBeDefined();
});
});
it("should delete successfully role1", () => {
fetchMock.deleteOnce(ROLE1_URL, {
status: 204
});
const store = mockStore({});
return store.dispatch(deleteRole(role1)).then(() => {
const actions = store.getActions();
expect(actions.length).toBe(2);
expect(actions[0].type).toEqual(DELETE_ROLE_PENDING);
expect(actions[0].payload).toBe(role1);
expect(actions[1].type).toEqual(DELETE_ROLE_SUCCESS);
});
});
it("should call the callback after successful delete", () => {
fetchMock.deleteOnce(ROLE1_URL, {
status: 204
});
let called = false;
const callMe = () => {
called = true;
};
const store = mockStore({});
return store.dispatch(deleteRole(role1, callMe)).then(() => {
expect(called).toBeTruthy();
});
});
it("should fail to delete role1", () => {
fetchMock.deleteOnce(ROLE1_URL, {
status: 500
});
const store = mockStore({});
return store.dispatch(deleteRole(role1)).then(() => {
const actions = store.getActions();
expect(actions[0].type).toEqual(DELETE_ROLE_PENDING);
expect(actions[0].payload).toBe(role1);
expect(actions[1].type).toEqual(DELETE_ROLE_FAILURE);
expect(actions[1].payload).toBeDefined();
});
});
});
describe("repository roles reducer", () => {
@@ -289,6 +398,23 @@ describe("repository roles reducer", () => {
expect(newState.byNames["WRITE"]).toBeDefined();
});
it("should remove role from state when delete succeeds", () => {
const state = {
list: {
entries: ["WRITE", "specialrole"]
},
byNames: {
specialrole: role1,
WRITE: role2
}
};
const newState = reducer(state, deleteRoleSuccess(role2));
expect(newState.byNames["specialrole"]).toBeDefined();
expect(newState.byNames["WRITE"]).toBeFalsy();
expect(newState.list.entries).toEqual(["specialrole"]);
});
it("should set roleCreatePermission to true if create link is present", () => {
const newState = reducer({}, fetchRolesSuccess(responseBody));
@@ -341,9 +467,9 @@ describe("repository roles selector", () => {
it("should return false", () => {
expect(isPermittedToCreateRoles({})).toBe(false);
expect(
isPermittedToCreateRoles({ roles: { list: { entry: {} } } })
).toBe(false);
expect(isPermittedToCreateRoles({ roles: { list: { entry: {} } } })).toBe(
false
);
expect(
isPermittedToCreateRoles({
roles: { list: { entry: { roleCreatePermission: false } } }
@@ -472,4 +598,56 @@ describe("repository roles selector", () => {
it("should return undefined when fetch role2 did not fail", () => {
expect(getFetchRoleFailure({}, "role2")).toBe(undefined);
});
it("should return true, when modify role1 is pending", () => {
const state = {
pending: {
[MODIFY_ROLE + "/role1"]: true
}
};
expect(isModifyRolePending(state, "role1")).toEqual(true);
});
it("should return false, when modify role1 is not pending", () => {
expect(isModifyRolePending({}, "role1")).toEqual(false);
});
it("should return error when modify role1 did fail", () => {
const state = {
failure: {
[MODIFY_ROLE + "/role1"]: error
}
};
expect(getModifyRoleFailure(state, "role1")).toEqual(error);
});
it("should return undefined when modify role1 did not fail", () => {
expect(getModifyRoleFailure({}, "role1")).toBe(undefined);
});
it("should return true, when delete role2 is pending", () => {
const state = {
pending: {
[DELETE_ROLE + "/role2"]: true
}
};
expect(isDeleteRolePending(state, "role2")).toEqual(true);
});
it("should return false, when delete role2 is not pending", () => {
expect(isDeleteRolePending({}, "role2")).toEqual(false);
});
it("should return error when delete role2 did fail", () => {
const state = {
failure: {
[DELETE_ROLE + "/role2"]: error
}
};
expect(getDeleteRoleFailure(state, "role2")).toEqual(error);
});
it("should return undefined when delete role2 did not fail", () => {
expect(getDeleteRoleFailure({}, "role2")).toBe(undefined);
});
});