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

View File

@@ -5,6 +5,14 @@ import type { Action } from "../../types/Action";
import type { PermissionCollection, Permission } from "../types/Permissions"; import type { PermissionCollection, Permission } from "../types/Permissions";
import { isPending } from "../../modules/pending"; import { isPending } from "../../modules/pending";
import { getFailure } from "../../modules/failure"; 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 = "scm/permissions/FETCH_PERMISSIONS";
export const FETCH_PERMISSIONS_PENDING = `${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}_${ export const MODIFY_PERMISSION_RESET = `${MODIFY_PERMISSION}_${
types.RESET_SUFFIX 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 REPOS_URL = "repositories";
const PERMISSIONS_URL = "permissions"; const PERMISSIONS_URL = "permissions";
const CONTENT_TYPE = "application/vnd.scmm-permission+json"; 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 // reducer
export default function reducer( export default function reducer(
state: Object = {}, state: Object = {},
@@ -195,17 +283,23 @@ export default function reducer(
case FETCH_PERMISSIONS_SUCCESS: case FETCH_PERMISSIONS_SUCCESS:
return { return {
...state, ...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: case MODIFY_PERMISSION_SUCCESS:
const positionOfPermission = action.payload.position; const positionOfPermission = action.payload.position;
const newPermission = newPermissions( const newPermission = newPermissions(
state[action.payload.position], state[action.payload.position].entries,
action.payload.permission action.payload.permission
); );
return { return {
...state, ...state,
[positionOfPermission]: newPermission [positionOfPermission]: {
...state[positionOfPermission],
entries: newPermission
}
}; };
default: default:
return state; return state;
@@ -220,7 +314,7 @@ export function getPermissionsOfRepo(
name: string name: string
) { ) {
if (state.permissions && state.permissions[namespace + "/" + name]) { if (state.permissions && state.permissions[namespace + "/" + name]) {
const permissions = state.permissions[namespace + "/" + name]; const permissions = state.permissions[namespace + "/" + name].entries;
return permissions; return permissions;
} }
} }

View File

@@ -12,6 +12,7 @@ import reducer, {
modifyPermissionSuccess, modifyPermissionSuccess,
getModifyPermissionFailure, getModifyPermissionFailure,
isModifyPermissionPending, isModifyPermissionPending,
createPermission,
MODIFY_PERMISSION_FAILURE, MODIFY_PERMISSION_FAILURE,
MODIFY_PERMISSION_PENDING, MODIFY_PERMISSION_PENDING,
FETCH_PERMISSIONS, FETCH_PERMISSIONS,
@@ -19,7 +20,12 @@ import reducer, {
FETCH_PERMISSIONS_SUCCESS, FETCH_PERMISSIONS_SUCCESS,
FETCH_PERMISSIONS_FAILURE, FETCH_PERMISSIONS_FAILURE,
MODIFY_PERMISSION_SUCCESS, MODIFY_PERMISSION_SUCCESS,
MODIFY_PERMISSION MODIFY_PERMISSION,
CREATE_PERMISSION,
CREATE_PERMISSION_PENDING,
CREATE_PERMISSION_SUCCESS,
CREATE_PERMISSION_FAILURE,
createPermissionSuccess
} from "./permissions"; } from "./permissions";
import type { Permission, PermissionCollection } from "../types/Permissions"; import type { Permission, PermissionCollection } from "../types/Permissions";
@@ -71,6 +77,11 @@ const hitchhiker_puzzle42Permissions: PermissionCollection = [
const hitchhiker_puzzle42RepoPermissions = { const hitchhiker_puzzle42RepoPermissions = {
_embedded: { _embedded: {
permissions: hitchhiker_puzzle42Permissions permissions: hitchhiker_puzzle42Permissions
},
_links: {
create: {
link: "link"
}
} }
}; };
@@ -203,6 +214,83 @@ describe("permission fetch", () => {
expect(actions[1].payload).toBeDefined(); 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", () => { describe("permissions reducer", () => {
@@ -230,19 +318,23 @@ describe("permissions reducer", () => {
) )
); );
expect(newState["hitchhiker/puzzle42"]).toBe( expect(newState["hitchhiker/puzzle42"].entries).toBe(
hitchhiker_puzzle42Permissions hitchhiker_puzzle42Permissions
); );
}); });
it("should update permission", () => { it("should update permission", () => {
const oldState = { const oldState = {
"hitchhiker/puzzle42": [hitchhiker_puzzle42Permission_user_eins] "hitchhiker/puzzle42": {
entries: [hitchhiker_puzzle42Permission_user_eins]
}
}; };
let permissionEdited = { ...hitchhiker_puzzle42Permission_user_eins }; let permissionEdited = { ...hitchhiker_puzzle42Permission_user_eins };
permissionEdited.type = "OWNER"; permissionEdited.type = "OWNER";
let expectedState = { let expectedState = {
"hitchhiker/puzzle42": [permissionEdited] "hitchhiker/puzzle42": {
entries: [permissionEdited]
}
}; };
const newState = reducer( const newState = reducer(
oldState, oldState,
@@ -260,7 +352,9 @@ describe("permissions selectors", () => {
it("should return the permissions of one repository", () => { it("should return the permissions of one repository", () => {
const state = { const state = {
permissions: { permissions: {
"hitchhiker/puzzle42": hitchhiker_puzzle42Permissions "hitchhiker/puzzle42": {
entries: hitchhiker_puzzle42Permissions
}
} }
}; };