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

API Doesn't Work For Uploading Attachments (PDFs) #10

Closed
jonasms opened this issue Jan 6, 2019 · 5 comments
Closed

API Doesn't Work For Uploading Attachments (PDFs) #10

jonasms opened this issue Jan 6, 2019 · 5 comments

Comments

@jonasms
Copy link

jonasms commented Jan 6, 2019

I have the following code:

const createdItemRes = await zoteroLibrary
.items()
.post([newItem]),

createdItem = createdItemRes.getData()[0];

const attachmentRes = await zoteroLibrary
.items(createdItem.key)
.attachment(documentData.title, pdfArrayBuffer)
.post();

This results in the following response error: Error: Upload stage 1: File already exists.

If, on the other hand, I do

const attachmentRes = await zoteroLibrary
                    .items()
                    .attachment(documentData.title, pdfArrayBuffer)
                    .post([newItem]);

I get the following runtime error: Cannot use both "file" and "body" in a single request.

@tnajdek
Copy link
Owner

tnajdek commented Jan 7, 2019

An attachment in Zotero is actually an item with itemType set to 'attachment', it also should have 'linkMode property, please see documentation for more details. Attachments can exist on their own (as top level/standalone items) but usually are attached to other items. For the purpose of this example, we will attach the attachment item to another (already existing) item identified by key SOMEITEM.

Here is a complete example how to create an item and upload a file (image) using zotero-api-client:

Let's say we have:

const api = require('zotero-api-client');
const fs = require('fs');
const filedata = fs.readFileSync('picture.jpg');

And some configuration:

const APIKEY = 'YOURAPIKEYHERE';
const USERID = 'YOURUSERIDHERE';
const ITEM_KEY = 'SOMEITEM'; // this is going to be the parent item

First we need to obtain the item template:

const template = (await api()
	.template('attachment')
	.get({ linkMode: 'imported_file'})).getData();

Then build the attachment item object:

const item = {
	...template,
	title: 'attached picture',
	parentItem: ITEM_KEY,
	filename: 'picture.jpg',
	contentType: 'image/jpeg',
};

Then create it:

const attachmentItem = (await api(APIKEY)
	.library(USERID)
	.items()
	.post([item])).getEntityByIndex(0);

Finally we upload a file and associate it with newly created attachment item:

const response = await api(APIKEY)
	.library(USERID)
	.items(attachmentItem.key)
	.attachment('picture.jpg', filedata.buffer)
	.post();

You can download the complete example here. Hope this helps!

@tnajdek tnajdek closed this as completed Jan 7, 2019
@jonasms
Copy link
Author

jonasms commented Jan 10, 2019

Hey @tnajdek,

Thank you for the great sample! I really appreciate the time you took for that.

Unfortunately, I'm getting the same error!

Do you have any thoughts on what might be occurring?

reason: "File already exists",
message: "Upload stage 1: File already exists"
options: {
  contentType:"application/x-www-form-urlencoded"
  credentials:"omit"
  executors:Array(1) []
  file:ArrayBuffer(250436) {}
  fileName:"LCERPA_2009-09.pdf"
  format:null
  ifNoneMatch:"*"
  method:"post"
  mode:"cors"
  mtime:undefined
  redirect:"follow"
  resource:Object {library: "u5329351", items: "HJIDAW8N", file: null}
  zoteroApiKey:"KTaCnpV9gtS9oRrsvNPAvkxl"
}

The code I'm running below:

uploadPDFToZotero = async (userEntity, documentData, pdfLocation) => {
        if (userEntity.zotero_user_id) {
            try {
                const pdfArrayBuffer = await fetch(pdfLocation).then(res => res.arrayBuffer()),

                    itemTemplate = (await zotero(userEntity.zotero_api_key)
                        .template('attachment')
                        .get({ linkMode: 'imported_file' })).getData(),

                    item = {
                        ...itemTemplate,
                        contentType: 'application/pdf',
                        filename: documentData.title,
                        title: documentData.title,
                    },

                    attachmentItem = (await zotero(userEntity.zotero_api_key)
                        .library('user', userEntity.zotero_user_id)
                        .items()
                        .post([item])).getEntityByIndex(0),

                    attachmentRes = await zotero(userEntity.zotero_api_key)
                        .library('user', userEntity.zotero_user_id)
                        .items(attachmentItem.key)
                        .attachment(documentData.title, pdfArrayBuffer)
                        .post();

                console.log('ATTACH RES: ', attachmentRes);
            } catch (err) {
                console.warn(err, err.reason, err.message, err.options);
            }
     }
}

I'm not using a parent key but according to the Zotero docs on uploading a file that shouldn't be an issue.

@tnajdek tnajdek reopened this Jan 10, 2019
@tnajdek
Copy link
Owner

tnajdek commented Jan 10, 2019

When the attachment item is deleted from Zotero, the attachment file itself will not be purged for some time, could it be that you're trying to re-upload file that you have previously uploaded? In that case the API will still create file association with the existing file so it should still work despite the error. Could you please confirm if this actually worked (for example by using the client to see if the attachment item is created)?

Perhaps the problem here is that zotero-api-client incorrectly reports this situation as an error when it actually isn't one.

@jonasms
Copy link
Author

jonasms commented Jan 10, 2019

Ahah! You are correct, the PDF was correctly uploaded.

🙏Huge help, thank you!

Indeed, perhaps in this case the file upload should be considered successful and it's status of already existing being noted in the success response.

@tnajdek
Copy link
Owner

tnajdek commented Jan 10, 2019

@jonasms Begining with version 0.22.0, zotero-api-client will no longer consider "File Already Exists" response as an error. I believe that's a better behaviour and will help avoid confusion like that in the future.

It's still possible to check whether existing file was used by looking at response.getData().exists where response is an instance of FileUploadResponse.

@tnajdek tnajdek closed this as completed Jan 10, 2019
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants