diff --git a/lib/RuntimeData.php b/lib/RuntimeData.php index 42ac9b99..7140d485 100644 --- a/lib/RuntimeData.php +++ b/lib/RuntimeData.php @@ -5,7 +5,7 @@ namespace JKingWeb\NewsSync; class RuntimeData { public $conf; public $db; - public $auth; + public $user; public function __construct(Conf $conf) { $this->conf = $conf; diff --git a/lib/User.php b/lib/User.php index 87300121..5360981b 100644 --- a/lib/User.php +++ b/lib/User.php @@ -16,10 +16,10 @@ class User { $path = __DIR__.$sep."User".$sep; $classes = []; foreach(glob($path."Driver?*.php") as $file) { - $name = basename($file, ".php"); - $name = NS_BASE."Db\\$name"; - if(class_exists($name)) { - $classes[$name] = $name::driverName(); + $drv = basename($file, ".php"); + $drv = NS_BASE."Db\\$drv"; + if(class_exists($drv)) { + $classes[$drv] = $drv::driverName(); } } return $classes; diff --git a/lib/User/Driver.php b/lib/User/Driver.php index eed2e25c..598d2f83 100644 --- a/lib/User/Driver.php +++ b/lib/User/Driver.php @@ -7,24 +7,38 @@ Interface Driver { const FUNC_INTERNAL = 1; const FUNC_EXTERNAL = 2; - const RIGHTS_NONE = 0; - const RIGHTS_DOMAIN_MANAGER = 25; - const RIGHTS_DOMAIN_ADMIN = 50; - const RIGHTS_GLOBAL_MANAGER = 75; - const RIGHTS_GLOBAL_ADMIN = 100; + const RIGHTS_NONE = 0; // normal user + const RIGHTS_DOMAIN_MANAGER = 25; // able to act for any normal users on same domain; cannot elevate other users + const RIGHTS_DOMAIN_ADMIN = 50; // able to act for any users on same domain not above themselves; may elevate users on same domain to domain manager or domain admin + const RIGHTS_GLOBAL_MANAGER = 75; // able to act for any user below themselves; can elevate users to domain manager or domain admin + const RIGHTS_GLOBAL_ADMIN = 100; // is completely unrestricted + // returns an instance of a class implementing this interface. Implemented as a static method for consistency with database classes static function create(\JKingWeb\NewsSync\RuntimeData $data): Driver; + // returns a human-friendly name for the driver (for display in installer, for example) static function driverName(): string; + // returns an array (or single queried member of same) of methods defined by this interface and whether the class implements the internal function or a custom version function driverFunctions(string $function = null); + // authenticates a user against their name and password function auth(string $user, string $password): bool; + // checks whether the logged in user is authorized to act for the affected user (used especially when granting rights) function authorize(string $affectedUser, string $action): bool; + // checks whether a user exists function userExists(string $user): bool; + // adds a user function userAdd(string $user, string $password = null): bool; + // removes a user function userRemove(string $user): bool; + // lists all users function userList(string $domain = null): array; + // sets a user's password; if the driver does not require the old password, it may be ignored function userPasswordSet(string $user, string $newPassword, string $oldPassword): bool; + // gets user metadata (currently not useful) function userPropertiesGet(string $user): array; + // sets user metadata (currently not useful) function userPropertiesSet(string $user, array $properties): array; + // returns a user's access level according to RIGHTS_* constants (or some custom semantics, if using custom implementation of authorize()) function userRightsGet(string $user): int; + // sets a user's access level function userRightsSet(string $user, int $level): bool; } \ No newline at end of file diff --git a/lib/User/DriverInternal.php b/lib/User/DriverInternal.php index 7e85cf36..da81947f 100644 --- a/lib/User/DriverInternal.php +++ b/lib/User/DriverInternal.php @@ -1,8 +1,9 @@ data = $data; - $this->db = $this->data->db; - } - static public function driverName(): string { - return "Internal"; + $name = str_replace(Driver::class, "", static::class); + return Lang::msg("Driver.User.$name.Name"); } public function driverFunctions(string $function = null) { @@ -42,4 +39,6 @@ class DriverInternal implements Driver { return Driver::FUNC_NOT_IMPLEMENTED; } } + + // see InternalFunctions.php for bulk of methods } \ No newline at end of file diff --git a/lib/User/InternalFunctions.php b/lib/User/InternalFunctions.php index 43fc285d..65a97f14 100644 --- a/lib/User/InternalFunctions.php +++ b/lib/User/InternalFunctions.php @@ -4,7 +4,12 @@ namespace JKingWeb\NewsSync\User; trait InternalFunctions { protected $actor = []; - + + public function __construct(\JKingWeb\NewsSync\RuntimeData $data) { + $this->data = $data; + $this->db = $this->data->db; + } + function auth(string $user, string $password): bool { if(!$this->data->user->exists($user)) return false; $hash = $this->db->userPasswordGet($user); diff --git a/locale/en.php b/locale/en.php index e6eb3b7a..a2f82162 100644 --- a/locale/en.php +++ b/locale/en.php @@ -1,5 +1,7 @@ 'Internal', + 'Exception.JKingWeb/NewsSync/Exception.uncoded' => 'The specified exception symbol {0} has no code specified in Exception.php', //this should not usually be encountered 'Exception.JKingWeb/NewsSync/Exception.unknown' => 'An unknown error has occurred', diff --git a/tests/TestConf.php b/tests/Conf/TestConf.php similarity index 100% rename from tests/TestConf.php rename to tests/Conf/TestConf.php diff --git a/tests/TestException.php b/tests/Exception/TestException.php similarity index 100% rename from tests/TestException.php rename to tests/Exception/TestException.php diff --git a/tests/TestLang.php b/tests/Lang/TestLang.php similarity index 100% rename from tests/TestLang.php rename to tests/Lang/TestLang.php diff --git a/tests/TestLangErrors.php b/tests/Lang/TestLangErrors.php similarity index 100% rename from tests/TestLangErrors.php rename to tests/Lang/TestLangErrors.php diff --git a/tests/testLangComplex.php b/tests/Lang/testLangComplex.php similarity index 100% rename from tests/testLangComplex.php rename to tests/Lang/testLangComplex.php diff --git a/tests/User/TestUser.php b/tests/User/TestUser.php new file mode 100644 index 00000000..aef45757 --- /dev/null +++ b/tests/User/TestUser.php @@ -0,0 +1,17 @@ +userDriver = Test\User\DriverInternalMock::class; + $this->data = new Test\RuntimeData($conf); + $this->data->user = new User($this->data); + } +} diff --git a/tests/lib/RuntimeData.php b/tests/lib/RuntimeData.php new file mode 100644 index 00000000..bfdb2e4e --- /dev/null +++ b/tests/lib/RuntimeData.php @@ -0,0 +1,13 @@ +conf = $conf; + } +} \ No newline at end of file diff --git a/tests/lib/User/DriverInternalMock.php b/tests/lib/User/DriverInternalMock.php new file mode 100644 index 00000000..2403a7f2 --- /dev/null +++ b/tests/lib/User/DriverInternalMock.php @@ -0,0 +1,89 @@ + Driver::FUNC_INTERNAL, + "authorize" => Driver::FUNC_INTERNAL, + "userList" => Driver::FUNC_INTERNAL, + "userExists" => Driver::FUNC_INTERNAL, + "userAdd" => Driver::FUNC_INTERNAL, + "userRemove" => Driver::FUNC_INTERNAL, + "userPasswordSet" => Driver::FUNC_INTERNAL, + "userPropertiesGet" => Driver::FUNC_INTERNAL, + "userPropertiesSet" => Driver::FUNC_INTERNAL, + "userRightsGet" => Driver::FUNC_INTERNAL, + "userRightsSet" => Driver::FUNC_INTERNAL, + ]; + + static public function create(\JKingWeb\NewsSync\RuntimeData $data): Driver { + return new static($data); + } + + static public function driverName(): string { + return "Mock Internal Driver"; + } + + public function driverFunctions(string $function = null) { + if($function===null) return $this->functions; + if(array_key_exists($function, $this->functions)) { + return $this->functions[$function]; + } else { + return Driver::FUNC_NOT_IMPLEMENTED; + } + } + + public function __construct(\JKingWeb\NewsSync\RuntimeData $data) { + $this->data = $data; + } + + function auth(string $user, string $password): bool { + return true; + } + + function authorize(string $affectedUser, string $action, int $newRightsLevel = 0): bool { + if($affectedUser==$this->data->user->id) return true; + return false; + } + + function userExists(string $user): bool { + return true; + } + + function userAdd(string $user, string $password = null): bool { + return true; + } + + function userRemove(string $user): bool { + return true; + } + + function userList(string $domain = null): array { + return []; + } + + function userPasswordSet(string $user, string $newPassword, string $oldPassword): bool { + return true; + } + + function userPropertiesGet(string $user): array { + return []; + } + + function userPropertiesSet(string $user, array $properties): array { + return []; + } + + function userRightsGet(string $user): int { + return 0; + } + + function userRightsSet(string $user, int $level): bool { + return true; + } +} \ No newline at end of file diff --git a/tests/phpunit.xml b/tests/phpunit.xml index a7167ed1..5b31655a 100644 --- a/tests/phpunit.xml +++ b/tests/phpunit.xml @@ -11,13 +11,18 @@ stopOnError="true"> - TestLang.php - TestLangComplex.php - TestException.php - TestLangErrors.php + Lang/TestLang.php + Lang/TestLangComplex.php + Lang/TestException.php + Lang/TestLangErrors.php - TestConf.php + Conf/TestConf.php + + + User/TestUser.php + + \ No newline at end of file