Permission denied for relation

In my project, the technical DB user (postgresql) is supposed to be read only.

For everything else, POST, PUT, DELETE are dealt via API.
Although quite often, I can receive a “permission denied” error even though I don’t “call” FA sequelize.

For instance :

router.post('/integrationDocuments', permissionMiddlewareCreator.create(), (request, response, next) => {
  const recordCreator = new RecordCreator(models.integrationDocuments);
  const data = request.body.data.attributes;
  const place_id = request.body.data.relationships.integration.data.id;;

  // file upload
  const fileBody = {
    attachment: {
      image_base: data['Document'],
      source_file_name: data['Nom du doc']
    }
  };

  axios.post(`${API_URL}/forest_admin/attachments`, fileBody, {
    headers: {
      'Authorization': `Bearer ${process.env.ACCESS_TOKEN}`,
      'X-CURRENT-USER-EMAIL': request.user.email
    },
  }).then(attachmentsResponse => {
    const body = {
      integration_document: {
        place_id,
        attachment_id: attachmentsResponse.data.id,
        kind: 'other'
      }
    };

    axios.post(`${API_URL}/forest_admin/integration_documents`, body, {
      headers: {
        'Authorization': `Bearer ${process.env.ACCESS_TOKEN}`,
        'X-CURRENT-USER-EMAIL': request.user.email
      }
    }).then(async res => {
      response.send(await recordCreator.serialize(res));
    }).catch(err => {
      response.status(400).send(err.response.data.error.message);
    });
  }).catch(attachmentsError => {
    response.status(400).send(attachmentsError.response.data.error.message);
  });
});

I receive :

[forest] ���  Unexpected error: permission denied for relation integration_documents
{
  "name": "SequelizeDatabaseError",
  "parent": {
    "length": 112,
    "name": "error",
    "severity": "ERROR",
    "code": "42501",
    "file": "aclchk.c",
    "line": "3411",
    "routine": "aclcheck_error",
    "sql": "UPDATE \"public\".\"integration_documents\" SET \"place_id\"=$1,\"updated_at\"=$2 WHERE \"id\" IN (NULL)"
  },
  "original": {
    "length": 112,
    "name": "error",
    "severity": "ERROR",
    "code": "42501",
    "file": "aclchk.c",
    "line": "3411",
    "routine": "aclcheck_error",
    "sql": "UPDATE \"public\".\"integration_documents\" SET \"place_id\"=$1,\"updated_at\"=$2 WHERE \"id\" IN (NULL)"
  },
  "sql": "UPDATE \"public\".\"integration_documents\" SET \"place_id\"=$1,\"updated_at\"=$2 WHERE \"id\" IN (NULL)",
  "stack": "SequelizeDatabaseError: permission denied for relation integration_documents\n    at Query.formatError (C:\\Users\\jvollant\\WebDev\\Syndic One Rebirth\\node_modules\\sequelize\\lib\\dialects\\postgres\\query.js:354:16)\n    at C:\\Users\\jvollant\\WebDev\\Syndic One Rebirth\\node_modules\\sequelize\\lib\\dialects\\postgres\\query.js:71:18\n    at tryCatcher (C:\\Users\\jvollant\\WebDev\\Syndic One Rebirth\\node_modules\\bluebird\\js\\release\\util.js:16:23)\n    at Promise._settlePromiseFromHandler (C:\\Users\\jvollant\\WebDev\\Syndic One Rebirth\\node_modules\\bluebird\\js\\release\\promise.js:547:31)\n    at Promise._settlePromise (C:\\Users\\jvollant\\WebDev\\Syndic One Rebirth\\node_modules\\bluebird\\js\\release\\promise.js:604:18)\n    at Promise._settlePromise0 (C:\\Users\\jvollant\\WebDev\\Syndic One Rebirth\\node_modules\\bluebird\\js\\release\\promise.js:649:10)\n    at Promise._settlePromises (C:\\Users\\jvollant\\WebDev\\Syndic One Rebirth\\node_modules\\bluebird\\js\\release\\promise.js:725:18)\n    at _drainQueueStep (C:\\Users\\jvollant\\WebDev\\Syndic One Rebirth\\node_modules\\bluebird\\js\\release\\async.js:93:12)\n    at _drainQueue (C:\\Users\\jvollant\\WebDev\\Syndic One Rebirth\\node_modules\\bluebird\\js\\release\\async.js:86:9)\n    at Async._drainQueues (C:\\Users\\jvollant\\WebDev\\Syndic One Rebirth\\node_modules\\bluebird\\js\\release\\async.js:102:5)\n    at Immediate.Async.drainQueues [as _onImmediate] (C:\\Users\\jvollant\\WebDev\\Syndic One Rebirth\\node_modules\\bluebird\\js\\release\\async.js:15:14)\n    at processImmediate (internal/timers.js:456:21)"
}

