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

Add image insertion support to codepress #89

Merged
merged 4 commits into from
Mar 12, 2020
Merged
Show file tree
Hide file tree
Changes from 3 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
46 changes: 46 additions & 0 deletions packages/client/codepress/src/app.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import * as fs from "fs";
import morgan from "morgan";
import * as path from "path";
import { promisify } from "util";
import fileUpload from "express-fileupload";

import { Course, ContentUtilityClass } from "@pairwise/common";

Expand Down Expand Up @@ -109,6 +110,43 @@ const app = express();
app.use(morgan("dev"));
app.use(cors());
app.use(bodyParser.json({ limit: "10mb" }));
app.use(
fileUpload({
createParentPath: true,
}),
);

app.post("/assets/:resourceId", (req, res, next) => {
const { resourceId } = req.params;
if (!resourceId || !resourceId.length) {
const err = new Error("No resourceId found for upload request");
next(err);
return;
}

const relDir = `assets/${req.params.resourceId}`;
const absDir = path.resolve(__dirname, "../../public", relDir);
// We only care about one file, and this just makes the types pass
const file = Array.isArray(req.files.asset)
? req.files.asset[0]
: req.files.asset;
const filename = `${file.md5}_${file.name}`;
const filepath = path.join(absDir, filename);

console.log(`[UPLOAD] saving file for ${req.params.resourceId} at `);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this supposed to log the filename, e.g. at ...? ?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah... Yes it is 😅

file.mv(filepath, err => {
if (err) {
next(err);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would this still result in res.send getting called later on line 142?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh good call. I don't think so, but even if not it's not obvious so I'll add an early return

}

res.send({
status: "OK",
data: {
filepath: path.join("/", relDir, filename),
},
});
});
});

