add handling of create link and createPermission handling

This commit is contained in:
Maren Süwer
2018-08-28 16:00:48 +02:00
parent de912f39e6
commit cc7474d4f4
3 changed files with 202 additions and 11 deletions

View File

@@ -70,7 +70,7 @@ class SinglePermission extends React.Component<Props, State> {
render() {
const { permission } = this.state;
const { t, loading, error } = this.props;
const types = ["READ", "OWNER", "GROUP"];
const types = ["READ", "OWNER", "WRITE"];
const deleteButton = this.props.permission._links.delete ? (
<DeleteButton label={t("edit-permission.delete-button")} />
) : null;
@@ -99,7 +99,10 @@ class SinglePermission extends React.Component<Props, State> {
<Checkbox checked={permission ? permission.groupPermission : false} />
</td>
{typeSelector}
<td>{deleteButton}</td> {errorNotification}
<td>
{deleteButton}
{errorNotification}
</td>
</tr>
);
}

View File

@@ -5,6 +5,14 @@ import type { Action } from "../../types/Action";
import type { PermissionCollection, Permission } from "../types/Permissions";
import { isPending } from "../../modules/pending";
import { getFailure } from "../../modules/failure";
import type { User } from "../../users/types/User";
import { Dispatch } from "redux";
import {
CREATE_USER_FAILURE,
CREATE_USER_PENDING,
CREATE_USER_RESET,
CREATE_USER_SUCCESS
} from "../../users/modules/users";
export const FETCH_PERMISSIONS = "scm/permissions/FETCH_PERMISSIONS";
export const FETCH_PERMISSIONS_PENDING = `${FETCH_PERMISSIONS}_${
@@ -29,6 +37,17 @@ export const MODIFY_PERMISSION_FAILURE = `${MODIFY_PERMISSION}_${
export const MODIFY_PERMISSION_RESET = `${MODIFY_PERMISSION}_${
types.RESET_SUFFIX
}`;
export const CREATE_PERMISSION = "scm/permissions/CREATE_PERMISSION";
export const CREATE_PERMISSION_PENDING = `${CREATE_PERMISSION}_${
types.PENDING_SUFFIX
}`;
export const CREATE_PERMISSION_SUCCESS = `$CREATE_PERMISSION}_${
types.SUCCESS_SUFFIX
}`;
export const CREATE_PERMISSION_FAILURE = `${CREATE_PERMISSION}_${
types.FAILURE_SUFFIX
}`;
const REPOS_URL = "repositories";
const PERMISSIONS_URL = "permissions";
const CONTENT_TYPE = "application/vnd.scmm-permission+json";
@@ -182,6 +201,75 @@ export function modifyPermissionReset(
};
}
// create permission
export function createPermission(
permission: Permission,
namespace: string,
name: string,
callback?: () => void
) {
return function(dispatch: Dispatch) {
dispatch(createPermissionPending(permission, namespace, name));
return apiClient
.post(
`${REPOS_URL}/${namespace}/${name}/${PERMISSIONS_URL}`,
permission,
CONTENT_TYPE
)
.then(() => {
dispatch(createPermissionSuccess(namespace, name));
if (callback) {
callback();
}
})
.catch(err =>
dispatch(
createPermissionFailure(
new Error(
`failed to add permission ${permission.name}: ${err.message}`
),
namespace,
name
)
)
);
};
}
export function createPermissionPending(
permission: Permission,
namespace: string,
name: string
): Action {
return {
type: CREATE_PERMISSION_PENDING,
payload: permission,
itemId: namespace + "/" + name
};
}
export function createPermissionSuccess(
namespace: string,
name: string
): Action {
return {
type: CREATE_PERMISSION_SUCCESS,
itemId: namespace + "/" + name
};
}
export function createPermissionFailure(
error: Error,
namespace: string,
name: string
): Action {
return {
type: CREATE_PERMISSION_FAILURE,
payload: error,
itemId: namespace + "/" + name
};
}
// reducer
export default function reducer(
state: Object = {},
@@ -195,17 +283,23 @@ export default function reducer(
case FETCH_PERMISSIONS_SUCCESS:
return {
...state,
[action.itemId]: action.payload._embedded.permissions
[action.itemId]: {
entries: action.payload._embedded.permissions,
createPermission: action.payload._links.create ? true : false
}
};
case MODIFY_PERMISSION_SUCCESS:
const positionOfPermission = action.payload.position;
const newPermission = newPermissions(
state[action.payload.position],
state[action.payload.position].entries,
action.payload.permission
);
return {
...state,
[positionOfPermission]: newPermission
[positionOfPermission]: {
...state[positionOfPermission],
entries: newPermission
}
};
default:
return state;
@@ -220,7 +314,7 @@ export function getPermissionsOfRepo(
name: string
) {
if (state.permissions && state.permissions[namespace + "/" + name]) {
const permissions = state.permissions[namespace + "/" + name];
const permissions = state.permissions[namespace + "/" + name].entries;
return permissions;
}
}

View File

@@ -12,6 +12,7 @@ import reducer, {
modifyPermissionSuccess,
getModifyPermissionFailure,
isModifyPermissionPending,
createPermission,
MODIFY_PERMISSION_FAILURE,
MODIFY_PERMISSION_PENDING,
FETCH_PERMISSIONS,
@@ -19,7 +20,12 @@ import reducer, {
FETCH_PERMISSIONS_SUCCESS,
FETCH_PERMISSIONS_FAILURE,
MODIFY_PERMISSION_SUCCESS,
MODIFY_PERMISSION
MODIFY_PERMISSION,
CREATE_PERMISSION,
CREATE_PERMISSION_PENDING,
CREATE_PERMISSION_SUCCESS,
CREATE_PERMISSION_FAILURE,
createPermissionSuccess
} from "./permissions";
import type { Permission, PermissionCollection } from "../types/Permissions";
@@ -71,6 +77,11 @@ const hitchhiker_puzzle42Permissions: PermissionCollection = [
const hitchhiker_puzzle42RepoPermissions = {
_embedded: {
permissions: hitchhiker_puzzle42Permissions
},
_links: {
create: {
link: "link"
}
}
};
@@ -203,6 +214,83 @@ describe("permission fetch", () => {
expect(actions[1].payload).toBeDefined();
});
});
it("should add a permission successfully", () => {
// unmatched
fetchMock.postOnce(REPOS_URL + "/hitchhiker/puzzle42/permissions", {
status: 204
});
// after create, the users are fetched again
fetchMock.getOnce(
REPOS_URL + "/hitchhiker/puzzle42",
hitchhiker_puzzle42RepoPermissions
);
const store = mockStore({});
return store
.dispatch(
createPermission(
hitchhiker_puzzle42Permission_user_eins,
"hitchhiker",
"puzzle42"
)
)
.then(() => {
const actions = store.getActions();
expect(actions[0].type).toEqual(CREATE_PERMISSION_PENDING);
expect(actions[1].type).toEqual(CREATE_PERMISSION_SUCCESS);
});
});
it("should fail adding a permission on HTTP 500", () => {
fetchMock.postOnce(REPOS_URL + "/hitchhiker/puzzle42/permissions", {
status: 500
});
const store = mockStore({});
return store
.dispatch(
createPermission(
hitchhiker_puzzle42Permission_user_eins,
"hitchhiker",
"puzzle42"
)
)
.then(() => {
const actions = store.getActions();
expect(actions[0].type).toEqual(CREATE_PERMISSION_PENDING);
expect(actions[1].type).toEqual(CREATE_PERMISSION_FAILURE);
expect(actions[1].payload).toBeDefined();
});
});
it("should call the callback after permission successfully created", () => {
// unmatched
fetchMock.postOnce(REPOS_URL + "/hitchhiker/puzzle42/permissions", {
status: 204
});
let callMe = "not yet";
const callback = () => {
callMe = "yeah";
};
const store = mockStore({});
return store
.dispatch(
createPermission(
hitchhiker_puzzle42Permission_user_eins,
"hitchhiker",
"puzzle42",
callback
)
)
.then(() => {
expect(callMe).toBe("yeah");
});
});
});
describe("permissions reducer", () => {
@@ -230,19 +318,23 @@ describe("permissions reducer", () => {
)
);
expect(newState["hitchhiker/puzzle42"]).toBe(
expect(newState["hitchhiker/puzzle42"].entries).toBe(
hitchhiker_puzzle42Permissions
);
});
it("should update permission", () => {
const oldState = {
"hitchhiker/puzzle42": [hitchhiker_puzzle42Permission_user_eins]
"hitchhiker/puzzle42": {
entries: [hitchhiker_puzzle42Permission_user_eins]
}
};
let permissionEdited = { ...hitchhiker_puzzle42Permission_user_eins };
permissionEdited.type = "OWNER";
let expectedState = {
"hitchhiker/puzzle42": [permissionEdited]
"hitchhiker/puzzle42": {
entries: [permissionEdited]
}
};
const newState = reducer(
oldState,
@@ -260,7 +352,9 @@ describe("permissions selectors", () => {
it("should return the permissions of one repository", () => {
const state = {
permissions: {
"hitchhiker/puzzle42": hitchhiker_puzzle42Permissions
"hitchhiker/puzzle42": {
entries: hitchhiker_puzzle42Permissions
}
}
};