diff --git a/cli/defaults/siteConfig.json b/cli/defaults/siteConfig.json
index 15243fce..67e4a79f 100644
--- a/cli/defaults/siteConfig.json
+++ b/cli/defaults/siteConfig.json
@@ -23,7 +23,7 @@
"publishing": {
"primaryClaimAddress": null,
"uploadDirectory": "/home/lbry/Uploads",
- "lbrynetHome": "/home/lbry",
+ "lbrynetHome": "/CURRENTLYUNUSED",
"thumbnailChannel": null,
"thumbnailChannelId": null,
"additionalClaimAddresses": [],
@@ -36,6 +36,17 @@
"publishingChannelWhitelist": [],
"channelClaimBidAmount": "0.1",
"fileClaimBidAmount": "0.01",
+ "fileSizeLimits": {
+ "image": 50000000,
+ "video": 50000000,
+ "audio": 50000000,
+ "text": 50000000,
+ "model": 50000000,
+ "application": 50000000,
+ "customByContentType": {
+ "application/octet-stream": 50000000
+ }
+ },
"maxSizeImage": 10000000,
"maxSizeGif": 50000000,
"maxSizeVideo": 50000000
@@ -49,7 +60,19 @@
"publicDisallowedTypesMain": []
},
"customFileExtensions": {
- "application/example-type": "example"
+ "application/x-troff-man": ".man",
+ "application/x-troff-me": ".me",
+ "application/x-mif": ".mif",
+ "application/x-troff-ms": ".ms",
+ "application/x-troff": ".roff",
+ "application/x-python-code": ".pyc",
+ "text/x-python": ".py",
+ "application/x-pn-realaudio": ".ram",
+ "application/x-sgml": ".sgm",
+ "model/stl": ".stl",
+ "image/pict": ".pct",
+ "text/xul": ".xul",
+ "text/x-go": "go"
}
},
"startup": {
diff --git a/client/src/components/DropzonePreviewImage/index.jsx b/client/src/components/DropzonePreviewImage/index.jsx
index d62abaeb..5aa6f730 100644
--- a/client/src/components/DropzonePreviewImage/index.jsx
+++ b/client/src/components/DropzonePreviewImage/index.jsx
@@ -5,8 +5,9 @@ class PublishPreview extends React.Component {
constructor (props) {
super(props);
this.state = {
- imgSource : '',
- defaultThumbnail: '/assets/img/video_thumb_default.png',
+ imgSource : '',
+ defaultVideoThumbnail: '/assets/img/video_thumb_default.png',
+ defaultThumbnail : '/assets/img/Speech_Logo_Main@OG-02.jpg',
};
}
componentDidMount () {
@@ -37,12 +38,13 @@ class PublishPreview extends React.Component {
};
}
setPreviewImageSource (file) {
- if (file.type !== 'video/mp4') {
+ if (this.props.thumbnail) {
+ this.setPreviewImageSourceFromFile(this.props.thumbnail);
+ } else if (file.type.substr(0, file.type.indexOf('/')) === 'image'){
this.setPreviewImageSourceFromFile(file);
+ } else if (file.type === 'video'){
+ this.setState({imgSource: this.state.defaultVideoThumbnail});
} else {
- if (this.props.thumbnail) {
- this.setPreviewImageSourceFromFile(this.props.thumbnail);
- }
this.setState({imgSource: this.state.defaultThumbnail});
}
}
diff --git a/client/src/components/FileViewer/index.jsx b/client/src/components/FileViewer/index.jsx
index 0d3d4866..8cd0172e 100644
--- a/client/src/components/FileViewer/index.jsx
+++ b/client/src/components/FileViewer/index.jsx
@@ -1,6 +1,5 @@
import React from 'react';
import ReactMarkdown from 'react-markdown';
-// TODO: get markdown settings from siteConfig
class FileViewer extends React.Component {
diff --git a/client/src/containers/AssetInfo/view.jsx b/client/src/containers/AssetInfo/view.jsx
index c1e6154d..70d63298 100644
--- a/client/src/containers/AssetInfo/view.jsx
+++ b/client/src/containers/AssetInfo/view.jsx
@@ -22,7 +22,6 @@ class AssetInfo extends React.Component {
const canonicalUrl = createCanonicalLink({ asset: { ...claimData, shortId: asset.shortId }});
const assetCanonicalUrl = `${host}${canonicalUrl}`;
// Todo Issue #882 centralize all this media type detection
- // Todo get markdown settings from siteConfig
const embedable = contentType.split('/')[0] === 'image' || contentType === 'video/mp4';
let channelCanonicalUrl;
@@ -38,7 +37,7 @@ class AssetInfo extends React.Component {
{ description && (
}
- content={
}
+ content={
}
/>
)}
{editable && (
diff --git a/client/src/containers/Dropzone/view.jsx b/client/src/containers/Dropzone/view.jsx
index a4a6d00e..cba685f9 100644
--- a/client/src/containers/Dropzone/view.jsx
+++ b/client/src/containers/Dropzone/view.jsx
@@ -1,13 +1,13 @@
import React from 'react';
-import { validateFile } from '../../utils/file';
import Memeify from '@components/Memeify';
import DropzonePreviewImage from '@components/DropzonePreviewImage';
import DropzoneDropItDisplay from '@components/DropzoneDropItDisplay';
import DropzoneInstructionsDisplay from '@components/DropzoneInstructionsDisplay';
+import validateFileForPublish from '@globalutils/validateFileForPublish';
-import { library } from '@fortawesome/fontawesome-svg-core'
-import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'
+import { library } from '@fortawesome/fontawesome-svg-core';
+import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
import { faEdit } from '@fortawesome/free-solid-svg-icons';
const isFacebook = (() => {
@@ -29,7 +29,7 @@ class Dropzone extends React.Component {
memeify : false,
};
- if(props.file) {
+ if (props.file) {
// No side effects allowed with `getDerivedStateFromProps`, so
// we must use `componentDidUpdate` and `constructor` routines.
// Note: `FileReader` has an `onloadend` side-effect
@@ -133,7 +133,7 @@ class Dropzone extends React.Component {
chooseFile (file) {
if (file) {
try {
- validateFile(file); // validate the file's name, type, and size
+ validateFileForPublish(file); // validate the file's name, type, and size
} catch (error) {
return this.props.setFileError(error.message);
}
diff --git a/client/src/utils/createAssetMetaTags.js b/client/src/utils/createAssetMetaTags.js
index 70bead44..e2a0b5ef 100644
--- a/client/src/utils/createAssetMetaTags.js
+++ b/client/src/utils/createAssetMetaTags.js
@@ -47,8 +47,6 @@ const createAssetMetaTags = asset => {
const ogThumbnailContentType = determineContentTypeFromExtension(claimData.thumbnail);
const ogThumbnail = claimData.thumbnail || defaultThumbnail;
- console.log('asset.claimData', asset.claimData);
-
// {property: 'og:title'] = ogTitle},
const metaTags = {
'og:title': ogTitle,
diff --git a/server/chainquery/models/ClaimModel.js b/server/chainquery/models/ClaimModel.js
index 022656f9..4fcc1af0 100644
--- a/server/chainquery/models/ClaimModel.js
+++ b/server/chainquery/models/ClaimModel.js
@@ -1,9 +1,17 @@
const logger = require('winston');
const mime = require('mime-types');
+const {
+ serving: { customFileExtensions },
+} = require('@config/siteConfig');
const getterMethods = {
generated_extension() {
- return mime.extension(this.content_type) ? mime.extension(this.content_type) : 'jpg';
+ logger.info('trying to generate extension', this.content_type);
+ if (customFileExtensions.hasOwnProperty(this.content_type)) {
+ return customFileExtensions[this.content_type];
+ } else {
+ return mime.extension(this.content_type) ? mime.extension(this.content_type) : 'jpg';
+ }
},
};
diff --git a/server/controllers/api/claim/publish/parsePublishApiRequestFiles.js b/server/controllers/api/claim/publish/parsePublishApiRequestFiles.js
index 3fdcdfc3..6979740e 100644
--- a/server/controllers/api/claim/publish/parsePublishApiRequestFiles.js
+++ b/server/controllers/api/claim/publish/parsePublishApiRequestFiles.js
@@ -1,5 +1,6 @@
const path = require('path');
const validateFileTypeAndSize = require('./validateFileTypeAndSize.js');
+const validateFileForPublish = require('./validateFileForPublish.js');
const parsePublishApiRequestFiles = ({ file, thumbnail }, isUpdate) => {
// make sure a file was provided
@@ -40,7 +41,7 @@ const parsePublishApiRequestFiles = ({ file, thumbnail }, isUpdate) => {
}
// validate the file
- if (file) validateFileTypeAndSize(file);
+ if (file) validateFileForPublish(file);
// return results
const obj = {
fileName: file.name,
diff --git a/server/controllers/api/claim/publish/validateFileForPublish.js b/server/controllers/api/claim/publish/validateFileForPublish.js
new file mode 100644
index 00000000..1047c048
--- /dev/null
+++ b/server/controllers/api/claim/publish/validateFileForPublish.js
@@ -0,0 +1,38 @@
+const logger = require('winston');
+
+const { publishing } = require('@config/siteConfig.json');
+
+const { fileSizeLimits } = publishing;
+
+const SIZE_MB = 1000000;
+
+const validateFileForPublish = file => {
+ let contentType = file.type;
+ let mediaType = contentType ? contentType.substr(0, contentType.indexOf('/')) : '';
+ let mediaTypeLimit = fileSizeLimits[mediaType] || false;
+ let customLimits = fileSizeLimits['customByContentType'];
+
+ if (!file) {
+ throw new Error('no file provided');
+ }
+
+ if (/'/.test(file.name)) {
+ throw new Error('apostrophes are not allowed in the file name');
+ }
+
+ if (Object.keys(customLimits).includes(contentType)) {
+ if (file.size > customLimits[contentType]) {
+ throw new Error(
+ `Sorry, type ${contentType} is limited to ${customLimits[contentType] / SIZE_MB} MB.`
+ );
+ }
+ }
+ if (mediaTypeLimit) {
+ if (file.size > mediaTypeLimit) {
+ throw new Error(`Sorry, type ${mediaType} is limited to ${mediaTypeLimit / SIZE_MB} MB.`);
+ }
+ }
+ return file;
+};
+
+module.exports = validateFileForPublish;
diff --git a/utils/validateFileForPublish.js b/utils/validateFileForPublish.js
new file mode 100644
index 00000000..ef129305
--- /dev/null
+++ b/utils/validateFileForPublish.js
@@ -0,0 +1,34 @@
+import { publishing } from '@config/siteConfig.json';
+
+const { fileSizeLimits } = publishing;
+
+const SIZE_MB = 1000000;
+
+export default function validateFileForPublish(file) {
+ let contentType = file.type;
+ let mediaType = contentType ? contentType.substr(0, contentType.indexOf('/')) : '';
+ let mediaTypeLimit = fileSizeLimits[mediaType] || false;
+ let customLimits = fileSizeLimits['customByContentType'];
+
+ if (!file) {
+ throw new Error('no file provided');
+ }
+
+ if (/'/.test(file.name)) {
+ throw new Error('apostrophes are not allowed in the file name');
+ }
+
+ if (Object.keys(customLimits).includes(contentType)) {
+ if (file.size > customLimits[contentType]) {
+ throw new Error(
+ `Sorry, type ${contentType} is limited to ${customLimits[contentType] / SIZE_MB} MB.`
+ );
+ }
+ }
+ if (mediaTypeLimit) {
+ if (file.size > mediaTypeLimit) {
+ throw new Error(`Sorry, type ${mediaType} is limited to ${mediaTypeLimit / SIZE_MB} MB.`);
+ }
+ }
+ return file;
+}