Правило Firebase разрешает только одно обновление в android studio - PullRequest
2 голосов
/ 26 марта 2020

Я создаю android приложение для голосования в студии. Он использует recyclerview для отображения информации о кандидатах из базы данных. Как только избиратель нажимает на кнопку голосования, кандидат добавляется в базу данных реального времени Firebase. Я хотел убедиться, что избиратель может проголосовать только один раз. Есть ли правило Firebase, которое я могу использовать, или я должен сделать это в коде? My firebase database.

The android interface

public void onBindViewHolder(@NonNull final MyViewHolder holder, final int position) {
        holder.name.setText(candidates.get(position).getFirstname());
        holder.party.setText(candidates.get(position).getParty());
        holder.category.setText(candidates.get(position).getCategory());
        Picasso.get().load(candidates.get(position).getImageurl()).into(holder.profilepic);

        holder.vote.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                updateTotalVotes("increaseTotalVotes", candidates.get(position).getImageurl());
            }
        });

    }

    public static void updateTotalVotes(final String operation, String key) {
        System.out.println("Inside updateTotalVotes");
        DatabaseReference rootRef = FirebaseDatabase.getInstance().getReference();

        DatabaseReference totalVotesRef = rootRef.child("candidates").child(key).child("totalVotes");
        totalVotesRef.runTransaction(new Transaction.Handler() {
            @Override
            public Transaction.Result doTransaction(MutableData mutableData) {
                System.out.println("Inside Transactions");
                Integer votes = mutableData.getValue(Integer.class);
                if (votes == null) {
                    System.out.println("Inside first if statement = null");
                    return Transaction.success(mutableData);
                }

                if (operation.equals("increaseTotalVotes")) {
                    System.out.println("Inside update Votes by adding 1");
                    mutableData.setValue(votes + 1);
                } else if (operation.equals("decreaseTotalVotes")){
                    mutableData.setValue(votes - 1);
                }

                return Transaction.success(mutableData);
            }

            @Override
            public void onComplete(DatabaseError databaseError, boolean b, DataSnapshot dataSnapshot) {
                // Log.d(TAG, databaseError.getMessage()); //Don't ignore errors!
            }
        });
    }

Ответы [ 2 ]

1 голос
/ 27 марта 2020

Правила безопасности Firebase не могут применять уникальное значение в указанном свойстве c для одного узла. Но (как это часто бывает с базами данных SQL), вы можете использовать конкретную модель данных c для реализации варианта использования.

Обычное решение для этого - использовать UID избирателя. в качестве ключа.

votes
  uid1: "candidate A"
  uid2: "candidate B"
  uid3: "candidate A"

Поскольку ключи должны быть уникальными в объекте JSON, эта структура по определению гарантирует, что каждый UID может голосовать только один раз.

Это отдельно от сохранения общего количества голосов за кандидата. Для этого вы можете использовать либо правила безопасности, либо облачные функции.

Выполнение этого в целях безопасности является привлекательным, поскольку это означает, что вам не понадобится код на стороне сервера. Но правила могут стать довольно сложными. Пример этого см. В моем ответе на этот вопрос: Безопасен ли способ быстрого запуска базы данных Firebase?

Более простой и в наши дни более распространенный подход заключается в том, чтобы сделать это с облачной функцией. Из недавнего проекта, над которым я работал, у меня есть эта облачная функция:

exports.countVote = functions.database.ref('/votes/{uid}').onCreate((snapshot, context) => {
  let value = snapshot.val();
  let countRef = snapshot.ref.parent.parent.parent.child(`totals/${value}`);
  return countRef.transaction(function(current) {
    return (current || 0) + 1;
  })
});

Так что это подсчитывает голоса для каждого уникального значения. Затем он гарантирует, что пользователи не смогут изменить свой существующий голос с:

{
  "rules": {
    "votes": {
      "$uid": {
        ".write": "auth.uid === $uid && !data.exists()"
      }
    }
  }
}

Таким образом, пользователь может голосовать, только если он использует свой собственный UID (переменная auth.uid предварительно заполнена и не может быть подделана) и если они еще не проголосовали.

0 голосов
/ 27 марта 2020

Краткий ответ - Нет, вы не можете по правилам db.

Но вы можете сделать это с помощью аутентификации, при которой пользователь может создать учетную запись и свою запись голосования в поддереве дерева. кандидат. Таким образом, число дочерних элементов поддерева - это число голосов за этого кандидата.

Обратите внимание: мое решение может быть нарушено, если будут созданы поддельные учетные записи, и мой совет использовать проверку подлинности телефона также, чтобы подтвердить учетную запись, не является поддельным.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...