-
Notifications
You must be signed in to change notification settings - Fork 21
[PROD RELASE] - Access & fixes #1470
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
Changes from all commits
caf0a6a
ebce38b
caeaa4f
9f4747a
6b554a4
7e2e4cf
0177659
30b31f9
5bbdaa5
b9c899a
affce2a
95e3658
1b468fa
eeccab3
549ccd4
ef88f60
e20e595
df4060e
7743fcf
aa72957
967457d
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -2,7 +2,7 @@ | |
| import { UserProfile, UserRole, UserTrait } from '~/libs/core' | ||
| import { availabilityOptions, preferredRoleOptions } from '~/libs/shared/lib/components/modify-open-to-work-modal' | ||
|
|
||
| import { ADMIN_ROLES, PHONE_NUMBER_ROLES } from '../config' | ||
| import { ADMIN_ROLES, EMAIL_VIEW_ROLES, PHONE_NUMBER_ROLES } from '../config' | ||
|
|
||
| declare global { | ||
| interface Window { tcUniNav: any } | ||
|
|
@@ -145,17 +145,13 @@ export function canDownloadProfile(authProfile: UserProfile | undefined, profile | |
| return true | ||
| } | ||
|
|
||
| // Check if user has admin roles | ||
| if (authProfile.roles?.some(role => ADMIN_ROLES.includes(role.toLowerCase() as UserRole))) { | ||
| return true | ||
| } | ||
|
|
||
| // Check if user has PM or Talent Manager roles | ||
| const allowedRoles = ['Project Manager', 'Talent Manager'] | ||
| if (authProfile | ||
| .roles?.some( | ||
| role => allowedRoles.some(allowed => role.toLowerCase() === allowed.toLowerCase()), | ||
| ) | ||
| // Check if user has admin roles or talent manager | ||
| if ( | ||
| authProfile.roles?.some(role => [ | ||
| UserRole.talentManager, | ||
| ...ADMIN_ROLES, | ||
| ].map(r => r.toLowerCase()) | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. [ |
||
| .includes(role.toLowerCase() as UserRole)) | ||
| ) { | ||
| return true | ||
| } | ||
|
|
@@ -193,6 +189,32 @@ export function canSeePhones(authProfile: UserProfile | undefined, profile: User | |
| return false | ||
| } | ||
|
|
||
| /** | ||
| * Check if the user can see email address | ||
| * @param authProfile - The authenticated user profile | ||
| * @param profile - The profile to check if the user can see email | ||
| * @returns {boolean} - Whether the user can see email | ||
| */ | ||
| export function canSeeEmail(authProfile: UserProfile | undefined, profile: UserProfile): boolean { | ||
| if (!authProfile) { | ||
| return false | ||
| } | ||
|
|
||
| if (authProfile.handle === profile.handle) { | ||
| return true | ||
| } | ||
|
|
||
| if (authProfile | ||
| .roles?.some( | ||
| role => EMAIL_VIEW_ROLES.some(allowed => role.toLowerCase() === allowed.toLowerCase()), | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. [💡 |
||
| ) | ||
| ) { | ||
| return true | ||
| } | ||
|
|
||
| return false | ||
| } | ||
|
|
||
| export function getAvailabilityLabel(value?: string): string | undefined { | ||
| return availabilityOptions.find(o => o.value === value)?.label | ||
| } | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -6,7 +6,7 @@ import { CopyButton } from '~/apps/admin/src/lib/components/CopyButton' | |
| import { IconOutline, IconSolid, Tooltip } from '~/libs/ui' | ||
|
|
||
| import { AddButton } from '../../components' | ||
| import { canSeePhones } from '../../lib/helpers' | ||
| import { canSeeEmail, canSeePhones } from '../../lib/helpers' | ||
|
|
||
| import { ModifyPhonesModal } from './ModifyPhonesModal' | ||
| import { PhoneCard } from './PhoneCard' | ||
|
|
@@ -21,6 +21,7 @@ interface PhonesProps { | |
| const Phones: FC<PhonesProps> = (props: PhonesProps) => { | ||
| const canEdit: boolean = props.authProfile?.handle === props.profile.handle | ||
| const canSeePhonesValue: boolean = canSeePhones(props.authProfile, props.profile) | ||
| const canSeeEmailValue: boolean = canSeeEmail(props.authProfile, props.profile) | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. [❗❗ |
||
|
|
||
| const [isEditMode, setIsEditMode]: [boolean, Dispatch<SetStateAction<boolean>>] | ||
| = useState<boolean>(false) | ||
|
|
@@ -50,6 +51,12 @@ const Phones: FC<PhonesProps> = (props: PhonesProps) => { | |
| }, 1000) | ||
| } | ||
|
|
||
| // Don't render anything if user cannot edit AND cannot see any contact info | ||
| const hasContactInfo = props.profile?.email || phones.length > 0 | ||
| if (!canEdit && (!canSeeEmailValue || !hasContactInfo)) { | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. [❗❗ |
||
| return <></> | ||
| } | ||
|
|
||
| return ( | ||
| <div className={styles.container}> | ||
| <div className={styles.titleWrap}> | ||
|
|
@@ -61,7 +68,7 @@ const Phones: FC<PhonesProps> = (props: PhonesProps) => { | |
| </Tooltip> | ||
| )} | ||
| </p> | ||
| {props.profile?.email && ( | ||
| {canSeeEmailValue && props.profile?.email && ( | ||
| <div className={styles.email}> | ||
| <div className={styles.emailIcon}> | ||
| <IconSolid.MailIcon width={20} height={20} /> | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -45,6 +45,7 @@ import type { SubmissionHistoryPartition } from '../../utils' | |
| import { TABLE_DATE_FORMAT } from '../../../config/index.config' | ||
| import { CollapsibleAiReviewsRow } from '../CollapsibleAiReviewsRow' | ||
| import { useRolePermissions, UseRolePermissionsResult } from '../../hooks' | ||
| import { SUBMISSION_DOWNLOAD_RESTRICTION_MESSAGE } from '../../constants' | ||
|
|
||
| import styles from './TabContentSubmissions.module.scss' | ||
|
|
||
|
|
@@ -240,24 +241,13 @@ export const TabContentSubmissions: FC<Props> = props => { | |
|
|
||
| const filteredSubmissions = useMemo<BackendSubmission[]>( | ||
| () => { | ||
|
|
||
| const filterFunc = (submissions: BackendSubmission[]): BackendSubmission[] => submissions | ||
| .filter(submission => { | ||
| if (!canViewSubmissions) { | ||
| return String(submission.memberId) === String(loginUserInfo?.userId) | ||
| } | ||
|
|
||
| return true | ||
| }) | ||
| const filteredByUserId = filterFunc(latestBackendSubmissions) | ||
| const filteredByUserIdSubmissions = filterFunc(props.submissions) | ||
| if (restrictToLatest && hasLatestFlag) { | ||
| return latestBackendSubmissions.length | ||
| ? filteredByUserId | ||
| : filteredByUserIdSubmissions | ||
| ? latestBackendSubmissions | ||
| : props.submissions | ||
| } | ||
|
|
||
| return filteredByUserIdSubmissions | ||
| return props.submissions | ||
| }, | ||
| [ | ||
| latestBackendSubmissions, | ||
|
|
@@ -288,13 +278,21 @@ export const TabContentSubmissions: FC<Props> = props => { | |
| ? undefined | ||
| : submission.virusScan | ||
| const failedScan = normalizedVirusScan === false | ||
| const isRestricted = isRestrictedBase || failedScan | ||
| const tooltipMessage = failedScan | ||
| const cannotDownloadSubmission = ( | ||
| !canViewSubmissions && String(submission.memberId) === String(loginUserInfo?.userId) | ||
| ) | ||
| const isRestricted = isRestrictedBase || failedScan || !cannotDownloadSubmission | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. [❗❗ |
||
| let tooltipMessage = failedScan | ||
| ? VIRUS_SCAN_FAILED_MESSAGE | ||
| : ( | ||
| getRestrictionMessageForMember(submission.memberId) | ||
| ?? restrictionMessage | ||
| ) | ||
|
|
||
| if (!cannotDownloadSubmission) { | ||
| tooltipMessage = SUBMISSION_DOWNLOAD_RESTRICTION_MESSAGE | ||
| } | ||
|
|
||
| const isButtonDisabled = Boolean( | ||
| props.isDownloading[submission.id] | ||
| || isRestricted, | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -13,7 +13,7 @@ import { useWindowSize, WindowSize } from '~/libs/shared' | |
| import { Table, TableColumn } from '~/libs/ui' | ||
|
|
||
| import { WITHOUT_APPEAL } from '../../../config/index.config' | ||
| import { ChallengeDetailContext } from '../../contexts' | ||
| import { ChallengeDetailContext, ReviewAppContext } from '../../contexts' | ||
| import { useSubmissionDownloadAccess } from '../../hooks/useSubmissionDownloadAccess' | ||
| import type { UseSubmissionDownloadAccessResult } from '../../hooks/useSubmissionDownloadAccess' | ||
| import { useRolePermissions } from '../../hooks/useRolePermissions' | ||
|
|
@@ -22,6 +22,7 @@ import { | |
| ChallengeDetailContextModel, | ||
| ChallengeInfo, | ||
| MappingReviewAppeal, | ||
| ReviewAppContextModel, | ||
| SubmissionInfo, | ||
| } from '../../models' | ||
| import { TableWrapper } from '../TableWrapper' | ||
|
|
@@ -70,7 +71,7 @@ export const TableAppeals: FC<TableAppealsProps> = (props: TableAppealsProps) => | |
| reviewers, | ||
| }: ChallengeDetailContextModel = useContext(ChallengeDetailContext) | ||
| const { width: screenWidth }: WindowSize = useWindowSize() | ||
|
|
||
| const { loginUserInfo }: ReviewAppContextModel = useContext(ReviewAppContext) | ||
| const downloadAccess: UseSubmissionDownloadAccessResult = useSubmissionDownloadAccess() | ||
| const { | ||
| getRestrictionMessageForMember, | ||
|
|
@@ -219,13 +220,45 @@ export const TableAppeals: FC<TableAppealsProps> = (props: TableAppealsProps) => | |
| [aggregatedResults], | ||
| ) | ||
|
|
||
| const { canViewAllSubmissions }: UseRolePermissionsResult = useRolePermissions() | ||
|
|
||
| const isCompletedDesignChallenge = useMemo(() => { | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. [💡 |
||
| if (!challengeInfo) return false | ||
| const type = challengeInfo.track.name ? String(challengeInfo.track.name) | ||
| .toLowerCase() : '' | ||
| const status = challengeInfo.status ? String(challengeInfo.status) | ||
| .toLowerCase() : '' | ||
| return type === 'design' && ( | ||
| status === 'completed' | ||
| ) | ||
| }, [challengeInfo]) | ||
|
|
||
| const isSubmissionsViewable = useMemo(() => { | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. [ |
||
| if (!challengeInfo?.metadata?.length) return false | ||
| return challengeInfo.metadata.some(m => m.name === 'submissionsViewable' && String(m.value) | ||
| .toLowerCase() === 'true') | ||
| }, [challengeInfo]) | ||
|
|
||
| const canViewSubmissions = useMemo(() => { | ||
| if (isCompletedDesignChallenge) { | ||
| return canViewAllSubmissions || isSubmissionsViewable | ||
| } | ||
|
|
||
| return true | ||
| }, [isCompletedDesignChallenge, isSubmissionsViewable, canViewAllSubmissions]) | ||
|
|
||
| const isSubmissionNotViewable = (submission: SubmissionRow): boolean => ( | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. [ |
||
| !canViewSubmissions && String(submission.memberId) !== String(loginUserInfo?.userId) | ||
| ) | ||
|
|
||
| const downloadButtonConfig = useMemo<DownloadButtonConfig>( | ||
| () => ({ | ||
| downloadSubmission, | ||
| getRestrictionMessageForMember, | ||
| isDownloading, | ||
| isSubmissionDownloadRestricted, | ||
| isSubmissionDownloadRestrictedForMember, | ||
| isSubmissionNotViewable, | ||
| ownedMemberIds, | ||
| restrictionMessage, | ||
| shouldRestrictSubmitterToOwnSubmission: false, | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -32,9 +32,10 @@ import { | |
| import { ChallengeDetailContext, ReviewAppContext } from '../../contexts' | ||
| import { updateReview } from '../../services' | ||
| import { ConfirmModal } from '../ConfirmModal' | ||
| import { useSubmissionDownloadAccess } from '../../hooks' | ||
| import { useRolePermissions, UseRolePermissionsResult, useSubmissionDownloadAccess } from '../../hooks' | ||
| import type { UseSubmissionDownloadAccessResult } from '../../hooks/useSubmissionDownloadAccess' | ||
| import { CollapsibleAiReviewsRow } from '../CollapsibleAiReviewsRow' | ||
| import { SUBMISSION_DOWNLOAD_RESTRICTION_MESSAGE } from '../../constants' | ||
|
|
||
| import styles from './TableCheckpointSubmissions.module.scss' | ||
|
|
||
|
|
@@ -65,6 +66,7 @@ export const TableCheckpointSubmissions: FC<Props> = (props: Props) => { | |
| const datas: Screening[] | undefined = props.datas | ||
| const downloadSubmission = props.downloadSubmission | ||
| const isDownloading = props.isDownloading | ||
| const { canViewAllSubmissions }: UseRolePermissionsResult = useRolePermissions() | ||
|
|
||
| const { | ||
| challengeInfo, | ||
|
|
@@ -115,6 +117,31 @@ export const TableCheckpointSubmissions: FC<Props> = (props: Props) => { | |
| getRestrictionMessageForMember, | ||
| }: UseSubmissionDownloadAccessResult = useSubmissionDownloadAccess() | ||
|
|
||
| const isCompletedDesignChallenge = useMemo(() => { | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. [ |
||
| if (!challengeInfo) return false | ||
| const type = challengeInfo.track.name ? String(challengeInfo.track.name) | ||
| .toLowerCase() : '' | ||
| const status = challengeInfo.status ? String(challengeInfo.status) | ||
| .toLowerCase() : '' | ||
| return type === 'design' && ( | ||
| status === 'completed' | ||
| ) | ||
| }, [challengeInfo]) | ||
|
|
||
| const isSubmissionsViewable = useMemo(() => { | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. [ |
||
| if (!challengeInfo?.metadata?.length) return false | ||
| return challengeInfo.metadata.some(m => m.name === 'submissionsViewable' && String(m.value) | ||
| .toLowerCase() === 'true') | ||
| }, [challengeInfo]) | ||
|
|
||
| const canViewSubmissions = useMemo(() => { | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. [ |
||
| if (isCompletedDesignChallenge) { | ||
| return canViewAllSubmissions || isSubmissionsViewable | ||
| } | ||
|
|
||
| return true | ||
| }, [isCompletedDesignChallenge, isSubmissionsViewable, canViewAllSubmissions]) | ||
|
|
||
| const openReopenDialog = useCallback( | ||
| (entry: Screening, isOwnReview: boolean): void => { | ||
| if (!entry.reviewId) { | ||
|
|
@@ -211,10 +238,18 @@ export const TableCheckpointSubmissions: FC<Props> = (props: Props) => { | |
| ? undefined | ||
| : data.virusScan | ||
| const failedScan = normalizedVirusScan === false | ||
| const isRestrictedForRow = isRestrictedBase || failedScan | ||
| const tooltipMessage = failedScan | ||
| const isDownloadDisabled = ( | ||
| !canViewSubmissions && String(data.memberId) !== String(loginUserInfo?.userId) | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. [💡 |
||
| ) | ||
| const isRestrictedForRow = isRestrictedBase || failedScan || isDownloadDisabled | ||
| let tooltipMessage = failedScan | ||
| ? 'Submission failed virus scan' | ||
| : (getRestrictionMessageForMember(data.memberId) ?? restrictionMessage) | ||
|
|
||
| if (isDownloadDisabled) { | ||
| tooltipMessage = SUBMISSION_DOWNLOAD_RESTRICTION_MESSAGE | ||
| } | ||
|
|
||
| const isButtonDisabled = Boolean( | ||
| isDownloading[data.submissionId] | ||
| || isRestrictedForRow, | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
[⚠️
correctness]The use of
role.toLowerCase()assumes that all roles are case-insensitive. IfUserRole.talentManageror any role inADMIN_ROLESis case-sensitive, this could lead to incorrect behavior. Consider ensuring that all roles are consistently cased or explicitly handle case sensitivity.