Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/310.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 在Firebase数据库中编写规则_Java_Android_Firebase_Firebase Realtime Database_Firebase Security - Fatal编程技术网

Java 在Firebase数据库中编写规则

Java 在Firebase数据库中编写规则,java,android,firebase,firebase-realtime-database,firebase-security,Java,Android,Firebase,Firebase Realtime Database,Firebase Security,我正在android上构建一个应用程序,用于管理用户和轮班。每个用户可以被分配到多个班次,并且每个班次可以有多个用户。每个班次都与一个日期相关联 以下是我的数据库在firebase中的结构: { "shift-assign" : { "key1" : { "111" : true, "222" : true, "888" : true }, "key2" : { "111" : true, "222" :

我正在android上构建一个应用程序,用于管理用户和轮班。每个用户可以被分配到多个班次,并且每个班次可以有多个用户。每个班次都与一个日期相关联

以下是我的数据库在firebase中的结构:

 {
  "shift-assign" : {
    "key1" : {
      "111" : true,
      "222" : true,
      "888" : true
    },
    "key2" : {
      "111" : true,
      "222" : true
    }
  },
  "shifts" : {
    "key1" : {
      "date" : "20191202",
      "endTime" : "02:00",
      "numOfEmps" : 4,
      "startTime" : "21:00",
      "wage" : 30
    },
    "key2" : {
      "date" : "20191202",
      "endTime" : "12:00",
      "numOfEmps" : 3,
      "startTime" : "08:00",
      "wage" : 10
    },
    "key3" : {
      "date" : "20191203",
      "endTime" : "06:00",
      "numOfEmps" : 3,
      "startTime" : "00:00",
      "wage" : 30
    }
  },
  "user-assign" : {
    "111" : {
      "key1" : true,
      "key2" : true
    },
    "222" : {
      "key1" : true,
      "key2" : true
    },
    "888" : {
      "key1" : true
    }
  },
  "users" : {
    "111" : {
      "active" : true,
      "email" : "111",
      "firstName" : "aaa",
      "id" : "111",
      "lastName" : "aaa",
      "password" : "111",
      "phone" : "1111111"
    },
    "222" : {
      "active" : true,
      "email" : "222",
      "firstName" : "bbb",
      "id" : "222",
      "lastName" : "bbb",
      "password" : "222",
      "phone" : "4444444"
    },
    "888" : {
      "active" : false,
      "email" : "888",
      "firstName" : "ccc",
      "id" : "888",
      "lastName" : "ccc",
      "password" : "888",
      "phone" : "5555555"
    },
    "99999" : {
      "active" : true,
      "firstName" : "Admin",
      "id" : "99999",
      "password" : "123"
    }
  }
}
当用户尝试将自己分配到一个班次时,我想在实际将其分配到班次之前检查一些约束

我尝试使用一个事务,但代码出错了,因为我需要引用事务中的不同节点

我的代码现在如下所示:

  private void AssignUserToShift() {
        // Constraint No. 0
        // user cannot be assigned to shifts whose date < today
        if(dates[0].compareTo(LocalDateTime.now().toLocalDate().format(dtf)) < 0){
            Toast.makeText(getApplicationContext(), "Cannot assign to prior dates", Toast.LENGTH_SHORT).show();
            return;
        }
        Map<String, Object> pathsToUpdate = new HashMap<>();
        pathsToUpdate.put("shift-assign/" + shiftKey + "/" + userId, true);
        pathsToUpdate.put("user-assign/" + userId + "/" + shiftKey, true);
        mDatabase.updateChildren(pathsToUpdate, new DatabaseReference.CompletionListener() {
            @Override
            public void onComplete(@Nullable DatabaseError databaseError, @NonNull DatabaseReference databaseReference) {
                if(databaseError == null) {
                    // add to adapter's list in GUI
                    AddUserToList();
                }else{
                    Toast.makeText(getApplicationContext(), "Could not update database entries", Toast.LENGTH_SHORT).show();
                }
            }
        });
    }
private void AssignUserToShift(){
//第0号限制
//无法将用户分配到日期<今天的班次
如果(日期[0]。比较到(LocalDateTime.now().toLocalDate().format(dtf))<0){
Toast.makeText(getApplicationContext(),“无法分配到以前的日期”,Toast.LENGTH_SHORT.show();
返回;
}
Map pathsToUpdate=new HashMap();
pathsToUpdate.put(“移位赋值/”+shiftKey+“/”+userId,true);
pathsToUpdate.put(“用户分配/”+userId+“/”+shiftKey,true);
mDatabase.updateChildren(路径更新,新数据库引用.CompletionListener(){
@凌驾
公共void onComplete(@Nullable-DatabaseError-DatabaseError,@NonNull-DatabaseReference-DatabaseReference){
if(databaseError==null){
//添加到GUI中适配器的列表
AddUserToList();
}否则{
Toast.makeText(getApplicationContext(),“无法更新数据库条目”,Toast.LENGTH_SHORT.show();
}
}
});
}
相反的方法是:

private void RemoveUserFromShift() {
    mUser user = userList.stream()
            .filter(u -> u.getId().equals(userId))
            .findAny()
            .orElse(null);
    if(user == null){
        Toast.makeText(UsersAssignedActivity.this, "You are not assigned to this shift.", Toast.LENGTH_SHORT).show();
        return;
    }

    AlertDialog.Builder builder = new AlertDialog.Builder(UsersAssignedActivity.this, R.style.AlertDialogCustom);
    builder.setMessage("Do you wish to remove yourself from this shift?");
    builder.setCancelable(false);
    builder.setPositiveButton("Yes",
            new DialogInterface.OnClickListener() {
                public void onClick(DialogInterface dialog, int i) {
                    Map<String, Object> pathsToDelete = new HashMap<>();
                    pathsToDelete.put("shift-assign/" + shiftKey + "/" + userId, null);
                    pathsToDelete.put("user-assign/" + userId + "/" + shiftKey, null);
                    mDatabase.updateChildren(pathsToDelete, new DatabaseReference.CompletionListener() {
                        @Override
                        public void onComplete(@Nullable DatabaseError databaseError, @NonNull DatabaseReference databaseReference) {
                            if(databaseError == null){
                                // remove from adapter's list in GUI
                                RemoveUserFromList();
                            }else{
                                Toast.makeText(UsersAssignedActivity.this, "Could not delete database entries", Toast.LENGTH_SHORT).show();
                            }
                        }
                    });
                }
            });
    builder.setNegativeButton("No",
            new DialogInterface.OnClickListener() {
                public void onClick(DialogInterface dialog, int i) {
                    dialog.cancel();
                }
            });
    AlertDialog alertDialog = builder.create();
    alertDialog.show();
}
private void RemoveUserFromShift(){
mUser user=userList.stream()
.filter(u->u.getId().equals(userId))
.findAny()
.orElse(空);
if(user==null){
Toast.makeText(UsersAssignedActivity.this,“您没有被分配到这个班次。”,Toast.LENGTH_SHORT.show();
返回;
}
AlertDialog.Builder=新建AlertDialog.Builder(UsersAssignedActivity.this,R.style.AlertDialogCustom);
setMessage(“您希望从该班次中退出吗?”);
builder.setCancelable(false);
builder.setPositiveButton(“是”,
新建DialogInterface.OnClickListener(){
公共void onClick(对话框接口对话框,int i){
Map pathsToDelete=new HashMap();
pathsToDelete.put(“移位赋值/”+shiftKey+“/”+userId,null);
pathsToDelete.put(“用户分配/”+userId+“/”+shiftKey,null);
mDatabase.updateChildren(路径stodelete,新数据库引用.CompletionListener(){
@凌驾
公共void onComplete(@Nullable-DatabaseError-DatabaseError,@NonNull-DatabaseReference-DatabaseReference){
if(databaseError==null){
//从GUI中的适配器列表中删除
RemoveUserFromList();
}否则{
Toast.makeText(UsersAssignedActivity.this,“无法删除数据库条目”,Toast.LENGTH_SHORT.show();
}
}
});
}
});
builder.setNegativeButton(“否”,
新建DialogInterface.OnClickListener(){
公共void onClick(对话框接口对话框,int i){
dialog.cancel();
}
});
AlertDialog AlertDialog=builder.create();
alertDialog.show();
}
所以我想我应该使用规则来代替,并检查服务器端的约束

我想编写满足以下条件的规则-

  • 用户不能分配到已满的班次。(其
    numOfEmps
    等于
    shift-assign/shiftKey
    下的子节点数)

  • 在某一日期,用户不能分配超过一半的班次(如果有4个班次与同一日期相关,并且用户已经被分配到其中一个班次,则他们只能在该日期再分配一个班次。)

  • 用户不能连续工作超过4天。(如果用户试图在某个日期将自己分配到某个班次,而该用户在前4天已被分配到某个班次,则他们将无法将自己分配到该班次)

  • 最后,如果用户尚未分配到此班次。我想这可以使用事务在客户端进行检查


  • 我怎么写这些规则

    您的问题有一个非常广泛的用例。我将向您展示如何从第一个要求开始:

    用户不能分配到已满的班次。(其numOfEmps等于shift assign/shiftKey下的子节点数)

    安全规则无法对数据执行任何聚合。由于此要求需要比较两个值,因此这两个值必须存储在数据库中规则中已知的路径上

    您已经有了
    numOfEmps
    ,但是您还需要存储已经注册轮班的人数。例如,您可以将注册人数添加到班次中,然后在每次添加/删除时进行更新:

    "shifts" : {
      "key1" : {
        "date" : "20191202",
        "endTime" : "02:00",
        "numOfEmps" : 4,
        "numSignups" : 3,
        "startTime" : "21:00",
        "wage" : 30
      },
    
    现在,您可以在安全规则中检查是否存在以下打开的插槽:

    {
      "rules": {
        "shift-assigns": {
          "$shiftid": {
            "$uid": {
              ".validate": "root.child('/shifts/$shiftid/numSignups').val() < root.child('/shifts/$shiftid/numOfEmps').val()"
            }
          }
        }
      }
    }
    
    {
    “规则”:{
    “班次分配”:{
    “$shiftid”:{
    “$uid”:{
    .validate:“root.child('/shifts/$shiftid/numSignups').val()
    当然,您还需要确保用户:

    • 只能使用som在班次中添加/删除自己