From 819362a50a1d74eaafe0b135d2a0f714320418e1 Mon Sep 17 00:00:00 2001 From: Petr Stefan Date: Thu, 22 Feb 2018 16:49:48 +0100 Subject: [PATCH] Forking of exercises for superadmins --- .../ForkExerciseForm/ForkExerciseForm.css | 4 +- .../ForkExerciseForm/ForkExerciseForm.js | 15 ++++-- src/pages/Exercise/Exercise.js | 53 ++++++++++++++----- src/redux/modules/users.js | 1 + 4 files changed, 52 insertions(+), 21 deletions(-) diff --git a/src/components/forms/ForkExerciseForm/ForkExerciseForm.css b/src/components/forms/ForkExerciseForm/ForkExerciseForm.css index ca4e570d0..824f8b236 100644 --- a/src/components/forms/ForkExerciseForm/ForkExerciseForm.css +++ b/src/components/forms/ForkExerciseForm/ForkExerciseForm.css @@ -1,4 +1,4 @@ -.formSpace { - padding-left: 10px; +.forkForm { + padding-left: 0px; display: flex; } diff --git a/src/components/forms/ForkExerciseForm/ForkExerciseForm.js b/src/components/forms/ForkExerciseForm/ForkExerciseForm.js index 20119434d..672fd4634 100644 --- a/src/components/forms/ForkExerciseForm/ForkExerciseForm.js +++ b/src/components/forms/ForkExerciseForm/ForkExerciseForm.js @@ -13,7 +13,7 @@ import { SuccessIcon } from '../../../components/icons'; import { forkStatuses } from '../../../redux/modules/exercises'; import { getFork } from '../../../redux/selectors/exercises'; import ResourceRenderer from '../../helpers/ResourceRenderer'; -import { getLocalizedName } from '../../../helpers/getLocalizedData'; +import { getGroupCanonicalLocalizedName } from '../../../helpers/getLocalizedData'; import withLinks from '../../../hoc/withLinks'; @@ -41,6 +41,7 @@ class ForkExerciseForm extends Component { hasSucceeded = false, invalid, groups, + groupsAccessor, intl: { locale } } = this.props; @@ -70,7 +71,7 @@ class ForkExerciseForm extends Component { defaultMessage="Saving failed. Please try again later." /> } -
+ {(...groups) => a.name.localeCompare(b.name, locale)) - .filter((item, pos, arr) => arr.indexOf(item) === pos) .map(group => ({ key: group.id, - name: getLocalizedName(group, locale) + name: getGroupCanonicalLocalizedName( + group, + groupsAccessor, + locale + ) })) + .sort((a, b) => a.name.localeCompare(b.name, locale)) )} />} @@ -140,6 +144,7 @@ ForkExerciseForm.propTypes = { push: PropTypes.func.isRequired, links: PropTypes.object, groups: ImmutablePropTypes.map, + groupsAccessor: PropTypes.func.isRequired, intl: PropTypes.shape({ locale: PropTypes.string.isRequired }).isRequired }; diff --git a/src/pages/Exercise/Exercise.js b/src/pages/Exercise/Exercise.js index 55ca0ed7d..5901e44b5 100644 --- a/src/pages/Exercise/Exercise.js +++ b/src/pages/Exercise/Exercise.js @@ -31,7 +31,7 @@ import { } from '../../components/icons'; import Confirm from '../../components/forms/Confirm'; import PipelinesSimpleList from '../../components/Pipelines/PipelinesSimpleList'; -// import ForkExerciseForm from '../../components/forms/ForkExerciseForm'; +import ForkExerciseForm from '../../components/forms/ForkExerciseForm'; import AssignExerciseButton from '../../components/buttons/AssignExerciseButton'; import { isSubmitting } from '../../redux/selectors/submission'; @@ -48,23 +48,31 @@ import { fetchHardwareGroups } from '../../redux/modules/hwGroups'; import { create as assignExercise } from '../../redux/modules/assignments'; import { exerciseSelector } from '../../redux/selectors/exercises'; import { referenceSolutionsSelector } from '../../redux/selectors/referenceSolutions'; -import { canEditExercise } from '../../redux/selectors/users'; +import { + canEditExercise, + isLoggedAsSuperAdmin +} from '../../redux/selectors/users'; import { deletePipeline, fetchExercisePipelines, create as createPipeline } from '../../redux/modules/pipelines'; import { exercisePipelinesSelector } from '../../redux/selectors/pipelines'; -import { fetchUsersGroupsIfNeeded } from '../../redux/modules/groups'; +import { + fetchUsersGroupsIfNeeded, + fetchInstanceGroups +} from '../../redux/modules/groups'; import { loggedInUserIdSelector } from '../../redux/selectors/auth'; import { supervisorOfSelector, - groupsSelector + groupsSelector, + groupDataAccessorSelector } from '../../redux/selectors/groups'; import withLinks from '../../hoc/withLinks'; import SupplementaryFilesTableContainer from '../../containers/SupplementaryFilesTableContainer/SupplementaryFilesTableContainer'; +import { fetchUser } from '../../redux/modules/users'; const messages = defineMessages({ groupsBox: { @@ -90,7 +98,15 @@ class Exercise extends Component { dispatch(fetchReferenceSolutionsIfNeeded(exerciseId)), dispatch(fetchHardwareGroups()), dispatch(fetchExercisePipelines(exerciseId)), - dispatch(fetchUsersGroupsIfNeeded(userId)) + dispatch(fetchUsersGroupsIfNeeded(userId)), + dispatch(fetchUser(userId)) + .then(res => res.value) + .then( + data => + data.privateData.role === 'superadmin' + ? dispatch(fetchInstanceGroups(data.privateData.instanceId)) + : Promise.resolve() + ) ]); componentWillMount() { @@ -141,12 +157,14 @@ class Exercise extends Component { initCreateReferenceSolution, exercisePipelines, deleteReferenceSolution, - push - // groups, - // forkExercise + push, + groups, + groupsAccessor, + forkExercise, + isSuperAdmin } = this.props; - // const { forkId } = this.state; + const { forkId } = this.state; const { links: { @@ -238,13 +256,16 @@ class Exercise extends Component { /> - {/* +

