Search code examples
node.jsgoogle-drive-api

Unable to transfer ownership in google drive v3 api in my node project


I tried following the docs but they don't provide a working example of how to use the feature.

This is my implementation:

async function transferOwner( ){
  const authClient = await authorize();
  const realFileId = '***fileId***';
  const newOwnerEmail = '@gmail.com';
  try{


    const drive = google.drive({version: 'v3', auth: authClient});

    const res = await drive.permissions.update({
      fileId: realFileId,
      permissionId: '***permission id that i found somehow***',
      transferOwnership: true,
      sendNotificationEmail: true,
      email: newOwnerEmail,
      "resource": {
        "role": "owner"
      }
    });


    console.log(result);
    console.log(`transfered ownership to ${newOwnerEmail}`);
    return result;
  } catch (err){
    console.log(`could not transfer ownership to ${newOwnerEmail}`);
    console.log(err);
      throw err
  }
}

When I execute this code, I get the status code as 200, but I don't see any owner getting changed in my drive.

What am i doing wrong?

This is the res if it is required. Though I have to delete a chunk of the response as stackoverflow was not making it easy to post this much content.

{ headers: {headers}, status: 200, statusText: 'OK', request: { responseURL: 'https://www.googleapis.com/drive/v3/files/RrBv4BK1yby5D/permissions/253029680?transferOwnership=true&sendNotificationEmail=true&email=%40gmail.com' }` transfered ownership to @gmail.com

Added * to places where i tried to hide any info.

I tried many ways to be able to change owner using my code, but nothing is working.

Each time I get the success message and the 200 status code, but in drive nothing is reflected.


Solution

  • Issue and workaround:

    In the current stage, when the owner of the file of the consumer account (gmai.com) is transferred, 2 steps are required to be run. Ref When I tested this using the following script before, the target account got an email for transferring the owner.

    const newOwnerEmail = "###@gmail.com";
    const fileId = "###";
    const drive = google.drive({version: 'v3', auth: authClient});
    
    const res = await drive.permissions.create({
      fileId: fileId,
      sendNotificationEmail: true,
      supportsAllDrives: true,
      requestBody: {
        role: "writer",
        type: "user",
        pendingOwner: true,
        emailAddress: newOwnerEmail,
      },
    });
    

    Now, when I tested this, unfortunately, the email is not sent, and also the value of pendingOwner is not changed to true. It keeps false. Because of this, I noticed that the owner cannot be transferred using the above script. I'm not sure whether this is the current specification or a bug.

    Fortunately, I noticed that when the existing permission is updated, the value of pendingOwner can be changed to true. By this, the target user can accept the transfer of the owner. In this answer, as a current workaround, I would like to propose a sample script for achieving this flow.

    Sample script:

    The sample script is as follows.

    const newOwnerEmail = "###@gmail.com";
    const fileId = "###";
    const drive = google.drive({version: 'v3', auth: authClient});
    
    const res1 = await drive.permissions.list({
      fileId,
      supportsAllDrives: true,
      pageSize: 100,
      fields: "*",
    });
    const permission = res1.data.permissions.find(
      ({ emailAddress }) => emailAddress == newOwnerEmail
    );
    let permissionId = "";
    if (permission) {
      permissionId = permission.id;
    } else {
      const { data: { id } } = await drive.permissions.create({
        fileId: fileId,
        sendNotificationEmail: true,
        supportsAllDrives: true,
        requestBody: {
          role: "writer",
          type: "user",
          pendingOwner: true, // It seems that this cannot be used. This might be a bug.
          emailAddress: newOwnerEmail,
        },
      });
      permissionId = id;
    }
    const res2 = await drive.permissions.update({
      fileId,
      permissionId,
      supportsAllDrives: true,
      requestBody: {
        role: "writer",
        pendingOwner: true,
      },
    });
    console.log(res2.data);
    
    • In this script, first, the permissions are retrieved and the permission ID of the target account is searched. When the permission is not found, a new permission is created and the permission ID is retrieved. Then, pendingOwner is updated by updating the permission with the permission ID. By this flow, when the target user confirms the permission of the file, the user can confirm "Accept ownership?" as follows. When the user accepts it, the owner of the file is transferred to the user.

    enter image description here

    Note:

    • As an important point of this workaround, when the permission of the file is updated, it seems that the email notification is not sent. So, when you use this workaround and want to notice it to the user, it is required to send an email and make the user accept the owner transfer. Please be careful about this.

    References: