Skip to content
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

Handle protected expense attachments #10824

Merged
merged 4 commits into from
Jan 6, 2025
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
20 changes: 6 additions & 14 deletions components/FilesViewerModal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,6 @@ import { FormattedMessage, useIntl } from 'react-intl';
import styled, { css } from 'styled-components';

import useKeyBoardShortcut, { ARROW_LEFT_KEY, ARROW_RIGHT_KEY } from '../lib/hooks/useKeyboardKey';
import { imagePreview } from '../lib/image-utils';
import { getFileExtensionFromUrl } from '../lib/url-helpers';

import { Dialog, DialogOverlay } from './ui/Dialog';
import { Box, Flex } from './Grid';
Expand Down Expand Up @@ -128,7 +126,7 @@ type FilesViewerModalProps = {
files?: {
url: string;
name?: string;
info?: { width: number };
info?: { width: number; type: string };
}[];
openFileUrl?: string;
allowOutsideInteraction?: boolean;
Expand Down Expand Up @@ -167,30 +165,24 @@ export default function FilesViewerModal({
useKeyBoardShortcut({ callback: onArrowLeft, keyMatch: ARROW_LEFT_KEY });

const selectedItem = files?.length ? files?.[selectedIndex] : null;
const selectedItemContentType = selectedItem?.info?.type;

const nbFiles = files?.length || 0;
const hasMultipleFiles = nbFiles > 1;
const contentWrapperRef = React.useRef(null);

const renderFile = (
{ url, info, name }: { url: string; name?: string; info?: { width: number } },
contentWrapperRef,
) => {
const renderFile = ({ url, name }: { url: string; name?: string; info?: { width: number } }, contentWrapperRef) => {
let content = null;
const fileExtension = getFileExtensionFromUrl(url);

const isText = ['csv', 'txt'].includes(fileExtension);
const isPdf = fileExtension === 'pdf';
const isText = ['text/csv', 'text/plain'].includes(selectedItemContentType);
const isPdf = 'application/pdf' === selectedItemContentType;

if (isText) {
content = <UploadedFilePreview size={288} url={url} alt={name} showFileName fileName={name} color="black.200" />;
} else if (isPdf) {
content = <PDFViewer pdfUrl={url} contentWrapperRef={contentWrapperRef} />;
} else {
const { width: imageWidth } = info || {};
const maxWidth = 1200;
const resizeWidth = Math.min(maxWidth, imageWidth ?? maxWidth);
content = <StyledImg src={imagePreview(url, null, { width: resizeWidth })} alt={name} />;
content = <StyledImg src={url} alt={name} />;
}

return <Content>{content}</Content>;
Expand Down
7 changes: 3 additions & 4 deletions components/expenses/ExpenseItemForm.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,15 +7,14 @@ import { escape, get, isEmpty, omit, pick, unescape } from 'lodash';
import Lottie from 'lottie-react';
import { AlertTriangle } from 'lucide-react';
import { defineMessages, FormattedMessage, useIntl } from 'react-intl';
import { isURL } from 'validator';

import expenseTypes from '../../lib/constants/expenseTypes';
import { formatValueAsCurrency } from '../../lib/currency-utils';
import { createError, ERROR } from '../../lib/errors';
import { standardizeExpenseItemIncurredAt } from '../../lib/expenses';
import { formatFormErrorMessage, requireFields } from '../../lib/form-utils';
import { API_V2_CONTEXT } from '../../lib/graphql/helpers';
import { cn } from '../../lib/utils';
import { cn, isValidUrl } from '../../lib/utils';
import { attachmentDropzoneParams } from './lib/attachments';
import { expenseItemsMustHaveFiles } from './lib/items';
import { updateExpenseFormWithUploadResult } from './lib/ocr';
Expand Down Expand Up @@ -92,7 +91,7 @@ export const validateExpenseItem = (expense, item) => {
if (expenseItemsMustHaveFiles(expense.type)) {
if (!item.url) {
errors.url = createError(ERROR.FORM_FIELD_REQUIRED);
} else if (!isURL(item.url)) {
} else if (!isValidUrl(item.url)) {
errors.url = createError(ERROR.FORM_FIELD_PATTERN);
} else if (item.__isUploading) {
errors.url = createError(ERROR.FORM_FILE_UPLOADING);
Expand Down Expand Up @@ -328,7 +327,7 @@ const ExpenseItemForm = ({
{requireFile && (
<Field name={getFieldName('url')}>
{({ field, meta }) => {
const hasValidUrl = field.value && isURL(field.value);
const hasValidUrl = field.value && isValidUrl(field.value);
return (
<StyledInputField
flex="0 0 112px"
Expand Down
4 changes: 4 additions & 0 deletions components/expenses/graphql/fragments.ts
Original file line number Diff line number Diff line change
Expand Up @@ -321,6 +321,7 @@ export const expensePageExpenseFieldsFragment = gql`
url
file {
id
type
... on ImageFileInfo {
width
}
Expand All @@ -338,6 +339,7 @@ export const expensePageExpenseFieldsFragment = gql`
name
info {
id
type
name
size
... on ImageFileInfo {
Expand Down Expand Up @@ -805,6 +807,7 @@ export const expensesListAdminFieldsFragment = gql`
amount
file {
id
type
... on ImageFileInfo {
width
}
Expand All @@ -821,6 +824,7 @@ export const expensesListAdminFieldsFragment = gql`
name
info {
id
type
... on ImageFileInfo {
width
}
Expand Down
11 changes: 11 additions & 0 deletions lib/image-utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,17 @@ function resizeImage(imageUrl, { width, height, query, baseUrl }) {
if (!query && imageUrl.match(/\.svg$/)) {
return imageUrl;
} // if we don't need to transform the image, no need to proxy it.

try {
const url = new URL(imageUrl);
if (url.origin === window.location.origin && /^\/api\/files\//.test(url.pathname)) {
url.searchParams.append('thumbnail', '');
return url.toString();
}
} catch (err) {
return null;
}

let queryurl = '';
if (query) {
queryurl = encodeURIComponent(query);
Expand Down
Loading