~emersion/public-inbox

gamja: Add support for uploading files with FILEHOST v1 PROPOSED

Alex McGrath: 1
 Add support for uploading files with FILEHOST

 3 files changed, 67 insertions(+), 3 deletions(-)
#1148591 .build.yml success
Export patchset (mbox)
How do I use this?

Copy & paste the following snippet into your terminal to import this patchset into git:

curl -s https://lists.sr.ht/~emersion/public-inbox/patches/49426/mbox | git am -3
Learn more about email & git

[PATCH gamja] Add support for uploading files with FILEHOST Export this patch

---
 components/app.js           | 41 +++++++++++++++++++++++++++++++++++++
 components/buffer-header.js | 25 +++++++++++++++++++---
 lib/irc.js                  |  4 ++++
 3 files changed, 67 insertions(+), 3 deletions(-)

diff --git a/components/app.js b/components/app.js
index a27c915..db3d713 100644
--- a/components/app.js
+++ b/components/app.js
@@ -226,6 +226,7 @@ export default class App extends Component {
		this.handleVerifyClick = this.handleVerifyClick.bind(this);
		this.handleVerifySubmit = this.handleVerifySubmit.bind(this);
		this.handleOpenSettingsClick = this.handleOpenSettingsClick.bind(this);
		this.handleUploadClick = this.handleUploadClick.bind(this);
		this.handleSettingsChange = this.handleSettingsChange.bind(this);
		this.handleSettingsDisconnect = this.handleSettingsDisconnect.bind(this);
		this.handleSwitchSubmit = this.handleSwitchSubmit.bind(this);
@@ -1904,6 +1905,43 @@ export default class App extends Component {
		this.openDialog("settings", { showProtocolHandler });
	}

	async handleUploadClick(event) {
		const file = event.target.files && event.target.files[0];
		if (!file) {
			return;
		}
		event.target.value = null;
		let serverID = State.getActiveServerID(this.state);
		let client = this.clients.get(serverID);
		const url = client.isupport.filehost();
		if (!url) {
			return;
		}
		let authHeaderVal;
		if (this.config.server.auth === "oauth2") {
			authHeaderVal = "Bearer " + this.state.connectParams.saslOauthBearer.token;
		} else {
			authHeaderVal =  "Basic " + btoa(this.state.connectParams.saslPlain.username
											 + ":" +
											 this.state.connectParams.saslPlain.password);
		}
		let response = await fetch(url, {
			method: "POST",
			body: file,
			headers: {
				"Authorization": authHeaderVal,
				"Content-Disposition": "attachment; filename=" + file.name
			}
		});
		let location = response.headers.get("location");
		if (location) {
			let fileUrl = new URL(url)
			fileUrl.pathname = location
			this.composer.current.setState({text: fileUrl.toString()});
			this.composer.current.focus()
		}
	}

	handleSettingsChange(settings) {
		store.settings.put(settings);
		this.setState({ settings });
@@ -1990,6 +2028,8 @@ export default class App extends Component {
				activeUser = activeServer.users.get(activeBuffer.name);
			}

			let client = this.clients.get(activeBuffer.server);

			bufferHeader = html`
				<section id="buffer-header">
					<${BufferHeader}
@@ -2004,6 +2044,7 @@ export default class App extends Component {
						onAddNetwork=${this.handleAddNetworkClick}
						onManageNetwork=${() => this.handleManageNetworkClick(activeBuffer.server)}
						onOpenSettings=${this.handleOpenSettingsClick}
						onUpload=${client.isupport.filehost() ? this.handleUploadClick : null}
					/>
				</section>
			`;
diff --git a/components/buffer-header.js b/components/buffer-header.js
index 5b2b56a..01ced0f 100644
--- a/components/buffer-header.js
+++ b/components/buffer-header.js
@@ -1,4 +1,4 @@
import { html, Component } from "../lib/index.js";
import { html, Component, createRef } from "../lib/index.js";
import linkify from "../lib/linkify.js";
import { strip as stripANSI } from "../lib/ansi.js";
import { BufferType, ServerStatus, getServerName } from "../state.js";
@@ -26,6 +26,8 @@ export default function BufferHeader(props) {
		fullyConnected = fullyConnected && props.bouncerNetwork.state === "connected";
	}

	let uploadRef = createRef();

	let description = null, actions = [];
	switch (props.buffer.type) {
	case BufferType.SERVER:
@@ -124,6 +126,14 @@ export default function BufferHeader(props) {
			description = linkify(stripANSI(props.buffer.topic), props.onChannelClick);
		}
		if (props.buffer.joined) {
			if (props.onUpload) {
				actions.push(html`
					<input type="file" accept="*" style="display: none;" ref=${uploadRef} onChange=${props.onUpload}></input>
					<button onClick=${() => {uploadRef.current.click();}}>
						Upload
					</button>
				`);
			}
			actions.push(html`
				<button
					key="part"
@@ -203,13 +213,22 @@ export default function BufferHeader(props) {
			description = html`<${NickStatus} status=${status}/> ${realname} ${details}`;
		}

		actions = html`
		if (props.onUpload) {
			actions.push(html`
					<input type="file" accept="*" style="display: none;" ref=${uploadRef} onChange=${props.onUpload}></input>
					<button onClick=${() => {uploadRef.current.click();}}>
						Upload
					</button>
				`);
		}

		actions.push(html`
			<button
				key="close"
				class="danger"
				onClick=${props.onClose}
			>Close</button>
		`;
		`);
		break;
	}

diff --git a/lib/irc.js b/lib/irc.js
index 86fa65a..3fa81e0 100644
--- a/lib/irc.js
+++ b/lib/irc.js
@@ -500,6 +500,10 @@ export class Isupport {
		}
		return parseInt(this.raw.get("LINELEN"), 10);
	}

	filehost() {
		return this.raw.get("SOJU.IM/FILEHOST");
	}
}

export function getMaxPrivmsgLen(isupport, nick, target) {
-- 
2.43.1
gamja/patches/.build.yml: SUCCESS in 24s

[Add support for uploading files with FILEHOST][0] from [Alex McGrath][1]

[0]: https://lists.sr.ht/~emersion/public-inbox/patches/49426
[1]: mailto:amk@amk.ie

✓ #1148591 SUCCESS gamja/patches/.build.yml https://builds.sr.ht/~emersion/job/1148591
Thanks for the patch! I haven't looked closely at the code, but as a more
general comment: I think I'd like to support this feature, but I'm not
sure what's the best way to expose it without being intrusive. I'd say
that a prominent button in the top bar is a bit too intrusive. I don't
have great alternative ideas currently.

I also wonder how to give feedback to the user that an upload is in
progress. Maybe we can keep this for later.

Additionally, would be nicer to not completely throw away any previous
text in the input field -- maybe append the URL with a space separator
if it's not empty.
I've merged part of this patch in 87e88ccccaf3, but only handling paste
events with files for now. (Drag-and-drop would be easy to add.)