Skip to content

fix: issue #1046 #1095

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Mar 4, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
58 changes: 41 additions & 17 deletions src/components/ChallengesComponent/ChallengeCard/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import styles from './ChallengeCard.module.scss'
import { getFormattedDuration, formatDate } from '../../../util/date'
import { CHALLENGE_STATUS, COMMUNITY_APP_URL, DIRECT_PROJECT_URL, MESSAGE, ONLINE_REVIEW_URL } from '../../../config/constants'
import ConfirmationModal from '../../Modal/ConfirmationModal'
import { checkChallengeEditPermission } from '../../../util/tc'
import AlertModal from '../../Modal/AlertModal'
import Tooltip from '../../Tooltip'

Expand All @@ -28,6 +29,9 @@ const DRAFT_MSG = 'In Draft'
const STALLED_TIME_LEFT_MSG = 'Challenge is currently on hold'
const FF_TIME_LEFT_MSG = 'Winner is working on fixes'

const PERMISSION_DELETE_MESSAGE_ERROR =
"You don't have permission to delete this challenge"

/**
* Format the remaining time of a challenge phase
* @param phase Challenge phase
Expand Down Expand Up @@ -187,7 +191,9 @@ class ChallengeCard extends React.Component {
isConfirm: false,
isLaunch: false,
isDeleteLaunch: false,
isSaving: false
isSaving: false,
isCheckChalengePermission: false,
hasEditChallengePermission: false
}
this.onUpdateConfirm = this.onUpdateConfirm.bind(this)
this.onUpdateLaunch = this.onUpdateLaunch.bind(this)
Expand All @@ -208,8 +214,19 @@ class ChallengeCard extends React.Component {
}

deleteModalLaunch () {
const { challenge } = this.props
if (!this.state.isDeleteLaunch) {
this.setState({ isDeleteLaunch: true })
checkChallengeEditPermission(challenge.id).then(hasPermission => {
this.setState({
isCheckChalengePermission: false,
hasEditChallengePermission: hasPermission
})
})
this.setState({
isDeleteLaunch: true,
isCheckChalengePermission: true,
hasEditChallengePermission: false
})
}
}

Expand Down Expand Up @@ -254,25 +271,32 @@ class ChallengeCard extends React.Component {
}

render () {
const { isLaunch, isConfirm, isSaving, isDeleteLaunch } = this.state
const { isLaunch, isConfirm, isSaving, isDeleteLaunch, isCheckChalengePermission, hasEditChallengePermission } = this.state
const { challenge, shouldShowCurrentPhase, reloadChallengeList } = this.props
const { phaseMessage, endTime } = getPhaseInfo(challenge)
const deleteMessage = isCheckChalengePermission
? 'Checking permissions...'
: `Do you want to delete "${challenge.name}"?`

return (
<div className={styles.item}>
{
isDeleteLaunch && !isConfirm && (
<ConfirmationModal
title='Confirm Delete'
message={`Do you want to delete "${challenge.name}"?`}
theme={theme}
isProcessing={isSaving}
errorMessage={this.state.error}
onCancel={this.resetModal}
onConfirm={this.onDeleteChallenge}
/>
)
}
{ isLaunch && !isConfirm && (
{isDeleteLaunch && !isConfirm && (
<ConfirmationModal
title='Confirm Delete'
message={deleteMessage}
theme={theme}
isProcessing={isSaving}
disableConfirmButton={!hasEditChallengePermission}
errorMessage={
!isCheckChalengePermission && !hasEditChallengePermission
? PERMISSION_DELETE_MESSAGE_ERROR
: this.state.error
}
onCancel={this.resetModal}
onConfirm={this.onDeleteChallenge}
/>
)}
{isLaunch && !isConfirm && (
<ConfirmationModal
title='Confirm Launch'
message={`Do you want to launch "${challenge.name}"?`}
Expand Down
4 changes: 3 additions & 1 deletion src/components/Modal/ConfirmationModal.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import styles from './ConfirmationModal.module.scss'
import OutlineButton from '../Buttons/OutlineButton'
import PrimaryButton from '../Buttons/PrimaryButton'

const ConfirmationModal = ({ title, message, errorMessage, theme, isProcessing, onCancel, onConfirm }) => (
const ConfirmationModal = ({ title, message, errorMessage, theme, isProcessing, onCancel, onConfirm, disableConfirmButton }) => (
<Modal theme={theme} onCancel={onCancel}>
<div className={styles.contentContainer}>
<div className={styles.title}>{title}</div>
Expand All @@ -23,6 +23,7 @@ const ConfirmationModal = ({ title, message, errorMessage, theme, isProcessing,
<div className={styles.button}>
<PrimaryButton
text={isProcessing ? 'Processing...' : 'Confirm'}
disabled={disableConfirmButton}
type={'info'}
onClick={onConfirm}
/>
Expand All @@ -39,6 +40,7 @@ ConfirmationModal.propTypes = {
errorMessage: PropTypes.string,
theme: PropTypes.shape(),
isProcessing: PropTypes.bool,
disableConfirmButton: PropTypes.bool,
onCancel: PropTypes.func,
onConfirm: PropTypes.func
}
Expand Down
39 changes: 39 additions & 0 deletions src/util/tc.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@
import { MARATHON_MATCH_SUBTRACKS, CHALLENGE_TRACKS, ALLOWED_USER_ROLES, ADMIN_ROLES, SUBMITTER_ROLE_UUID } from '../config/constants'
import _ from 'lodash'
import { decodeToken } from 'tc-auth-lib'
import { fetchResources, fetchResourceRoles } from '../services/challenges'
import store from '../config/store'

export const RATING_COLORS = [{
color: '#9D9FA0' /* Grey */,
Expand Down Expand Up @@ -77,3 +79,40 @@ export const getResourceRoleByName = (resourceRoles, name) => {
return _.find(resourceRoles, { name }) || null
}
}

/**
* check edit permission
* @param {number} challengeId challenge Id
*
* @returns {boolean} hasPermission
*/
export const checkChallengeEditPermission = async (challengeId) => {
const state = store.getState()
const token = state.auth.token
const loggedInUser = state.auth.user
const hasProjectAccess = state.projects.hasProjectAccess

const isAdmin = checkAdmin(token)
if (isAdmin) {
return true
}
if (!hasProjectAccess) {
return false
}

return Promise.all([fetchResources(challengeId), fetchResourceRoles()]).then(
([challengeResources, resourceRoles]) => {
const userRoles = _.filter(
challengeResources,
cr => cr.memberId === `${loggedInUser.userId}`
)
const userResourceRoles = _.filter(resourceRoles, rr =>
_.some(userRoles, ur => ur.roleId === rr.id)
)
return _.some(
userResourceRoles,
urr => urr.fullWriteAccess && urr.isActive
)
}
)
}