+ {isSuperAdmin && + forkExercise(forkId, formData)} - /> */} - + groupsAccessor={groupsAccessor} + />} }

@@ -489,7 +510,9 @@ Exercise.propTypes = { links: PropTypes.object, deleteReferenceSolution: PropTypes.func.isRequired, forkExercise: PropTypes.func.isRequired, - groups: ImmutablePropTypes.map + groups: ImmutablePropTypes.map, + isSuperAdmin: PropTypes.bool, + groupsAccessor: PropTypes.func.isRequired }; export default withLinks( @@ -507,7 +530,9 @@ export default withLinks( canEditExercise(userId, exerciseId)(state), referenceSolutions: referenceSolutionsSelector(exerciseId)(state), exercisePipelines: exercisePipelinesSelector(exerciseId)(state), - groups: groupsSelector(state) + groups: groupsSelector(state), + groupsAccessor: groupDataAccessorSelector(state), + isSuperAdmin: isLoggedAsSuperAdmin(state) }; }, (dispatch, { params: { exerciseId } }) => ({ diff --git a/src/redux/modules/users.js b/src/redux/modules/users.js index ca60a576d..19618a918 100644 --- a/src/redux/modules/users.js +++ b/src/redux/modules/users.js @@ -45,6 +45,7 @@ export const fetchAllUsers = actions.fetchMany({ endpoint: fetchManyEndpoint }); export const loadUserData = actions.pushResource; +export const fetchUser = actions.fetchResource; export const fetchUserIfNeeded = actions.fetchIfNeeded; export const validateRegistrationData = (email, password) => createApiAction({