Skip to content

Commit 6a11585

Browse files
Martin Kruliskrulis-martin
authored andcommitted
Allowing solution files to be always downloaded in ZIP archive. Changing name of that ZIP file to include name of the author.
1 parent 2ba7e8a commit 6a11585

File tree

7 files changed

+55
-30
lines changed

7 files changed

+55
-30
lines changed

src/components/ReferenceSolutions/ReferenceSolutionDetail/ReferenceSolutionDetail.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -139,9 +139,9 @@ class ReferenceSolutionDetail extends Component {
139139
</a>
140140
</Col>
141141
))}
142-
{files.length > 1 && (
142+
{files.length > 0 && (
143143
<Col lg={6} md={12}>
144-
<DownloadSolutionArchiveContainer solutionId={id} isReference={true} />
144+
<DownloadSolutionArchiveContainer solutionId={id} submittedBy={submittedBy} isReference={true} />
145145
</Col>
146146
)}
147147
</Row>

src/components/Solutions/SolutionDetail/SolutionDetail.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -130,9 +130,9 @@ class SolutionDetail extends Component {
130130
</a>
131131
</Col>
132132
))}
133-
{files.length > 1 && (
133+
{files.length > 0 && (
134134
<Col lg={6} md={12}>
135-
<DownloadSolutionArchiveContainer solutionId={id} />
135+
<DownloadSolutionArchiveContainer solutionId={id} submittedBy={submittedBy} />
136136
</Col>
137137
)}
138138
</Row>
Lines changed: 43 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,54 +1,76 @@
11
import React from 'react';
22
import PropTypes from 'prop-types';
3+
import ImmutablePropTypes from 'react-immutable-proptypes';
34
import { FormattedMessage } from 'react-intl';
45
import { connect } from 'react-redux';
56

67
import { downloadSolutionArchive } from '../../redux/modules/submissionEvaluations';
78
import { downloadSolutionArchive as downloadRefSolutionArchive } from '../../redux/modules/referenceSolutionEvaluations';
9+
import { getUser } from '../../redux/selectors/users';
810
import SolutionArchiveInfoBox from '../../components/Solutions/SolutionArchiveInfoBox';
911
import Button from '../../components/widgets/TheButton';
1012
import Icon from '../../components/icons';
13+
import ResourceRenderer from '../../components/helpers/ResourceRenderer';
14+
import { toPlainAscii } from '../../helpers/common';
1115

12-
const DownloadResultArchiveContainer = ({
16+
const solutionArchiveFileName = (solutionId, user) => {
17+
const name = toPlainAscii(`${user.name.lastName}-${user.name.firstName}`);
18+
return `${name}_${solutionId}.zip`;
19+
};
20+
21+
const DownloadSolutionArchiveContainer = ({
1322
solutionId,
1423
downloadSolutionArchive,
1524
downloadRefSolutionArchive,
1625
isReference = false,
1726
simpleButton = false,
1827
variant = 'primary',
1928
size = null,
20-
}) =>
21-
simpleButton ? (
22-
<Button onClick={isReference ? downloadRefSolutionArchive : downloadSolutionArchive} variant={variant} size={size}>
23-
<Icon icon={['far', 'file-archive']} gapRight />
24-
<FormattedMessage id="app.solutionArchiveInfoBox.description" defaultMessage="All files in a ZIP archive" />
25-
</Button>
26-
) : (
27-
<a href="#" onClick={isReference ? downloadRefSolutionArchive : downloadSolutionArchive}>
28-
<SolutionArchiveInfoBox id={solutionId} />
29-
</a>
30-
);
29+
submittedByUser,
30+
}) => (
31+
<ResourceRenderer resource={submittedByUser}>
32+
{user =>
33+
simpleButton ? (
34+
<Button
35+
onClick={isReference ? downloadRefSolutionArchive(user) : downloadSolutionArchive(user)}
36+
variant={variant}
37+
size={size}>
38+
<Icon icon={['far', 'file-archive']} gapRight />
39+
<FormattedMessage id="app.solutionArchiveInfoBox.description" defaultMessage="All files in a ZIP archive" />
40+
</Button>
41+
) : (
42+
<a href="#" onClick={isReference ? downloadRefSolutionArchive(user) : downloadSolutionArchive(user)}>
43+
<SolutionArchiveInfoBox id={solutionId} />
44+
</a>
45+
)
46+
}
47+
</ResourceRenderer>
48+
);
3149

32-
DownloadResultArchiveContainer.propTypes = {
50+
DownloadSolutionArchiveContainer.propTypes = {
3351
solutionId: PropTypes.string.isRequired,
34-
downloadSolutionArchive: PropTypes.func.isRequired,
35-
downloadRefSolutionArchive: PropTypes.func.isRequired,
52+
submittedBy: PropTypes.string.isRequired,
3653
isReference: PropTypes.bool,
3754
simpleButton: PropTypes.bool,
3855
variant: PropTypes.string,
3956
size: PropTypes.string,
57+
submittedByUser: ImmutablePropTypes.map,
58+
downloadSolutionArchive: PropTypes.func.isRequired,
59+
downloadRefSolutionArchive: PropTypes.func.isRequired,
4060
};
4161

4262
export default connect(
43-
(state, props) => ({}),
63+
(state, { submittedBy }) => ({
64+
submittedByUser: getUser(submittedBy)(state),
65+
}),
4466
(dispatch, { solutionId }) => ({
45-
downloadSolutionArchive: e => {
67+
downloadSolutionArchive: user => e => {
4668
e.preventDefault();
47-
dispatch(downloadSolutionArchive(solutionId));
69+
dispatch(downloadSolutionArchive(solutionId, solutionArchiveFileName(solutionId, user)));
4870
},
49-
downloadRefSolutionArchive: e => {
71+
downloadRefSolutionArchive: user => e => {
5072
e.preventDefault();
51-
dispatch(downloadRefSolutionArchive(solutionId));
73+
dispatch(downloadRefSolutionArchive(solutionId, solutionArchiveFileName(solutionId, user)));
5274
},
5375
})
54-
)(DownloadResultArchiveContainer);
76+
)(DownloadSolutionArchiveContainer);

src/containers/SourceCodeViewerContainer/SourceCodeViewerContainer.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -90,13 +90,14 @@ class SourceCodeViewerContainer extends Component {
9090
<FormattedMessage id="app.sourceCodeViewer.downloadButton" defaultMessage="Download file" />
9191
</Button>
9292

93-
{files.length > 1 && (
93+
{files.length > 0 && (
9494
<DownloadSolutionArchiveContainer
9595
solutionId={solutionId}
9696
simpleButton
9797
size="sm"
9898
variant="outline-secondary"
9999
isReference={isReference}
100+
submittedBy={submittedBy}
100101
/>
101102
)}
102103

src/helpers/common.js

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,8 +55,10 @@ export const safeSet = (obj, path, value) => {
5555
};
5656

5757
/*
58-
* IDs Management
58+
* String and related (ID management) functions
5959
*/
60+
export const toPlainAscii = str => str && str.normalize('NFD').replace(/[^-_a-zA-Z0-9.()[\] ]/g, '');
61+
6062
export const encodeId = id => {
6163
return 'BID' + btoa(id);
6264
};

src/pages/AssignmentStats/AssignmentStats.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ import { isReady, getJsData, getId } from '../../redux/helpers/resourceManager';
5252

5353
import { getLocalizedName } from '../../helpers/localizedData';
5454
import withLinks from '../../helpers/withLinks';
55-
import { safeGet, identity, arrayToObject } from '../../helpers/common';
55+
import { safeGet, identity, arrayToObject, toPlainAscii } from '../../helpers/common';
5656

5757
const prepareTableColumnDescriptors = defaultMemoize((loggedUserId, assignmentId, groupId, locale, links) => {
5858
const { SOLUTION_DETAIL_URI_FACTORY } = links;
@@ -255,7 +255,7 @@ class AssignmentStats extends Component {
255255
const name =
256256
assignment &&
257257
safeGet(assignment, ['localizedTexts', ({ locale }) => locale === pageLocale, 'name'], assignment.name);
258-
const safeName = name && name.normalize('NFD').replace(/[^-_a-zA-Z0-9.()[\] ]/g, '');
258+
const safeName = toPlainAscii(name);
259259
return `${safeName || assignmentId}.zip`;
260260
};
261261

src/redux/helpers/api/download.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import { createApiAction } from '../../middleware/apiMiddleware';
22
import { addNotification } from '../../modules/notifications';
33

4-
const trivialFileNameSelector = (id, state) => id;
4+
const trivialFileNameSelector = (id, _) => id;
55

66
export const downloadHelper =
77
({ fetch, endpoint, actionType, fileNameSelector = trivialFileNameSelector, contentType }) =>

0 commit comments

Comments
 (0)