Правила Firestore - разрешают обновлять только определенные поля документа - PullRequest
0 голосов
/ 17 января 2019

Моя цель

Я хочу разрешить ТОЛЬКО пользователям обновлять определенное поле в пользовательских документах других.


Мой пользовательский документ

/* BEFORE */
{
  id: 'uid1',
  profile: { /* a map of personal info */ },
  connectedUsers: {
    uid2: true,
    uid3: true,
  }
}

/* AFTER */
{
  id: 'uid1',
  profile: { /* a map of personal info */ },
  connectedUsers: {
    uid2: true,
    uid3: true,
    uid4: true, // <--- added.
  }
}

Запрос

const selfUserId = 'uid4';

db.runTransaction(function(transaction) {

    return transaction.update(userDocRef).then(function(userDoc) {

        if (!userDoc.exists) { throw "Document does not exist!"; }

        transaction.update(userDocRef, 'connectedUsers.${selfUserId}', true);
    });
}

Мое понимание того, как работают правила:

  • request.resource.dara является целевым документом entire after изменение.

  • Для операции update вышеизложенное остается верным. Я не совсем понимаю, что означают Документы:

Для операций обновления, которые изменяют только подмножество документа В полях переменная request.resource будет содержать в ожидании состояние документа после операции.

исх


Мои правила: (см. Обновление ниже)

function existingData() { return resource.data }
function expectedData() { return request.resource.data }
  • проверьте, добавлено ли запрашивающее uid после обновления.
function isAddingRequester() {
  return expectedData().connectedUsers[requesterId()] != null
}
  • проверьте, добавлен ли только элемент 1 или 0 в connectedUsers после обновления. 0, если запрашивающая сторона уже есть в списке.
function isAddingOneAtMost() {
  return expectedData().connectedUsers.size() == existingData().connectedUsers.size() + 1
  || expectedData().connectedUsers.size() == existingData().connectedUsers.size()
}
  • проверить, не изменились ли все остальные поля пользовательского документа после обновления.
function isNotChangingOtherFields() {
  return expectedData().id == existingData().id
  && expectedData().profile == existingData().profile
}

Мои вопросы

  • Правильно ли я понимаю, как правила Firestore работают? Что означает упомянутый выше документ под pending document state?

  • Отражают ли мои реализации правил мои намерения? Я запутался после поиска и узнал, что на симуляторе может быть ошибка.

  • в моей isNotChangingOtherFields функции, могу ли я сравнить объект profile напрямую с оператором ==?


Обновление - 2018/01/17 15:00

Удалено existingData() и expectedData().

function isAddingRequester() {
  return request.resource.data.connectedUsers[requesterId()] != null
}

function isAddingOneAtMost() {
  return (request.resource.data.connectedUsers.size() == resource.data.connectedUsers.size() + 1)
  || (request.resource.data.connectedUsers.size() == resource.data.connectedUsers.size()) // NOTE: if the requester is already in the list.
}

function isNotChangingOtherFields() {
  return request.resource.data.profile == resource.data.profile
  && request.resource.data.id == resource.data.id
}

function isNotAddingOtherFields() {
  return request.resource.data.size() == resource.data.size()
}

Результаты отладки

Интересно, что результаты НЕ одинаковы в симуляторе и на производстве.

// PASSED in simulator & production:      
allow update: if isAddingRequester();

// PASSED in simulator but NOT production:
allow update: if isNotChangingOtherFields();

// PASSED in simulator but NOT production:
allow update: if isNotAddingOtherFields();

// FAILED in both simulator AND production:
allow update: if isAddingOneAtMost();

// NOTE: inserted 2 mock data before update.
// PASSED in simulator:
allow update: if resource.data.connectedUsers.size() == 2;

// FAILED in simulator:
allow update: if request.resource.data.connectedUsers.size() == 3; 
// PASSED in simulator:
allow update: if request.resource.data.connectedUsers.size() == 1; 

Вопрос

Если request.resource является документом после обновления, почему request.resource.data.connectedUsers.size() 1 вместо 3 (2 существующих + 1 новое добавленное)?

Связанные данные (из симулятора)

Если у меня есть функция:

expectedData() { return request.resource.data }

И я получил такие неожиданные результаты:


// PASSED:
allow update: if request.resource.data.id == expectedData().id;

// FAILED if the order is changed.
allow update: if expectedData().id == request.resource.data.id;

...