Skip to content

Commit

Permalink
Add findOrCreate helper methods (#6168)
Browse files Browse the repository at this point in the history
  • Loading branch information
cmelchior authored Sep 24, 2018
1 parent e3cb81c commit f9b665a
Show file tree
Hide file tree
Showing 5 changed files with 225 additions and 1 deletion.
2 changes: 1 addition & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,14 +7,14 @@

### Enhancements

* [ObjectServer] Added `RealmPermissions.findOrCreate(String roleName)` and `ClassPermissions.findOrCreate(String roleName)` (#6168).
* `@RealmClass("name")` and `@RealmField("name")` can now be used as a shorthand for defining custom name mappings (#6145).
* Added support for `RealmQuery.limit(long limit)` (#544).

### Internal

* Updated to Object Store commit: 7e19c51af72c3343b453b8a13c82dfda148e4bbc


## 5.5.1 (YYYY-MM-DD)

### Enhancements
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -520,6 +520,118 @@ public void allPrivileges() {
assertNoAccess(nobody);
}

@Test
public void findOrCreate_unmanagedObjectThrows() {
RealmPermissions realmPermissions = new RealmPermissions();
try {
realmPermissions.findOrCreate("foo");
fail();
} catch (IllegalStateException ignored) {
}

ClassPermissions classPermissions = new ClassPermissions();
try {
classPermissions.findOrCreate("foo");
fail();
} catch (IllegalStateException ignored) {
}
}

@Test
public void findOrCreate_notInTransactionThrows() {
RealmPermissions realmPermissions = realm.getPermissions();
try {
realmPermissions.findOrCreate("foo");
fail();
} catch (IllegalStateException ignored) {
}

ClassPermissions classPermissions = realm.getPermissions(ClassPermissions.class);
try {
classPermissions.findOrCreate("foo");
fail();
} catch (IllegalStateException ignored) {
}
}

@Test
public void findOrCreate_nullThrows() {
realm.beginTransaction();
RealmPermissions realmPermissions = realm.getPermissions();
try {
//noinspection ConstantConditions
realmPermissions.findOrCreate(null);
fail();
} catch (IllegalArgumentException ignored) {
}

ClassPermissions classPermissions = realm.getPermissions(ClassPermissions.class);
try {
//noinspection ConstantConditions
classPermissions.findOrCreate(null);
fail();
} catch (IllegalArgumentException ignored) {
}
}

@Test
public void findOrCreate_createRole() {
realm.beginTransaction();
assertNull(realm.where(Role.class).equalTo("name", "role1").findFirst());
assertNull(realm.where(Role.class).equalTo("name", "role2").findFirst());

// Realm permissions
RealmPermissions realmPermissions = realm.getPermissions();
Permission p = realmPermissions.findOrCreate("role1");
assertEquals("role1", p.getRole().getName());
assertTrue(p.getRole().getMembers().isEmpty());

// Class permissions
ClassPermissions classPermissions = realm.getPermissions(ClassPermissions.class);
p = classPermissions.findOrCreate("role2");
assertEquals("role2", p.getRole().getName());
assertTrue(p.getRole().getMembers().isEmpty());
}

@Test
public void findOrCreate_createPermission() {
realm.beginTransaction();
realm.createObject(Role.class, "role1");

RealmPermissions realmPermissions = realm.getPermissions();
assertEquals(1, realmPermissions.getPermissions().size());
Permission p = realmPermissions.findOrCreate("role1");
assertNoAccess(p);
assertEquals("role1", p.getRole().getName());
assertEquals(2, realmPermissions.getPermissions().size());
assertTrue(p.equals(realmPermissions.getPermissions().last()));

// Class permissions
ClassPermissions classPermissions = realm.getPermissions(ClassPermissions.class);
assertEquals(1, classPermissions.getPermissions().size());
p = classPermissions.findOrCreate("role2");
assertNoAccess(p);
assertEquals("role2", p.getRole().getName());
assertEquals(2, classPermissions.getPermissions().size());
assertTrue(p.equals(classPermissions.getPermissions().last()));
}

@Test
public void findOrCreate_findExistingPermission() {
realm.beginTransaction();

RealmPermissions realmPermissions = realm.getPermissions();
Permission p = realmPermissions.findOrCreate("everyone");
assertFullAccess(p);
assertEquals("everyone", p.getRole().getName());

ClassPermissions classPermissions = realm.getPermissions(ClassPermissions.class);
p = classPermissions.findOrCreate("everyone");
assertFullAccess(p);
assertEquals("everyone", p.getRole().getName());
}


private void assertFullAccess(RealmPrivileges privileges) {
assertTrue(privileges.canRead());
assertTrue(privileges.canUpdate());
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
/*
* Copyright 2018 Realm Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package io.realm.internal.sync;

import io.realm.Realm;
import io.realm.RealmList;
import io.realm.RealmObject;
import io.realm.internal.annotations.ObjectServer;
import io.realm.sync.permissions.Permission;
import io.realm.sync.permissions.Role;

/**
* Helper class for working with fine-grained permissions
*/
@ObjectServer
public class PermissionHelper {

/**
* Finds or creates the permission object for a given role. Creating objects if they cannot
* be found.
*
* @param container RealmObject containg the permission objects
* @param permissions the list of permissions
* @param roleName the role to search for
* @return
*/
public static Permission findOrCreatePermissionForRole(RealmObject container, RealmList<Permission> permissions, String roleName) {
if (!container.isManaged()) {
throw new IllegalStateException("'findOrCreate()' can only be called on managed objects.");
}
Realm realm = container.getRealm();
if (!realm.isInTransaction()) {
throw new IllegalStateException("'findOrCreate()' can only be called inside a write transaction.");
}

// Find existing permission object or create new one
Permission permission = permissions.where().equalTo("role.name", roleName).findFirst();
if (permission == null) {

// Find existing role or create new one
Role role = realm.where(Role.class).equalTo("name", roleName).findFirst();
if (role == null) {
role = realm.createObject(Role.class, roleName);
}

permission = realm.copyToRealm(new Permission.Builder(role).noPrivileges().build());
permissions.add(permission);
}

return permission;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
import io.realm.annotations.RealmClass;
import io.realm.annotations.Required;
import io.realm.internal.annotations.ObjectServer;
import io.realm.internal.sync.PermissionHelper;

/**
* Class describing all permissions related to a given Realm model class. These permissions will
Expand Down Expand Up @@ -61,6 +62,7 @@ public ClassPermissions() {
* @param clazz class to create permissions.
*/
public ClassPermissions(Class<? extends RealmModel> clazz) {
//noinspection ConstantConditions
if (clazz == null) {
throw new IllegalArgumentException("Non-null 'clazz' required.");
}
Expand Down Expand Up @@ -89,4 +91,26 @@ public String getName() {
public RealmList<Permission> getPermissions() {
return permissions;
}

/**
* Finds the permissions associated with a given {@link Role}. If either the role or the permission
* object doesn't exists, it will be created.
* <p>
* If the {@link Permission} object is created because one didn't exist already, it will be
* created with all privileges disabled.
* <p>
* If the the {@link Role} object is created because one didn't exists, it will be created
* with no members.
*
* @param roleName name of the role to find.
* @return permission object for the given role.
* @throws IllegalStateException if this object is not managed by Realm.
* @throws IllegalStateException if this method is not called inside a write transaction.
* @throws IllegalArgumentException if a {@code null} or empty
*/
public Permission findOrCreate(String roleName) {
// Error handling done in the helper class
return PermissionHelper.findOrCreatePermissionForRole(this, permissions, roleName);
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -15,11 +15,13 @@
*/
package io.realm.sync.permissions;

import io.realm.Realm;
import io.realm.RealmList;
import io.realm.RealmObject;
import io.realm.annotations.PrimaryKey;
import io.realm.annotations.RealmClass;
import io.realm.internal.annotations.ObjectServer;
import io.realm.internal.sync.PermissionHelper;

/**
* Class describing all permissions related to a given Realm. Permissions attached to this class
Expand Down Expand Up @@ -48,4 +50,25 @@ public RealmPermissions() {
public RealmList<Permission> getPermissions() {
return permissions;
}

/**
* Finds the permissions associated with a given {@link Role}. If either the role or the permission
* object doesn't exists, it will be created.
* <p>
* If the {@link Permission} object is created because one didn't exist already, it will be
* created with all privileges disabled.
* <p>
* If the role {@link Role} object is created because one didn't exists, it will be created
* with no members.
*
* @param roleName name of the role to find.
* @return permission object for the given role.
* @throws IllegalStateException if this object is not managed by Realm.
* @throws IllegalStateException if this method is not called inside a write transaction.
* @throws IllegalArgumentException if a {@code null} or empty
*/
public Permission findOrCreate(String roleName) {
// Error handling done in the helper class
return PermissionHelper.findOrCreatePermissionForRole(this, permissions, roleName);
}
}

0 comments on commit f9b665a

Please sign in to comment.