app.get("/courses", (_, res) => {
api.courses.getAll().then(courses =>
Expand Down Expand Up @@ -171,4 +209,12 @@ app.get("/", (req, res) => {
});
});

app.use((err, _, res, __) => {
res.status(500).send({
status: "Error",
data: null,
error: err.message,
});
});

export default app;
2 changes: 2 additions & 0 deletions packages/client/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@
"@monaco-editor/react": "^2.3.0",
"@sentry/browser": "^5.12.4",
"@types/classnames": "^2.2.9",
"@types/express-fileupload": "^1.1.2",
"@types/getenv": "^1.0.0",
"@types/jest": "25.1.1",
"@types/lunr": "^2.3.2",
Expand All @@ -59,6 +60,7 @@
"concurrently": "^5.0.2",
"console-feed": "^2.8.10",
"debug": "^4.1.1",
"express-fileupload": "^1.1.6",
"getenv": "^1.0.0",
"history": "4.10.1",
"husky": "^3.1.0",
Expand Down
22 changes: 22 additions & 0 deletions packages/client/public/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,28 @@
To begin the development, run `npm start` or `yarn start`.
To create a production bundle, use `npm run build` or `yarn build`.
-->
<% if (process.env.REACT_APP_CODEPRESS === "true") { %>
<!--
Live Reload was causing issues for us in codepress. Namely it was
occasionally reloading before we saved and it would reload on image
upload, which would prevent saving.
-->
<script>
{
var WS = window.WebSocket;
function DevWebSocket(s) {
if (s === "ws:localhost:3000/sockjs-node") {
console.info("[CODEPRESS NOTICE] Live Reload Has Been Disabled");
return {};
} else {
// Pass through other usage of sockets
return new WS(s);
}
}
window.WebSocket = DevWebSocket;
iansinnott marked this conversation as resolved.
Show resolved Hide resolved
}
</script>
<% } %>
<script async src="https://js.stripe.com/v3/"></script>
</body>
</html>
28 changes: 28 additions & 0 deletions packages/client/src/components/ContentEditor.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,28 @@ import { map } from "rxjs/operators";
import { Editor } from "slate-react";
import { Leaf, Selection } from "slate";
import { List } from "immutable";
import { CODEPRESS_HOST, CODEPRESS } from "tools/client-env";

const RichMarkdownEditor = React.lazy(() => import("rich-markdown-editor"));

const uploadFile = (file: File, resourceId: string): Promise<string> => {
const formData = new FormData();

formData.append("asset", file, file.name);

return fetch(`${CODEPRESS_HOST}/assets/${resourceId}`, {
method: "POST",
body: formData,
redirect: "follow",
})
.then(x => x.json())
.then(x => x.data.filepath)
.catch(err => {
console.warn("[ERR]", err);
toaster.error(`Could not upload\n${err.message}`);
});
};

// All adapted from the markdown shortcuts that ship with the lib by default:
// https://github.com/outline/rich-markdown-editor/blob/master/src/plugins/MarkdownShortcuts.js
const MarkdownShortcuts = (): SlatePlugin => {
Expand Down Expand Up @@ -294,6 +313,13 @@ class ContentEditor extends React.Component<Props> {
.toPromise();
};

handleFileUpload = (file: File): Promise<string> => {
if (!this.props.challengeId) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would it make sense to move the error checking to the uploadFile method?

Not a big deal if it stays here.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah that would work too. Will update.

return Promise.reject(new Error("No challenge ID provided for upload"));
}
return uploadFile(file, this.props.challengeId);
};

render() {
const { history, plugins = [], ...props } = this.props;
return (
Expand All @@ -302,6 +328,7 @@ class ContentEditor extends React.Component<Props> {
plugins={[...plugins, markdownShortcuts]}
theme={editorTheme}
onSearchLink={this.getSearchLinks}
uploadImage={this.handleFileUpload}
onShowToast={message => {
toaster.toast.show({
message,
Expand Down Expand Up @@ -528,6 +555,7 @@ const EditorExternalStyles = styled.div`

const mapStateToProps = (state: ReduxStoreState) => ({
searchResults: Modules.selectors.challenges.getSearchResults(state),
challengeId: Modules.selectors.challenges.getCurrentChallengeId(state),
});

const dispatchProps = {
Expand Down
28 changes: 28 additions & 0 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -4046,6 +4046,13 @@
resolved "https://registry.yarnpkg.com/@types/events/-/events-3.0.0.tgz#2862f3f58a9a7f7c3e78d79f130dd4d71c25c2a7"
integrity sha512-EaObqwIvayI5a8dCzhFrjKzVwKLxjoG9T6Ppd5CEo07LRKfQ8Yokw54r5+Wq7FaBQ+yXRvQAYPrHwya1/UFt9g==

"@types/express-fileupload@^1.1.2":
version "1.1.2"
resolved "https://registry.yarnpkg.com/@types/express-fileupload/-/express-fileupload-1.1.2.tgz#3cc420abd0614b71cc7f2743c9d0b70182025922"
integrity sha512-a2rhTcnF1NBphmp6/fKGW+udO0yYafUi6oDxYoutB6L5Hd9qBvlE0by4CB2mqTzXdp0qz+56Zt9SHOGN2TGhBQ==
dependencies:
"@types/express" "*"

"@types/express-serve-static-core@*":
version "4.17.1"
resolved "https://registry.yarnpkg.com/@types/express-serve-static-core/-/express-serve-static-core-4.17.1.tgz#82be64a77211b205641e0209096fd3afb62481d3"
Expand Down Expand Up @@ -6670,6 +6677,13 @@ busboy@^0.2.11:
dicer "0.2.5"
readable-stream "1.1.x"

busboy@^0.3.1:
version "0.3.1"
resolved "https://registry.yarnpkg.com/busboy/-/busboy-0.3.1.tgz#170899274c5bf38aae27d5c62b71268cd585fd1b"
integrity sha512-y7tTxhGKXcyBxRKAni+awqx8uqaJKrSFSNFSeRG5CsWNdmy2BIK+6VGWEW7TZnIO/533mtMEA4rOevQV815YJw==
dependencies:
dicer "0.3.0"

byline@^5.0.0:
version "5.0.0"
resolved "https://registry.yarnpkg.com/byline/-/byline-5.0.0.tgz#741c5216468eadc457b03410118ad77de8c1ddb1"
Expand Down Expand Up @@ -8908,6 +8922,13 @@ dicer@0.2.5:
readable-stream "1.1.x"
streamsearch "0.1.2"

dicer@0.3.0:
version "0.3.0"
resolved "https://registry.yarnpkg.com/dicer/-/dicer-0.3.0.tgz#eacd98b3bfbf92e8ab5c2fdb71aaac44bb06b872"
integrity sha512-MdceRRWqltEG2dZqO769g27N/3PXfcKl04VhYnBlo2YhH7zPi88VebsjTKclaOyiuMaGU72hTfw3VkUitGcVCA==
dependencies:
streamsearch "0.1.2"

diff-sequences@^24.9.0:
version "24.9.0"
resolved "https://registry.yarnpkg.com/diff-sequences/-/diff-sequences-24.9.0.tgz#5715d6244e2aa65f48bba0bc972db0b0b11e95b5"
Expand Down Expand Up @@ -10073,6 +10094,13 @@ expect@^24.9.0:
jest-message-util "^24.9.0"
jest-regex-util "^24.9.0"

express-fileupload@^1.1.6:
version "1.1.6"
resolved "https://registry.yarnpkg.com/express-fileupload/-/express-fileupload-1.1.6.tgz#0ac2659ad8c1128c92c8580fd6e15b8b15343db0"
integrity sha512-w24zPWT8DkoIxSVkbxYPo9hkTiLpCQQzNsLRTCnecBhfbYv+IkIC5uLw2MIUAxBZ+7UMmXPjGxlhzUXo4RcbZw==
dependencies:
busboy "^0.3.1"

express-graphql@^0.9.0:
version "0.9.0"
resolved "https://registry.yarnpkg.com/express-graphql/-/express-graphql-0.9.0.tgz#00fd8552f866bac5c9a4612b2c4c82076107b3c2"
Expand Down