I don’t understand why FA performs a
UPDATE \"public\".\"integration_documents\" SET \"place_id\"=$1,\"updated_at\"=$2 WHERE \"id\" IN (NULL)
since I call my API to di that.

Hi @JeremyV :wave: it is pretty strange, i didn’t see any reason about calling this update in database.
I see you use the relationships data attribute, can you explain me a little bit the impacted schema please. What are the relationships that gravitate around the integrationDocuments table please?

For instance we have this:

IntegrationDocuments.belongsTo(models.places, {
      foreignKey: {
        name: 'placeIdKey',
        field: 'place_id',
      },
      as: 'place',
    });
IntegrationDocuments.belongsTo(models.integrations, {
      foreignKey: {
        name: 'placeIdKey',
        field: 'place_id',
      },
      as: 'integration',
    });

Another example, when I create an integrationBudget record, I get the following error message.
image

I create a new integrationBudget from the integration related data.

I receive this “integration update failed” message but

  • I created a budget, didn’t updated an integration
  • when i come back to the related data table view, the new record have successfully been created
// This model was generated by Lumber. However, you remain in control of your models.
// Learn how here: https://docs.forestadmin.com/documentation/v/v6/reference-guide/models/enrich-your-models
module.exports = (sequelize, DataTypes) => {
  const { Sequelize } = sequelize;
  // This section contains the fields of your model, mapped to your table's columns.
  // Learn more here: https://docs.forestadmin.com/documentation/v/v6/reference-guide/models/enrich-your-models#declaring-a-new-field-in-a-model
  const IntegrationBudgets = sequelize.define('integrationBudgets', {
    partnerComment: {
      type: DataTypes.STRING,
    },
    refusalComment: {
      type: DataTypes.STRING,
    },
    state: {
      type: DataTypes.ENUM([
        'initializing',
        'waiting',
        'accepted',
        'refused'
      ]),
    },
    createdAt: {
      type: DataTypes.DATE,
    },
    updatedAt: {
      type: DataTypes.DATE,
    },
  }, {
    tableName: 'integration_budgets',
    underscored: true,
    schema: process.env.DATABASE_SCHEMA,
  });

  // This section contains the relationships for this model. See: https://docs.forestadmin.com/documentation/v/v6/reference-guide/relationships#adding-relationships.
  IntegrationBudgets.associate = (models) => {
    IntegrationBudgets.belongsTo(models.places, {
      foreignKey: {
        name: 'placeIdKey',
        field: 'place_id',
      },
      as: 'place',
    });
    IntegrationBudgets.belongsTo(models.integrations, {
      foreignKey: {
        name: 'placeIdKey',
        field: 'place_id',
      },
      as: 'integration',
    });
    IntegrationBudgets.hasMany(models.integrationBudgetEntries, {
      foreignKey: {
        name: 'integrationBudgetIdKey',
        field: 'integration_budget_id',
      },
      as: 'integrationBudgetIntegrationBudgetEntries',
    });
  };

  return IntegrationBudgets;
};

To make sur i understand, you trying to create a related data inside a record details.
integrationBudget has many integrationBudgetEntries and you try to associate a new integrationBudgetEntries to a specific integrationBudget by accessing the related data of this integrationBudget. Is that right?

If i understand well, the error is throw by the next call.
We run POST to create the integrationBudgetEntries and after that we run a
POST /forest/integrationBudget/: integrationBudgetId/relationships/integrationBudgetEntries to link relation between theme.
So i think you must have a look to this route to override it.
let me know if that help.

@Arnaud_Moncel

integration has many integrationBudgets and I try to associate a new integrationBudget to a specific integration by accessing the related data of this integration .

So Integration is my main collection. I create about everything from there.
In an integration record summary view, I have about 15 related datas.

My example is as follows:

  • I am inside an integration summary view
  • I display my integrationBudget related data
  • I create a new integrationBudget record from there
  • API is being called but I get the error message “update intergration”
  • if i go back to the related datas, the new integrationBudget has been successfully created despite the error message.

I do not want the error message.

What you call “the next call” is already being performed by my API provider.
If I had to override the
POST /forest/integrations/:integration_id/relationships/integrationBudgets
what should I do ? I do not have APIs specifically for the relations.

Should I have to do that for all collections that I access via related datas ?

Unfortunately yes, it is a wanted behavior.
You need to override all the has-many related data routes linked to your integration entity.

to do that simply add this piece of code for all this related data.

router.post('/integration/: integrationId/relationships/integrationBudget', (req, res, next) => {
  res.sendStatus(200);
});
router.post('/integration/: integrationId/relationships/anotherRelation', (req, res, next) => {
  res.sendStatus(200);
});
router.post('/integration/: integrationId/relationships/etc', (req, res, next) => {
  res.sendStatus(200);
});
``` 
let me know
1 Like

I’ve overridden more than 100 routes these couple of days. I no longer have these errors.
Thank you @Arnaud_Moncel .