Local API: Support write requests

This commit is contained in:
Abe Jellinek 2026-05-12 13:48:04 -04:00
parent 7ea59414a8
commit f6a54610a6
7 changed files with 3082 additions and 56 deletions

View file

@ -485,24 +485,42 @@ Zotero_Preferences.Advanced = {
let checkbox = document.getElementById('zotero-prefpane-advanced-enable-local-api');
let availableMessage = document.getElementById('zotero-prefpane-advanced-local-api-available');
let authorizationsSection = document.getElementById('zotero-prefpane-advanced-local-api-write-authorizations');
let serverDisabledSection = document.getElementById('zotero-prefpane-advanced-server-disabled');
if (!serverEnabled) {
checkbox.disabled = true;
availableMessage.hidden = true;
authorizationsSection.hidden = true;
serverDisabledSection.hidden = false;
return;
}
checkbox.disabled = false;
availableMessage.hidden = !localAPIEnabled;
authorizationsSection.hidden = !localAPIEnabled;
serverDisabledSection.hidden = true;
document.l10n.setArgs(availableMessage, {
url: `http://localhost:${Zotero.Server.port}/api/`
});
if (localAPIEnabled) {
this.updateLocalAPIClearAuthorizationsButton();
}
},
async updateLocalAPIClearAuthorizationsButton() {
let clearButton = document.getElementById('zotero-prefpane-advanced-local-api-clear');
let count = await Zotero.Server.LocalAPI.getAuthorizationCount();
clearButton.disabled = count === 0;
},
async clearLocalAPIAuthorizations() {
await Zotero.Server.LocalAPI.clearAuthorizations();
await this.updateLocalAPIClearAuthorizationsButton();
},
enableServerForLocalAPI() {
Zotero.Prefs.set('httpServer.enabled', true);
Zotero.Utilities.Internal.quit(true);

View file

@ -49,6 +49,13 @@
>
<html:code class="local-api-url" data-l10n-name="url"/>
</label>
<hbox id="zotero-prefpane-advanced-local-api-write-authorizations" align="center" hidden="true">
<button
id="zotero-prefpane-advanced-local-api-clear"
data-l10n-id="preferences-advanced-local-api-clear-authorizations"
oncommand="Zotero_Preferences.Advanced.clearLocalAPIAuthorizations()"
/>
</hbox>
<hbox id="zotero-prefpane-advanced-server-disabled" align="center" hidden="true">
<label data-l10n-id="preferences-advanced-server-disabled"/>
<button

View file

@ -260,7 +260,7 @@ Zotero.Server.RequestHandler.prototype._bodyData = function () {
}
}
// handle envelope
this._processEndpoint("POST", data); // async
this._processEndpoint(this.requestMethod || "POST", data); // async
}
@ -367,16 +367,23 @@ Zotero.Server.RequestHandler.prototype.handleRequest = async function () {
else if (request.method == "GET") {
this._processEndpoint("GET", null); // async
}
else if (request.method == "POST") {
else if (request.method == "POST" || request.method == "PUT"
|| request.method == "PATCH" || request.method == "DELETE") {
const contentLengthRe = /^([0-9]+)$/;
this.requestMethod = request.method;
// parse content length
var m = contentLengthRe.exec(this.headers['content-length']);
if(!m) {
if (!m) {
// DELETE is allowed to have no body
if (request.method == "DELETE") {
this._processEndpoint("DELETE", null); // async
return;
}
this._requestFinished(this._generateResponse(400, "text/plain", "Content-length not provided\n"));
return;
}
this.bodyLength = parseInt(m[1]);
this._bodyData();
} else {
@ -420,7 +427,8 @@ Zotero.Server.RequestHandler.prototype._processEndpoint = async function (method
}
var data = null;
if (method === 'POST' && this.contentType) {
if ((method === 'POST' || method === 'PUT' || method === 'PATCH' || method === 'DELETE')
&& this.contentType) {
// check that endpoint supports contentType
var supportedDataTypes = endpoint.supportedDataTypes;
if (supportedDataTypes && supportedDataTypes != '*'

File diff suppressed because it is too large Load diff

View file

@ -77,6 +77,8 @@ preferences-citation-dialog-mode-library =
preferences-advanced-enable-local-api =
.label = Allow other applications on this computer to communicate with { -app-name }
preferences-advanced-local-api-available = Available at <code data-l10n-name="url">{ $url }</span>
preferences-advanced-local-api-clear-authorizations =
.label = Clear Write Authorizations
preferences-advanced-server-disabled = The { -app-name } HTTP server is disabled.
preferences-advanced-server-enable-and-restart =
.label = Enable and Restart

View file

@ -900,3 +900,9 @@ plugins-blocked-plugin =
.message = This plugin has been disabled by { -app-name }.
data-dir-unsupported-storage = This can happen if the { -app-name } data directory is in a cloud storage folder (OneDrive, Dropbox, etc.) or on a network share.
local-api-authorize-title = Local API Authorization
local-api-authorize-text = “{ $appName }”, an application running on your computer, wants to modify your { -app-name } library.
local-api-authorize-allow = Allow
local-api-authorize-always-allow = Always Allow
local-api-authorize-deny = Deny

File diff suppressed because it is too large Load diff