├── .gitignore ├── src ├── main │ ├── resources │ │ ├── sql │ │ │ ├── mysql │ │ │ │ ├── V2_update.sql │ │ │ │ ├── V5_update.sql │ │ │ │ ├── V6_update.sql │ │ │ │ ├── V7_update.sql │ │ │ │ ├── V3_update.sql │ │ │ │ └── V4_update.sql │ │ │ └── common │ │ │ │ ├── V2_update.sql │ │ │ │ ├── V6_update.sql │ │ │ │ ├── V5_update.sql │ │ │ │ ├── V7_update.sql │ │ │ │ ├── V3_update.sql │ │ │ │ └── V4_update.sql │ │ ├── org │ │ │ └── tyrannyofheaven │ │ │ │ └── bukkit │ │ │ │ └── zPermissions │ │ │ │ └── config.yml │ │ └── plugin.yml │ └── java │ │ └── org │ │ └── tyrannyofheaven │ │ └── bukkit │ │ └── zPermissions │ │ ├── ReadOnlyException.java │ │ ├── uuid │ │ └── BulkUuidConverter.java │ │ ├── RefreshCause.java │ │ ├── service │ │ ├── PlayerPrefixHandler.java │ │ └── DefaultPlayerPrefixHandler.java │ │ ├── dao │ │ ├── MissingGroupException.java │ │ ├── PermissionServiceException.java │ │ ├── PermissionDao.java │ │ ├── PermissionService.java │ │ └── DummyPermissionDao.java │ │ ├── util │ │ ├── MetadataConstants.java │ │ ├── RefreshTask.java │ │ ├── GlobPattern.java │ │ ├── SearchTask.java │ │ └── ExpirationRefreshHandler.java │ │ ├── command │ │ ├── UuidCacheCommands.java │ │ ├── TrackTypeCompleter.java │ │ ├── GroupTypeCompleter.java │ │ └── DirTypeCompleter.java │ │ ├── ZPermissionsConfig.java │ │ ├── model │ │ ├── PermissionWorld.java │ │ ├── PermissionRegion.java │ │ ├── DataVersion.java │ │ ├── Inheritance.java │ │ ├── UuidDisplayNameCache.java │ │ ├── Membership.java │ │ ├── Entry.java │ │ ├── EntityMetadata.java │ │ └── PermissionEntity.java │ │ ├── listener │ │ ├── ZPermissionsFallbackListener.java │ │ ├── ZPermissionsRegionPlayerListener.java │ │ └── ZPermissionsPlayerListener.java │ │ ├── ZPermissionsCore.java │ │ ├── region │ │ ├── RegionStrategy.java │ │ ├── FactoidRegionStrategy.java │ │ ├── ResidenceRegionStrategy.java │ │ ├── FactionsRegionStrategy.java │ │ └── WorldGuardRegionStrategy.java │ │ ├── vault │ │ ├── PermissionCompatibility.java │ │ └── ChatCompatibility.java │ │ ├── storage │ │ ├── StorageStrategy.java │ │ └── DummyStorageStrategy.java │ │ ├── QualifiedPermission.java │ │ ├── ZPermissionsPlayerUpdateEvent.java │ │ └── ZPermissionsRankChangeEvent.java └── test │ └── java │ └── org │ └── tyrannyofheaven │ └── bukkit │ └── zPermissions │ ├── MemoryResolverTest.java │ ├── dao │ ├── MemoryDaoTest.java │ └── NewAvajeDaoTest.java │ └── NewAvajeResolverTest.java ├── NOTICE ├── repo ├── com │ ├── massivecraft │ │ ├── mcore │ │ │ ├── 7.2.1 │ │ │ │ ├── mcore-7.2.1.jar │ │ │ │ └── mcore-7.2.1.pom │ │ │ └── maven-metadata-local.xml │ │ └── Factions │ │ │ ├── 2.4.0 │ │ │ ├── Factions-2.4.0.jar │ │ │ └── Factions-2.4.0.pom │ │ │ └── maven-metadata-local.xml │ └── bekvon │ │ └── bukkit │ │ └── Residence │ │ ├── 2.6.6.4 │ │ ├── Residence-2.6.6.4.jar │ │ └── Residence-2.6.6.4.pom │ │ └── maven-metadata-local.xml └── me │ └── tabinol │ └── factoid │ └── Factoid │ ├── 0.3 │ ├── Factoid-0.3.jar │ └── Factoid-0.3.pom │ └── maven-metadata-local.xml ├── .hgignore ├── .hgtags ├── doc ├── vault.md ├── temporary.md ├── tables.md ├── schemaupdate.md ├── quickstart.md ├── permissions.md ├── admins.md └── developers.md └── etc ├── b-to-z.py ├── gen-test-dump.py └── pex-to-z.py /.gitignore: -------------------------------------------------------------------------------- 1 | /.classpath 2 | /.project 3 | /.settings 4 | /target 5 | -------------------------------------------------------------------------------- /src/main/resources/sql/mysql/V2_update.sql: -------------------------------------------------------------------------------- 1 | ALTER TABLE ${Membership} ADD expiration DATETIME; 2 | -------------------------------------------------------------------------------- /src/main/resources/sql/common/V2_update.sql: -------------------------------------------------------------------------------- 1 | ALTER TABLE ${Membership} ADD expiration TIMESTAMP; 2 | -------------------------------------------------------------------------------- /NOTICE: -------------------------------------------------------------------------------- 1 | zPermissions includes software developed at 2 | The Apache Software Foundation (http://www.apache.org/). 3 | -------------------------------------------------------------------------------- /repo/com/massivecraft/mcore/7.2.1/mcore-7.2.1.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ezeiger92/zPermissions/HEAD/repo/com/massivecraft/mcore/7.2.1/mcore-7.2.1.jar -------------------------------------------------------------------------------- /repo/me/tabinol/factoid/Factoid/0.3/Factoid-0.3.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ezeiger92/zPermissions/HEAD/repo/me/tabinol/factoid/Factoid/0.3/Factoid-0.3.jar -------------------------------------------------------------------------------- /repo/com/massivecraft/Factions/2.4.0/Factions-2.4.0.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ezeiger92/zPermissions/HEAD/repo/com/massivecraft/Factions/2.4.0/Factions-2.4.0.jar -------------------------------------------------------------------------------- /repo/com/bekvon/bukkit/Residence/2.6.6.4/Residence-2.6.6.4.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ezeiger92/zPermissions/HEAD/repo/com/bekvon/bukkit/Residence/2.6.6.4/Residence-2.6.6.4.jar -------------------------------------------------------------------------------- /src/main/resources/sql/mysql/V5_update.sql: -------------------------------------------------------------------------------- 1 | CREATE TABLE ${DataVersion} ( 2 | name VARCHAR(255), 3 | version BIGINT NOT NULL, 4 | timestamp DATETIME NOT NULL, 5 | PRIMARY KEY (name) 6 | ); 7 | -------------------------------------------------------------------------------- /src/main/resources/sql/common/V6_update.sql: -------------------------------------------------------------------------------- 1 | ALTER TABLE ${Membership} ADD display_name VARCHAR(255); 2 | UPDATE ${Membership} SET display_name = member; 3 | ALTER TABLE ${Membership} ALTER COLUMN display_name SET NOT NULL; 4 | -------------------------------------------------------------------------------- /src/main/resources/sql/common/V5_update.sql: -------------------------------------------------------------------------------- 1 | CREATE TABLE ${DataVersion} ( 2 | name VARCHAR(255), 3 | version BIGINT NOT NULL, 4 | timestamp TIMESTAMP NOT NULL, 5 | PRIMARY KEY (name) 6 | ); 7 | CREATE SEQUENCE ${DataVersion}_seq; 8 | -------------------------------------------------------------------------------- /src/main/resources/sql/mysql/V6_update.sql: -------------------------------------------------------------------------------- 1 | ALTER TABLE ${Membership} ADD display_name VARCHAR(255); 2 | UPDATE ${Membership} SET display_name = member; 3 | ALTER TABLE ${Membership} CHANGE display_name display_name VARCHAR(255) NOT NULL; 4 | -------------------------------------------------------------------------------- /src/main/resources/sql/mysql/V7_update.sql: -------------------------------------------------------------------------------- 1 | CREATE TABLE ${UuidDisplayNameCache} ( 2 | name VARCHAR(255), 3 | display_name VARCHAR(255) NOT NULL, 4 | uuid VARCHAR(255) NOT NULL, 5 | timestamp DATETIME NOT NULL, 6 | PRIMARY KEY (name) 7 | ); 8 | -------------------------------------------------------------------------------- /.hgignore: -------------------------------------------------------------------------------- 1 | syntax: glob 2 | .classpath 3 | .project 4 | .settings 5 | target 6 | ResolverTest*.sql 7 | ResolverTest*.db 8 | AvajeDaoTest*.sql 9 | AvajeDaoTest*.db 10 | NewAvajeDaoTest*.sql 11 | NewAvajeDaoTest*.db 12 | NewAvajeResolverTest*.sql 13 | NewAvajeResolverTest*.db 14 | -------------------------------------------------------------------------------- /src/main/resources/sql/common/V7_update.sql: -------------------------------------------------------------------------------- 1 | CREATE TABLE ${UuidDisplayNameCache} ( 2 | name VARCHAR(255), 3 | display_name VARCHAR(255) NOT NULL, 4 | uuid VARCHAR(255) NOT NULL, 5 | timestamp TIMESTAMP NOT NULL, 6 | PRIMARY KEY (name) 7 | ); 8 | CREATE SEQUENCE ${UuidDisplayNameCache}_seq; 9 | -------------------------------------------------------------------------------- /repo/com/massivecraft/mcore/maven-metadata-local.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | com.massivecraft 4 | mcore 5 | 6 | 7.2.1 7 | 8 | 7.2.1 9 | 10 | 20170607040709 11 | 12 | 13 | -------------------------------------------------------------------------------- /repo/me/tabinol/factoid/Factoid/maven-metadata-local.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | me.tabinol.factoid 4 | Factoid 5 | 6 | 0.3 7 | 8 | 0.3 9 | 10 | 20170607040819 11 | 12 | 13 | -------------------------------------------------------------------------------- /repo/com/massivecraft/Factions/maven-metadata-local.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | com.massivecraft 4 | Factions 5 | 6 | 2.4.0 7 | 8 | 2.4.0 9 | 10 | 20170607040844 11 | 12 | 13 | -------------------------------------------------------------------------------- /repo/com/bekvon/bukkit/Residence/maven-metadata-local.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | com.bekvon.bukkit 4 | Residence 5 | 6 | 2.6.6.4 7 | 8 | 2.6.6.4 9 | 10 | 20170607040742 11 | 12 | 13 | -------------------------------------------------------------------------------- /repo/com/massivecraft/mcore/7.2.1/mcore-7.2.1.pom: -------------------------------------------------------------------------------- 1 | 2 | 4 | 4.0.0 5 | com.massivecraft 6 | mcore 7 | 7.2.1 8 | POM was created from install:install-file 9 | 10 | -------------------------------------------------------------------------------- /repo/me/tabinol/factoid/Factoid/0.3/Factoid-0.3.pom: -------------------------------------------------------------------------------- 1 | 2 | 4 | 4.0.0 5 | me.tabinol.factoid 6 | Factoid 7 | 0.3 8 | POM was created from install:install-file 9 | 10 | -------------------------------------------------------------------------------- /repo/com/massivecraft/Factions/2.4.0/Factions-2.4.0.pom: -------------------------------------------------------------------------------- 1 | 2 | 4 | 4.0.0 5 | com.massivecraft 6 | Factions 7 | 2.4.0 8 | POM was created from install:install-file 9 | 10 | -------------------------------------------------------------------------------- /repo/com/bekvon/bukkit/Residence/2.6.6.4/Residence-2.6.6.4.pom: -------------------------------------------------------------------------------- 1 | 2 | 4 | 4.0.0 5 | com.bekvon.bukkit 6 | Residence 7 | 2.6.6.4 8 | POM was created from install:install-file 9 | 10 | -------------------------------------------------------------------------------- /src/main/resources/sql/common/V3_update.sql: -------------------------------------------------------------------------------- 1 | CREATE TABLE ${EntityMetadata} ( 2 | id BIGINT, 3 | entity_id BIGINT NOT NULL, 4 | name VARCHAR(255) NOT NULL, 5 | string_value VARCHAR(255), 6 | integer_value BIGINT, 7 | real_value DOUBLE PRECISION, 8 | boolean_value BOOL, 9 | PRIMARY KEY (id), 10 | UNIQUE (entity_id, name) 11 | ); 12 | CREATE SEQUENCE ${EntityMetadata}_seq; 13 | CREATE INDEX ON ${EntityMetadata} (entity_id); 14 | ALTER TABLE ${EntityMetadata} ADD CONSTRAINT fk_${EntityMetadata}_entity FOREIGN KEY (entity_id) REFERENCES ${PermissionEntity} (id); 15 | -------------------------------------------------------------------------------- /src/main/resources/sql/mysql/V3_update.sql: -------------------------------------------------------------------------------- 1 | CREATE TABLE ${EntityMetadata} ( 2 | id BIGINT NOT NULL AUTO_INCREMENT, 3 | entity_id BIGINT NOT NULL, 4 | name VARCHAR(255) NOT NULL, 5 | string_value VARCHAR(255), 6 | integer_value BIGINT, 7 | real_value DOUBLE PRECISION, 8 | boolean_value TINYINT(1), 9 | PRIMARY KEY (id), 10 | UNIQUE (entity_id, name) 11 | ); 12 | CREATE INDEX ix_${EntityMetadata}_entity ON ${EntityMetadata} (entity_id); 13 | ALTER TABLE ${EntityMetadata} ADD CONSTRAINT fk_${EntityMetadata}_entity FOREIGN KEY (entity_id) REFERENCES ${PermissionEntity} (id); 14 | -------------------------------------------------------------------------------- /src/main/resources/sql/common/V4_update.sql: -------------------------------------------------------------------------------- 1 | CREATE TABLE ${Inheritance} ( 2 | id BIGINT, 3 | child_id BIGINT NOT NULL, 4 | parent_id BIGINT NOT NULL, 5 | ordering INTEGER NOT NULL, 6 | PRIMARY KEY (id), 7 | UNIQUE (child_id, parent_id) 8 | ); 9 | CREATE SEQUENCE ${Inheritance}_seq; 10 | CREATE INDEX ON ${Inheritance} (child_id); 11 | CREATE INDEX ON ${Inheritance} (parent_id); 12 | ALTER TABLE ${Inheritance} ADD CONSTRAINT fk_${Inheritance}_child FOREIGN KEY (child_id) REFERENCES ${PermissionEntity} (id); 13 | ALTER TABLE ${Inheritance} ADD CONSTRAINT fk_${Inheritance}_parent FOREIGN KEY (parent_id) REFERENCES ${PermissionEntity} (id); 14 | -------------------------------------------------------------------------------- /src/main/resources/sql/mysql/V4_update.sql: -------------------------------------------------------------------------------- 1 | CREATE TABLE ${Inheritance} ( 2 | id BIGINT NOT NULL AUTO_INCREMENT, 3 | child_id BIGINT NOT NULL, 4 | parent_id BIGINT NOT NULL, 5 | ordering INTEGER NOT NULL, 6 | PRIMARY KEY (id), 7 | UNIQUE (child_id, parent_id) 8 | ); 9 | CREATE INDEX ix_${Inheritance}_child ON ${Inheritance} (child_id); 10 | CREATE INDEX ix_${Inheritance}_parent ON ${Inheritance} (parent_id); 11 | ALTER TABLE ${Inheritance} ADD CONSTRAINT fk_${Inheritance}_child FOREIGN KEY (child_id) REFERENCES ${PermissionEntity} (id); 12 | ALTER TABLE ${Inheritance} ADD CONSTRAINT fk_${Inheritance}_parent FOREIGN KEY (parent_id) REFERENCES ${PermissionEntity} (id); 13 | -------------------------------------------------------------------------------- /src/main/java/org/tyrannyofheaven/bukkit/zPermissions/ReadOnlyException.java: -------------------------------------------------------------------------------- 1 | package org.tyrannyofheaven.bukkit.zPermissions; 2 | 3 | /** 4 | * Exception thrown when attempting a write operation when configured as read-only. 5 | * 6 | * @author zerothangel 7 | */ 8 | public class ReadOnlyException extends RuntimeException { 9 | 10 | private static final long serialVersionUID = -1190631455357421902L; 11 | 12 | public ReadOnlyException() { 13 | } 14 | 15 | public ReadOnlyException(String message, Throwable cause) { 16 | super(message, cause); 17 | } 18 | 19 | public ReadOnlyException(String message) { 20 | super(message); 21 | } 22 | 23 | public ReadOnlyException(Throwable cause) { 24 | super(cause); 25 | } 26 | 27 | } 28 | -------------------------------------------------------------------------------- /src/main/java/org/tyrannyofheaven/bukkit/zPermissions/uuid/BulkUuidConverter.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2014 ZerothAngel 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package org.tyrannyofheaven.bukkit.zPermissions.uuid; 17 | 18 | public interface BulkUuidConverter { 19 | 20 | public void migrate() throws Exception; 21 | 22 | } 23 | -------------------------------------------------------------------------------- /src/main/java/org/tyrannyofheaven/bukkit/zPermissions/RefreshCause.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2013 ZerothAngel 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package org.tyrannyofheaven.bukkit.zPermissions; 17 | 18 | /** 19 | * Cause of refresh event. Internal use only. 20 | * 21 | * @author zerothangel 22 | */ 23 | public enum RefreshCause { 24 | COMMAND, 25 | GROUP_CHANGE, 26 | MOVEMENT; 27 | } 28 | -------------------------------------------------------------------------------- /src/test/java/org/tyrannyofheaven/bukkit/zPermissions/MemoryResolverTest.java: -------------------------------------------------------------------------------- 1 | package org.tyrannyofheaven.bukkit.zPermissions; 2 | 3 | import java.util.Collections; 4 | 5 | import org.tyrannyofheaven.bukkit.zPermissions.dao.FilePermissionDao; 6 | import org.tyrannyofheaven.bukkit.zPermissions.dao.InMemoryPermissionService; 7 | 8 | public class MemoryResolverTest extends AbstractResolverTest { 9 | 10 | public MemoryResolverTest() { 11 | permissionService = new InMemoryPermissionService(); 12 | permissionService.setPermissionDao(new FilePermissionDao(permissionService)); 13 | resolver = new PermissionsResolver(permissionService); 14 | resolver.setDefaultGroup(TEST_GROUP1); 15 | resolver.setGroupPermissionFormats(Collections.singleton("group.%s")); 16 | resolver.setAssignedGroupPermissionFormats(Collections.singleton("assignedgroup.%s")); 17 | } 18 | 19 | @Override 20 | protected void begin() { 21 | } 22 | 23 | @Override 24 | protected void commit() { 25 | } 26 | 27 | @Override 28 | protected void end() { 29 | } 30 | 31 | } 32 | -------------------------------------------------------------------------------- /src/main/java/org/tyrannyofheaven/bukkit/zPermissions/service/PlayerPrefixHandler.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2014 ZerothAngel 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package org.tyrannyofheaven.bukkit.zPermissions.service; 17 | 18 | import java.util.UUID; 19 | 20 | import org.tyrannyofheaven.bukkit.zPermissions.ZPermissionsService; 21 | 22 | public interface PlayerPrefixHandler { 23 | 24 | public String getPlayerPrefix(ZPermissionsService service, UUID uuid); 25 | 26 | public String getPlayerSuffix(ZPermissionsService service, UUID uuid); 27 | 28 | } 29 | -------------------------------------------------------------------------------- /src/main/java/org/tyrannyofheaven/bukkit/zPermissions/dao/MissingGroupException.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2011 ZerothAngel 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package org.tyrannyofheaven.bukkit.zPermissions.dao; 17 | 18 | /** 19 | * Thrown when referencing a non-existent group. 20 | * 21 | * @author zerothangel 22 | */ 23 | public class MissingGroupException extends PermissionServiceException { 24 | 25 | private static final long serialVersionUID = 1066889464517437579L; 26 | 27 | private final String groupName; 28 | 29 | public MissingGroupException(String groupName) { 30 | this.groupName = groupName; 31 | } 32 | 33 | public String getGroupName() { 34 | return groupName; 35 | } 36 | 37 | } 38 | -------------------------------------------------------------------------------- /.hgtags: -------------------------------------------------------------------------------- 1 | 6065729cd178c08e9861e57ee400305c4dc2e5b7 0.9 2 | 9797c16b57c0951decbb6d4fc65afb52585b06f1 0.9.1 3 | 021705f6f6f97813ea1967fcf4cf801935a97cfc 0.9.2 4 | 00d1b3fa4c1e8c098a0fffd8a4bcc995bef5cf81 0.9.3 5 | fc9bc996dbb40709fd2881c07c14cc5f194a9dbd 0.9.4 6 | 96cdcd21da04999f15e082606d1729b41a9c1806 0.9.5 7 | f054e7f0d96ba126c997da7f3d019cdcfb3048c1 0.9.6 8 | a78f92c0446f0430007ceada4feb43c455751ff8 0.9.7 9 | cb1b281981f788a4a3b15d6e304a090794b41a6e 0.9.8 10 | 06f2e6f3401ec0739c1914388baf35e7a332dc5a 0.9.9 11 | 38b97ac74fbeade3bb55796358a60367a3fb63af 0.9.10 12 | f8b8abdd5d9cf2aca79ea2cabf3c9ce4c254a67d 0.9.11 13 | 649089a654fbc8ee4b2783aa9450ba3877adb70d 0.9.12 14 | 6f9a4db4326c9f39a7edcfcbbcd4bc5ebac91887 0.9.13 15 | 32ba8ebb29c35194649e0b70e8e6000ead4d9794 0.9.14 16 | f93638bb3c297eecc5892363d73e66d0134d1dd2 0.9.15 17 | 6a9ccbbf03d1d04c40ef84043655c370d0369307 0.9.16 18 | d15a9c06d35c12e7d6367c5a171596dbb26fdd36 0.9.17 19 | e80be92fee980c76a2abbd8bfeb375543fd9b942 0.9.18 20 | 6451e28c35502dc16033fc84e395e8867053d147 0.9.19 21 | d640e0ff325aa24e055467ecdfec8bc840bd55df 1.0 22 | 0d18aea4c0d27a187835a516ef6f6143bd291e64 1.0.1 23 | 8a8c90500b8d143bff5bbb6596fd270360000d3d 1.0.1a 24 | ad0bb8bfc3c9af078e76f54446c2543be3e0f734 1.1 25 | aca48fe33f9f98b8a22be328e9c7f19cc6a692a9 1.1.1 26 | 636cc917e9aad3d2ab1754e5f63bf3f43f5da990 1.2 27 | da5b510f9c20da0b1cf83218e835537d65b2c787 1.3beta1 28 | -------------------------------------------------------------------------------- /src/main/java/org/tyrannyofheaven/bukkit/zPermissions/util/MetadataConstants.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2013 ZerothAngel 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package org.tyrannyofheaven.bukkit.zPermissions.util; 17 | 18 | /** 19 | * Simple holder for the names of common metadata properties. These properties 20 | * have no intrinsic significance but do affect Vault. 21 | * 22 | * @author zerothangel 23 | */ 24 | public class MetadataConstants { 25 | 26 | public static final String PREFIX_KEY = "prefix"; 27 | 28 | public static final String SUFFIX_KEY = "suffix"; 29 | 30 | public static final String PRIMARY_GROUP_TRACK_KEY = "Vault.primary-group.track"; 31 | 32 | private MetadataConstants() { 33 | throw new AssertionError("Don't instantiate me!"); 34 | } 35 | 36 | } 37 | -------------------------------------------------------------------------------- /src/main/java/org/tyrannyofheaven/bukkit/zPermissions/dao/PermissionServiceException.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2011 ZerothAngel 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package org.tyrannyofheaven.bukkit.zPermissions.dao; 17 | 18 | /** 19 | * Thrown for any errors originating within PermissionService. 20 | * 21 | * @author zerothangel 22 | */ 23 | public class PermissionServiceException extends RuntimeException { 24 | 25 | private static final long serialVersionUID = 79973002335863673L; 26 | 27 | public PermissionServiceException() { 28 | } 29 | 30 | public PermissionServiceException(String message) { 31 | super(message); 32 | } 33 | 34 | public PermissionServiceException(Throwable cause) { 35 | super(cause); 36 | } 37 | 38 | public PermissionServiceException(String message, Throwable cause) { 39 | super(message, cause); 40 | } 41 | 42 | } 43 | -------------------------------------------------------------------------------- /src/main/resources/org/tyrannyofheaven/bukkit/zPermissions/config.yml: -------------------------------------------------------------------------------- 1 | config-version: 19 2 | 3 | database-support: true 4 | 5 | database-read-only: false 6 | 7 | database: 8 | username: us3r 9 | isolation: SERIALIZABLE 10 | driver: org.sqlite.JDBC 11 | password: passw0rd 12 | url: jdbc:sqlite:plugins/zPermissions/zPermissions.db 13 | 14 | 15 | region-support: true 16 | 17 | group-permission: 'group.%s' 18 | 19 | assigned-group-permission: '' 20 | 21 | assigned-groups-can-include-default: true 22 | 23 | default-group: default 24 | 25 | explicit-default-group-membership: false 26 | 27 | default-track: default 28 | 29 | dump-directory: zPermissions-dumps 30 | 31 | default-temp-permission-timeout: 60 32 | 33 | tracks: 34 | default: 35 | - default 36 | - somegroup 37 | - someothergroup 38 | 39 | default-primary-group-track: '' 40 | 41 | kick-on-error: true 42 | 43 | kick-ops-on-error: false 44 | 45 | auto-refresh-interval: -1 46 | 47 | auto-refresh-force: false 48 | 49 | opaque-inheritance: true 50 | 51 | interleaved-player-permissions: true 52 | 53 | rank-admin-broadcast: false 54 | 55 | region-managers: 56 | - WorldGuard 57 | - Residence 58 | - Factions 59 | - Factoid 60 | 61 | inherited-metadata: false 62 | 63 | native-vault-bridges: true 64 | 65 | vault-prefix-includes-group: true 66 | 67 | vault-metadata-includes-group: true 68 | 69 | vault-group-test-uses-assigned-only: false 70 | 71 | vault-get-groups-uses-assigned-only: false 72 | 73 | vault-player-prefix-format: '' 74 | 75 | vault-player-suffix-format: '' 76 | 77 | log-vault-changes: false 78 | 79 | debug: false 80 | -------------------------------------------------------------------------------- /src/test/java/org/tyrannyofheaven/bukkit/zPermissions/dao/MemoryDaoTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2011, 2012 ZerothAngel 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package org.tyrannyofheaven.bukkit.zPermissions.dao; 17 | 18 | import org.tyrannyofheaven.bukkit.zPermissions.model.PermissionRegion; 19 | import org.tyrannyofheaven.bukkit.zPermissions.model.PermissionWorld; 20 | 21 | public class MemoryDaoTest extends AbstractDaoTest { 22 | 23 | public MemoryDaoTest() { 24 | getPermissionService().setPermissionDao(new FilePermissionDao(getPermissionService())); 25 | } 26 | 27 | @Override 28 | protected void begin() { 29 | } 30 | 31 | @Override 32 | protected void commit() { 33 | } 34 | 35 | @Override 36 | protected void end() { 37 | } 38 | 39 | @Override 40 | protected PermissionWorld getWorld(String name) { 41 | return getPermissionService().getWorld(name); 42 | } 43 | 44 | @Override 45 | protected PermissionRegion getRegion(String name) { 46 | return getPermissionService().getRegion(name); 47 | } 48 | 49 | } 50 | -------------------------------------------------------------------------------- /src/main/java/org/tyrannyofheaven/bukkit/zPermissions/command/UuidCacheCommands.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2014 ZerothAngel 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package org.tyrannyofheaven.bukkit.zPermissions.command; 17 | 18 | import org.bukkit.command.CommandSender; 19 | import org.tyrannyofheaven.bukkit.util.command.Command; 20 | import org.tyrannyofheaven.bukkit.util.command.Option; 21 | import org.tyrannyofheaven.bukkit.util.uuid.UuidResolver; 22 | 23 | public class UuidCacheCommands { 24 | 25 | private final UuidResolver uuidResolver; 26 | 27 | public UuidCacheCommands(UuidResolver uuidResolver) { 28 | this.uuidResolver = uuidResolver; 29 | } 30 | 31 | @Command(value="invalidate", description="Invalidate cache entry for a single name") 32 | public void invalidate(CommandSender sender, @Option(value="player", completer="player") String playerName) { 33 | uuidResolver.invalidate(playerName); 34 | } 35 | 36 | @Command(value="invalidate-all", description="Invalidate all cache entries") 37 | public void invalidate(CommandSender sender) { 38 | uuidResolver.invalidateAll(); 39 | } 40 | 41 | } 42 | -------------------------------------------------------------------------------- /src/main/java/org/tyrannyofheaven/bukkit/zPermissions/command/TrackTypeCompleter.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2012 ZerothAngel 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package org.tyrannyofheaven.bukkit.zPermissions.command; 17 | 18 | import java.util.ArrayList; 19 | import java.util.Collections; 20 | import java.util.List; 21 | 22 | import org.bukkit.command.CommandSender; 23 | import org.bukkit.util.StringUtil; 24 | import org.tyrannyofheaven.bukkit.util.command.TypeCompleter; 25 | import org.tyrannyofheaven.bukkit.zPermissions.ZPermissionsConfig; 26 | 27 | public class TrackTypeCompleter implements TypeCompleter { 28 | 29 | private final ZPermissionsConfig config; 30 | 31 | public TrackTypeCompleter(ZPermissionsConfig config) { 32 | this.config = config; 33 | } 34 | 35 | @Override 36 | public List complete(Class clazz, String arg, CommandSender sender, String partial) { 37 | if (clazz == String.class) { 38 | List result = new ArrayList<>(); 39 | StringUtil.copyPartialMatches(partial, config.getTracks(), result); 40 | // NB not sorted, left in definition order 41 | return result; 42 | } 43 | return Collections.emptyList(); 44 | } 45 | 46 | } 47 | -------------------------------------------------------------------------------- /src/main/java/org/tyrannyofheaven/bukkit/zPermissions/command/GroupTypeCompleter.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2012 ZerothAngel 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package org.tyrannyofheaven.bukkit.zPermissions.command; 17 | 18 | import java.util.ArrayList; 19 | import java.util.Collections; 20 | import java.util.List; 21 | 22 | import org.bukkit.command.CommandSender; 23 | import org.bukkit.util.StringUtil; 24 | import org.tyrannyofheaven.bukkit.util.command.TypeCompleter; 25 | import org.tyrannyofheaven.bukkit.zPermissions.dao.PermissionService; 26 | 27 | public class GroupTypeCompleter implements TypeCompleter { 28 | 29 | private final PermissionService permissionService; 30 | 31 | public GroupTypeCompleter(PermissionService permissionService) { 32 | this.permissionService = permissionService; 33 | } 34 | 35 | @Override 36 | public List complete(Class clazz, String arg, CommandSender sender, String partial) { 37 | if (clazz == String.class) { 38 | List result = new ArrayList<>(); 39 | StringUtil.copyPartialMatches(partial, permissionService.getEntityNames(true), result); 40 | Collections.sort(result); 41 | return result; 42 | } 43 | return Collections.emptyList(); 44 | } 45 | 46 | } 47 | -------------------------------------------------------------------------------- /src/main/java/org/tyrannyofheaven/bukkit/zPermissions/ZPermissionsConfig.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2013 ZerothAngel 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package org.tyrannyofheaven.bukkit.zPermissions; 17 | 18 | import java.io.File; 19 | import java.util.List; 20 | 21 | /** 22 | * Holds configuration data used by other modules, namely the command handlers. 23 | * 24 | * @author zerothangel 25 | */ 26 | public interface ZPermissionsConfig { 27 | 28 | public List getTracks(); 29 | 30 | public String getDefaultTrack(); 31 | 32 | public List getTrack(String trackName); 33 | 34 | public File getDumpDirectory(); 35 | 36 | public boolean isRankAdminBroadcast(); 37 | 38 | public int getDefaultTempPermissionTimeout(); 39 | 40 | public String getDefaultPrimaryGroupTrack(); 41 | 42 | public boolean isVaultPrefixIncludesGroup(); 43 | 44 | public boolean isVaultMetadataIncludesGroup(); 45 | 46 | public boolean isVaultGroupTestUsesAssignedOnly(); 47 | 48 | public boolean isVaultGetGroupsUsesAssignedOnly(); 49 | 50 | public boolean isInheritedMetadata(); 51 | 52 | public String getVaultPlayerPrefixFormat(); 53 | 54 | public String getVaultPlayerSuffixFormat(); 55 | 56 | public int getSearchBatchSize(); 57 | 58 | public int getSearchDelay(); 59 | 60 | public boolean isServiceMetadataPrefixHack(); 61 | 62 | } 63 | -------------------------------------------------------------------------------- /src/main/java/org/tyrannyofheaven/bukkit/zPermissions/model/PermissionWorld.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2011 ZerothAngel 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package org.tyrannyofheaven.bukkit.zPermissions.model; 17 | 18 | import javax.persistence.Entity; 19 | import javax.persistence.Id; 20 | import javax.persistence.Table; 21 | import javax.persistence.UniqueConstraint; 22 | 23 | /** 24 | * Represents a world that permission entries may be associated with. 25 | * 26 | * @author zerothangel 27 | */ 28 | @Entity 29 | @Table(name="worlds") 30 | @UniqueConstraint(columnNames="name") 31 | public class PermissionWorld { 32 | 33 | private Long id; 34 | 35 | private String name; 36 | 37 | @Id 38 | public Long getId() { 39 | return id; 40 | } 41 | 42 | public void setId(Long id) { 43 | this.id = id; 44 | } 45 | 46 | public String getName() { 47 | return name; 48 | } 49 | 50 | public void setName(String name) { 51 | this.name = name; 52 | } 53 | 54 | @Override 55 | public boolean equals(Object obj) { 56 | if (obj == this) return true; 57 | if (!(obj instanceof PermissionWorld)) return false; 58 | PermissionWorld o = (PermissionWorld)obj; 59 | return getName() == null ? o.getName() == null : getName().equals(o.getName()); 60 | } 61 | 62 | @Override 63 | public int hashCode() { 64 | return getName() == null ? 0 : getName().hashCode(); 65 | } 66 | 67 | @Override 68 | public String toString() { 69 | return String.format("World[%s]", getName()); 70 | } 71 | 72 | } 73 | -------------------------------------------------------------------------------- /src/main/java/org/tyrannyofheaven/bukkit/zPermissions/model/PermissionRegion.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2011 ZerothAngel 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package org.tyrannyofheaven.bukkit.zPermissions.model; 17 | 18 | import javax.persistence.Entity; 19 | import javax.persistence.Id; 20 | import javax.persistence.Table; 21 | import javax.persistence.UniqueConstraint; 22 | 23 | /** 24 | * Represents a region that permission entries may be associated with. 25 | * 26 | * @author zerothangel 27 | */ 28 | @Entity 29 | @Table(name="regions") 30 | @UniqueConstraint(columnNames="name") 31 | public class PermissionRegion { 32 | 33 | private Long id; 34 | 35 | private String name; 36 | 37 | @Id 38 | public Long getId() { 39 | return id; 40 | } 41 | 42 | public void setId(Long id) { 43 | this.id = id; 44 | } 45 | 46 | public String getName() { 47 | return name; 48 | } 49 | 50 | public void setName(String name) { 51 | this.name = name; 52 | } 53 | 54 | @Override 55 | public boolean equals(Object obj) { 56 | if (obj == this) return true; 57 | if (!(obj instanceof PermissionRegion)) return false; 58 | PermissionRegion o = (PermissionRegion)obj; 59 | return getName() == null ? o.getName() == null : getName().equals(o.getName()); 60 | } 61 | 62 | @Override 63 | public int hashCode() { 64 | return getName() == null ? 0 : getName().hashCode(); 65 | } 66 | 67 | @Override 68 | public String toString() { 69 | return String.format("Region[%s]", getName()); 70 | } 71 | 72 | } 73 | -------------------------------------------------------------------------------- /src/main/java/org/tyrannyofheaven/bukkit/zPermissions/command/DirTypeCompleter.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2012 ZerothAngel 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package org.tyrannyofheaven.bukkit.zPermissions.command; 17 | 18 | import java.io.File; 19 | import java.util.ArrayList; 20 | import java.util.Collections; 21 | import java.util.List; 22 | 23 | import org.bukkit.command.CommandSender; 24 | import org.bukkit.util.StringUtil; 25 | import org.tyrannyofheaven.bukkit.util.command.TypeCompleter; 26 | import org.tyrannyofheaven.bukkit.zPermissions.ZPermissionsConfig; 27 | 28 | public class DirTypeCompleter implements TypeCompleter { 29 | 30 | private final ZPermissionsConfig config; 31 | 32 | public DirTypeCompleter(ZPermissionsConfig config) { 33 | // Dump directory is modifyable via reload, so we have to do this... 34 | this.config = config; 35 | } 36 | 37 | @Override 38 | public List complete(Class clazz, String arg, CommandSender sender, String partial) { 39 | if (clazz == String.class) { 40 | File[] files = config.getDumpDirectory().listFiles(); 41 | if (files != null) { 42 | List result = new ArrayList<>(); 43 | for (File file : files) { 44 | if (file.isFile() && !file.getName().startsWith(".") && StringUtil.startsWithIgnoreCase(file.getName(), partial)) 45 | result.add(file.getName()); 46 | } 47 | Collections.sort(result); 48 | return result; 49 | } 50 | } 51 | return Collections.emptyList(); 52 | } 53 | 54 | } 55 | -------------------------------------------------------------------------------- /src/main/java/org/tyrannyofheaven/bukkit/zPermissions/listener/ZPermissionsFallbackListener.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2011 ZerothAngel 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package org.tyrannyofheaven.bukkit.zPermissions.listener; 17 | 18 | import static org.tyrannyofheaven.bukkit.util.ToHMessageUtils.colorize; 19 | import static org.tyrannyofheaven.bukkit.util.ToHMessageUtils.sendMessage; 20 | 21 | import org.bukkit.event.EventHandler; 22 | import org.bukkit.event.EventPriority; 23 | import org.bukkit.event.Listener; 24 | import org.bukkit.event.player.PlayerJoinEvent; 25 | import org.bukkit.event.player.PlayerLoginEvent; 26 | 27 | /** 28 | * Listener installed if things don't initialize properly. Allows no one to 29 | * log in. 30 | * 31 | * @author zerothangel 32 | */ 33 | public class ZPermissionsFallbackListener implements Listener { 34 | 35 | private static final String KICK_MESSAGE = "zPermissions failed to initialize"; 36 | 37 | private final boolean kickOpsOnError; 38 | 39 | public ZPermissionsFallbackListener(boolean kickOpsOnError) { 40 | this.kickOpsOnError = kickOpsOnError; 41 | } 42 | 43 | @EventHandler(priority=EventPriority.HIGHEST) 44 | public void onPlayerLogin(PlayerLoginEvent event) { 45 | if (kickOpsOnError || !event.getPlayer().isOp()) 46 | event.disallow(PlayerLoginEvent.Result.KICK_OTHER, KICK_MESSAGE); 47 | } 48 | 49 | @EventHandler 50 | public void onPlayerJoin(PlayerJoinEvent event) { 51 | if (event.getPlayer().isOp()) { 52 | sendMessage(event.getPlayer(), colorize("{RED}zPermissions failed to initialize; All non-OP log-ins disallowed!")); 53 | } 54 | } 55 | 56 | } 57 | -------------------------------------------------------------------------------- /doc/vault.md: -------------------------------------------------------------------------------- 1 | ## Vault Support ## 2 | 3 | zPermissions more or less implements 100% of the [Vault](http://dev.bukkit.org/server-mods/vault/) APIs for both permissions and chat. Currently, zPermissions support is built-in to Vault. 4 | 5 | ### Vault Permissions API Notes ### 6 | 7 | * Permissions support was added at around Vault 1.2.13. 8 | * All API methods are supported. 9 | * All player-related methods should work on offline players. 10 | * Due to restrictions I've placed on the zPermissions API, all Vault API methods that modify permissions or membership will execute equivalent commands as console. 11 | * zPermissions groups are universal — they apply to all worlds. Therefore, the world argument to playerAddGroup() and playerRemoveGroup() is ignored. 12 | * zPermissions has no real concept of a "primary group." By default, the primary group of a player is the highest-weight group assigned to that player, i.e. the first group returned when doing a `/permissions player ... groups` or `/permissions mygroups` command. 13 | 14 | Starting with Vault 1.2.26, the primary group can also be controlled by using a metadata property on a player. 15 | 16 | For example: 17 | 18 | /permissions player Alice metadata set Vault.primary-group.track Admin 19 | 20 | Or alternatively: 21 | 22 | /permissions player Alice settrack Admin 23 | 24 | Assuming Alice has been previously promoted on the Admin track, her primary group will be the highest-ranked group from that track regardless of assignment priorities. 25 | 26 | If Alice is not on the Admin track then the behavior returns to the default, i.e. the highest-weight assigned group. 27 | 28 | ### Vault Chat API Notes ### 29 | 30 | * Chat support was added in Vault 1.2.25. 31 | * The primary group is determined as explained above. 32 | * All Vault API "player info" and "group info" methods are supported. They map directly to zPermissions metadata properties. 33 | * All Vault API methods that set prefix/suffix/infos will execute an equivalent command as console. 34 | * Prefixes and suffixes are set by the `prefix` and `suffix` (string) metadata properties on both players and groups. 35 | 36 | Examples: 37 | 38 | /permissions group VIP md set prefix [VIP] 39 | /permissions player Bob metadata set prefix &f 40 | /permissions group Mod prefix "[Mod: " 41 | /permissions group Mod suffix ] 42 | -------------------------------------------------------------------------------- /src/main/java/org/tyrannyofheaven/bukkit/zPermissions/model/DataVersion.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2013 ZerothAngel 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package org.tyrannyofheaven.bukkit.zPermissions.model; 17 | 18 | import java.util.Date; 19 | 20 | import javax.persistence.Column; 21 | import javax.persistence.Entity; 22 | import javax.persistence.Id; 23 | import javax.persistence.Temporal; 24 | import javax.persistence.TemporalType; 25 | 26 | /** 27 | * Entity class to keep track of the current data version. 28 | * 29 | * @author zerothangel 30 | */ 31 | @Entity 32 | public class DataVersion { 33 | 34 | private String name; 35 | 36 | private long version; 37 | 38 | private Date timestamp; 39 | 40 | @Id 41 | public String getName() { 42 | return name; 43 | } 44 | 45 | public void setName(String name) { 46 | this.name = name; 47 | } 48 | 49 | @Column(nullable=false) 50 | public long getVersion() { 51 | return version; 52 | } 53 | 54 | public void setVersion(long version) { 55 | this.version = version; 56 | } 57 | 58 | @Column(nullable=false) 59 | @Temporal(TemporalType.TIMESTAMP) 60 | public Date getTimestamp() { 61 | return timestamp; 62 | } 63 | 64 | public void setTimestamp(Date timestamp) { 65 | this.timestamp = timestamp; 66 | } 67 | 68 | @Override 69 | public boolean equals(Object obj) { 70 | if (obj == this) return true; 71 | if (!(obj instanceof DataVersion)) return false; 72 | DataVersion o = (DataVersion)obj; 73 | return getName().equals(o.getName()); 74 | } 75 | 76 | @Override 77 | public int hashCode() { 78 | return getName().hashCode(); 79 | } 80 | 81 | @Override 82 | public String toString() { 83 | return String.format("%s #%d (%s)", getName(), getVersion(), getTimestamp()); 84 | } 85 | 86 | } 87 | -------------------------------------------------------------------------------- /doc/temporary.md: -------------------------------------------------------------------------------- 1 | ## Temporary Permissions & Groups ## 2 | 3 | zPermissions supports two methods of giving players temporary permissions: the settemp command and temporary group assignments. 4 | 5 | ### settemp ### 6 | 7 | The settemp command looks like so: 8 | 9 | /permissions player settemp [-t ] [value] 10 | 11 | The timeout is in seconds and, if omitted, will default to the value specified in config.yml. Ideally, the timeout should be something short — a few seconds to a few minutes. The reason being that settemp is implemented using Bukkit's own support for temporary permissions. Which means that these temporary permissions are truly temporary — they will disappear when any of the following happens: the player logs off, the server is restarted, and of course, when they expire. 12 | 13 | ## Temporary Group Assignments ## 14 | 15 | The group..add command will take an optional duration or timestamp: 16 | 17 | /permissions group add [] 18 | 19 | As will the player..setgroup command: 20 | 21 | /permissions player setgroup [] 22 | 23 | The duration defaults to days and may be modified by adding any of the following suffixes: 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 |
SuffixUnits
min, mins, minute, minutesMinutes
h, hour, hoursHours
d, day, daysDays
m, month, monthsMonths
y, year, yearsYears
33 | 34 | A timestamp takes either of the following forms: 35 | 36 | 37 | 38 | 39 | 40 |
FormatExample
YYYY-MM-DDThh:mm2013-06-14T19:46
YYYY-MM-DD2013-06-14
41 | (In reality, it will take any [ISO 8601](http://en.wikipedia.org/wiki/ISO_8601) formatted timestamp including seconds and timezone offset.) 42 | 43 | If you use temporary group assignments in lieu of (settemp) temporary permissions (maybe because you want the permissions to persist until expiration, regardless of the player logging off or server restarting), you might consider setting the weight of the group to some negative number so it doesn't intefere with the primary group determination [as described here](http://dev.bukkit.org/bukkit-plugins/zpermissions/pages/vault-support/). This might only be needed if you use a chat formatting plugin with zPermissions as your source of prefixes/suffixes. 44 | -------------------------------------------------------------------------------- /src/main/java/org/tyrannyofheaven/bukkit/zPermissions/model/Inheritance.java: -------------------------------------------------------------------------------- 1 | package org.tyrannyofheaven.bukkit.zPermissions.model; 2 | 3 | import javax.persistence.Column; 4 | import javax.persistence.Entity; 5 | import javax.persistence.Id; 6 | import javax.persistence.ManyToOne; 7 | import javax.persistence.Table; 8 | import javax.persistence.UniqueConstraint; 9 | 10 | @Entity 11 | @Table(name="inheritances") 12 | @UniqueConstraint(columnNames={"child_id", "parent_id"}) 13 | public class Inheritance implements Comparable { 14 | 15 | private Long id; 16 | 17 | private PermissionEntity child; 18 | 19 | private PermissionEntity parent; 20 | 21 | private int ordering; 22 | 23 | @Id 24 | public Long getId() { 25 | return id; 26 | } 27 | 28 | public void setId(Long id) { 29 | this.id = id; 30 | } 31 | 32 | @Column(name="child_id") 33 | @ManyToOne(optional=false) 34 | public PermissionEntity getChild() { 35 | return child; 36 | } 37 | 38 | public void setChild(PermissionEntity child) { 39 | this.child = child; 40 | } 41 | 42 | @Column(name="parent_id") 43 | @ManyToOne(optional=false) 44 | public PermissionEntity getParent() { 45 | return parent; 46 | } 47 | 48 | public void setParent(PermissionEntity parent) { 49 | this.parent = parent; 50 | } 51 | 52 | @Column(nullable=false) 53 | public int getOrdering() { 54 | return ordering; 55 | } 56 | 57 | public void setOrdering(int ordering) { 58 | this.ordering = ordering; 59 | } 60 | 61 | @Override 62 | public boolean equals(Object obj) { 63 | if (obj == this) return true; 64 | if (!(obj instanceof Inheritance)) return false; 65 | Inheritance o = (Inheritance)obj; 66 | return getParent().equals(o.getParent()) && 67 | getChild().equals(o.getChild()); 68 | } 69 | 70 | @Override 71 | public int hashCode() { 72 | int result = 17; 73 | result = 37 * result + getParent().hashCode(); 74 | result = 37 * result + getChild().hashCode(); 75 | return result; 76 | } 77 | 78 | @Override 79 | public String toString() { 80 | return String.format("Inheritance[%s > %s]", getParent().getName(), getChild().getName()); 81 | } 82 | 83 | @Override 84 | public int compareTo(Inheritance o) { 85 | // Assumes child is the same... i.e. this sorts the parents 86 | return getOrdering() - o.getOrdering(); 87 | } 88 | 89 | } 90 | -------------------------------------------------------------------------------- /doc/tables.md: -------------------------------------------------------------------------------- 1 | # Customizing Table Names # 2 | 3 | If, for whatever reason, you cannot set up bukkit.yml to assign one database per plugin, you can choose to customize the names of zPermissions' tables instead. Doing so will help avoid table name collisions. 4 | 5 | zPermissions has 9 tables. The tables and their default names are: 6 | 7 | * `ToHSchemaVersion` — zperms\_schema_version 8 | * `Entry` — entries 9 | * `Membership` — memberships 10 | * `PermissionEntity` — entities 11 | * `PermissionRegion` — regions 12 | * `PermissionWorld` — worlds 13 | * `EntityMetadata` — metadata 14 | * `Inheritance` — inheritances 15 | * `DataVersion` — data_version 16 | 17 | To customize the names, simply add something like the following to your config.yml: 18 | 19 | tables: 20 | ToHSchemaVersion: zp_schema_version 21 | Entry: zp_entries 22 | Membership: zp_memberships 23 | PermissionEntity: zp_entities 24 | PermissionRegion: zp_regions 25 | PermissionWorld: zp_worlds 26 | EntityMetadata: zp_metadata 27 | Inheritance: zp_inheritances 28 | DataVersion: zp_data_version 29 | 30 | (In this example, the default table names are prefixed with `zp_`.) 31 | 32 | Note that zPermissions will only create the tables if it notices the `ToHSchemaVersion` or `PermissionEntity` tables missing. When changing table names, you should drop all old tables (or `ALTER TABLE ... RENAME TO ...` appropriately). You should change all table names in the configuration at once. 33 | 34 | I have no plans to automate table renaming at all since it would put multi-server/shared-server schemas at risk. 35 | 36 | Also, don't forget you can `/permissions import ...` and `/permissions export ...`, between databases and even between a database and the flat-file. 37 | 38 | Lastly, the table names you specify in config.yml can actually be qualified using the following forms: 39 | 40 | * `catalog.schema.tableName` 41 | * `schema.tableName` 42 | * `tableName` 43 | 44 | For example, 45 | 46 | tables: 47 | ToHSchemaVersion: myserver.zperms_schema_version 48 | Entry: myserver.entries 49 | Membership: myserver.memberships 50 | PermissionEntity: myserver.entities 51 | PermissionRegion: myserver.regions 52 | PermissionWorld: myserver.worlds 53 | EntityMetadata: myserver.metadata 54 | Inheritance: myserver.inheritances 55 | DataVersion: myserver.data_version 56 | 57 | This would place all your tables in the `myserver` schema. Note that named schema support varies from database to database. 58 | -------------------------------------------------------------------------------- /src/main/java/org/tyrannyofheaven/bukkit/zPermissions/model/UuidDisplayNameCache.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2014 ZerothAngel 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package org.tyrannyofheaven.bukkit.zPermissions.model; 17 | 18 | import static org.tyrannyofheaven.bukkit.util.uuid.UuidUtils.uncanonicalizeUuid; 19 | 20 | import java.util.Date; 21 | import java.util.UUID; 22 | 23 | import javax.persistence.Column; 24 | import javax.persistence.Entity; 25 | import javax.persistence.Id; 26 | import javax.persistence.Table; 27 | import javax.persistence.Temporal; 28 | import javax.persistence.TemporalType; 29 | import javax.persistence.Transient; 30 | 31 | import org.tyrannyofheaven.bukkit.util.uuid.UuidUtils; 32 | 33 | @Entity 34 | @Table(name="uuidcache") 35 | public class UuidDisplayNameCache { 36 | 37 | private String name; 38 | 39 | private String displayName; 40 | 41 | private String uuidString; 42 | 43 | private Date timestamp; 44 | 45 | @Id 46 | public String getName() { 47 | return name; 48 | } 49 | 50 | public void setName(String name) { 51 | this.name = name; 52 | } 53 | 54 | @Column(nullable=false) 55 | public String getDisplayName() { 56 | return displayName; 57 | } 58 | 59 | public void setDisplayName(String displayName) { 60 | this.displayName = displayName; 61 | } 62 | 63 | @Column(name="uuid", nullable=false) 64 | public String getUuidString() { 65 | return uuidString; 66 | } 67 | 68 | public void setUuidString(String uuid) { 69 | this.uuidString = uuid; 70 | } 71 | 72 | @Column(nullable=false) 73 | @Temporal(TemporalType.TIMESTAMP) 74 | public Date getTimestamp() { 75 | return timestamp; 76 | } 77 | 78 | public void setTimestamp(Date timestamp) { 79 | this.timestamp = timestamp; 80 | } 81 | 82 | @Transient 83 | public UUID getUuid() { 84 | return uncanonicalizeUuid(getUuidString()); 85 | } 86 | 87 | public void setUuid(UUID uuid) { 88 | setUuidString(UuidUtils.canonicalizeUuid(uuid)); 89 | } 90 | 91 | } 92 | -------------------------------------------------------------------------------- /src/main/java/org/tyrannyofheaven/bukkit/zPermissions/dao/PermissionDao.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2014 ZerothAngel 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package org.tyrannyofheaven.bukkit.zPermissions.dao; 17 | 18 | import java.util.Collection; 19 | 20 | import org.tyrannyofheaven.bukkit.zPermissions.model.EntityMetadata; 21 | import org.tyrannyofheaven.bukkit.zPermissions.model.Entry; 22 | import org.tyrannyofheaven.bukkit.zPermissions.model.Inheritance; 23 | import org.tyrannyofheaven.bukkit.zPermissions.model.Membership; 24 | import org.tyrannyofheaven.bukkit.zPermissions.model.PermissionEntity; 25 | import org.tyrannyofheaven.bukkit.zPermissions.model.PermissionRegion; 26 | import org.tyrannyofheaven.bukkit.zPermissions.model.PermissionWorld; 27 | 28 | /** 29 | * Data-access interface for zPermissions. Mainly concerned with CUD operations 30 | * (that is, CRUD without the R). 31 | * 32 | * @author zerothangel 33 | */ 34 | public interface PermissionDao { 35 | 36 | public void createRegion(PermissionRegion region); 37 | 38 | public void createWorld(PermissionWorld world); 39 | 40 | public void createEntity(PermissionEntity entity); 41 | 42 | public void createOrUpdateEntry(Entry entry); 43 | 44 | public void deleteEntry(Entry entry); 45 | 46 | public void createOrUpdateMembership(Membership membership); 47 | 48 | public void setEntityParent(PermissionEntity entity, PermissionEntity parent); 49 | 50 | public void createOrUpdateInheritance(Inheritance inheritance); 51 | 52 | public void deleteInheritance(Inheritance inheritance); 53 | 54 | public void setEntityPriority(PermissionEntity entity, int priority); 55 | 56 | public void deleteRegions(Collection regions); 57 | 58 | public void deleteWorlds(Collection worlds); 59 | 60 | public void deleteEntity(PermissionEntity entity); 61 | 62 | public void deleteMembership(Membership membership); 63 | 64 | public void createOrUpdateMetadata(EntityMetadata metadata); 65 | 66 | public void deleteMetadata(EntityMetadata metadata); 67 | 68 | public void updateDisplayName(PermissionEntity entity); 69 | 70 | public void updateDisplayName(Membership membership); 71 | 72 | } -------------------------------------------------------------------------------- /doc/schemaupdate.md: -------------------------------------------------------------------------------- 1 | ## Schema Updates ## 2 | 3 | On rare occassions, the current version of zPermissions may perform a schema update. (**Read the change log to see if this is the case.**) If you're using the file-based storage, then none of this applies to you. If you're using a database, then read on. 4 | 5 | **I will only support automated schema updates for H2, MySQL, and PostgreSQL.** That's not to say that zPermissions doesn't work with database X; [Avaje Ebean](http://www.avaje.org/) supports a wide range of databases and zPermissions will probably happily work with most of them. However, as far as developing & testing goes, H2, MySQL, and PostgreSQL are all I have access to. 6 | 7 | **Regardless of which database you use, you should back up your permissions before running a new version of zPermissions that will update your schema.** (Again, the change log will clearly say if the current version will do this.) You can make a backup by performing an export like so: 8 | 9 | /permissions export 10 | 11 | This will create an export file (which is nothing more than a list of commands to re-create your permissions set up) in the configured dump directory. By default, this is `zPermissions-dumps` in your server directory. 12 | 13 | Alternatively (or additionally), you can make an SQL backup as well. How you do that depends on what database you're using. (And you're advised to look at your database administration docs for more details...) 14 | 15 | ### Unsupported Databases ### 16 | 17 | If you have an unsupported database (something other than the 3 I mentioned), then you pretty much only have one choice: 18 | 19 | 1. Perform a `/permissions export` with the prior version of zPermissions 20 | 2. DROP all zPermissions tables, indexes, sequences, etc. 21 | 3. Run the new version of zPermissions 22 | 4. Perform a `/permissions import` 23 | 24 | (A more advanced alternative is to manually update your schema. Depending on what changes, this can be very simple to very complicated. You're almost better off doing the above steps. But here's a hint anyway: Look in the `sql/common` directory in the zPermissions JAR file.) 25 | 26 | ### Schema Version History ### 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 |
VersionzPerms VersionDescription
10.9.17 and earlierInitial schema
20.9.18Adds expiration column to Membership table
30.9.18Adds EntityMetadata table
41.0Adds Inheritance table
51.1Adds DataVersion table
60 | -------------------------------------------------------------------------------- /src/main/java/org/tyrannyofheaven/bukkit/zPermissions/ZPermissionsCore.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2013 ZerothAngel 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package org.tyrannyofheaven.bukkit.zPermissions; 17 | 18 | import java.util.Collection; 19 | import java.util.Set; 20 | import java.util.UUID; 21 | 22 | import org.bukkit.Location; 23 | import org.bukkit.entity.Player; 24 | 25 | /** 26 | * Core operations (usually concerning the online permissions system aka Bukkit) 27 | * called by command handlers and event handlers. 28 | * 29 | * @author zerothangel 30 | */ 31 | public interface ZPermissionsCore { 32 | 33 | // Refreshing the attachments of a set of players 34 | 35 | public void refreshPlayer(UUID uuid, RefreshCause cause); 36 | 37 | public void refreshPlayers(); // Also invalidates metadata cache of refreshed players 38 | 39 | // NB called from async thread 40 | public void refreshPlayers(Collection playerUuids); // Also invalidates metadata cache of refreshed players 41 | 42 | public boolean refreshAffectedPlayers(String groupName); // Also invalidates metadata cache of refreshed players 43 | 44 | // Refreshing the temporary group membership timer 45 | 46 | public void refreshExpirations(); 47 | 48 | public void refreshExpirations(UUID uuid); 49 | 50 | // Config + storage reload 51 | 52 | public void reload(); 53 | 54 | // Storage reload 55 | 56 | public void refresh(boolean force, Runnable runnable); 57 | 58 | // Player attachment control 59 | 60 | public void setBukkitPermissions(Player player, Location location, boolean force, RefreshCause eventCause); 61 | 62 | public void removeBukkitPermissions(Player player, boolean recalculate); 63 | 64 | // Utility 65 | 66 | public Set getRegions(Location location, Player player); 67 | 68 | public void logExternalChange(String message, Object...args); 69 | 70 | public void updateDisplayName(UUID uuid, String displayName); 71 | 72 | public void handleExplicitDefaultGroupMembership(final UUID uuid, final String displayName); 73 | 74 | // Metadata cache management 75 | 76 | public void invalidateMetadataCache(String name, UUID uuid, boolean group); 77 | 78 | public void invalidateMetadataCache(); 79 | 80 | } 81 | -------------------------------------------------------------------------------- /src/main/java/org/tyrannyofheaven/bukkit/zPermissions/region/RegionStrategy.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2013 ZerothAngel 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package org.tyrannyofheaven.bukkit.zPermissions.region; 17 | 18 | import java.util.Set; 19 | 20 | import org.bukkit.Location; 21 | import org.bukkit.entity.Player; 22 | 23 | /** 24 | * Generic strategy for region support. Only requirement from region plugins is 25 | * being able to return a set of region names that contain a given location. 26 | * 27 | * @author zerothangel 28 | */ 29 | public interface RegionStrategy { 30 | 31 | // General / detection 32 | 33 | /** 34 | * Returns the name of the region manager. 35 | * 36 | * @return the name of the region manager 37 | */ 38 | public String getName(); 39 | 40 | /** 41 | * Returns whether or not this region plugin is present. 42 | * 43 | * @return true if present. In which case this strategy will be used as the 44 | * main RegionStrategy and {@link #init()} will be called. 45 | */ 46 | public boolean isPresent(); 47 | 48 | // Lifecycle 49 | 50 | /** 51 | * Attempt to initialize the region manager. Initialization may be synchronous or 52 | * happen later (e.g. PluginEnableEvent). After initialization, {@link #isEnabled()} 53 | * should always return true. 54 | */ 55 | public void init(); 56 | 57 | /** 58 | * Returns whether this RegionStrategy is ready. 59 | * 60 | * @return true if ready to receive calls to {@link #getRegions(Location)}. 61 | */ 62 | public boolean isEnabled(); 63 | 64 | /** 65 | * Do any cleanup. Once this method completes, {@link #isEnabled()} should return false. 66 | * Will be called regardless of {@link #isEnabled()} state, but only if {@link #init()} was called. 67 | */ 68 | public void shutdown(); 69 | 70 | // Service 71 | 72 | /** 73 | * Retrieve the name of all regions that contain the given ocation. 74 | * 75 | * @param location the location 76 | * @param player the player in question (for supplemental info) 77 | * @return name of containing regions or empty set. Never null. Region names 78 | * must be in all lowercase. 79 | */ 80 | public Set getRegions(Location location, Player player); 81 | 82 | } 83 | -------------------------------------------------------------------------------- /src/main/java/org/tyrannyofheaven/bukkit/zPermissions/listener/ZPermissionsRegionPlayerListener.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2011, 2012 ZerothAngel 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package org.tyrannyofheaven.bukkit.zPermissions.listener; 17 | 18 | import org.bukkit.event.EventHandler; 19 | import org.bukkit.event.EventPriority; 20 | import org.bukkit.event.Listener; 21 | import org.bukkit.event.player.PlayerMoveEvent; 22 | import org.bukkit.event.player.PlayerRespawnEvent; 23 | import org.bukkit.event.player.PlayerTeleportEvent; 24 | import org.tyrannyofheaven.bukkit.zPermissions.RefreshCause; 25 | import org.tyrannyofheaven.bukkit.zPermissions.ZPermissionsCore; 26 | 27 | /** 28 | * Additional player events to listen on if (WorldGuard) region support is 29 | * enabled. 30 | * 31 | * @author zerothangel 32 | */ 33 | public class ZPermissionsRegionPlayerListener implements Listener { 34 | 35 | private final ZPermissionsCore core; 36 | 37 | public ZPermissionsRegionPlayerListener(ZPermissionsCore plugin) { 38 | this.core = plugin; 39 | } 40 | 41 | @EventHandler(priority=EventPriority.MONITOR, ignoreCancelled=true) 42 | public void onPlayerTeleport(PlayerTeleportEvent event) { 43 | // Conditionally update if world or region changed 44 | core.setBukkitPermissions(event.getPlayer(), event.getTo(), false, RefreshCause.MOVEMENT); 45 | } 46 | 47 | @EventHandler(priority=EventPriority.MONITOR, ignoreCancelled=true) 48 | public void onPlayerMove(PlayerMoveEvent event) { 49 | // Only bother if player actually moved to a new block 50 | if (event.getFrom().getBlockX() != event.getTo().getBlockX() || 51 | event.getFrom().getBlockY() != event.getTo().getBlockY() || 52 | event.getFrom().getBlockZ() != event.getTo().getBlockZ()) { 53 | // Conditionally update if containing regions changed 54 | core.setBukkitPermissions(event.getPlayer(), event.getTo(), false, RefreshCause.MOVEMENT); 55 | } 56 | } 57 | 58 | @EventHandler(priority=EventPriority.MONITOR, ignoreCancelled=true) 59 | public void onPlayerRespawn(PlayerRespawnEvent event) { 60 | // Conditionally update if respawning in a different world or region 61 | core.setBukkitPermissions(event.getPlayer(), event.getRespawnLocation(), false, RefreshCause.MOVEMENT); 62 | } 63 | 64 | } 65 | -------------------------------------------------------------------------------- /doc/quickstart.md: -------------------------------------------------------------------------------- 1 | # Quick Start # 2 | 3 | ## Storage Set-Up ## 4 | 5 | zPermissions was primarily developed with using a (real) SQL database in mind. However, you can also opt to use it with a simple flat-file storage method. For SQL storage, zPermissions uses the persistence library included with CraftBukkit (called [Avaje Ebean](http://avaje.org/)). This persistence library is normally configured from the bukkit.yml file, under the `database` section. 6 | 7 | The first thing to do is to decide how you want to set up zPermissions's permission storage: Will you be connecting to a database server? Use a flat-file? Or as another alternative, use an embedded database? 8 | 9 | ### Database Server ### 10 | 11 | The most common free and open source database servers are [MySQL](http://dev.mysql.com/) and [PostgreSQL](http://www.postgresql.org/). Note that if you don't already have a basic understanding of setting up and administering these database servers, look and read their respective documentation. Alternatively, you might want to consider using the zPermissions flat-file approach. 12 | 13 | Detailed instructions on configuring zPermissions with SQL database servers may be found at the [For Server Admins page](http://dev.bukkit.org/server-mods/zpermissions/pages/for-server-admins/). 14 | 15 | ### Flat-File Storage ### 16 | 17 | To use flat-file storage, you must start your server with zPermissions at least once to create its config.yml. You can leave bukkit.yml as-is (i.e. configured for SQLite, which isn't compatible with zPermissions) since zPermissions will fall back to flat-file storage anyway. Once the config.yml has been created, set the following option to `false`: 18 | 19 | database-support: false 20 | 21 | ### Embedded Database ### 22 | 23 | To use an embedded database (similar to SQLite), see the [H2](http://www.h2database.com/) instructions at the [For Server Admins page](http://dev.bukkit.org/server-mods/zpermissions/pages/for-server-admins/). 24 | 25 | ## ebean.properties SEVERE message ## 26 | 27 | Note that you may see the following error in your logs: 28 | 29 | [SEVERE] ebean.properties not found 30 | 31 | This is perfectly normal and harmless. But if you want to get rid of the message, simply create an empty file called `ebean.properties` in the same directory as bukkit.yml. 32 | 33 | ## The Default Group ## 34 | 35 | The default group is determined by the `default-group` option in zPermissions's config.yml. Out-of-the-box, the default-group is named `default`. (If you change this option, be sure to `reload` your server or `/permissions reload` zPermissions.) 36 | 37 | Regardless of whether or not you change the default group, when zPermissions starts up with a new database or a new flat-file, **it will have no groups defined.** 38 | 39 | So one of the first things you'll probably want to do is create the default group. 40 | 41 | If you left the default group alone: 42 | 43 | /permissions group default create 44 | 45 | Or if you changed it, for example, to `guest`: 46 | 47 | /permissions group guest create 48 | 49 | Once this is done, you can start assigning permissions to it. 50 | -------------------------------------------------------------------------------- /src/main/java/org/tyrannyofheaven/bukkit/zPermissions/vault/PermissionCompatibility.java: -------------------------------------------------------------------------------- 1 | package org.tyrannyofheaven.bukkit.zPermissions.vault; 2 | 3 | import net.milkbowl.vault.permission.Permission; 4 | 5 | import org.bukkit.Bukkit; 6 | import org.bukkit.OfflinePlayer; 7 | import org.tyrannyofheaven.bukkit.zPermissions.PermissionsResolver; 8 | 9 | // Implementation of all non-OfflinePlayer-based player methods 10 | public abstract class PermissionCompatibility extends Permission { 11 | 12 | private final PermissionsResolver resolver; 13 | 14 | public PermissionCompatibility(PermissionsResolver resolver) { 15 | this.resolver = resolver; 16 | } 17 | 18 | @Override 19 | public boolean playerHas(String world, String player, String permission) { 20 | OfflinePlayer offlinePlayer = Bukkit.getOfflinePlayer(player); 21 | if (offlinePlayer == null) return false; 22 | return playerHas(world, offlinePlayer, permission); 23 | } 24 | 25 | @Override 26 | public boolean playerAdd(String world, String player, String permission) { 27 | OfflinePlayer offlinePlayer = Bukkit.getOfflinePlayer(player); 28 | if (offlinePlayer == null) return false; 29 | return playerAdd(world, offlinePlayer, permission); 30 | } 31 | 32 | @Override 33 | public boolean playerRemove(String world, String player, String permission) { 34 | OfflinePlayer offlinePlayer = Bukkit.getOfflinePlayer(player); 35 | if (offlinePlayer == null) return false; 36 | return playerRemove(world, offlinePlayer, permission); 37 | } 38 | 39 | @Override 40 | public boolean playerInGroup(String world, String player, String group) { 41 | OfflinePlayer offlinePlayer = Bukkit.getOfflinePlayer(player); 42 | if (offlinePlayer == null) return false; 43 | return playerInGroup(world, offlinePlayer, group); 44 | } 45 | 46 | @Override 47 | public boolean playerAddGroup(String world, String player, String group) { 48 | OfflinePlayer offlinePlayer = Bukkit.getOfflinePlayer(player); 49 | if (offlinePlayer == null) return false; 50 | return playerAddGroup(world, offlinePlayer, group); 51 | } 52 | 53 | @Override 54 | public boolean playerRemoveGroup(String world, String player, String group) { 55 | OfflinePlayer offlinePlayer = Bukkit.getOfflinePlayer(player); 56 | if (offlinePlayer == null) return false; 57 | return playerRemoveGroup(world, offlinePlayer, group); 58 | } 59 | 60 | @Override 61 | public String[] getPlayerGroups(String world, String player) { 62 | OfflinePlayer offlinePlayer = Bukkit.getOfflinePlayer(player); 63 | if (offlinePlayer == null) return new String[] { resolver.getDefaultGroup() }; 64 | return getPlayerGroups(world, offlinePlayer); 65 | } 66 | 67 | @Override 68 | public String getPrimaryGroup(String world, String player) { 69 | OfflinePlayer offlinePlayer = Bukkit.getOfflinePlayer(player); 70 | if (offlinePlayer == null) return resolver.getDefaultGroup(); 71 | return getPrimaryGroup(world, offlinePlayer); 72 | } 73 | 74 | } 75 | -------------------------------------------------------------------------------- /src/main/java/org/tyrannyofheaven/bukkit/zPermissions/storage/StorageStrategy.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2012 ZerothAngel 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package org.tyrannyofheaven.bukkit.zPermissions.storage; 17 | 18 | import java.util.Map; 19 | 20 | import org.tyrannyofheaven.bukkit.util.transaction.TransactionStrategy; 21 | import org.tyrannyofheaven.bukkit.zPermissions.dao.PermissionService; 22 | 23 | /** 24 | * Encompasses initialization/shutdown and all other aspects of permissions 25 | * data persistence. 26 | * 27 | * @author zerothangel 28 | */ 29 | public interface StorageStrategy { 30 | 31 | /** 32 | * Perform any required initialization. Called once from the zPermissions 33 | * onEnable() handler. 34 | * 35 | * @param configMap Configuration map containing key-value pairs 36 | */ 37 | public void init(Map configMap); 38 | 39 | /** 40 | * Perform any required cleanup. Called from the zPermissions onDisable() 41 | * handler. 42 | */ 43 | public void shutdown(); 44 | 45 | /** 46 | * A request to re-read from the permissions store. Whether this is actually 47 | * done is implementation-dependent. 48 | * 49 | * @param force A hint on whether or not to force a refresh. For conditional 50 | * refreshes, this will be false. 51 | * @param finishTask If permissions were actually re-read and finishTask is 52 | * not-null, this task should be run synchronously 53 | * in the main thread. 54 | */ 55 | public void refresh(boolean force, Runnable finishTask); 56 | 57 | /** 58 | * Retrieve an instance of {@link PermissionService} that is associated with 59 | * this storage strategy. 60 | * 61 | * @return the PermissionService instance 62 | */ 63 | public PermissionService getPermissionService(); 64 | 65 | /** 66 | * Retrieve an instance of {@link TransactionStrategy} that is associated 67 | * with this storage strategy. This version is typically used for 68 | * read-only transactions or transactions that are not safe to retry 69 | * (because of being poorly written :P). 70 | * 71 | * @return a TransactionStrategy 72 | */ 73 | public TransactionStrategy getTransactionStrategy(); 74 | 75 | /** 76 | * Retrieve an instance of {@link TransactionStrategy} that is associated 77 | * with this storage strategy. This version should support retries if it 78 | * makes sense (e.g. SQL transactions with rollback). Typical used with 79 | * simple operations (single PermissionService method call). 80 | * 81 | * @return a TransactionStrategy 82 | */ 83 | public TransactionStrategy getRetryingTransactionStrategy(); 84 | 85 | } 86 | -------------------------------------------------------------------------------- /etc/b-to-z.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | from __future__ import print_function 3 | 4 | import sys 5 | try: 6 | import yaml 7 | except ImportError: 8 | exit('Install PyYAML from first') 9 | 10 | 11 | __author__ = 'ZerothAngel' 12 | __license__ = 'Public Domain' 13 | 14 | 15 | def parse_perms(perms): 16 | result = {} 17 | for p in perms: 18 | if p.startswith('^'): 19 | result[p[1:]] = False 20 | else: 21 | result[p] = True 22 | return result 23 | 24 | 25 | def parse_file(groups, stream): 26 | y = yaml.load(stream) 27 | 28 | g = y.get('groups', {}) 29 | for group_name,data in g.items(): 30 | perms = data.get('permissions', []) 31 | parents = data.get('groups', []) 32 | meta = data.get('meta', {}) 33 | 34 | group_data = {} 35 | group_data['permissions'] = parse_perms(perms) 36 | group_data['parents'] = parents 37 | group_data['prefix'] = meta.get('prefix') 38 | group_data['suffix'] = meta.get('suffix') 39 | 40 | groups[group_name] = group_data 41 | 42 | 43 | def dump_group(name, data, out): 44 | # Preamble 45 | print('# Group %s' % name, file=out) 46 | print('permissions group %s create' % name, file=out) 47 | # Permissions 48 | for perm,value in data['permissions'].items(): 49 | print('permissions group %s set %s %s' % 50 | (name, perm, str(value).lower()), file=out) 51 | if perm.lower().startswith('group.'): 52 | print('WARNING: Group %s has a %s permission; ' 53 | 'zPerms sets these automatically. Consider deleting it.' % 54 | (name, perm)) 55 | # Parent 56 | parents = data['parents'] 57 | if parents: 58 | print('permissions group %s setparent %s' % (name, parents[0]), 59 | file=out) 60 | if len(parents) > 1: 61 | print('WARNING: Group %s has more than one parent. Using only one.' % name, file=sys.stderr) 62 | 63 | # Prefix/suffix 64 | prefix = data['prefix'] 65 | if prefix: 66 | print('permissions group %s metadata set prefix %s' % (name, prefix), 67 | file=out) 68 | suffix = data['suffix'] 69 | if suffix: 70 | print('permissions group %s metadata set suffix %s' % (name, suffix), 71 | file=out) 72 | 73 | 74 | def make_dump(groups, out): 75 | # Gather root groups (parentless groups) 76 | roots = [k for k,v in groups.items() if not v['parents']] 77 | 78 | to_dump = roots 79 | while to_dump: 80 | group_name = to_dump.pop(0) 81 | dump_group(group_name, groups[group_name], out) 82 | 83 | # Queue up all children 84 | # Have to scan. Bleah. 85 | children = [k for k,v in groups.items() if group_name in v['parents']] 86 | 87 | to_dump.extend(children) 88 | 89 | 90 | if __name__ == '__main__': 91 | groups = {} 92 | 93 | if len(sys.argv) < 2: 94 | exit('Usage: %s [ ...]' % sys.argv[0]) 95 | elif len(sys.argv) > 2: 96 | for fn in sys.argv[2:]: 97 | with open(fn, 'rt') as f: 98 | parse_file(groups, f) 99 | else: 100 | parse_file(groups, sys.stdin) 101 | 102 | with open(sys.argv[1], 'wt') as out: 103 | make_dump(groups, out) 104 | -------------------------------------------------------------------------------- /src/main/java/org/tyrannyofheaven/bukkit/zPermissions/dao/PermissionService.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2011 ZerothAngel 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package org.tyrannyofheaven.bukkit.zPermissions.dao; 17 | 18 | import java.util.Date; 19 | import java.util.List; 20 | import java.util.UUID; 21 | 22 | import org.tyrannyofheaven.bukkit.zPermissions.model.EntityMetadata; 23 | import org.tyrannyofheaven.bukkit.zPermissions.model.Entry; 24 | import org.tyrannyofheaven.bukkit.zPermissions.model.Membership; 25 | import org.tyrannyofheaven.bukkit.zPermissions.model.PermissionEntity; 26 | 27 | /** 28 | * Mid-tier service interface for zPermissions permissions store. 29 | * 30 | * @author zerothangel 31 | */ 32 | public interface PermissionService { 33 | 34 | public Boolean getPermission(String name, UUID uuid, boolean group, String region, String world, String permission); 35 | 36 | public void setPermission(String name, UUID uuid, boolean group, String region, String world, String permission, boolean value); 37 | 38 | public boolean unsetPermission(String name, UUID uuid, boolean group, String region, String world, String permission); 39 | 40 | public void addMember(String groupName, UUID memberUuid, String memberName, Date expiration); 41 | 42 | public boolean removeMember(String groupName, UUID memberUuid); 43 | 44 | // NB: Resolver critical path 45 | public List getGroups(UUID memberUuid); 46 | 47 | public List getMembers(String group); 48 | 49 | public PermissionEntity getEntity(String name, UUID uuid, boolean group); 50 | 51 | public List getEntities(boolean group); 52 | 53 | public void setGroup(UUID playerUuid, String playerName, String groupName, Date expiration); 54 | 55 | // Technically deprecated 56 | public void setParent(String groupName, String parentName); 57 | 58 | public void setParents(String groupName, List parentNames); 59 | 60 | public void setPriority(String groupName, int priority); 61 | 62 | public boolean deleteEntity(String name, UUID uuid, boolean group); 63 | 64 | // NB: Resolver critical path 65 | public List getAncestry(String groupName); 66 | 67 | // NB: Resolver critical path 68 | public List getEntries(String name, UUID uuid, boolean group); 69 | 70 | public boolean createGroup(String name); 71 | 72 | public List getEntityNames(boolean group); 73 | 74 | public Object getMetadata(String name, UUID uuid, boolean group, String metadataName); 75 | 76 | public List getAllMetadata(String name, UUID uuid, boolean group); 77 | 78 | public void setMetadata(String name, UUID uuid, boolean group, String metadataName, Object value); 79 | 80 | public boolean unsetMetadata(String name, UUID uuid, boolean group, String metadataName); 81 | 82 | public void updateDisplayName(UUID uuid, String displayName); 83 | 84 | } 85 | -------------------------------------------------------------------------------- /doc/permissions.md: -------------------------------------------------------------------------------- 1 | ## Permissions ## 2 | 3 | ### Meta-Permissions ### 4 | 5 | * zpermissions.* — All-inclusive permission. Given to ops by default. 6 | * zpermissions.player.* — All `/permissions player` commands 7 | * zpermissions.group.* — All `/permissions group` commands 8 | * zpermissions.rank — Use of all rank commands 9 | * zpermissions.rank.* — Allows rank commands on all tracks 10 | * zpermissions.rank.<track> — Allows rank commands on a specific track 11 | 12 | ### General Permissions ### 13 | 14 | * zpermissions.player.view — `/permissions player` read-only management commands 15 | * zpermissions.player.manage — `/permissions player` management commands 16 | * zpermissions.player.chat — `/permissions player` chat commands 17 | * zpermissions.group.view — `/permissions group` read-only management commands 18 | * zpermissions.group.manage — `/permissions group` management commands 19 | * zpermissions.group.chat — `/permissions group` chat commands 20 | * zpermissions.list — `/permissions list` command 21 | * zpermissions.check — `/permissions check` command 22 | * zpermissions.check.other — `/permissions check` on other players 23 | * zpermissions.inspect — `/permissions inspect` command 24 | * zpermissions.inspect.other — `/permissions inspect` on other players 25 | * zpermissions.diff — `/permissions diff` command 26 | * zpermissions.search — `/permissions search` command 27 | * zpermissions.mygroups — `/permissions mygroups` command 28 | * zpermissions.reload — `/permissions reload` command 29 | * zpermissions.refresh — `/permissions refresh` command 30 | * zpermissions.export — `/permissions export` command 31 | * zpermissions.import — `/permissions import` command 32 | * zpermissions.purge — `/permissions purge` command 33 | 34 | ### Rank Permissions ### 35 | 36 | * zpermissions.promote — `/promote` command 37 | * zpermissions.promote.* — Allows `/promote` on all tracks 38 | * zpermissions.promote.<track> — Allows `/promote` on a specific track 39 | * zpermissions.demote — `/demote` command 40 | * zpermissions.demote.* — Allows `/demote` on all tracks 41 | * zpermissions.demote.<track> — Allows `/demote` on a specific track 42 | * zpermissions.setrank — `/setrank` command 43 | * zpermissions.setrank.* — Allows `/setrank` on all tracks 44 | * zpermissions.setrank.<track> — Allows `/setrank` on a specific track 45 | * zpermissions.unsetrank — `/unsetrank` command 46 | * zpermissions.unsetrank.* — Allows `/unsetrank` on all tracks 47 | * zpermissions.unsetrank.<track> — Allows `/unsetrank` on a specific track 48 | 49 | ### Notification Permissions ### 50 | * zpermissions.notify.* — Receives all notifications. 51 | * zpermissions.notify.rank — Receives all rank command notifications. 52 | * zpermissions.notify.promote — Receives all `/promote` notifications. 53 | * zpermissions.notify.demote — Receives all `/demote` notifications. 54 | * zpermissions.notify.setrank — Receives all `/setrank` notifications. 55 | * zpermissions.notify.unsetrank — Receives all `/unsetrank` notifications. 56 | * zpermissions.notify.expiration — Receives temporary membership expiration notifications. 57 | 58 | For zpermissions.notify.rank (and related permissions) to work, the config.yml option rank-admin-broadcast must be set to false. 59 | -------------------------------------------------------------------------------- /src/main/java/org/tyrannyofheaven/bukkit/zPermissions/QualifiedPermission.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2011 ZerothAngel 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package org.tyrannyofheaven.bukkit.zPermissions; 17 | 18 | import static org.tyrannyofheaven.bukkit.util.ToHStringUtils.hasText; 19 | 20 | /** 21 | * Holder/parser for world-specific permissions as specified on the command-line. 22 | * Permissions with no world specifier assume the world is null (i.e. global 23 | * permission). Permissions specific to a world should be "<world>:<permission>" 24 | * 25 | * @author zerothangel 26 | */ 27 | public class QualifiedPermission { 28 | 29 | private final String region; 30 | 31 | private final String world; 32 | 33 | private final String permission; 34 | 35 | public QualifiedPermission(String qualifiedPermission) { 36 | // Pull out region, if present 37 | String[] parts = qualifiedPermission.split("/", 2); 38 | if (parts.length == 1) { 39 | // No region 40 | region = null; 41 | } 42 | else { 43 | region = parts[0]; 44 | qualifiedPermission = parts[1]; 45 | } 46 | 47 | // Break up into world/permission, as appropriate 48 | parts = qualifiedPermission.split(":", 2); 49 | if (parts.length == 1) { 50 | // No world 51 | world = null; 52 | permission = parts[0]; 53 | } 54 | else { 55 | world = parts[0]; 56 | permission = parts[1]; 57 | } 58 | } 59 | 60 | public QualifiedPermission(String region, String world, String permission) { 61 | if (!hasText(region)) 62 | region = null; 63 | if (!hasText(world)) 64 | world = null; 65 | if (!hasText(permission)) 66 | throw new IllegalArgumentException("permission must have a value"); 67 | 68 | this.region = region; 69 | this.world = world; 70 | this.permission = permission; 71 | } 72 | 73 | /** 74 | * Return the region if this is a region-specific permission 75 | * @return 76 | */ 77 | public String getRegion() { 78 | return region; 79 | } 80 | 81 | /** 82 | * Return the name of the world if this is a world-specific permission. 83 | * 84 | * @return the name of the world or null if global 85 | */ 86 | public String getWorld() { 87 | return world; 88 | } 89 | 90 | /** 91 | * Return the permission. 92 | * 93 | * @return the permission 94 | */ 95 | public String getPermission() { 96 | return permission; 97 | } 98 | 99 | @Override 100 | public String toString() { 101 | return String.format("%s%s%s", 102 | (getRegion() == null ? "" : getRegion() + "/"), 103 | (getWorld() == null ? "" : getWorld() + ":"), 104 | getPermission()); 105 | } 106 | 107 | } 108 | -------------------------------------------------------------------------------- /src/main/java/org/tyrannyofheaven/bukkit/zPermissions/ZPermissionsPlayerUpdateEvent.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2013 ZerothAngel 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package org.tyrannyofheaven.bukkit.zPermissions; 17 | 18 | import org.bukkit.entity.Player; 19 | import org.bukkit.event.HandlerList; 20 | import org.bukkit.event.player.PlayerEvent; 21 | 22 | /** 23 | * Bukkit event fired off whenever zPermissions might potentially change an 24 | * online player's permissions. This includes world changes, commands that affect 25 | * the groups or permissions of a player, as well as certain movement-based 26 | * events (when region-support is enabled). 27 | * 28 | *

Note that unconditional permissions changes that occur during 29 | * standard Bukkit events (namely: PlayerLoginEvent, PlayerJoinEvent, 30 | * PlayerQuitEvent) do not fire off this event. 31 | * 32 | *

Also note that this event may be called even if the player's permissions 33 | * did not actually change. However, for its PlayerMoveEvent handler (when 34 | * region-support is enabled), zPermissions guarantees that this event will be 35 | * called only when the player crosses a region boundary. 36 | */ 37 | public class ZPermissionsPlayerUpdateEvent extends PlayerEvent { 38 | 39 | private final Cause cause; 40 | 41 | /** 42 | * Creates a player permissions change event. 43 | * 44 | * @param who the affected player 45 | * @param cause the cause of this permissions change 46 | */ 47 | public ZPermissionsPlayerUpdateEvent(Player who, Cause cause) { 48 | super(who); 49 | if (cause == null) 50 | throw new IllegalArgumentException("cause cannot be null"); 51 | this.cause = cause; 52 | } 53 | 54 | /** 55 | * Returns the cause of this permissions change. 56 | * 57 | * @return the cause of this permissions change 58 | */ 59 | public Cause getCause() { 60 | return cause; 61 | } 62 | 63 | private static final HandlerList handlers = new HandlerList(); 64 | 65 | public HandlerList getHandlers() { 66 | return handlers; 67 | } 68 | 69 | public static HandlerList getHandlerList() { 70 | return handlers; 71 | } 72 | 73 | public static enum Cause { 74 | /** 75 | * Permissions change to the player caused by a command. Includes changes 76 | * through the API. Note that the settemp command cannot be covered since 77 | * there's no visibility as to when the permission goes away. 78 | */ 79 | COMMAND, 80 | 81 | /** 82 | * An associated group was changed. Includes command line, changes 83 | * through the API, group membership expirations, and server-wide changes 84 | * (reload, refresh, etc. since these force a re-read from storage). 85 | */ 86 | GROUP_CHANGE, 87 | 88 | /** 89 | * Player movement, including movement within the same world (if 90 | * region-support is enabled) and movement to a different world. 91 | */ 92 | MOVEMENT; 93 | } 94 | 95 | } 96 | -------------------------------------------------------------------------------- /src/main/java/org/tyrannyofheaven/bukkit/zPermissions/model/Membership.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2011 ZerothAngel 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package org.tyrannyofheaven.bukkit.zPermissions.model; 17 | 18 | import java.util.Date; 19 | import java.util.UUID; 20 | 21 | import javax.persistence.Column; 22 | import javax.persistence.Entity; 23 | import javax.persistence.Id; 24 | import javax.persistence.ManyToOne; 25 | import javax.persistence.Table; 26 | import javax.persistence.Temporal; 27 | import javax.persistence.TemporalType; 28 | import javax.persistence.Transient; 29 | import javax.persistence.UniqueConstraint; 30 | 31 | import org.tyrannyofheaven.bukkit.util.uuid.UuidUtils; 32 | 33 | /** 34 | * Represents group membership. 35 | * 36 | * @author zerothangel 37 | */ 38 | @Entity 39 | @Table(name="memberships") 40 | @UniqueConstraint(columnNames={"member", "group_id"}) 41 | public class Membership { 42 | 43 | private Long id; 44 | 45 | private String member; 46 | 47 | private String displayName; 48 | 49 | private PermissionEntity group; 50 | 51 | private Date expiration; 52 | 53 | @Id 54 | public Long getId() { 55 | return id; 56 | } 57 | 58 | public void setId(Long id) { 59 | this.id = id; 60 | } 61 | 62 | public String getMember() { 63 | return member; 64 | } 65 | 66 | public void setMember(String member) { 67 | this.member = member; 68 | } 69 | 70 | public String getDisplayName() { 71 | return displayName; 72 | } 73 | 74 | public void setDisplayName(String displayName) { 75 | this.displayName = displayName; 76 | } 77 | 78 | @Column(name="group_id") 79 | @ManyToOne(optional=false) 80 | public PermissionEntity getGroup() { 81 | return group; 82 | } 83 | 84 | public void setGroup(PermissionEntity group) { 85 | this.group = group; 86 | } 87 | 88 | @Temporal(TemporalType.TIMESTAMP) 89 | public Date getExpiration() { 90 | return expiration; 91 | } 92 | 93 | public void setExpiration(Date expiration) { 94 | this.expiration = expiration; 95 | } 96 | 97 | @Transient 98 | public UUID getUuid() { 99 | return UuidUtils.uncanonicalizeUuid(getMember()); 100 | } 101 | 102 | @Override 103 | public boolean equals(Object obj) { 104 | if (obj == this) return true; 105 | if (!(obj instanceof Membership)) return false; 106 | Membership o = (Membership)obj; 107 | return getMember().equals(o.getMember()) && 108 | getGroup().equals(o.getGroup()); 109 | } 110 | 111 | @Override 112 | public int hashCode() { 113 | int result = 17; 114 | result = 37 * result + getMember().hashCode(); 115 | result = 37 * result + getGroup().hashCode(); 116 | return result; 117 | } 118 | 119 | @Override 120 | public String toString() { 121 | return String.format("Membership[%s -> %s/%s]", getGroup().getName(), getMember(), getDisplayName()); 122 | } 123 | 124 | } 125 | -------------------------------------------------------------------------------- /src/main/java/org/tyrannyofheaven/bukkit/zPermissions/region/FactoidRegionStrategy.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2013 ZerothAngel 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package org.tyrannyofheaven.bukkit.zPermissions.region; 17 | 18 | import java.util.Collections; 19 | import java.util.Set; 20 | 21 | import me.tabinol.factoid.Factoid; 22 | import me.tabinol.factoid.lands.Land; 23 | 24 | import org.bukkit.Bukkit; 25 | import org.bukkit.Location; 26 | import org.bukkit.entity.Player; 27 | import org.bukkit.event.EventHandler; 28 | import org.bukkit.event.Listener; 29 | import org.bukkit.event.server.PluginEnableEvent; 30 | import org.bukkit.plugin.Plugin; 31 | import org.tyrannyofheaven.bukkit.util.ToHLoggingUtils; 32 | import org.tyrannyofheaven.bukkit.zPermissions.ZPermissionsCore; 33 | 34 | /** 35 | * RegionStrategy implementation for Factoid. 36 | * 37 | * @author zerothangel, Tabinol 38 | */ 39 | public class FactoidRegionStrategy implements RegionStrategy, Listener { 40 | 41 | private static final String RM_PLUGIN_NAME = "Factoid"; 42 | 43 | private final Plugin plugin; 44 | 45 | private final ZPermissionsCore core; 46 | 47 | private boolean enabled; 48 | 49 | public FactoidRegionStrategy(Plugin plugin, ZPermissionsCore core) { 50 | this.plugin = plugin; 51 | this.core = core; 52 | } 53 | 54 | @Override 55 | public String getName() { 56 | return RM_PLUGIN_NAME; 57 | } 58 | 59 | @Override 60 | public boolean isPresent() { 61 | return Bukkit.getPluginManager().getPlugin(RM_PLUGIN_NAME) != null; 62 | } 63 | 64 | @Override 65 | public void init() { 66 | detectFactoidPlugin(); 67 | if (!isEnabled()) { 68 | // Not yet loaded, listen for its enable event 69 | Bukkit.getPluginManager().registerEvents(this, plugin); 70 | } 71 | } 72 | 73 | @Override 74 | public boolean isEnabled() { 75 | return enabled; 76 | } 77 | 78 | @Override 79 | public void shutdown() { 80 | enabled = false; 81 | } 82 | 83 | @Override 84 | public Set getRegions(Location location, Player player) { 85 | Land land = Factoid.getLands().getLand(location); 86 | if (land != null) { 87 | return Collections.singleton(land.getName()); // Land name is always lower case 88 | } 89 | return Collections.emptySet(); 90 | } 91 | 92 | @EventHandler 93 | public void onPluginEnable(PluginEnableEvent event) { 94 | if (!isEnabled() && RM_PLUGIN_NAME.equals(event.getPlugin().getName())) { 95 | detectFactoidPlugin(); 96 | if (isEnabled()) { 97 | ToHLoggingUtils.log(plugin, "%s region support enabled.", getName()); 98 | core.refreshPlayers(); 99 | } 100 | } 101 | } 102 | 103 | private void detectFactoidPlugin() { 104 | Plugin plugin = Bukkit.getPluginManager().getPlugin(RM_PLUGIN_NAME); 105 | enabled = plugin != null && plugin.isEnabled(); 106 | // Nothing else to do 107 | } 108 | 109 | } 110 | -------------------------------------------------------------------------------- /src/main/java/org/tyrannyofheaven/bukkit/zPermissions/region/ResidenceRegionStrategy.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2013 ZerothAngel 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package org.tyrannyofheaven.bukkit.zPermissions.region; 17 | 18 | import java.util.Collections; 19 | import java.util.Set; 20 | 21 | import org.bukkit.Bukkit; 22 | import org.bukkit.Location; 23 | import org.bukkit.entity.Player; 24 | import org.bukkit.event.EventHandler; 25 | import org.bukkit.event.Listener; 26 | import org.bukkit.event.server.PluginEnableEvent; 27 | import org.bukkit.plugin.Plugin; 28 | import org.tyrannyofheaven.bukkit.util.ToHLoggingUtils; 29 | import org.tyrannyofheaven.bukkit.zPermissions.ZPermissionsCore; 30 | 31 | import com.bekvon.bukkit.residence.Residence; 32 | import com.bekvon.bukkit.residence.protection.ClaimedResidence; 33 | 34 | /** 35 | * RegionStrategy implementation for Residence. 36 | * 37 | * @author zerothangel 38 | */ 39 | public class ResidenceRegionStrategy implements RegionStrategy, Listener { 40 | 41 | private static final String RM_PLUGIN_NAME = "Residence"; 42 | 43 | private final Plugin plugin; 44 | 45 | private final ZPermissionsCore core; 46 | 47 | private boolean enabled; 48 | 49 | public ResidenceRegionStrategy(Plugin plugin, ZPermissionsCore core) { 50 | this.plugin = plugin; 51 | this.core = core; 52 | } 53 | 54 | @Override 55 | public String getName() { 56 | return RM_PLUGIN_NAME; 57 | } 58 | 59 | @Override 60 | public boolean isPresent() { 61 | return Bukkit.getPluginManager().getPlugin(RM_PLUGIN_NAME) != null; 62 | } 63 | 64 | @Override 65 | public void init() { 66 | detectResidencePlugin(); 67 | if (!isEnabled()) { 68 | // Not yet loaded, listen for its enable event 69 | Bukkit.getPluginManager().registerEvents(this, plugin); 70 | } 71 | } 72 | 73 | @Override 74 | public boolean isEnabled() { 75 | return enabled; 76 | } 77 | 78 | @Override 79 | public void shutdown() { 80 | enabled = false; 81 | } 82 | 83 | @Override 84 | public Set getRegions(Location location, Player player) { 85 | ClaimedResidence res = Residence.getResidenceManager().getByLoc(location); 86 | if (res != null) { 87 | return Collections.singleton(res.getName().toLowerCase()); 88 | } 89 | return Collections.emptySet(); 90 | } 91 | 92 | @EventHandler 93 | public void onPluginEnable(PluginEnableEvent event) { 94 | if (!isEnabled() && RM_PLUGIN_NAME.equals(event.getPlugin().getName())) { 95 | detectResidencePlugin(); 96 | if (isEnabled()) { 97 | ToHLoggingUtils.log(plugin, "%s region support enabled.", getName()); 98 | core.refreshPlayers(); 99 | } 100 | } 101 | } 102 | 103 | private void detectResidencePlugin() { 104 | Plugin plugin = Bukkit.getPluginManager().getPlugin(RM_PLUGIN_NAME); 105 | enabled = plugin != null && plugin.isEnabled(); 106 | // Nothing else to do 107 | } 108 | 109 | } 110 | -------------------------------------------------------------------------------- /src/main/java/org/tyrannyofheaven/bukkit/zPermissions/ZPermissionsRankChangeEvent.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2013 ZerothAngel 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package org.tyrannyofheaven.bukkit.zPermissions; 17 | 18 | import org.bukkit.event.Event; 19 | import org.bukkit.event.HandlerList; 20 | 21 | /** 22 | * Bukkit event fired off whenever a rank command successfully completes. 23 | */ 24 | public class ZPermissionsRankChangeEvent extends Event { 25 | 26 | private final String playerName; 27 | 28 | private final String track; 29 | 30 | private final String fromGroup; 31 | 32 | private final String toGroup; 33 | 34 | /** 35 | * Create a rank change event. 36 | * 37 | * @param playerName the name of the player 38 | * @param track the name of the track 39 | * @param fromGroup the previous group. May be null. 40 | * @param toGroup the new group. May be null. 41 | */ 42 | public ZPermissionsRankChangeEvent(String playerName, String track, String fromGroup, String toGroup) { 43 | if (playerName == null || playerName.trim().isEmpty()) 44 | throw new IllegalArgumentException("playerName must have a value"); 45 | if (track == null || track.trim().isEmpty()) 46 | throw new IllegalArgumentException("track must have a value"); 47 | if (fromGroup != null && fromGroup.trim().isEmpty()) 48 | fromGroup = null; 49 | if (toGroup != null && toGroup.trim().isEmpty()) 50 | toGroup = null; 51 | 52 | this.playerName = playerName; 53 | this.track = track; 54 | this.fromGroup = fromGroup; 55 | this.toGroup = toGroup; 56 | } 57 | 58 | /** 59 | * The name of the player whose rank has changed. Note that there's no 60 | * guarantee about the letter case of the name (it will be as was entered 61 | * from the command line). 62 | * 63 | * @return the name of the player 64 | */ 65 | public String getPlayerName() { 66 | return playerName; 67 | } 68 | 69 | /** 70 | * The name of the track. Note that there's no guarantee about the letter 71 | * case of the name. 72 | * 73 | * @return the name of the track 74 | */ 75 | public String getTrack() { 76 | return track; 77 | } 78 | 79 | /** 80 | * The player's previous group. This may be null meaning the 81 | * player was not previously on any group in this track. 82 | * 83 | * @return the previous group 84 | */ 85 | public String getFromGroup() { 86 | return fromGroup; 87 | } 88 | 89 | /** 90 | * The player's new group. This may be null meaning the player 91 | * was removed from all groups in this track. 92 | * 93 | * @return the new group 94 | */ 95 | public String getToGroup() { 96 | return toGroup; 97 | } 98 | 99 | private static final HandlerList handlers = new HandlerList(); 100 | 101 | public HandlerList getHandlers() { 102 | return handlers; 103 | } 104 | 105 | public static HandlerList getHandlerList() { 106 | return handlers; 107 | } 108 | 109 | } 110 | -------------------------------------------------------------------------------- /src/test/java/org/tyrannyofheaven/bukkit/zPermissions/dao/NewAvajeDaoTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2011, 2012 ZerothAngel 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package org.tyrannyofheaven.bukkit.zPermissions.dao; 17 | 18 | import org.tyrannyofheaven.bukkit.zPermissions.model.EntityMetadata; 19 | import org.tyrannyofheaven.bukkit.zPermissions.model.Entry; 20 | import org.tyrannyofheaven.bukkit.zPermissions.model.Inheritance; 21 | import org.tyrannyofheaven.bukkit.zPermissions.model.Membership; 22 | import org.tyrannyofheaven.bukkit.zPermissions.model.PermissionEntity; 23 | import org.tyrannyofheaven.bukkit.zPermissions.model.PermissionRegion; 24 | import org.tyrannyofheaven.bukkit.zPermissions.model.PermissionWorld; 25 | 26 | import com.avaje.ebean.EbeanServer; 27 | import com.avaje.ebean.EbeanServerFactory; 28 | import com.avaje.ebean.config.DataSourceConfig; 29 | import com.avaje.ebean.config.ServerConfig; 30 | 31 | public class NewAvajeDaoTest extends AbstractDaoTest { 32 | 33 | private static EbeanServer ebeanServer; 34 | 35 | public NewAvajeDaoTest() { 36 | // Bleh. But Avaje doesn't like being initialized more than once. 37 | // And Maven instantiates this class for each test. 38 | synchronized (NewAvajeDaoTest.class) { 39 | if (ebeanServer == null) { 40 | ServerConfig config = new ServerConfig(); 41 | config.setName(NewAvajeDaoTest.class.getSimpleName()); 42 | config.setDefaultServer(false); 43 | 44 | DataSourceConfig dataSourceConfig = new DataSourceConfig(); 45 | dataSourceConfig.setDriver("org.h2.Driver"); 46 | dataSourceConfig.setUsername("username"); 47 | dataSourceConfig.setPassword("password"); 48 | dataSourceConfig.setUrl("jdbc:h2:NewAvajeDaoTest"); 49 | 50 | config.setDataSourceConfig(dataSourceConfig); 51 | 52 | config.setDdlGenerate(true); 53 | config.setDdlRun(true); 54 | 55 | config.addClass(PermissionEntity.class); 56 | config.addClass(Inheritance.class); 57 | config.addClass(PermissionRegion.class); 58 | config.addClass(PermissionWorld.class); 59 | config.addClass(Entry.class); 60 | config.addClass(Membership.class); 61 | config.addClass(EntityMetadata.class); 62 | 63 | ebeanServer = EbeanServerFactory.create(config); 64 | } 65 | } 66 | 67 | getPermissionService().setPermissionDao(new AvajePermissionDao(getPermissionService(), ebeanServer, null)); 68 | } 69 | 70 | EbeanServer getEbeanServer() { 71 | return ebeanServer; 72 | } 73 | 74 | @Override 75 | protected void begin() { 76 | getEbeanServer().beginTransaction(); 77 | } 78 | 79 | @Override 80 | protected void commit() { 81 | getEbeanServer().commitTransaction(); 82 | } 83 | 84 | @Override 85 | protected void end() { 86 | getEbeanServer().endTransaction(); 87 | } 88 | 89 | @Override 90 | protected PermissionWorld getWorld(String name) { 91 | return getEbeanServer().find(PermissionWorld.class).where().eq("name", name).findUnique(); 92 | } 93 | 94 | @Override 95 | protected PermissionRegion getRegion(String name) { 96 | return getEbeanServer().find(PermissionRegion.class).where().eq("name", name).findUnique(); 97 | } 98 | 99 | } 100 | -------------------------------------------------------------------------------- /src/test/java/org/tyrannyofheaven/bukkit/zPermissions/NewAvajeResolverTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2011 ZerothAngel 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package org.tyrannyofheaven.bukkit.zPermissions; 17 | 18 | 19 | import java.util.Collections; 20 | 21 | import org.tyrannyofheaven.bukkit.zPermissions.dao.AvajePermissionDao; 22 | import org.tyrannyofheaven.bukkit.zPermissions.dao.InMemoryPermissionService; 23 | import org.tyrannyofheaven.bukkit.zPermissions.model.EntityMetadata; 24 | import org.tyrannyofheaven.bukkit.zPermissions.model.Entry; 25 | import org.tyrannyofheaven.bukkit.zPermissions.model.Inheritance; 26 | import org.tyrannyofheaven.bukkit.zPermissions.model.Membership; 27 | import org.tyrannyofheaven.bukkit.zPermissions.model.PermissionEntity; 28 | import org.tyrannyofheaven.bukkit.zPermissions.model.PermissionRegion; 29 | import org.tyrannyofheaven.bukkit.zPermissions.model.PermissionWorld; 30 | 31 | import com.avaje.ebean.EbeanServer; 32 | import com.avaje.ebean.EbeanServerFactory; 33 | import com.avaje.ebean.config.DataSourceConfig; 34 | import com.avaje.ebean.config.ServerConfig; 35 | 36 | public class NewAvajeResolverTest extends AbstractResolverTest { 37 | 38 | private static EbeanServer ebeanServer; 39 | 40 | public NewAvajeResolverTest() { 41 | // Bleh. But Avaje doesn't like being initialized more than once. 42 | // And Maven instantiates this class for each test. 43 | synchronized (NewAvajeResolverTest.class) { 44 | if (ebeanServer == null) { 45 | ServerConfig config = new ServerConfig(); 46 | config.setName(NewAvajeResolverTest.class.getSimpleName()); 47 | config.setDefaultServer(false); 48 | 49 | DataSourceConfig dataSourceConfig = new DataSourceConfig(); 50 | dataSourceConfig.setDriver("org.h2.Driver"); 51 | dataSourceConfig.setUsername("username"); 52 | dataSourceConfig.setPassword("password"); 53 | dataSourceConfig.setUrl("jdbc:h2:NewAvajeResolverTest"); 54 | 55 | config.setDataSourceConfig(dataSourceConfig); 56 | 57 | config.setDdlGenerate(true); 58 | config.setDdlRun(true); 59 | 60 | config.addClass(PermissionEntity.class); 61 | config.addClass(Inheritance.class); 62 | config.addClass(PermissionRegion.class); 63 | config.addClass(PermissionWorld.class); 64 | config.addClass(Entry.class); 65 | config.addClass(Membership.class); 66 | config.addClass(EntityMetadata.class); 67 | 68 | ebeanServer = EbeanServerFactory.create(config); 69 | } 70 | } 71 | 72 | permissionService = new InMemoryPermissionService(); 73 | permissionService.setPermissionDao(new AvajePermissionDao(permissionService, ebeanServer, null)); 74 | resolver = new PermissionsResolver(permissionService); 75 | resolver.setDefaultGroup(TEST_GROUP1); 76 | resolver.setGroupPermissionFormats(Collections.singleton("group.%s")); 77 | resolver.setAssignedGroupPermissionFormats(Collections.singleton("assignedgroup.%s")); 78 | } 79 | 80 | EbeanServer getEbeanServer() { 81 | return ebeanServer; 82 | } 83 | 84 | protected void begin() { 85 | getEbeanServer().beginTransaction(); 86 | } 87 | 88 | protected void commit() { 89 | getEbeanServer().commitTransaction(); 90 | } 91 | 92 | protected void end() { 93 | getEbeanServer().endTransaction(); 94 | } 95 | 96 | } 97 | -------------------------------------------------------------------------------- /src/main/java/org/tyrannyofheaven/bukkit/zPermissions/model/Entry.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2011 ZerothAngel 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package org.tyrannyofheaven.bukkit.zPermissions.model; 17 | 18 | import javax.persistence.Column; 19 | import javax.persistence.Entity; 20 | import javax.persistence.Id; 21 | import javax.persistence.JoinColumn; 22 | import javax.persistence.ManyToOne; 23 | import javax.persistence.Table; 24 | import javax.persistence.UniqueConstraint; 25 | 26 | /** 27 | * A permission entry. 28 | * 29 | * @author zerothangel 30 | */ 31 | @Entity 32 | @Table(name="entries") 33 | @UniqueConstraint(columnNames={"entity_id", "region_id", "world_id", "permission"}) 34 | public class Entry { 35 | 36 | private Long id; 37 | 38 | private PermissionEntity entity; 39 | 40 | private PermissionRegion region; 41 | 42 | private PermissionWorld world; 43 | 44 | private String permission; 45 | 46 | private boolean value; 47 | 48 | @Id 49 | public Long getId() { 50 | return id; 51 | } 52 | 53 | public void setId(Long id) { 54 | this.id = id; 55 | } 56 | 57 | @JoinColumn(name="entity_id") 58 | @ManyToOne(optional=false) 59 | public PermissionEntity getEntity() { 60 | return entity; 61 | } 62 | 63 | public void setEntity(PermissionEntity owner) { 64 | this.entity = owner; 65 | } 66 | 67 | @JoinColumn(name="region_id") 68 | @ManyToOne(optional=true) 69 | public PermissionRegion getRegion() { 70 | return region; 71 | } 72 | 73 | public void setRegion(PermissionRegion region) { 74 | this.region = region; 75 | } 76 | 77 | @JoinColumn(name="world_id") 78 | @ManyToOne(optional=true) 79 | public PermissionWorld getWorld() { 80 | return world; 81 | } 82 | 83 | public void setWorld(PermissionWorld world) { 84 | this.world = world; 85 | } 86 | 87 | @Column(nullable=false) 88 | public String getPermission() { 89 | return permission; 90 | } 91 | 92 | public void setPermission(String permission) { 93 | this.permission = permission; 94 | } 95 | 96 | @Column(nullable=false) 97 | public boolean isValue() { 98 | return value; 99 | } 100 | 101 | public void setValue(boolean value) { 102 | this.value = value; 103 | } 104 | 105 | @Override 106 | public boolean equals(Object obj) { 107 | if (obj == this) return true; 108 | if (!(obj instanceof Entry)) return false; 109 | Entry o = (Entry)obj; 110 | return getEntity().equals(o.getEntity()) && 111 | (getRegion() == null ? o.getRegion() == null : getRegion().equals(o.getRegion())) && 112 | (getWorld() == null ? o.getWorld() == null : getWorld().equals(o.getWorld())) && 113 | getPermission().equals(o.getPermission()); 114 | } 115 | 116 | @Override 117 | public int hashCode() { 118 | int result = 17; 119 | result = 37 * result + getEntity().hashCode(); 120 | result = 37 * result + (getRegion() == null ? 0 : getRegion().hashCode()); 121 | result = 37 * result + (getWorld() == null ? 0 : getWorld().hashCode()); 122 | result = 37 * result + getPermission().hashCode(); 123 | return result; 124 | } 125 | 126 | @Override 127 | public String toString() { 128 | return String.format("%s%s%s -> %s", 129 | (getRegion() == null ? "" : getRegion().getName() + "/"), 130 | (getWorld() == null ? "" : getWorld().getName() + ":"), 131 | getPermission(), 132 | isValue()); 133 | } 134 | 135 | } 136 | -------------------------------------------------------------------------------- /src/main/java/org/tyrannyofheaven/bukkit/zPermissions/dao/DummyPermissionDao.java: -------------------------------------------------------------------------------- 1 | // Released to the public domain 2 | package org.tyrannyofheaven.bukkit.zPermissions.dao; 3 | 4 | import java.util.Collection; 5 | 6 | import org.tyrannyofheaven.bukkit.zPermissions.model.EntityMetadata; 7 | import org.tyrannyofheaven.bukkit.zPermissions.model.Entry; 8 | import org.tyrannyofheaven.bukkit.zPermissions.model.Inheritance; 9 | import org.tyrannyofheaven.bukkit.zPermissions.model.Membership; 10 | import org.tyrannyofheaven.bukkit.zPermissions.model.PermissionEntity; 11 | import org.tyrannyofheaven.bukkit.zPermissions.model.PermissionRegion; 12 | import org.tyrannyofheaven.bukkit.zPermissions.model.PermissionWorld; 13 | 14 | /* 15 | * Fairly straightforward, the PermissionDao is responsible for all CUD (Create, 16 | * Update, Delete) operations. Reading can also be handled here, but since reading 17 | * always involves reading the full store in one shot, it normally falls under 18 | * the purview of the matching StorageStrategy's init() & refresh() methods. 19 | * 20 | * There are a few rules to follow when implementing each method: 21 | * 1. NEVER block. If you must perform blocking I/O, do it asynchronously. 22 | * 2. Never modify the passed-in object. 23 | * 3. You may want to make a copy of any pertinent properties of the passed-in 24 | * object. It may not be wise to hold on to it, especially if acting async. 25 | * 26 | * There are at least two styles of implementation: 27 | * 1. Implement each method normally, e.g. createEntity() will actually perform 28 | * I/O to create that entity somewhere. AvajePermissionDao is an example. 29 | * 2. Each method simply sets a dirty flag. An asynchronous thread periodically 30 | * checks the dirty flag, and if dirty, will call InMemoryPermissionService's 31 | * getPlayer()/getGroups()/getWorlds()/getRegions() methods to get a snapshot 32 | * of the current state which is then written out somewhere. FilePermissionDao 33 | * is an example. 34 | * 35 | * Note, getPlayer()/getGroups() etc. should be in a single synchronized block, 36 | * synchronized on the InMemoryPermissionService instance. Also note that 37 | * the returned collections and objects by getPlayer() etc. MUST NEVER be 38 | * modified. 39 | * 40 | * Note, createRegion(), createWorld(), createEntity() should do nothing if the 41 | * object in question already exists. 42 | */ 43 | public class DummyPermissionDao implements PermissionDao { 44 | 45 | @Override 46 | public void createRegion(PermissionRegion region) { 47 | } 48 | 49 | @Override 50 | public void createWorld(PermissionWorld world) { 51 | } 52 | 53 | @Override 54 | public void createEntity(PermissionEntity entity) { 55 | } 56 | 57 | @Override 58 | public void createOrUpdateEntry(Entry entry) { 59 | } 60 | 61 | @Override 62 | public void deleteEntry(Entry entry) { 63 | } 64 | 65 | @Override 66 | public void createOrUpdateMembership(Membership membership) { 67 | } 68 | 69 | @Override 70 | public void setEntityParent(PermissionEntity entity, PermissionEntity parent) { 71 | } 72 | 73 | @Override 74 | public void createOrUpdateInheritance(Inheritance inheritance) { 75 | } 76 | 77 | @Override 78 | public void deleteInheritance(Inheritance inheritance) { 79 | } 80 | 81 | @Override 82 | public void setEntityPriority(PermissionEntity entity, int priority) { 83 | } 84 | 85 | @Override 86 | public void deleteRegions(Collection regions) { 87 | } 88 | 89 | @Override 90 | public void deleteWorlds(Collection worlds) { 91 | } 92 | 93 | @Override 94 | public void deleteEntity(PermissionEntity entity) { 95 | } 96 | 97 | @Override 98 | public void deleteMembership(Membership membership) { 99 | } 100 | 101 | @Override 102 | public void createOrUpdateMetadata(EntityMetadata metadata) { 103 | } 104 | 105 | @Override 106 | public void deleteMetadata(EntityMetadata metadata) { 107 | } 108 | 109 | @Override 110 | public void updateDisplayName(PermissionEntity entity) { 111 | } 112 | 113 | @Override 114 | public void updateDisplayName(Membership membership) { 115 | } 116 | 117 | } 118 | -------------------------------------------------------------------------------- /src/main/java/org/tyrannyofheaven/bukkit/zPermissions/vault/ChatCompatibility.java: -------------------------------------------------------------------------------- 1 | package org.tyrannyofheaven.bukkit.zPermissions.vault; 2 | 3 | import net.milkbowl.vault.chat.Chat; 4 | import net.milkbowl.vault.permission.Permission; 5 | 6 | import org.bukkit.Bukkit; 7 | import org.bukkit.OfflinePlayer; 8 | 9 | // Implementation of all non-OfflinePlayer-based player methods 10 | public abstract class ChatCompatibility extends Chat { 11 | 12 | public ChatCompatibility(Permission perms) { 13 | super(perms); 14 | } 15 | 16 | @Override 17 | public String getPlayerPrefix(String world, String player) { 18 | OfflinePlayer offlinePlayer = Bukkit.getOfflinePlayer(player); 19 | if (offlinePlayer == null) return ""; 20 | return getPlayerPrefix(world, offlinePlayer); 21 | } 22 | 23 | @Override 24 | public void setPlayerPrefix(String world, String player, String prefix) { 25 | OfflinePlayer offlinePlayer = Bukkit.getOfflinePlayer(player); 26 | if (offlinePlayer == null) return; 27 | setPlayerPrefix(world, offlinePlayer, prefix); 28 | } 29 | 30 | @Override 31 | public String getPlayerSuffix(String world, String player) { 32 | OfflinePlayer offlinePlayer = Bukkit.getOfflinePlayer(player); 33 | if (offlinePlayer == null) return ""; 34 | return getPlayerSuffix(world, offlinePlayer); 35 | } 36 | 37 | @Override 38 | public void setPlayerSuffix(String world, String player, String suffix) { 39 | OfflinePlayer offlinePlayer = Bukkit.getOfflinePlayer(player); 40 | if (offlinePlayer == null) return; 41 | setPlayerSuffix(world, offlinePlayer, suffix); 42 | } 43 | 44 | @Override 45 | public int getPlayerInfoInteger(String world, String player, String node, int defaultValue) { 46 | OfflinePlayer offlinePlayer = Bukkit.getOfflinePlayer(player); 47 | if (offlinePlayer == null) return defaultValue; 48 | return getPlayerInfoInteger(world, offlinePlayer, node, defaultValue); 49 | } 50 | 51 | @Override 52 | public void setPlayerInfoInteger(String world, String player, String node, int value) { 53 | OfflinePlayer offlinePlayer = Bukkit.getOfflinePlayer(player); 54 | if (offlinePlayer == null) return; 55 | setPlayerInfoInteger(world, offlinePlayer, node, value); 56 | } 57 | 58 | @Override 59 | public double getPlayerInfoDouble(String world, String player, String node, double defaultValue) { 60 | OfflinePlayer offlinePlayer = Bukkit.getOfflinePlayer(player); 61 | if (offlinePlayer == null) return defaultValue; 62 | return getPlayerInfoDouble(world, offlinePlayer, node, defaultValue); 63 | } 64 | 65 | @Override 66 | public void setPlayerInfoDouble(String world, String player, String node, double value) { 67 | OfflinePlayer offlinePlayer = Bukkit.getOfflinePlayer(player); 68 | if (offlinePlayer == null) return; 69 | setPlayerInfoDouble(world, offlinePlayer, node, value); 70 | } 71 | 72 | @Override 73 | public boolean getPlayerInfoBoolean(String world, String player, String node, boolean defaultValue) { 74 | OfflinePlayer offlinePlayer = Bukkit.getOfflinePlayer(player); 75 | if (offlinePlayer == null) return defaultValue; 76 | return getPlayerInfoBoolean(world, offlinePlayer, node, defaultValue); 77 | } 78 | 79 | @Override 80 | public void setPlayerInfoBoolean(String world, String player, String node, boolean value) { 81 | OfflinePlayer offlinePlayer = Bukkit.getOfflinePlayer(player); 82 | if (offlinePlayer == null) return; 83 | setPlayerInfoBoolean(world, offlinePlayer, node, value); 84 | } 85 | 86 | @Override 87 | public String getPlayerInfoString(String world, String player, String node, String defaultValue) { 88 | OfflinePlayer offlinePlayer = Bukkit.getOfflinePlayer(player); 89 | if (offlinePlayer == null) return defaultValue; 90 | return getPlayerInfoString(world, offlinePlayer, node, defaultValue); 91 | } 92 | 93 | @Override 94 | public void setPlayerInfoString(String world, String player, String node, String value) { 95 | OfflinePlayer offlinePlayer = Bukkit.getOfflinePlayer(player); 96 | if (offlinePlayer == null) return; 97 | setPlayerInfoString(world, offlinePlayer, node, value); 98 | } 99 | 100 | } 101 | -------------------------------------------------------------------------------- /etc/gen-test-dump.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | import random 4 | 5 | 6 | WORLDS = [None] * 8 + ['world', 'world_nether', 'creative', 'hardcore'] 7 | 8 | REGIONS = [None] * 20 + ['Region%d' % i for i in range(10)] 9 | 10 | NUM_PLAYERS = 100 11 | 12 | NUM_PERMISSIONS_PER_PLAYER = 50 13 | 14 | NUM_GROUPS = (3, 13, 23, 31, 41) 15 | 16 | NUM_PERMISSIONS_PER_GROUP = 50 17 | 18 | NUM_PLAYERS_PER_GROUP = 50 19 | 20 | PLAYER_MEMBER_POOL_SIZE = 1000 21 | 22 | METADATA_TYPES = [str, int, float, bool] 23 | 24 | STR_ALPHABET = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz' 25 | 26 | NUM_METADATA_PER_PLAYER = 10 27 | 28 | NUM_METADATA_PER_GROUP = 10 29 | 30 | 31 | groups_at_depth = [] 32 | for i in range(len(NUM_GROUPS)): 33 | groups_at_depth.append([]) 34 | 35 | 36 | def generate_metadata(name, is_group, count): 37 | for i in range(count): 38 | type = METADATA_TYPES[random.randint(0, len(METADATA_TYPES) - 1)] 39 | suffix = '' 40 | if type is str: 41 | length = random.randint(5,20) 42 | value = [] 43 | for j in range(length): 44 | value.append(STR_ALPHABET[random.randint(0, len(STR_ALPHABET) - 1)]) 45 | value = ''.join(value) 46 | elif type is int: 47 | suffix = 'int' 48 | value = random.randint(-10000, 10000) 49 | elif type is float: 50 | suffix = 'real' 51 | value = random.random() * 20000.0 - 10000.0 52 | elif type is bool: 53 | suffix = 'bool' 54 | value = random.randint(0,1) 55 | if value == 0: 56 | value = 'false' 57 | else: 58 | value = 'true' 59 | print('permissions %s %s metadata set%s metadata.%s.%d %s' % ( 60 | is_group and 'group' or 'player', 61 | name, 62 | suffix, 63 | name.lower(), 64 | i, 65 | value)) 66 | 67 | 68 | def generate_permissions(name, is_group, count): 69 | for i in range(count): 70 | region = REGIONS[random.randint(0, len(REGIONS) - 1)] 71 | if region is None: 72 | region = '' 73 | else: 74 | region += '/' 75 | world = WORLDS[random.randint(0, len(WORLDS) - 1)] 76 | if world is None: 77 | world = '' 78 | else: 79 | world += ':' 80 | print('permissions %s %s set %s%spermission.%s.%d true' % ( 81 | is_group and 'group' or 'player', 82 | name, 83 | region.lower(), 84 | world.lower(), 85 | name.lower(), 86 | i)) 87 | 88 | 89 | def generate_group(name, depth): 90 | if depth == 0: 91 | # Nothing special 92 | print('permissions group %s create' % name) 93 | else: 94 | print('permissions group %s create' % name) 95 | # Pick random parent of previous depth 96 | potential_parents = groups_at_depth[depth - 1] 97 | parent = potential_parents[random.randint(0, len(potential_parents) - 1)] 98 | print('permissions group %s setparents %s' % (name, parent)) 99 | print('permissions group %s setweight 0' % name) 100 | assert name not in groups_at_depth[depth] 101 | groups_at_depth[depth].append(name) 102 | 103 | 104 | def generate_members(name, count): 105 | members = set([]) 106 | while len(members) < count: 107 | p = random.randint(0, PLAYER_MEMBER_POOL_SIZE - 1) 108 | if p in members: 109 | continue 110 | members.add(p) 111 | print('permissions group %s add testplayer%d' % (name, p)) 112 | 113 | 114 | def main(): 115 | for p in range(NUM_PLAYERS): 116 | generate_permissions('TestPlayer%d' % p, False, 117 | NUM_PERMISSIONS_PER_PLAYER) 118 | generate_metadata('TestPlayer%d' % p, False, NUM_METADATA_PER_PLAYER) 119 | 120 | group_count = 0 121 | for depth, num_at_depth in enumerate(NUM_GROUPS): 122 | for g in range(num_at_depth): 123 | name = 'TestGroup%d' % group_count 124 | group_count += 1 125 | generate_group(name, depth) 126 | generate_permissions(name, True, NUM_PERMISSIONS_PER_GROUP) 127 | generate_members(name, NUM_PLAYERS_PER_GROUP) 128 | generate_metadata(name, True, NUM_METADATA_PER_GROUP) 129 | 130 | 131 | if __name__ == '__main__': 132 | main() 133 | -------------------------------------------------------------------------------- /src/main/java/org/tyrannyofheaven/bukkit/zPermissions/util/RefreshTask.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2012 ZerothAngel 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package org.tyrannyofheaven.bukkit.zPermissions.util; 17 | 18 | import static org.tyrannyofheaven.bukkit.util.ToHLoggingUtils.debug; 19 | import static org.tyrannyofheaven.bukkit.util.ToHLoggingUtils.error; 20 | import static org.tyrannyofheaven.bukkit.util.ToHLoggingUtils.warn; 21 | import static org.tyrannyofheaven.bukkit.util.ToHStringUtils.delimitedString; 22 | 23 | import java.util.Collection; 24 | import java.util.LinkedHashSet; 25 | import java.util.LinkedList; 26 | import java.util.Queue; 27 | import java.util.Set; 28 | import java.util.UUID; 29 | 30 | import org.bukkit.Bukkit; 31 | import org.bukkit.plugin.Plugin; 32 | import org.tyrannyofheaven.bukkit.zPermissions.RefreshCause; 33 | import org.tyrannyofheaven.bukkit.zPermissions.ZPermissionsCore; 34 | 35 | /** 36 | * Periodically calls {@link ZPermissionsCore#refreshPlayer(UUID, RefreshCause)} on the 37 | * given queue of players. 38 | * 39 | * @author zerothangel 40 | */ 41 | public class RefreshTask implements Runnable { 42 | 43 | private final ZPermissionsCore core; 44 | 45 | private final Plugin plugin; 46 | 47 | private int delay; 48 | 49 | private final Queue playersToRefresh = new LinkedList<>(); // synchronized on this 50 | 51 | private int taskId = -1; // synchronized on this 52 | 53 | public RefreshTask(ZPermissionsCore core, Plugin plugin) { 54 | this.core = core; 55 | this.plugin = plugin; 56 | } 57 | 58 | public void setDelay(int delay) { 59 | if (delay < 0) 60 | delay = 0; 61 | this.delay = delay; 62 | } 63 | 64 | public synchronized void start(Collection playerUuids) { 65 | if (playerUuids == null || playerUuids.isEmpty()) 66 | return; // Nothing to do 67 | 68 | // Build a set to maintain uniqueness 69 | Set nextPlayersToRefresh = new LinkedHashSet<>(playersToRefresh); 70 | 71 | // Remember who to refresh 72 | nextPlayersToRefresh.addAll(playerUuids); 73 | 74 | // Replace queue with set 75 | playersToRefresh.clear(); 76 | playersToRefresh.addAll(nextPlayersToRefresh); 77 | 78 | // Schedule task if not already scheduled 79 | if (taskId < 0) { 80 | debug(plugin, "Scheduling background refresh"); 81 | scheduleTask(); 82 | } 83 | } 84 | 85 | private void scheduleTask() { 86 | if ((taskId = Bukkit.getScheduler().scheduleSyncDelayedTask(plugin, this, (long)delay)) < 0) { 87 | error(plugin, "Failed to schedule RefreshTask! Remaining players: %s", delimitedString(", ", playersToRefresh)); 88 | } 89 | } 90 | 91 | public synchronized void stop() { 92 | if (taskId > -1) { 93 | warn(plugin, "RefreshTask cancelled prematurely! Remaining players: %s", delimitedString(", ", playersToRefresh)); 94 | Bukkit.getScheduler().cancelTask(taskId); 95 | taskId = -1; 96 | } 97 | } 98 | 99 | @Override 100 | public synchronized void run() { 101 | taskId = -1; 102 | 103 | if (!playersToRefresh.isEmpty()) { 104 | UUID playerToRefresh = playersToRefresh.remove(); 105 | 106 | // Refresh single player 107 | core.invalidateMetadataCache("ignored", playerToRefresh, false); 108 | core.refreshPlayer(playerToRefresh, RefreshCause.GROUP_CHANGE); // NB Assumes all who call start() are doing so for group- or server-wide changes 109 | } 110 | 111 | // Schedule next player 112 | if (!playersToRefresh.isEmpty()) { 113 | scheduleTask(); 114 | } 115 | else 116 | debug(plugin, "Done doing background refresh!"); 117 | } 118 | 119 | } 120 | -------------------------------------------------------------------------------- /src/main/java/org/tyrannyofheaven/bukkit/zPermissions/region/FactionsRegionStrategy.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2013 ZerothAngel 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package org.tyrannyofheaven.bukkit.zPermissions.region; 17 | 18 | import java.util.Collections; 19 | import java.util.Set; 20 | 21 | import org.bukkit.Bukkit; 22 | import org.bukkit.Location; 23 | import org.bukkit.entity.Player; 24 | import org.bukkit.event.EventHandler; 25 | import org.bukkit.event.Listener; 26 | import org.bukkit.event.server.PluginEnableEvent; 27 | import org.bukkit.plugin.Plugin; 28 | import org.tyrannyofheaven.bukkit.util.ToHLoggingUtils; 29 | import org.tyrannyofheaven.bukkit.zPermissions.ZPermissionsCore; 30 | 31 | import com.massivecraft.factions.Rel; 32 | import com.massivecraft.factions.entity.BoardColls; 33 | import com.massivecraft.factions.entity.Faction; 34 | import com.massivecraft.factions.entity.UPlayer; 35 | import com.massivecraft.mcore.ps.PS; 36 | 37 | /** 38 | * RegionStrategy implementation for Factions. 39 | * 40 | * @author zerothangel 41 | */ 42 | public class FactionsRegionStrategy implements RegionStrategy, Listener { 43 | 44 | private static final String RM_PLUGIN_NAME = "Factions"; 45 | 46 | private final Plugin plugin; 47 | 48 | private final ZPermissionsCore core; 49 | 50 | private boolean factionsEnabled; 51 | 52 | public FactionsRegionStrategy(Plugin plugin, ZPermissionsCore core) { 53 | this.plugin = plugin; 54 | this.core = core; 55 | } 56 | 57 | @Override 58 | public String getName() { 59 | return RM_PLUGIN_NAME; 60 | } 61 | 62 | @Override 63 | public boolean isPresent() { 64 | return Bukkit.getPluginManager().getPlugin(RM_PLUGIN_NAME) != null; 65 | } 66 | 67 | @Override 68 | public void init() { 69 | detectFactionsPlugin(); 70 | if (!isEnabled()) { 71 | // Not yet loaded, listen for its enable event 72 | Bukkit.getPluginManager().registerEvents(this, plugin); 73 | } 74 | } 75 | 76 | @Override 77 | public boolean isEnabled() { 78 | return factionsEnabled; 79 | } 80 | 81 | @Override 82 | public void shutdown() { 83 | factionsEnabled = false; 84 | } 85 | 86 | @Override 87 | public Set getRegions(Location location, Player player) { 88 | if (isEnabled()) { 89 | // This indirection is necessary to avoid NoClassDefErrors when 90 | // Factions is not present. 91 | return FactionsHelper.getRegions(location, player); 92 | } 93 | return Collections.emptySet(); 94 | } 95 | 96 | @EventHandler 97 | public void onPluginEnable(PluginEnableEvent event) { 98 | if (!isEnabled() && RM_PLUGIN_NAME.equals(event.getPlugin().getName())) { 99 | detectFactionsPlugin(); 100 | if (isEnabled()) { 101 | ToHLoggingUtils.log(plugin, "%s region support enabled.", getName()); 102 | core.refreshPlayers(); 103 | } 104 | } 105 | } 106 | 107 | private void detectFactionsPlugin() { 108 | Plugin plugin = Bukkit.getPluginManager().getPlugin(RM_PLUGIN_NAME); 109 | factionsEnabled = plugin.isEnabled(); 110 | } 111 | 112 | private static class FactionsHelper { 113 | 114 | private static Set getRegions(Location location, Player player) { 115 | Faction faction = BoardColls.get().getFactionAt(PS.valueOf(location)); 116 | UPlayer uplayer = UPlayer.get(player); 117 | if (faction != null && uplayer != null) { 118 | Rel rel = uplayer.getRelationTo(faction); 119 | if (rel != null) { 120 | return Collections.singleton(rel.name().toLowerCase()); 121 | } 122 | } 123 | return Collections.emptySet(); 124 | } 125 | 126 | } 127 | 128 | } 129 | -------------------------------------------------------------------------------- /doc/admins.md: -------------------------------------------------------------------------------- 1 | # For Server Admins # 2 | 3 | ## Database Setup ## 4 | 5 | As mentioned, zPermissions does **NOT** work with SQLite, the default database used by CraftBukkit. If you would like something similar to SQLite (a Java-based, embedded database), I recommend [H2](http://www.h2database.com/). 6 | 7 | Example bukkit.yml settings follow. 8 | 9 | ### MySQL ### 10 | 11 | MySQL is probably the easiest database to use, especially since CraftBukkit already includes its driver. The relevant settings in your bukkit.yml would look something like: 12 | 13 | database: 14 | username: bukkit 15 | isolation: SERIALIZABLE 16 | driver: com.mysql.jdbc.Driver 17 | password: walrus 18 | url: jdbc:mysql://127.0.0.1:3306/{NAME} 19 | 20 | If you do use the above URL (one database per plugin — extremely recommended), be sure to create a database for zPermissions before using it. 21 | 22 | ### H2 ### 23 | 24 | Setting up CraftBukkit to use H2 is bit involved. One way to do it is: 25 | 26 | 1. Put h2.jar in the same directory as craftbukkit.jar 27 | 28 | 2. Change the way you launch CraftBukkit so you add h2.jar to the Java classpath. Something like: 29 | 30 | java {your-normal-Java-options} -cp craftbukkit.jar:h2.jar org.bukkit.craftbukkit.Main 31 | 32 | 3. Your bukkit.yml database settings would look something like: 33 | 34 | database: 35 | username: bukkit 36 | isolation: SERIALIZABLE 37 | driver: org.h2.Driver 38 | password: walrus 39 | url: jdbc:h2:{DIR}{NAME} 40 | 41 | ### PostgreSQL ### 42 | 43 | Setting up for PostgreSQL is similar to H2. 44 | 45 | 1. Put postgresql.jar in the same directory as craftbukkit.jar 46 | 47 | 2. Change the way you launch CraftBukkit so you add postgresql.jar to the Java classpath. Something like: 48 | 49 | java {your-normal-Java-options} -cp craftbukkit.jar:postgresql.jar org.bukkit.craftbukkit.Main 50 | 51 | 3. Your bukkit.yml database settings would look something like: 52 | 53 | database: 54 | username: bukkit 55 | isolation: SERIALIZABLE 56 | driver: org.postgresql.Driver 57 | password: walrus 58 | url: jdbc:postgresql://127.0.0.1/{NAME} 59 | 60 | As in the MySQL case, this configuration assigns a database to each plugin. Be sure to create one for zPermissions ahead of time and **remember** PostgreSQL's names are case-sensitive, so be sure to use quotes: 61 | 62 | create database 'zPermissions' with owner bukkit; 63 | 64 | ### Others ### 65 | 66 | Other databases will probably work, provided it's supported by [Avaje Ebean](http://avaje.org/) and zPermissions's data model. The setup will probably be similar to PostgreSQL. 67 | 68 | ## Using a Test Database ## 69 | 70 | If your test Bukkit server happens to use the same database server as your production Bukkit server, you can specify a different database by simply prefixing or suffixing {NAME} in the URL with a string of your choice. For example: 71 | 72 | database: 73 | ... omitted ... 74 | url: jdbc:mysql://127.0.0.1:3306/{NAME}_test 75 | 76 | zPermissions on your test server would then use the database named zPermissions_test. Note that this will, of course, affect other plugins that also use Bukkit persistence. 77 | 78 | ## Permission Entry ## 79 | 80 | The fact that zPermissions only has an SQL backend means there are only two ways to enter permissions: 81 | 82 | 1. Through the command line (console or in-game... I recommend console) 83 | 2. If you're masochistic enough, INSERTing directly into zPermissions's SQL tables. 84 | 85 | I strongly recommend taking advantage of CraftBukkit's `permissions.yml` file (found in the server root), where you can define custom permissions with any number of children. For example: 86 | 87 | server.basics: 88 | description: Basic permissions for this server 89 | children: 90 | commandbook.motd: true 91 | commandbook.rules: true 92 | commandbook.say: true 93 | commandbook.say.me: true 94 | commandbook.who: true 95 | 96 | With that, when you give the `server.basics` permission to a player or group, that player or group automatically gets those 5 commandbook permissions. 97 | 98 | If you have a well-organized `permissions.yml`, you would ideally only need to assign a handful of permissions per group or player. 99 | 100 | ### There is Another... ### 101 | 102 | An advanced alternative is to abuse/take advantage of zPermissions's import feature. zPermissions's dump files are nothing more than text files with zPermissions commands. So you can enter all your commands in a file ahead of time, place it in zPermissions's dump directory (by default, the `zPermissions-dumps` directory off the server root), and then run the `/permissions import ` command. 103 | 104 | But note, your database must be absolutely empty (no players or groups). So either purge everyone/everything or drop zPermissions's tables or database... 105 | -------------------------------------------------------------------------------- /src/main/java/org/tyrannyofheaven/bukkit/zPermissions/region/WorldGuardRegionStrategy.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2013 ZerothAngel 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package org.tyrannyofheaven.bukkit.zPermissions.region; 17 | 18 | import java.util.ArrayList; 19 | import java.util.Collections; 20 | import java.util.LinkedHashSet; 21 | import java.util.List; 22 | import java.util.Set; 23 | 24 | import org.bukkit.Bukkit; 25 | import org.bukkit.Location; 26 | import org.bukkit.entity.Player; 27 | import org.bukkit.event.EventHandler; 28 | import org.bukkit.event.Listener; 29 | import org.bukkit.event.server.PluginEnableEvent; 30 | import org.bukkit.plugin.Plugin; 31 | import org.tyrannyofheaven.bukkit.util.ToHLoggingUtils; 32 | import org.tyrannyofheaven.bukkit.zPermissions.ZPermissionsCore; 33 | 34 | import com.google.common.collect.Iterables; 35 | import com.sk89q.worldedit.bukkit.BukkitAdapter; 36 | import com.sk89q.worldguard.WorldGuard; 37 | import com.sk89q.worldguard.bukkit.WorldGuardPlugin; 38 | import com.sk89q.worldguard.protection.ApplicableRegionSet; 39 | import com.sk89q.worldguard.protection.regions.ProtectedRegion; 40 | 41 | /** 42 | * RegionStrategy implementation for WorldGuard. 43 | * 44 | * @author zerothangel 45 | */ 46 | public class WorldGuardRegionStrategy implements RegionStrategy, Listener { 47 | 48 | private static final String RM_PLUGIN_NAME = "WorldGuard"; 49 | 50 | private final Plugin plugin; 51 | 52 | private final ZPermissionsCore core; 53 | 54 | private WorldGuardPlugin worldGuardPlugin; 55 | 56 | public WorldGuardRegionStrategy(Plugin plugin, ZPermissionsCore core) { 57 | this.plugin = plugin; 58 | this.core = core; 59 | } 60 | 61 | @Override 62 | public String getName() { 63 | return RM_PLUGIN_NAME; 64 | } 65 | 66 | @Override 67 | public boolean isPresent() { 68 | return Bukkit.getPluginManager().getPlugin(RM_PLUGIN_NAME) != null; 69 | } 70 | 71 | @Override 72 | public void init() { 73 | detectWorldGuardPlugin(); 74 | if (!isEnabled()) { 75 | // Not yet loaded, listen for its enable event 76 | Bukkit.getPluginManager().registerEvents(this, plugin); 77 | } 78 | } 79 | 80 | @Override 81 | public boolean isEnabled() { 82 | return worldGuardPlugin != null; 83 | } 84 | 85 | @Override 86 | public void shutdown() { 87 | worldGuardPlugin = null; 88 | } 89 | 90 | @Override 91 | public Set getRegions(Location location, Player player) { 92 | if (isEnabled()) { 93 | ApplicableRegionSet ars = WorldGuard.getInstance().getPlatform().getRegionContainer() 94 | .createQuery().getApplicableRegions(BukkitAdapter.adapt(location)); 95 | // Note, sorted from high to low priority, i.e. reverse application order 96 | List sorted = new ArrayList<>(); 97 | Iterables.addAll(sorted, ars); 98 | Collections.reverse(sorted); // Now it is in application order 99 | 100 | Set result = new LinkedHashSet<>(); // Preserve ordering for resolver 101 | for (ProtectedRegion pr : sorted) { 102 | // Ignore global region 103 | if (!"__global__".equals(pr.getId())) // NB: Hardcoded and not available as constant in WorldGuard 104 | result.add(pr.getId().toLowerCase()); 105 | } 106 | return result; 107 | } 108 | return Collections.emptySet(); 109 | } 110 | 111 | @EventHandler 112 | public void onPluginEnable(PluginEnableEvent event) { 113 | if (!isEnabled() && RM_PLUGIN_NAME.equals(event.getPlugin().getName())) { 114 | detectWorldGuardPlugin(); 115 | if (isEnabled()) { 116 | ToHLoggingUtils.log(plugin, "%s region support enabled.", getName()); 117 | core.refreshPlayers(); 118 | } 119 | } 120 | } 121 | 122 | private void detectWorldGuardPlugin() { 123 | Plugin plugin = Bukkit.getPluginManager().getPlugin(RM_PLUGIN_NAME); 124 | if (plugin instanceof WorldGuardPlugin && plugin.isEnabled()) { 125 | worldGuardPlugin = (WorldGuardPlugin)plugin; 126 | } 127 | else { 128 | worldGuardPlugin = null; 129 | } 130 | } 131 | 132 | } 133 | -------------------------------------------------------------------------------- /src/main/java/org/tyrannyofheaven/bukkit/zPermissions/storage/DummyStorageStrategy.java: -------------------------------------------------------------------------------- 1 | // Released to the public domain 2 | package org.tyrannyofheaven.bukkit.zPermissions.storage; 3 | 4 | import java.util.Map; 5 | 6 | import org.tyrannyofheaven.bukkit.util.transaction.NullTransactionStrategy; 7 | import org.tyrannyofheaven.bukkit.util.transaction.TransactionStrategy; 8 | import org.tyrannyofheaven.bukkit.zPermissions.dao.DummyPermissionDao; 9 | import org.tyrannyofheaven.bukkit.zPermissions.dao.InMemoryPermissionService; 10 | import org.tyrannyofheaven.bukkit.zPermissions.dao.PermissionService; 11 | 12 | /* 13 | * This is the top-level storage interface. A custom implementation can be used 14 | * by setting the custom-storage-strategy option in zPermissions' config.yml. 15 | * 16 | * To be used this way, this class must have a no-arg constructor. 17 | * 18 | * Note that init() and refresh() are usually responsible for loading from 19 | * whatever store you use. However, loading can be delegated to the PermissionDao 20 | * implementation, if it makes more sense to do it that way (and it usually does). 21 | * 22 | * Loading usually consists of: 23 | * 1. Instantiating a new MemoryState instance 24 | * 2. Using the static methods in InMemoryPermissionService to create entities 25 | * (and filling out their permissions and metadata) and memberships. Note, 26 | * letter case matters for certain properties: Entry#permission, EntityMetadata#name, 27 | * Membership#member. When in doubt, check the loading code in AvajePermissionDao & 28 | * FilePermissionDao. 29 | * 3. Calling your InMemoryPermissionService instance's setMemoryState() method. 30 | * 31 | * Also see javadocs for StorageStrategy. 32 | */ 33 | public class DummyStorageStrategy implements StorageStrategy { 34 | 35 | private final InMemoryPermissionService permissionService = new InMemoryPermissionService(); 36 | 37 | private final DummyPermissionDao permissionDao = new DummyPermissionDao(); // You may want to pass permissionService to the constructor 38 | 39 | private final TransactionStrategy transactionStrategy = new NullTransactionStrategy(); 40 | 41 | public DummyStorageStrategy() { 42 | permissionService.setPermissionDao(permissionDao); 43 | } 44 | 45 | @Override 46 | public void init(Map configMap) { 47 | /* 48 | * Perform initialization. Feel free to use blocking I/O. 49 | * Simple implementations may simply call refresh(true, null) 50 | */ 51 | } 52 | 53 | @Override 54 | public void shutdown() { 55 | /* 56 | * Perform cleanup or final I/O. Can also block. 57 | */ 58 | } 59 | 60 | @Override 61 | public void refresh(boolean force, Runnable finishTask) { 62 | /* 63 | * Normal calls to this should NEVER block. (However, if called from init() 64 | * above, it should block so initialization does not continue until 65 | * everything has loaded. See AvajeStorageStrategy for an example of how 66 | * this is handled.) 67 | * 68 | * Only execute finishTask if in-memory representation changed 69 | * (i.e. InMemoryPermissionService#setMemoryState() was called) and 70 | * finishTask != null 71 | * 72 | * If you do execute finishTask, remember the contract dictates that it 73 | * must execute in the main thread. 74 | */ 75 | } 76 | 77 | @Override 78 | public PermissionService getPermissionService() { 79 | /* 80 | * Should return your PermissionService implementation, which should 81 | * basically be an InMemoryPermissionService instance (unless you 82 | * feel like re-implementing THAT interface) 83 | */ 84 | return permissionService; 85 | } 86 | 87 | /* 88 | * In the olden days (pre-1.0), there were two distinct TransactionStrategy 89 | * instances. However, if you use InMemoryPermissionService as your 90 | * PermissionService implementation, the distinction doesn't matter anymore. 91 | * 92 | * Both getters should return the same instance, and it will usually be 93 | * one of two implementations: 94 | * 95 | * NullTransactionStrategy - If you don't actually do any I/O in PermissionDao, e.g. 96 | * you just set a dirty flag and perform I/O elsewhere (similar to FilePermissionDao). 97 | * AsyncTransactionStrategy - If your store is transactional (e.g. requires a real 98 | * TransactionStrategy implementation) and your I/O would normally block. 99 | * Databases fall under this. (Also see AvajePermissionDao.) 100 | * 101 | * If your I/O is blocking but not transactional, you can probably get away 102 | * with using NullTransactionStrategy. 103 | */ 104 | 105 | @Override 106 | public TransactionStrategy getTransactionStrategy() { 107 | return transactionStrategy; 108 | } 109 | 110 | @Override 111 | public TransactionStrategy getRetryingTransactionStrategy() { 112 | return transactionStrategy; 113 | } 114 | 115 | } 116 | -------------------------------------------------------------------------------- /src/main/java/org/tyrannyofheaven/bukkit/zPermissions/model/EntityMetadata.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2013 ZerothAngel 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package org.tyrannyofheaven.bukkit.zPermissions.model; 17 | 18 | import javax.persistence.Column; 19 | import javax.persistence.Entity; 20 | import javax.persistence.Id; 21 | import javax.persistence.JoinColumn; 22 | import javax.persistence.ManyToOne; 23 | import javax.persistence.Table; 24 | import javax.persistence.Transient; 25 | import javax.persistence.UniqueConstraint; 26 | 27 | @Entity 28 | @Table(name="metadata") 29 | @UniqueConstraint(columnNames={"entity_id", "name"}) 30 | public class EntityMetadata { 31 | 32 | private Long id; 33 | 34 | private PermissionEntity entity; 35 | 36 | private String name; 37 | 38 | private String stringValue; 39 | 40 | private Long integerValue; 41 | 42 | private Double realValue; 43 | 44 | private Boolean booleanValue; 45 | 46 | @Id 47 | public Long getId() { 48 | return id; 49 | } 50 | 51 | public void setId(Long id) { 52 | this.id = id; 53 | } 54 | 55 | @JoinColumn(name="entity_id") 56 | @ManyToOne(optional=false) 57 | public PermissionEntity getEntity() { 58 | return entity; 59 | } 60 | 61 | public void setEntity(PermissionEntity entity) { 62 | this.entity = entity; 63 | } 64 | 65 | @Column(nullable=false) 66 | public String getName() { 67 | return name; 68 | } 69 | 70 | public void setName(String name) { 71 | this.name = name; 72 | } 73 | 74 | public String getStringValue() { 75 | return stringValue; 76 | } 77 | 78 | public void setStringValue(String stringValue) { 79 | this.stringValue = stringValue; 80 | } 81 | 82 | public Long getIntegerValue() { 83 | return integerValue; 84 | } 85 | 86 | public void setIntegerValue(Long integerValue) { 87 | this.integerValue = integerValue; 88 | } 89 | 90 | public Double getRealValue() { 91 | return realValue; 92 | } 93 | 94 | public void setRealValue(Double realValue) { 95 | this.realValue = realValue; 96 | } 97 | 98 | public Boolean getBooleanValue() { 99 | return booleanValue; 100 | } 101 | 102 | public void setBooleanValue(Boolean booleanValue) { 103 | this.booleanValue = booleanValue; 104 | } 105 | 106 | @Transient 107 | public Object getValue() { 108 | if (getStringValue() != null) 109 | return getStringValue(); 110 | else if (getIntegerValue() != null) 111 | return getIntegerValue(); 112 | else if (getRealValue() != null) 113 | return getRealValue(); 114 | else if (getBooleanValue() != null) 115 | return getBooleanValue(); 116 | else 117 | return null; 118 | } 119 | 120 | public void setValue(Object value) { 121 | setStringValue(null); 122 | setIntegerValue(null); 123 | setRealValue(null); 124 | setBooleanValue(null); 125 | 126 | if (value instanceof String) { 127 | setStringValue((String)value); 128 | } 129 | else if (value instanceof Integer) { 130 | setIntegerValue(((Number)value).longValue()); 131 | } 132 | else if (value instanceof Long) { 133 | setIntegerValue((Long)value); 134 | } 135 | else if (value instanceof Float) { 136 | setRealValue(((Number)value).doubleValue()); 137 | } 138 | else if (value instanceof Double) { 139 | setRealValue((Double)value); 140 | } 141 | else if (value instanceof Boolean) { 142 | setBooleanValue((Boolean)value); 143 | } 144 | else 145 | throw new IllegalArgumentException("Invalid metadata value"); 146 | } 147 | 148 | @Override 149 | public boolean equals(Object obj) { 150 | if (obj == this) return true; 151 | if (!(obj instanceof EntityMetadata)) return false; 152 | EntityMetadata o = (EntityMetadata)obj; 153 | return getEntity().equals(o.getEntity()) && 154 | getName().equals(o.getName()); 155 | } 156 | 157 | @Override 158 | public int hashCode() { 159 | int result = 17; 160 | result = 37 * result + getEntity().hashCode(); 161 | result = 37 * result + getName().hashCode(); 162 | return result; 163 | } 164 | 165 | @Override 166 | public String toString() { 167 | return String.format("EntityMetadata[%s]", getName()); 168 | } 169 | 170 | } 171 | -------------------------------------------------------------------------------- /src/main/java/org/tyrannyofheaven/bukkit/zPermissions/util/GlobPattern.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Licensed to the Apache Software Foundation (ASF) under one 3 | * or more contributor license agreements. See the NOTICE file 4 | * distributed with this work for additional information 5 | * regarding copyright ownership. The ASF licenses this file 6 | * to you under the Apache License, Version 2.0 (the 7 | * "License"); you may not use this file except in compliance 8 | * with the License. You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | */ 18 | 19 | package org.tyrannyofheaven.bukkit.zPermissions.util; 20 | 21 | import java.util.regex.Pattern; 22 | import java.util.regex.PatternSyntaxException; 23 | 24 | /** 25 | * A class for POSIX glob pattern with brace expansions. 26 | */ 27 | public class GlobPattern { 28 | private static final char BACKSLASH = '\\'; 29 | private Pattern compiled; 30 | private boolean hasWildcard = false; 31 | 32 | /** 33 | * Construct the glob pattern object with a glob pattern string 34 | * @param globPattern the glob pattern string 35 | */ 36 | public GlobPattern(String globPattern) { 37 | set(globPattern); 38 | } 39 | 40 | /** 41 | * @return the compiled pattern 42 | */ 43 | public Pattern compiled() { 44 | return compiled; 45 | } 46 | 47 | /** 48 | * Compile glob pattern string 49 | * @param globPattern the glob pattern 50 | * @return the pattern object 51 | */ 52 | public static Pattern compile(String globPattern) { 53 | return new GlobPattern(globPattern).compiled(); 54 | } 55 | 56 | /** 57 | * Match input against the compiled glob pattern 58 | * @param s input chars 59 | * @return true for successful matches 60 | */ 61 | public boolean matches(CharSequence s) { 62 | return compiled.matcher(s).matches(); 63 | } 64 | 65 | /** 66 | * Set and compile a glob pattern 67 | * @param glob the glob pattern string 68 | */ 69 | public void set(String glob) { 70 | StringBuilder regex = new StringBuilder(); 71 | int setOpen = 0; 72 | int curlyOpen = 0; 73 | int len = glob.length(); 74 | hasWildcard = false; 75 | 76 | for (int i = 0; i < len; i++) { 77 | char c = glob.charAt(i); 78 | 79 | switch (c) { 80 | case BACKSLASH: 81 | if (++i >= len) { 82 | error("Missing escaped character", glob, i); 83 | } 84 | regex.append(c).append(glob.charAt(i)); 85 | continue; 86 | case '.': 87 | case '$': 88 | case '(': 89 | case ')': 90 | case '|': 91 | case '+': 92 | // escape regex special chars that are not glob special chars 93 | regex.append(BACKSLASH); 94 | break; 95 | case '*': 96 | regex.append('.'); 97 | hasWildcard = true; 98 | break; 99 | case '?': 100 | regex.append('.'); 101 | hasWildcard = true; 102 | continue; 103 | case '{': // start of a group 104 | regex.append("(?:"); // non-capturing 105 | curlyOpen++; 106 | hasWildcard = true; 107 | continue; 108 | case ',': 109 | regex.append(curlyOpen > 0 ? '|' : c); 110 | continue; 111 | case '}': 112 | if (curlyOpen > 0) { 113 | // end of a group 114 | curlyOpen--; 115 | regex.append(")"); 116 | continue; 117 | } 118 | break; 119 | case '[': 120 | if (setOpen > 0) { 121 | error("Unclosed character class", glob, i); 122 | } 123 | setOpen++; 124 | hasWildcard = true; 125 | break; 126 | case '^': // ^ inside [...] can be unescaped 127 | if (setOpen == 0) { 128 | regex.append(BACKSLASH); 129 | } 130 | break; 131 | case '!': // [! needs to be translated to [^ 132 | regex.append(setOpen > 0 && '[' == glob.charAt(i - 1) ? '^' : '!'); 133 | continue; 134 | case ']': 135 | // Many set errors like [][] could not be easily detected here, 136 | // as []], []-] and [-] are all valid POSIX glob and java regex. 137 | // We'll just let the regex compiler do the real work. 138 | setOpen = 0; 139 | break; 140 | default: 141 | } 142 | regex.append(c); 143 | } 144 | 145 | if (setOpen > 0) { 146 | error("Unclosed character class", glob, len); 147 | } 148 | if (curlyOpen > 0) { 149 | error("Unclosed group", glob, len); 150 | } 151 | compiled = Pattern.compile(regex.toString()); 152 | } 153 | 154 | /** 155 | * @return true if this is a wildcard pattern (with special chars) 156 | */ 157 | public boolean hasWildcard() { 158 | return hasWildcard; 159 | } 160 | 161 | private static void error(String message, String pattern, int pos) { 162 | throw new PatternSyntaxException(message, pattern, pos); 163 | } 164 | } 165 | -------------------------------------------------------------------------------- /doc/developers.md: -------------------------------------------------------------------------------- 1 | # For Plugin Developers # 2 | 3 | ## If you really must have an API... ## 4 | 5 | Since 0.9.8, zPermissions has provided an API for common, read-only operations. It was originally developed with [Vault](http://dev.bukkit.org/server-mods/vault/) in mind, but of course, anyone can use it. 6 | 7 | The API methods are exposed via the [ZPermissionsService](https://github.com/ZerothAngel/zPermissions/blob/master/src/main/java/org/tyrannyofheaven/bukkit/zPermissions/ZPermissionsService.java) interface. 8 | 9 | First, you will need to add zPermissions-X.Y.Z.jar to your build path somehow. If your project uses Maven, add the following repository to your POM: 10 | 11 | 12 | tyrannyofheaven.org 13 | http://maven.tyrannyofheaven.org/ 14 | 15 | 16 | Then add the following dependency: 17 | 18 | 19 | org.tyrannyofheaven.bukkit 20 | zPermissions 21 | [0.9.8,) 22 | provided 23 | 24 | 25 | If you don't use Maven (and why not?), you can visit my [Maven repository](http://maven.tyrannyofheaven.org/org/tyrannyofheaven/bukkit/zPermissions/) directly and download any version > 0.9.8. 26 | 27 | Next, to get an actual implementation of this interface, your plugin should do something like the following: 28 | 29 | ZPermissionsService service = null; 30 | try { 31 | service = Bukkit.getServicesManager().load(ZPermissionsService.class); 32 | } 33 | catch (NoClassDefFoundError e) { 34 | // Eh... 35 | } 36 | if (service == null) { 37 | // zPermissions not found, do something else 38 | } 39 | 40 | Ideally, you would do the lookup once (e.g. store the result in an instance or static variable) and, in addition to your plugin's onEnable(), possibly also perform the check inside a PluginEnableEvent handler. But the above is the general gist of it. 41 | 42 | Note that if you are only checking for ZPermissionsService in your plugin's onEnable() method then you will need to add a line like the following to your plugin.yml: 43 | 44 | softdepend: [zPermissions] 45 | 46 | Finally, if you look at the actual interface, you'll see that it only covers read-only operations. Operations that modify the state of zPermissions are still **only supported via the command line.** So you would probably use something like Bukkit.dispatchCommand(). 47 | 48 | What follows is the old (and of course, still supported!), non-zPermissions-specific Bukkit-only method of interacting with zPermissions... 49 | 50 | ## Checking Group Membership ## 51 | 52 | As far as checking group membership, I strongly advocate the method hinted at by Dinnerbone in his [Permissions FAQ](http://forums.bukkit.org/threads/permissions-faq.25080/). Namely, using permissions to denote group membership. 53 | 54 | zPermissions follows the convention put forth by the developers of WorldEdit, WorldGuard, etc., that is, check group membership by checking for a specific permission of the form: 55 | 56 | group. 57 | 58 | So a player in the `visitor` group will have the `group.visitor` permission automatically set to true. A player in the `admin` group will have the `group.admin` permission set to true, etc. 59 | 60 | (And, of course, in zPermissions, the form of this permission is configurable — see the `group-permission` option in config.yml.) 61 | 62 | Despite zPermissions doing this automatically, the beautiful thing about this convention is that *any* Superperms provider can provide the required permission. If necessary, server admins can just manually add the permission to each of their groups. 63 | 64 | ## Enumerating a Player's Groups ## 65 | 66 | This can be easily done using only the Bukkit permissions API. For example: 67 | 68 | private static final String GROUP_PREFIX = "group."; 69 | 70 | ... 71 | 72 | public Set getGroupsForPlayer(Player player) { 73 | Set groups = new HashSet(); 74 | for (PermissionAttachmentInfo pai : player.getEffectivePermissions()) { 75 | if (!pai.getPermission().startsWith(GROUP_PREFIX) || !pai.getValue()) 76 | continue; 77 | groups.add(pai.getPermission().substring(GROUP_PREFIX.length())); 78 | } 79 | return groups; 80 | } 81 | 82 | It is **STRONGLY** recommended that you actually make `GROUP_PREFIX` configurable. Do not hardcode it. This gives the server admin more flexibility. 83 | 84 | ## Changing Group Membership / Promoting / Demoting ## 85 | 86 | I have no plans to provide any sort of public API for changing group memberships. I absolutely abhor writing to implementations (see what it's like for a modern plugin to support the half dozen or so economy plugins... although that might be a bad example due to the existence of Vault/Register API :P). 87 | 88 | Unless Bukkit someday provides a groups management API (which seems like a bad idea, as it would be dictating an implementation detail to Superperms providers), the only supported method to programmatically modify group memberships in zPermissions **is through the command line**. 89 | 90 | Excuting another plugin's commands is easy. And the awesome thing about using commands: you can make it configurable. Instead of compiling against X different plugins, just provide a command template that the server admin can easily change. For example, for zPermissions: 91 | 92 | permissions player %player% setgroup %group% 93 | 94 | And the plugin would make the necessary substitutions before handing the command off to the server to be executed. 95 | 96 | Actual implementation left up to any enterprising developers... ;) 97 | -------------------------------------------------------------------------------- /src/main/java/org/tyrannyofheaven/bukkit/zPermissions/listener/ZPermissionsPlayerListener.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2011 ZerothAngel 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package org.tyrannyofheaven.bukkit.zPermissions.listener; 17 | 18 | import static org.tyrannyofheaven.bukkit.util.ToHLoggingUtils.debug; 19 | 20 | import org.bukkit.Bukkit; 21 | import org.bukkit.event.EventHandler; 22 | import org.bukkit.event.EventPriority; 23 | import org.bukkit.event.Listener; 24 | import org.bukkit.event.player.AsyncPlayerPreLoginEvent; 25 | import org.bukkit.event.player.PlayerChangedWorldEvent; 26 | import org.bukkit.event.player.PlayerJoinEvent; 27 | import org.bukkit.event.player.PlayerLoginEvent; 28 | import org.bukkit.event.player.PlayerQuitEvent; 29 | import org.bukkit.plugin.Plugin; 30 | import org.tyrannyofheaven.bukkit.util.uuid.UuidResolver; 31 | import org.tyrannyofheaven.bukkit.zPermissions.RefreshCause; 32 | import org.tyrannyofheaven.bukkit.zPermissions.ZPermissionsCore; 33 | 34 | /** 35 | * PlayerListener for zPermissions. Simply updates or removes the zPermissions 36 | * permissions as appropriate. 37 | * 38 | * @author zerothangel 39 | */ 40 | public class ZPermissionsPlayerListener implements Listener { 41 | 42 | private final ZPermissionsCore core; 43 | 44 | private final Plugin plugin; 45 | 46 | private final UuidResolver uuidResolver; 47 | 48 | public ZPermissionsPlayerListener(ZPermissionsCore core, Plugin plugin, UuidResolver uuidResolver) { 49 | this.core = core; 50 | this.plugin = plugin; 51 | this.uuidResolver = uuidResolver; 52 | } 53 | 54 | @EventHandler(priority=EventPriority.MONITOR) 55 | public void onAsyncPlayerPreLogin(AsyncPlayerPreLoginEvent event) { 56 | if (event.getLoginResult() == AsyncPlayerPreLoginEvent.Result.ALLOWED) { 57 | // Update display name 58 | core.updateDisplayName(event.getUniqueId(), event.getName()); 59 | } 60 | } 61 | 62 | // Do this early for the benefit of anything listening on the same event 63 | @EventHandler(priority=EventPriority.LOWEST) 64 | public void onPlayerLogin(PlayerLoginEvent event) { 65 | debug(plugin, "%s logged in", event.getPlayer().getName()); 66 | core.setBukkitPermissions(event.getPlayer(), event.getPlayer().getLocation(), true, null); 67 | // NB don't bother with expirations until join 68 | } 69 | 70 | @EventHandler(priority=EventPriority.MONITOR) 71 | public void onPlayerLoginMonitor(PlayerLoginEvent event) { 72 | // If they aren't sticking around... 73 | if (event.getResult() != PlayerLoginEvent.Result.ALLOWED) { 74 | // Forget about them 75 | debug(plugin, "%s is not allowed to log in", event.getPlayer().getName()); 76 | core.removeBukkitPermissions(event.getPlayer(), false); // They're getting booted, no need to recalc 77 | } 78 | } 79 | 80 | @EventHandler(priority=EventPriority.LOWEST) 81 | public void onPlayerJoin(PlayerJoinEvent event) { 82 | debug(plugin, "%s joining", event.getPlayer().getName()); 83 | // NB eventCause is null because it's a given that the player's permissions has changed on join 84 | // (ignore the fact that it actually changed on login for now) 85 | core.setBukkitPermissions(event.getPlayer(), event.getPlayer().getLocation(), true, null); // Does this need to be forced again? 86 | // Wait for next tick... 87 | Bukkit.getScheduler().scheduleSyncDelayedTask(plugin, new Runnable() { 88 | @Override 89 | public void run() { 90 | core.refreshExpirations(); 91 | } 92 | }); 93 | } 94 | 95 | @EventHandler(priority=EventPriority.MONITOR) 96 | public void onPlayerJoinMonitor(PlayerJoinEvent event) { 97 | // Make default group membership explicit, if configured to do so... 98 | core.handleExplicitDefaultGroupMembership(event.getPlayer().getUniqueId(), event.getPlayer().getName()); 99 | } 100 | 101 | @EventHandler(priority=EventPriority.MONITOR) 102 | public void onPlayerQuit(PlayerQuitEvent event) { 103 | debug(plugin, "%s quitting", event.getPlayer().getName()); 104 | core.removeBukkitPermissions(event.getPlayer(), false); // They're leaving, no need to recalc 105 | // Wait for next tick... 106 | Bukkit.getScheduler().scheduleSyncDelayedTask(plugin, new Runnable() { 107 | @Override 108 | public void run() { 109 | core.refreshExpirations(); 110 | } 111 | }); 112 | // Pre-load cache of UuidResolver 113 | uuidResolver.preload(event.getPlayer().getName(), event.getPlayer().getUniqueId()); 114 | } 115 | 116 | @EventHandler(priority=EventPriority.LOWEST) 117 | public void onPlayerChangedWorld(PlayerChangedWorldEvent event) { 118 | core.setBukkitPermissions(event.getPlayer(), event.getPlayer().getLocation(), false, RefreshCause.MOVEMENT); 119 | } 120 | 121 | } 122 | -------------------------------------------------------------------------------- /src/main/java/org/tyrannyofheaven/bukkit/zPermissions/service/DefaultPlayerPrefixHandler.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2014 ZerothAngel 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package org.tyrannyofheaven.bukkit.zPermissions.service; 17 | 18 | import java.util.ArrayList; 19 | import java.util.Collections; 20 | import java.util.HashMap; 21 | import java.util.List; 22 | import java.util.Map; 23 | import java.util.UUID; 24 | 25 | import org.tyrannyofheaven.bukkit.zPermissions.ZPermissionsConfig; 26 | import org.tyrannyofheaven.bukkit.zPermissions.ZPermissionsService; 27 | import org.tyrannyofheaven.bukkit.zPermissions.util.MetadataConstants; 28 | 29 | public class DefaultPlayerPrefixHandler implements PlayerPrefixHandler { 30 | 31 | private final ZPermissionsConfig config; 32 | 33 | public DefaultPlayerPrefixHandler(ZPermissionsConfig config) { 34 | this.config = config; 35 | } 36 | 37 | /* (non-Javadoc) 38 | * @see org.tyrannyofheaven.bukkit.zPermissions.vault.PlayerPrefixHandler#getPlayerPrefix(java.lang.String) 39 | */ 40 | @Override 41 | public String getPlayerPrefix(ZPermissionsService service, UUID uuid) { 42 | String prefix; 43 | 44 | if (config.getVaultPlayerPrefixFormat().isEmpty()) { 45 | prefix = service.getPlayerMetadata(uuid, MetadataConstants.PREFIX_KEY, String.class); 46 | if (prefix == null && config.isVaultPrefixIncludesGroup()) 47 | prefix = service.getGroupMetadata(service.getPlayerPrimaryGroup(uuid), MetadataConstants.PREFIX_KEY, String.class); 48 | } 49 | else { 50 | prefix = getFormattedPrefixSuffix(service, uuid, config.getVaultPlayerPrefixFormat(), true); 51 | } 52 | 53 | if (prefix == null) 54 | return ""; 55 | else 56 | return prefix; 57 | } 58 | 59 | /* (non-Javadoc) 60 | * @see org.tyrannyofheaven.bukkit.zPermissions.vault.PlayerPrefixHandler#getPlayerSuffix(java.lang.String) 61 | */ 62 | @Override 63 | public String getPlayerSuffix(ZPermissionsService service, UUID uuid) { 64 | String suffix; 65 | 66 | if (config.getVaultPlayerSuffixFormat().isEmpty()) { 67 | suffix = service.getPlayerMetadata(uuid, MetadataConstants.SUFFIX_KEY, String.class); 68 | if (suffix == null && config.isVaultPrefixIncludesGroup()) 69 | suffix = service.getGroupMetadata(service.getPlayerPrimaryGroup(uuid), MetadataConstants.SUFFIX_KEY, String.class); 70 | } 71 | else { 72 | suffix = getFormattedPrefixSuffix(service, uuid, config.getVaultPlayerSuffixFormat(), false); 73 | } 74 | 75 | if (suffix == null) 76 | return ""; 77 | else 78 | return suffix; 79 | } 80 | 81 | private String getFormattedPrefixSuffix(ZPermissionsService service, UUID uuid, String format, boolean isPrefix) { 82 | Map subMap = new HashMap<>(); 83 | // Scan format, only calculate tokens that exist in it 84 | if (format.contains("%p")) { 85 | // Player 86 | String value = service.getPlayerMetadata(uuid, isPrefix ? MetadataConstants.PREFIX_KEY : MetadataConstants.SUFFIX_KEY, String.class); 87 | if (value == null) value = ""; 88 | subMap.put("%p", value); 89 | } 90 | if (format.contains("%g")) { 91 | // Primary Group 92 | String value = service.getGroupMetadata(service.getPlayerPrimaryGroup(uuid), isPrefix ? MetadataConstants.PREFIX_KEY : MetadataConstants.SUFFIX_KEY, String.class); 93 | if (value == null) value = ""; 94 | subMap.put("%g", value); 95 | } 96 | if (format.contains("%a")) { 97 | // All Groups 98 | List groups = getPlayerGroups(service, uuid); 99 | Collections.reverse(groups); // groups is in application order. We actually want it in display order. 100 | StringBuilder sb = new StringBuilder(); 101 | for (String group : groups) { 102 | String value = service.getGroupMetadata(group, isPrefix ? MetadataConstants.PREFIX_KEY : MetadataConstants.SUFFIX_KEY, String.class); 103 | if (value == null) value = ""; 104 | sb.append(value); 105 | } 106 | subMap.put("%a", sb.toString()); 107 | } 108 | if (format.contains("%A")) { 109 | // All Groups Reversed 110 | List groups = getPlayerGroups(service, uuid); 111 | StringBuilder sb = new StringBuilder(); 112 | for (String group : groups) { 113 | String value = service.getGroupMetadata(group, isPrefix ? MetadataConstants.PREFIX_KEY : MetadataConstants.SUFFIX_KEY, String.class); 114 | if (value == null) value = ""; 115 | sb.append(value); 116 | } 117 | subMap.put("%A", sb.toString()); 118 | } 119 | 120 | // Perform substitution 121 | String result = format; 122 | for (Map.Entry me : subMap.entrySet()) { 123 | result = result.replaceAll(me.getKey(), me.getValue()); 124 | } 125 | return result; 126 | } 127 | 128 | private List getPlayerGroups(ZPermissionsService service, UUID uuid) { 129 | if (config.isVaultGetGroupsUsesAssignedOnly()) 130 | return service.getPlayerAssignedGroups(uuid); 131 | else 132 | return new ArrayList<>(service.getPlayerGroups(uuid)); 133 | } 134 | 135 | } 136 | -------------------------------------------------------------------------------- /src/main/java/org/tyrannyofheaven/bukkit/zPermissions/util/SearchTask.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2014 ZerothAngel 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package org.tyrannyofheaven.bukkit.zPermissions.util; 17 | 18 | import static org.tyrannyofheaven.bukkit.util.ToHLoggingUtils.log; 19 | import static org.tyrannyofheaven.bukkit.zPermissions.util.Utils.formatPlayerName; 20 | 21 | import java.util.HashMap; 22 | import java.util.List; 23 | import java.util.Map; 24 | import java.util.Set; 25 | import java.util.UUID; 26 | import java.util.concurrent.atomic.AtomicInteger; 27 | 28 | import org.bukkit.Bukkit; 29 | import org.bukkit.plugin.Plugin; 30 | import org.tyrannyofheaven.bukkit.util.transaction.TransactionCallback; 31 | import org.tyrannyofheaven.bukkit.zPermissions.PermissionsResolver; 32 | import org.tyrannyofheaven.bukkit.zPermissions.model.Entry; 33 | import org.tyrannyofheaven.bukkit.zPermissions.model.PermissionEntity; 34 | import org.tyrannyofheaven.bukkit.zPermissions.storage.StorageStrategy; 35 | 36 | public class SearchTask implements Runnable { 37 | 38 | private static final AtomicInteger searchIdGenerator = new AtomicInteger(); 39 | 40 | private final int searchId; 41 | 42 | private final Plugin plugin; 43 | 44 | private final StorageStrategy storageStrategy; 45 | 46 | private final PermissionsResolver resolver; 47 | 48 | private final String permission; 49 | 50 | private final List players; 51 | 52 | private final List groups; 53 | 54 | private final boolean effective; 55 | 56 | private final String world; 57 | 58 | private final Set regions; 59 | 60 | private final boolean showUuid; 61 | 62 | private int batchSize = 1; 63 | 64 | private int delay = 5; 65 | 66 | public SearchTask(Plugin plugin, StorageStrategy storageStrategy, PermissionsResolver resolver, String permission, List players, List groups, boolean effective, String world, Set regions, boolean showUuid) { 67 | this.searchId = searchIdGenerator.incrementAndGet(); 68 | this.plugin = plugin; 69 | this.storageStrategy = storageStrategy; 70 | this.resolver = resolver; 71 | this.permission = permission.toLowerCase(); 72 | this.players = players; 73 | this.groups = groups; 74 | this.effective = effective; 75 | this.world = world; 76 | this.regions = regions; 77 | this.showUuid = showUuid; 78 | } 79 | 80 | public int getSearchId() { 81 | return searchId; 82 | } 83 | 84 | public int getBatchSize() { 85 | return batchSize; 86 | } 87 | 88 | public void setBatchSize(int batchSize) { 89 | this.batchSize = batchSize; 90 | } 91 | 92 | public int getDelay() { 93 | return delay; 94 | } 95 | 96 | public void setDelay(int delay) { 97 | this.delay = delay; 98 | } 99 | 100 | @Override 101 | public void run() { 102 | int size = 0; 103 | 104 | while (size < getBatchSize() && !players.isEmpty()) { 105 | UUID uuid = players.remove(0); 106 | 107 | PermissionEntity entity = storageStrategy.getPermissionService().getEntity("ignored", uuid, false); 108 | if (entity != null && !entity.getPermissions().isEmpty()) { 109 | if (checkPermissions(entity) || (effective && checkEffectivePermissions(entity))) { 110 | log(plugin, "Search result (#%d): player %s", getSearchId(), formatPlayerName(entity, showUuid)); 111 | } 112 | } 113 | 114 | size++; 115 | } 116 | 117 | while (size < getBatchSize() && !groups.isEmpty()) { 118 | String groupName = groups.remove(0); 119 | 120 | PermissionEntity entity = storageStrategy.getPermissionService().getEntity(groupName, null, true); 121 | if (entity != null && !entity.getPermissions().isEmpty()) { 122 | if (checkPermissions(entity) || (effective && checkEffectivePermissions(entity))) { 123 | log(plugin, "Search result (#%d): group %s", getSearchId(), entity.getDisplayName()); 124 | } 125 | } 126 | 127 | size++; 128 | } 129 | 130 | if (players.isEmpty() && groups.isEmpty()) { 131 | log(plugin, "Search result (#%d): All done!", getSearchId()); 132 | } 133 | else { 134 | Bukkit.getScheduler().scheduleSyncDelayedTask(plugin, this, getDelay()); 135 | } 136 | } 137 | 138 | private boolean checkPermissions(PermissionEntity entity) { 139 | for (Entry e : entity.getPermissions()) { 140 | if (e.getPermission().contains(permission)) 141 | return true; 142 | } 143 | return false; 144 | } 145 | 146 | private boolean checkEffectivePermissions(final PermissionEntity entity) { 147 | Map rootPermissions = storageStrategy.getTransactionStrategy().execute(new TransactionCallback>() { 148 | @Override 149 | public Map doInTransaction() throws Exception { 150 | if (entity.isGroup()) { 151 | return resolver.resolveGroup(entity.getDisplayName(), world, regions); 152 | } 153 | else { 154 | return resolver.resolvePlayer(entity.getUuid(), world, regions).getPermissions(); 155 | } 156 | } 157 | }, true); 158 | Map permissions = new HashMap<>(); 159 | Utils.calculateChildPermissions(permissions, rootPermissions, false); 160 | for (String k : permissions.keySet()) { 161 | if (k.contains(permission)) 162 | return true; 163 | } 164 | return false; 165 | } 166 | 167 | } 168 | -------------------------------------------------------------------------------- /etc/pex-to-z.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | from __future__ import print_function 3 | 4 | import sys 5 | import re 6 | try: 7 | import yaml 8 | except ImportError: 9 | exit('Install PyYAML from first') 10 | 11 | 12 | __author__ = 'ZerothAngel' 13 | __license__ = 'Public Domain' 14 | 15 | 16 | MULTI_PERM = re.compile(r"""(.*)\(((?:[^)]+\|)*(?:[^)]+))\)(.*)""") 17 | 18 | 19 | def sorted_items(d): 20 | result = [] 21 | result.extend(d.items()) 22 | result.sort(key=lambda x: x[0].lower()) 23 | return result 24 | 25 | 26 | def expand_perm(perm): 27 | m = MULTI_PERM.match(perm) 28 | if m: 29 | return [m.group(1) + p + m.group(3) for p in m.group(2).split('|')] 30 | else: 31 | return [perm] 32 | 33 | 34 | def parse_perms(world, perms): 35 | if world: 36 | world = world + ':' 37 | else: 38 | world = '' 39 | 40 | result = {} 41 | for p in perms: 42 | if p.startswith('-'): 43 | for perm in expand_perm(p[1:]): 44 | result[world + perm] = False 45 | else: 46 | for perm in expand_perm(p): 47 | result[world + perm] = True 48 | return result 49 | 50 | 51 | def parse_worlds(worlds): 52 | if not worlds: 53 | return {} 54 | result = {} 55 | for world_name,data in worlds.items(): 56 | perms = data.get('permissions', []) 57 | 58 | result.update(parse_perms(world_name, perms)) 59 | return result 60 | 61 | 62 | def parse_file(players, groups, stream): 63 | y = yaml.load(stream) 64 | 65 | g = y.get('groups', {}) 66 | for group_name,data in g.items(): 67 | perms = data.get('permissions', []) 68 | worlds = data.get('worlds', {}) 69 | parents = data.get('inheritance', []) 70 | 71 | group_data = {} 72 | group_data['permissions'] = parse_perms(None, perms) 73 | group_data['permissions'].update(parse_worlds(worlds)) 74 | group_data['parents'] = parents 75 | group_data['prefix'] = data.get('prefix') 76 | group_data['suffix'] = data.get('suffix') 77 | 78 | groups[group_name] = group_data 79 | 80 | u = y.get('users', {}) 81 | for user_name,data in u.items(): 82 | perms = data.get('permissions', []) 83 | worlds = data.get('worlds', {}) 84 | memberships = data.get('group', []) 85 | 86 | if memberships: 87 | for group_name in memberships: 88 | group_data = groups.get(group_name) 89 | if group_data is None: 90 | print('WARNING: %s is a member of %s, but the group does not exist' % (user_name, group_name), file=sys.stderr) 91 | continue 92 | members = groups[group_name].get('members', []) 93 | members.append(user_name) 94 | groups[group_name]['members'] = members 95 | 96 | player_data = {} 97 | player_data['permissions'] = parse_perms(None, perms) 98 | player_data['permissions'].update(parse_worlds(worlds)) 99 | player_data['prefix'] = data.get('prefix') 100 | player_data['suffix'] = data.get('suffix') 101 | 102 | players[user_name] = player_data 103 | 104 | 105 | def dump_permissions(name, is_group, permissions, out): 106 | entity_type = is_group and 'group' or 'player' 107 | for perm,value in sorted_items(permissions): 108 | print('permissions %s %s set %s %s' % 109 | (entity_type, name, perm, str(value).lower()), file=out) 110 | if is_group and perm.lower().startswith('group.'): 111 | print('WARNING: Group %s has a %s permission; ' 112 | 'zPerms sets these automatically. Consider deleting it.' % 113 | (name, perm)) 114 | 115 | 116 | def dump_prefix_suffix(name, is_group, prefix, suffix, out): 117 | entity_type = is_group and 'group' or 'player' 118 | if prefix: 119 | print('permissions %s %s metadata set prefix %s' % (entity_type, name, prefix), 120 | file=out) 121 | if suffix: 122 | print('permissions %s %s metadata set suffix %s' % (entity_type, name, suffix), 123 | file=out) 124 | 125 | def dump_player(name, data, out): 126 | perms = data['permissions'] 127 | prefix = data['prefix'] 128 | suffix = data['suffix'] 129 | 130 | if not (perms or prefix or suffix): 131 | return # Nothing to do 132 | 133 | # Preamble 134 | print('# Player %s' % name, file=out) 135 | # Permissions 136 | dump_permissions(name, False, perms, out) 137 | 138 | # Prefix/suffix 139 | dump_prefix_suffix(name, False, prefix, suffix, out) 140 | 141 | 142 | def dump_group(name, data, out): 143 | # Preamble 144 | print('# Group %s' % name, file=out) 145 | print('permissions group %s create' % name, file=out) 146 | # Permissions 147 | dump_permissions(name, True, data['permissions'], out) 148 | # Parent 149 | parents = data['parents'] 150 | if parents: 151 | print('permissions group %s setparent %s' % (name, parents[0]), 152 | file=out) 153 | if len(parents) > 1: 154 | print('WARNING: Group %s has more than one parent. Using only one.' % name, file=sys.stderr) 155 | 156 | # Prefix/suffix 157 | dump_prefix_suffix(name, True, data['prefix'], data['suffix'], out) 158 | 159 | # Members 160 | members = data.get('members', []) 161 | for member in members: 162 | print('permissions group %s add %s' % (name, member), file=out) 163 | 164 | 165 | def make_dump(players, groups, out): 166 | # Dump players 167 | for player_name,data in players.items(): 168 | dump_player(player_name, data, out) 169 | 170 | # Gather root groups (parentless groups) 171 | roots = [k for k,v in groups.items() if not v['parents']] 172 | 173 | to_dump = roots 174 | while to_dump: 175 | group_name = to_dump.pop(0) 176 | dump_group(group_name, groups[group_name], out) 177 | 178 | # Queue up all children 179 | # Have to scan. Bleah. 180 | children = [k for k,v in groups.items() if group_name in v['parents']] 181 | children.sort() 182 | 183 | to_dump.extend(children) 184 | 185 | 186 | if __name__ == '__main__': 187 | players = {} 188 | groups = {} 189 | 190 | if len(sys.argv) < 2: 191 | exit('Usage: %s [ ...]' % sys.argv[0]) 192 | elif len(sys.argv) > 2: 193 | for fn in sys.argv[2:]: 194 | with open(fn, 'rt') as f: 195 | parse_file(players, groups, f) 196 | else: 197 | parse_file(players, groups, sys.stdin) 198 | 199 | with open(sys.argv[1], 'wt') as out: 200 | make_dump(players, groups, out) 201 | -------------------------------------------------------------------------------- /src/main/resources/plugin.yml: -------------------------------------------------------------------------------- 1 | name: zPermissions 2 | version: ${version} 3 | main: org.tyrannyofheaven.bukkit.zPermissions.ZPermissionsPlugin 4 | description: Superperms implementation with Bukkit database backend 5 | author: ZerothAngel 6 | database: false 7 | load: STARTUP 8 | api-version: 1.13 9 | 10 | commands: 11 | permissions: 12 | description: Top-level command for zPermissions 13 | aliases: [perm, perms, zpermissions, zperm, zperms] 14 | promote: 15 | description: Promote a player up a rank 16 | aliases: [rankup, zpromote] 17 | demote: 18 | description: Demote a player down a rank 19 | aliases: [rankdown, zdemote] 20 | setrank: 21 | description: Set the rank of a player 22 | aliases: zsetrank 23 | unsetrank: 24 | description: Remove a player from a track 25 | aliases: zunsetrank 26 | 27 | permissions: 28 | zpermissions.*: 29 | description: All-inclusive permission for zPermissions 30 | default: op 31 | children: 32 | zpermissions.player.*: true 33 | zpermissions.group.*: true 34 | zpermissions.list: true 35 | zpermissions.check: true 36 | zpermissions.check.other: true 37 | zpermissions.inspect: true 38 | zpermissions.inspect.other: true 39 | zpermissions.diff: true 40 | zpermissions.search: true 41 | zpermissions.mygroups: true 42 | zpermissions.mychat: true 43 | zpermissions.reload: true 44 | zpermissions.refresh: true 45 | zpermissions.export: true 46 | zpermissions.import: true 47 | zpermissions.purge: true 48 | zpermissions.cleanup: true 49 | zpermissions.rank: true 50 | zpermissions.rank.*: true 51 | zpermissions.uuid-cache: true 52 | zpermissions.rank: 53 | description: Allows use of all rank-related commands 54 | children: 55 | zpermissions.promote: true 56 | zpermissions.demote: true 57 | zpermissions.setrank: true 58 | zpermissions.unsetrank: true 59 | zpermissions.rank.*: 60 | description: Allows use of rank commands on all tracks 61 | children: 62 | zpermissions.promote.*: true 63 | zpermissions.demote.*: true 64 | zpermissions.setrank.*: true 65 | zpermissions.unsetrank.*: true 66 | zpermissions.player: 67 | description: Allows use of the /permissions player command 68 | children: 69 | zpermissions.player.*: true 70 | zpermissions.player.*: 71 | description: Allows use of the /permissions player command 72 | children: 73 | zpermissions.player.manage: true 74 | zpermissions.player.manage: 75 | children: 76 | zpermissions.player.view: true 77 | zpermissions.player.chat: true 78 | zpermissions.group: 79 | description: Allows use of the /permissions group command 80 | children: 81 | zpermissions.group.*: true 82 | zpermissions.group.*: 83 | description: Allows use of the /permissions group command 84 | children: 85 | zpermissions.group.manage: true 86 | zpermissions.group.manage: 87 | children: 88 | zpermissions.group.view: true 89 | zpermissions.group.chat: true 90 | zpermissions.list: 91 | description: Allows use of the /permissions list command 92 | zpermissions.check: 93 | description: Allows use of the /permissions check command 94 | zpermissions.check.other: 95 | description: Allows use of the /permissions check command on others 96 | zpermissions.inspect: 97 | description: Allows use of the /permissions inspect command 98 | zpermissions.inspect.other: 99 | description: Allows use of the /permissions inspect command on others 100 | zpermissions.diff: 101 | description: Allows use of the /permissions diff command 102 | zpermissions.search: 103 | description: Allows use of the /permissions search command 104 | zpermissions.mygroups: 105 | description: Allows use of the /permissions mygroups command 106 | zpermissions.mychat: 107 | description: Allows use of the /permissions prefix and /permissions suffix commands 108 | zpermissions.reload: 109 | description: Allows use of the /permissions reload command 110 | zpermissions.refresh: 111 | description: Allows use of the /permissions refresh command 112 | zpermissions.export: 113 | description: Allows use of the /permissions export command 114 | zpermissions.import: 115 | description: Allows use of the /permissions import command 116 | zpermissions.purge: 117 | description: Allows use of the /permissions purge command 118 | zpermissions.cleanup: 119 | description: Allows use of the /permissions cleanup command 120 | zpermissions.promote: 121 | description: Allows use of the /promote command 122 | zpermissions.promote.*: 123 | description: Allows use of /promote on all tracks 124 | zpermissions.demote: 125 | description: Allows use of the /demote command 126 | zpermissions.demote.*: 127 | description: Allows use of /demote on all tracks 128 | zpermissions.setrank: 129 | description: Allows use of the /setrank command 130 | zpermissions.setrank.*: 131 | description: Allows use of /setrank on all tracks 132 | zpermissions.unsetrank: 133 | description: Allows use of the /unsetrank command 134 | zpermissions.unsetrank.*: 135 | description: Allows use of /unsetrank on all tracks 136 | zpermissions.notify.*: 137 | description: Receives all notifications 138 | default: false 139 | children: 140 | zpermissions.notify.rank: true 141 | zpermissions.notify.expiration: true 142 | zpermissions.notify.rank: 143 | description: Receives rank command notitifications 144 | default: false 145 | children: 146 | zpermissions.notify.promote: true 147 | zpermissions.notify.demote: true 148 | zpermissions.notify.setrank: true 149 | zpermissions.notify.unsetrank: true 150 | zpermissions.notify.promote: 151 | description: Receives /promote notifications 152 | default: false 153 | zpermissions.notify.demote: 154 | description: Receives /demote notifications 155 | default: false 156 | zpermissions.notify.setrank: 157 | description: Receives /setrank notifications 158 | default: false 159 | zpermissions.notify.unsetrank: 160 | description: Receives /unsetrank notifications 161 | default: false 162 | zpermissions.notify.expiration: 163 | description: Receives temporary membership expiration notifications 164 | default: false 165 | zpermissions.notify.self.*: 166 | description: Receives all notifications for self 167 | default: false 168 | children: 169 | zpermissions.notify.self.expiration: true 170 | zpermissions.notify.self.expiration: 171 | description: Receives temporary membership expiration notifications for self 172 | default: false 173 | zpermissions.error.detail: 174 | description: Receives full details about missing permissions 175 | default: true 176 | zpermissions.uuid-cache: 177 | description: Allows use of /permissions uuid-cache commands 178 | -------------------------------------------------------------------------------- /src/main/java/org/tyrannyofheaven/bukkit/zPermissions/util/ExpirationRefreshHandler.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2013 ZerothAngel 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package org.tyrannyofheaven.bukkit.zPermissions.util; 17 | 18 | import static org.tyrannyofheaven.bukkit.util.ToHLoggingUtils.debug; 19 | import static org.tyrannyofheaven.bukkit.util.ToHMessageUtils.broadcast; 20 | import static org.tyrannyofheaven.bukkit.util.ToHMessageUtils.colorize; 21 | import static org.tyrannyofheaven.bukkit.util.ToHMessageUtils.sendMessage; 22 | 23 | import java.util.Comparator; 24 | import java.util.Date; 25 | import java.util.LinkedHashSet; 26 | import java.util.PriorityQueue; 27 | import java.util.Queue; 28 | import java.util.Set; 29 | import java.util.UUID; 30 | import java.util.concurrent.Executors; 31 | import java.util.concurrent.ScheduledExecutorService; 32 | import java.util.concurrent.ScheduledFuture; 33 | import java.util.concurrent.TimeUnit; 34 | 35 | import org.bukkit.Bukkit; 36 | import org.bukkit.entity.Player; 37 | import org.bukkit.plugin.Plugin; 38 | import org.tyrannyofheaven.bukkit.zPermissions.ZPermissionsCore; 39 | import org.tyrannyofheaven.bukkit.zPermissions.model.Membership; 40 | import org.tyrannyofheaven.bukkit.zPermissions.storage.StorageStrategy; 41 | 42 | public class ExpirationRefreshHandler implements Runnable { 43 | 44 | private static final Comparator MEMBERSHIP_EXPIRATION_COMPARATOR = new Comparator() { 45 | @Override 46 | public int compare(Membership a, Membership b) { 47 | return a.getExpiration().compareTo(b.getExpiration()); 48 | } 49 | }; 50 | 51 | private static final long FUDGE = 1000L; 52 | 53 | private final ZPermissionsCore core; 54 | 55 | private final StorageStrategy storageStrategy; 56 | 57 | private final Plugin plugin; 58 | 59 | private final ScheduledExecutorService executorService; 60 | 61 | private final Queue membershipQueue = new PriorityQueue<>(11, MEMBERSHIP_EXPIRATION_COMPARATOR); // synchronized on this 62 | 63 | private ScheduledFuture scheduledFuture; // synchronized on this 64 | 65 | public ExpirationRefreshHandler(ZPermissionsCore core, StorageStrategy storageStrategy, Plugin plugin) { 66 | this.core = core; 67 | this.storageStrategy = storageStrategy; 68 | this.plugin = plugin; 69 | 70 | executorService = Executors.newSingleThreadScheduledExecutor(); 71 | } 72 | 73 | public synchronized void rescan() { 74 | membershipQueue.clear(); 75 | Date now = new Date(); 76 | for (Player player : Bukkit.getOnlinePlayers()) { 77 | for (Membership membership : storageStrategy.getPermissionService().getGroups(player.getUniqueId())) { 78 | if (membership.getExpiration() != null && membership.getExpiration().after(now)) { 79 | membershipQueue.add(membership); 80 | } 81 | } 82 | } 83 | 84 | debug(plugin, "Potential future expirations: %s", membershipQueue); 85 | 86 | // Queue up task 87 | run(); 88 | } 89 | 90 | @Override 91 | public synchronized void run() { 92 | Set toRefresh = new LinkedHashSet<>(); 93 | final Set expired = new LinkedHashSet<>(); 94 | 95 | // Gather up memberships that have already expired 96 | Date now = new Date(); 97 | Membership next = membershipQueue.peek(); 98 | while (next != null && !next.getExpiration().after(now)) { 99 | membershipQueue.remove(); 100 | 101 | toRefresh.add(next.getUuid()); 102 | expired.add(next); 103 | 104 | now = new Date(); 105 | next = membershipQueue.peek(); 106 | } 107 | 108 | debug(plugin, "Refreshing expired players: %s", toRefresh); 109 | // NB Metadata cache for offline players not invalidated. 110 | // This might become a problem. But nothing can be done unless we 111 | // run a timer for each and every membership, online or offline. 112 | core.refreshPlayers(toRefresh); 113 | 114 | // Send notifications 115 | if (!expired.isEmpty()) { 116 | Bukkit.getScheduler().scheduleSyncDelayedTask(plugin, new Runnable() { 117 | @Override 118 | public void run() { 119 | for (Membership membership : expired) { 120 | Player player = Bukkit.getPlayer(membership.getUuid()); 121 | if (player != null && player.hasPermission("zpermissions.notify.self.expiration")) { 122 | sendMessage(player, colorize("{YELLOW}Your membership to {DARK_GREEN}%s{YELLOW} has expired."), membership.getGroup().getDisplayName()); 123 | } 124 | broadcast(plugin, "zpermissions.notify.expiration", 125 | "Player %s is no longer a member of %s", 126 | membership.getDisplayName(), membership.getGroup().getDisplayName()); 127 | } 128 | } 129 | }); 130 | } 131 | 132 | // Cancel previous task 133 | if (scheduledFuture != null) { 134 | scheduledFuture.cancel(false); 135 | scheduledFuture = null; 136 | } 137 | 138 | // Schedule new task 139 | if (next != null) { 140 | now = new Date(); 141 | long delay = next.getExpiration().getTime() - now.getTime(); 142 | 143 | if (delay < 0L) 144 | delay = 0L; // Weird... 145 | 146 | debug(plugin, "Next expiration is %dms away", delay); 147 | 148 | final Runnable realThis = this; 149 | scheduledFuture = executorService.schedule(new Runnable() { 150 | @Override 151 | public void run() { 152 | debug(plugin, "Expiring..."); 153 | Bukkit.getScheduler().scheduleSyncDelayedTask(plugin, realThis); 154 | } 155 | }, delay + FUDGE, TimeUnit.MILLISECONDS); 156 | } 157 | else 158 | debug(plugin, "No future expirations"); 159 | } 160 | 161 | public void shutdown() { 162 | if (scheduledFuture != null) { 163 | scheduledFuture.cancel(false); 164 | scheduledFuture = null; 165 | } 166 | executorService.shutdownNow(); 167 | } 168 | 169 | } 170 | -------------------------------------------------------------------------------- /src/main/java/org/tyrannyofheaven/bukkit/zPermissions/model/PermissionEntity.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2011 ZerothAngel 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package org.tyrannyofheaven.bukkit.zPermissions.model; 17 | 18 | import java.util.ArrayList; 19 | import java.util.Collections; 20 | import java.util.HashMap; 21 | import java.util.HashSet; 22 | import java.util.LinkedHashSet; 23 | import java.util.List; 24 | import java.util.Map; 25 | import java.util.Set; 26 | import java.util.UUID; 27 | 28 | import javax.persistence.CascadeType; 29 | import javax.persistence.Column; 30 | import javax.persistence.Entity; 31 | import javax.persistence.Id; 32 | import javax.persistence.ManyToOne; 33 | import javax.persistence.OneToMany; 34 | import javax.persistence.Table; 35 | import javax.persistence.Transient; 36 | import javax.persistence.UniqueConstraint; 37 | 38 | import org.tyrannyofheaven.bukkit.util.ToHUtils; 39 | import org.tyrannyofheaven.bukkit.util.uuid.UuidUtils; 40 | 41 | /** 42 | * The permission entity — something that can have a set of permission 43 | * entries. Originally I had different classes for players and groups, but 44 | * Avaje's handling of inheritance seems a bit wonky. So I've basically 45 | * collapsed both classes into this single class, using {@link #isGroup()} as 46 | * a discriminator. Ugh... 47 | * 48 | * @author zerothangel 49 | */ 50 | @Entity 51 | @Table(name="entities") 52 | @UniqueConstraint(columnNames={"name", "is_group"}) 53 | public class PermissionEntity { 54 | 55 | private Long id; 56 | 57 | private String name; 58 | 59 | private boolean group; 60 | 61 | private String displayName; 62 | 63 | private int priority; 64 | 65 | private PermissionEntity parent; 66 | 67 | private Set permissions = new HashSet<>(); 68 | 69 | private Set memberships = new HashSet<>(); 70 | 71 | private Set inheritancesAsParent = new HashSet<>(); 72 | 73 | private Set inheritancesAsChild = new HashSet<>(); 74 | 75 | private Set metadata = new HashSet<>(); 76 | 77 | @Transient 78 | private final Map metadataMap = new HashMap<>(); 79 | 80 | @Id 81 | public Long getId() { 82 | return id; 83 | } 84 | 85 | public void setId(Long id) { 86 | this.id = id; 87 | } 88 | 89 | @Column(nullable=false) 90 | public String getName() { 91 | return name; 92 | } 93 | 94 | public void setName(String name) { 95 | this.name = name; 96 | } 97 | 98 | @Column(name="is_group", nullable=false) 99 | public boolean isGroup() { 100 | return group; 101 | } 102 | 103 | public void setGroup(boolean group) { 104 | this.group = group; 105 | } 106 | 107 | @Column(nullable=false) 108 | public String getDisplayName() { 109 | return displayName; 110 | } 111 | 112 | public void setDisplayName(String displayName) { 113 | this.displayName = displayName; 114 | } 115 | 116 | @ManyToOne(optional=true) 117 | public PermissionEntity getParent() { 118 | return parent; 119 | } 120 | 121 | public void setParent(PermissionEntity parent) { 122 | this.parent = parent; 123 | } 124 | 125 | @OneToMany(mappedBy="entity", cascade=CascadeType.ALL) 126 | public Set getPermissions() { 127 | return permissions; 128 | } 129 | 130 | public void setPermissions(Set permissions) { 131 | this.permissions = permissions; 132 | } 133 | 134 | public int getPriority() { 135 | return priority; 136 | } 137 | 138 | public void setPriority(int priority) { 139 | this.priority = priority; 140 | } 141 | 142 | @OneToMany(mappedBy="group", cascade=CascadeType.ALL) 143 | public Set getMemberships() { 144 | return memberships; 145 | } 146 | 147 | public void setMemberships(Set memberships) { 148 | this.memberships = memberships; 149 | } 150 | 151 | @OneToMany(mappedBy="parent", cascade=CascadeType.ALL) 152 | public Set getInheritancesAsParent() { 153 | return inheritancesAsParent; 154 | } 155 | 156 | public void setInheritancesAsParent(Set inheritancesAsParent) { 157 | this.inheritancesAsParent = inheritancesAsParent; 158 | } 159 | 160 | @OneToMany(mappedBy="child", cascade=CascadeType.ALL) 161 | public Set getInheritancesAsChild() { 162 | return inheritancesAsChild; 163 | } 164 | 165 | public void setInheritancesAsChild(Set inheritancesAsChild) { 166 | this.inheritancesAsChild = inheritancesAsChild; 167 | } 168 | 169 | @Transient 170 | public List getParents() { 171 | List inheritances = new ArrayList<>(getInheritancesAsChild()); 172 | Collections.sort(inheritances); 173 | List result = new ArrayList<>(inheritances.size()); 174 | for (Inheritance i : inheritances) 175 | result.add(i.getParent()); 176 | return result; 177 | } 178 | 179 | @Transient 180 | public Set getChildrenNew() { 181 | Set result = new LinkedHashSet<>(getInheritancesAsParent().size()); 182 | for (Inheritance i : getInheritancesAsParent()) 183 | result.add(i.getChild()); 184 | return result; 185 | } 186 | 187 | @OneToMany(mappedBy="entity", cascade=CascadeType.ALL) 188 | public Set getMetadata() { 189 | return metadata; 190 | } 191 | 192 | public void setMetadata(Set metadata) { 193 | this.metadata = metadata; 194 | } 195 | 196 | @Transient 197 | public Map getMetadataMap() { 198 | return metadataMap; 199 | } 200 | 201 | public void updateMetadataMap() { 202 | getMetadataMap().clear(); 203 | for (EntityMetadata em : getMetadata()) { 204 | getMetadataMap().put(em.getName().toLowerCase(), em); 205 | } 206 | } 207 | 208 | @Transient 209 | public UUID getUuid() { 210 | ToHUtils.assertFalse(isGroup(), "Only valid for players"); 211 | return UuidUtils.uncanonicalizeUuid(getName()); 212 | } 213 | 214 | @Override 215 | public boolean equals(Object obj) { 216 | if (obj == this) return true; 217 | if (!(obj instanceof PermissionEntity)) return false; 218 | PermissionEntity o = (PermissionEntity)obj; 219 | return getName().equals(o.getName()) && 220 | isGroup() == o.isGroup(); 221 | } 222 | 223 | @Override 224 | public int hashCode() { 225 | int result = 17; 226 | result = 37 * result + getName().hashCode(); 227 | result = 37 * result + Boolean.valueOf(isGroup()).hashCode(); 228 | return result; 229 | } 230 | 231 | @Override 232 | public String toString() { 233 | return String.format("Entity[%s,%s,%s]", getName(), getDisplayName(), isGroup()); 234 | } 235 | 236 | } 237 | --------------------------------------------------------------------------------