Page MenuHomeDevCentral

No OneTemporary

diff --git a/composer.json b/composer.json
index 8cf9fbc..4034319 100644
--- a/composer.json
+++ b/composer.json
@@ -1,51 +1,51 @@
{
"name": "waystone/waystone",
"type": "library",
"description": "Modular libraries to build applications with Obsidian Workspaces",
"keywords": [
"framework",
"keruald",
"waystone",
"obsidian"
],
"license": "BSD-2-Clause",
"homepage": "https://waystone.nasqueron.org",
"authors": [
{
"name": "Sébastien Santoro",
"email": "dereckson@espace-win.org"
}
],
"require": {
"keruald/database": "0.6.1",
- "keruald/omnitools": "0.16.0",
+ "keruald/omnitools": "dev-develop/1.x@dev",
"keruald/yaml": "0.1.1",
"netresearch/jsonmapper": "^v5.0.0",
"smarty/smarty": "^5.6.0",
"vlucas/phpdotenv": "^v5.6.2",
"ext-mysqli": "*"
},
"require-dev": {
"nasqueron/codestyle": "^0.1.2",
"phpunit/phpunit": "^12.5",
"squizlabs/php_codesniffer": "^4.0"
},
"replace": {
"waystone/orbeon-forms": "0.1.0",
"waystone/workspaces": "1.0.0"
},
"autoload": {
"psr-4": {
"Waystone\\Apps\\OrbeonForms\\": "apps/orbeon-forms/src/",
"Waystone\\Apps\\OrbeonForms\\Tests\\": "apps/orbeon-forms/tests/",
"Waystone\\Workspaces\\": "workspaces/src/",
"Waystone\\Workspaces\\Tests\\": "workspaces/tests/"
}
},
"scripts": {
"lint-src": "find */src -type f -name '*.php' | xargs -I {} php -l {} 1> /dev/null",
"lint-tests": "find */tests -type f -name '*.php' | xargs -n1 php -l",
"test": "vendor/bin/phpunit"
},
"minimum-stability": "dev"
}
diff --git a/workspaces/src/Engines/Auth/Actions/GivePermissionUserAction.php b/workspaces/src/Engines/Auth/Actions/GivePermissionUserAction.php
index 16ae66b..a174789 100644
--- a/workspaces/src/Engines/Auth/Actions/GivePermissionUserAction.php
+++ b/workspaces/src/Engines/Auth/Actions/GivePermissionUserAction.php
@@ -1,131 +1,134 @@
<?php
/**
* _, __, _, _ __, _ _, _, _
* / \ |_) (_ | | \ | /_\ |\ |
* \ / |_) , ) | |_/ | | | | \|
* ~ ~ ~ ~ ~ ~ ~ ~ ~ ~
*
* Give permission user action class
*
* @package ObsidianWorkspaces
* @subpackage Auth
* @author Sébastien Santoro aka Dereckson <dereckson@espace-win.org>
* @license http://www.opensource.org/licenses/bsd-license.php BSD
* @filesource
*
*/
namespace Waystone\Workspaces\Engines\Auth\Actions;
use Waystone\Workspaces\Engines\Auth\Permission;
use Waystone\Workspaces\Engines\Auth\UserAction;
+use Waystone\Workspaces\Engines\Framework\Resources;
use Waystone\Workspaces\Engines\Serialization\ArrayDeserializable;
use Exception;
use InvalidArgumentException;
use JsonSerializable;
/**
* User action to grant user a permission
*/
class GivePermissionUserAction extends UserAction
implements ArrayDeserializable, JsonSerializable {
/**
* @var string The permission name
*/
public $permissionName;
/**
* @var int The permission flag
*/
public $permissionFlag = 1;
/**
* @var string The target resource type
*/
public $resourceType;
/**
* @var string The target resource identifier
*/
public $resourceIdentifier;
/**
* Executes the user action
*/
public function run () {
- if (!$id = resolve_resource_id($this->resourceType,
- $this->resourceIdentifier)) {
- throw new Exception("Can't get identifier from resource "
+ $id = Resources::resolveID($this->resourceType, $this->resourceIdentifier);
+
+ if ($id->isNone()) {
+ throw new Exception("Can't resolve resource "
. $this->resourceType . " " . $this->resourceIdentifier);
}
+
$this->targetUser->setPermission(
- $this->resourceType, $id,
+ $this->resourceType, $id->getValue(),
$this->permissionName, $this->permissionFlag,
);
}
/**
* Loads a GivePermissionUserAction instance from an associative array.
*
* @param object $data The associative array to deserialize
*
* @return GivePermissionUserAction The deserialized instance
*/
public static function loadFromArray (mixed $data) : self {
// Validate mandatory data
if (!array_key_exists("resource", $data)) {
throw new InvalidArgumentException("A resource property, with two mandatory type and id property is required.");
}
if (!array_key_exists("permission", $data)) {
throw new InvalidArgumentException("A permission property, with a mandatory name property and a facultative flag property is required.");
}
$resource = $data["resource"];
$permission = $data["permission"];
if (!array_key_exists("name", $permission)) {
throw new InvalidArgumentException("Permission name is required.");
}
if (!array_key_exists("type", $resource)) {
throw new InvalidArgumentException("Resource type is required.");
}
if (!array_key_exists("id", $resource)) {
throw new InvalidArgumentException("Resource id is required.");
}
// Build instance
$instance = new GivePermissionUserAction();
$instance->resourceType =
Permission::getResourceTypeLetterFromCode($resource["type"]);
$instance->resourceIdentifier = $resource["id"];
$instance->permissionName = $permission["name"];
if (array_key_exists("flag", $permission)) {
$instance->permissionFlag = $permission["flag"];
}
return $instance;
}
/**
* Serializes the object to a value that can be serialized natively by
* json_encode().
*
* @return object The serializable value
*/
public function jsonSerialize () {
//TODO: if you wish strict code here, we need such a class.
$data->resource->type =
Permission::getResourceTypeCodeFromLetter($this->resourceType);
$data->resource->id = $this->resourceIdentifier;
$data->permission->name = $this->permissionName;
$data->permission->flag = $this->permissionFlag;
return $data;
}
}
diff --git a/workspaces/src/Engines/Auth/AuthenticationMethod.php b/workspaces/src/Engines/Auth/AuthenticationMethod.php
index 12b9b59..1240366 100644
--- a/workspaces/src/Engines/Auth/AuthenticationMethod.php
+++ b/workspaces/src/Engines/Auth/AuthenticationMethod.php
@@ -1,273 +1,281 @@
<?php
/**
* _, __, _, _ __, _ _, _, _
* / \ |_) (_ | | \ | /_\ |\ |
* \ / |_) , ) | |_/ | | | | \|
* ~ ~ ~ ~ ~ ~ ~ ~ ~ ~
*
* Authentication method class
*
* @package ObsidianWorkspaces
* @subpackage Auth
* @author Sébastien Santoro aka Dereckson <dereckson@espace-win.org>
* @license http://www.opensource.org/licenses/bsd-license.php BSD
* @filesource
*/
namespace Waystone\Workspaces\Engines\Auth;
use Waystone\Workspaces\Engines\Auth\Actions\AddToGroupUserAction;
use Waystone\Workspaces\Engines\Auth\Actions\GivePermissionUserAction;
use Waystone\Workspaces\Engines\Framework\Context;
use Waystone\Workspaces\Engines\Serialization\ArrayDeserializable;
+use Keruald\OmniTools\DataTypes\Option\None;
+use Keruald\OmniTools\DataTypes\Option\Option;
+use Keruald\OmniTools\DataTypes\Option\Some;
+
use Language;
use Message;
use User;
use Exception;
use InvalidArgumentException;
/**
* Authentication method class
*
* This class has to be extended to implement custom authentication methods.
*/
abstract class AuthenticationMethod implements ArrayDeserializable {
/**
* @var User The local user matching the authentication
*/
public $localUser;
/**
* @var string The username
*/
public $name;
/**
* @var string The e-mail address
*/
public $email;
/**
* @var string The authentication method identifiant
*/
public $id;
/**
* @var string The remote identity provider user identifiant
*/
public $remoteUserId;
/**
* @var Message The localized authentication login message
*/
public $loginMessage;
/**
* @var boolean Determines if the authentication method could be used to
* register new users
*/
public $canCreateUser = false;
/**
* @var Array Actions to execute if a user is created, each instance a
* member of UserAction
*/
public $createUserActions = [];
/**
* @var Context The site context
*/
public $context;
/**
* @var Message The localized authentication error message
*/
public $loginError;
/**
* Gets authentication link for this method
*/
public abstract function getAuthenticationLink ();
/**
* Handles request
*/
public abstract function handleRequest ();
/**
* Runs actions planned on user create
*/
protected function runCreateUserActions () {
foreach ($this->createUserActions as $action) {
$action->targetUser = $this->localUser;
$action->run();
}
}
/**
* Finds user from available data
*
- * @return User the user if a user has been found; otherwise, false.
+ * @return Option<User> the user if a user has been found; otherwise, false.
*/
- private function findUser () {
+ private function findUser () : Option {
if ($this->remoteUserId != '') {
$user = User::getUserFromRemoteIdentity(
$this->id, $this->remoteUserId,
);
if ($user !== null) {
- return $user;
+ return new Some($user);
}
}
if ($this->email != '') {
$user = User::get_user_from_email($this->email);
- if ($user !== null) {
+ if ($user->isSome()) {
return $user;
}
}
- return null;
+ return new None;
}
/**
* Signs in or creates a new user
*
* @return boolean true if user has been successfully logged in; otherwise,
* false.
*/
public function signInOrCreateUser () {
// At this stage, if we don't already have a user instance,
// we're fetching it by remote user id or mail.
//
// If no result is returned, we're creating a new user if needed.
//
// Finally, we proceed to log in.
if ($this->localUser === null) {
- $this->localUser = $this->findUser();
+ $user = $this->findUser();
+
+ if ($user->isSome()) {
+ $this->localUser = $user->getValue();
+ }
}
if ($this->localUser === null) {
if (!$this->canCreateUser) {
$this->loginError =
Language::get("ExternalLoginCantCreateAccount");
return false;
} else {
$this->createUser();
if ($this->localUser === null) {
throw new Exception("Can't sign in: after correct remote authentication, an error occurred creating locally a new user.");
}
}
}
$this->signIn($this->localUser);
return true;
}
/**
* Signs in the specified user
*
* @param User The user to log in
*/
public function signIn (User $user) {
$this->context->session->user_login($user->id);
}
/**
* Creates a new user based on the authentication provisioning information
*
* @return User The user created
*/
public function createUser () {
if (!$this->canCreateUser) {
throw new Exception("Can't create user: the canCreateUser property is set at false.");
}
$user = User::create();
$user->name = $this->name;
$user->email = $this->email;
$user->save_to_database();
$user->setRemoteIdentity(
$this->id, $this->remoteUserId,
);
$this->localUser = $user;
$this->runCreateUserActions();
}
/**
* Gets authentication method from ID
*
* @param string $id The authentication method id
* @param Context $context The site context
*
* @return AuthenticationMethod The authentication method matching the id
*/
public static function getFromId ($id, $context) {
if ($context->workspace != null) {
foreach (
$context->workspace->configuration->authenticationMethods as
$authenticationMethod
) {
if ($authenticationMethod->id == $id) {
return $authenticationMethod;
}
}
}
return null;
}
/**
* Loads an AuthenticationMethod instance from a generic array.
* Typically used to deserialize a configuration.
*
* @param array $data The associative array to deserialize
*
* @return AuthenticationMethod The deserialized instance
* @throws InvalidArgumentException|Exception
*/
public static function loadFromArray (array $data) : self {
$instance = new static;
if (!array_key_exists("id", $data)) {
throw new InvalidArgumentException("Authentication method id is required.");
}
$instance->id = $data["id"];
$message = $data["loginMessage"] ?? Language::get("SignIn");
$instance->loginMessage = new Message($message);
if (array_key_exists("createUser", $data)) {
$createUser = $data["createUser"];
if (array_key_exists("enabled", $createUser)) {
$instance->canCreateUser = ($createUser["enabled"] === true);
}
$addToGroups = $createUser["addToGroups"] ?? [];
foreach ($addToGroups as $actionData) {
$instance->createUserActions[] =
AddToGroupUserAction::loadFromArray($actionData);
}
$givePermissions = $createUser["givePermissions"] ?? [];
foreach ($createUser["givePermissions"] as $actionData) {
$instance->createUserActions[] =
GivePermissionUserAction::loadFromArray($actionData);
}
}
return $instance;
}
}
diff --git a/workspaces/src/Engines/Framework/Resources.php b/workspaces/src/Engines/Framework/Resources.php
new file mode 100644
index 0000000..6412445
--- /dev/null
+++ b/workspaces/src/Engines/Framework/Resources.php
@@ -0,0 +1,50 @@
+<?php
+
+namespace Waystone\Workspaces\Engines\Framework;
+
+use Waystone\Workspaces\Engines\Workspaces\Workspace;
+
+use Keruald\OmniTools\DataTypes\Option\None;
+use Keruald\OmniTools\DataTypes\Option\Option;
+use Keruald\OmniTools\DataTypes\Option\Some;
+
+use User;
+use UserGroup;
+
+use InvalidArgumentException;
+
+class Resources {
+
+ /**
+ * @return Option<int>
+ */
+ public static function resolveID (string $resource_type, string $identifier) : Option {
+ //Trivial cases: already an ID, null or void ID
+ if (is_numeric($identifier)) {
+ return new Some((int)$identifier);
+ }
+
+ if (!$identifier) {
+ return new None;
+ }
+
+ //Searches identifier
+ switch ($resource_type) {
+ case 'U':
+ return User::resolveUserID($identifier);
+
+ case 'G':
+ $group = UserGroup::fromCode($identifier);
+
+ return new Some($group->id);
+
+ case 'W':
+ $workspace = Workspace::fromCode($identifier);
+
+ return new Some($workspace->id);
+
+ default:
+ throw new InvalidArgumentException("Unknown resource type: $resource_type", E_USER_ERROR);
+ }
+ }
+}
diff --git a/workspaces/src/includes/GlobalFunctions.php b/workspaces/src/includes/GlobalFunctions.php
index a9cafff..a2004bd 100644
--- a/workspaces/src/includes/GlobalFunctions.php
+++ b/workspaces/src/includes/GlobalFunctions.php
@@ -1,196 +1,156 @@
<?php
use Waystone\Workspaces\Engines\Workspaces\Workspace;
-////////////////////////////////////////////////////////////////////////////////
-/// ///
-/// Information helper functions ///
-/// ///
-////////////////////////////////////////////////////////////////////////////////
-
-/**
- * Gets the resource ID from an identifier
- *
- * @param $resource_type the resource type
- * @param $identifier resource identifier
- * @return mixed the resource ID (as integer), or NULL if unknown
- */
-function resolve_resource_id ($resource_type, $identifier) {
- //Trivial cases: already an ID, null or void ID
- if (is_numeric($identifier)) {
- return $identifier;
- }
- if (!$identifier) {
- return NULL;
- }
-
- //Searches identifier
- switch ($resource_type) {
- case 'U':
- return get_user_id($identifier);
-
- case 'G':
- $group = UserGroup::fromCode($identifier);
- return $group->id;
-
- case 'W':
- $workspace = Workspace::fromCode($identifier);
- return $workspace->id;
-
- default:
- throw new Exception("Unknown resource type: $resource_type", E_USER_ERROR);
- }
-}
-
////////////////////////////////////////////////////////////////////////////////
/// ///
/// Misc helper functions ///
/// ///
////////////////////////////////////////////////////////////////////////////////
//Plural management
/*
* Gets a "s" if the specified amount requests the plural
* @param mixed $amount the quantity (should be numeric)
* @return string 's' if the amount is greater or equal than 2 ; otherwise, ''
*/
function s ($amount) {
if ($amount >= 2 || $amount <= -2 ) return 's';
}
/**
* Gets file extension
* @param string $file the file to get the extension
* @return string the file extension
*/
function get_extension ($file) {
$dotPosition = strrpos($file, ".");
return substr($file, $dotPosition + 1);
}
/**
* Gets file name
* @param string $file the file to get the extension
* @return string the file name
*/
function get_filename ($file) {
//TODO: clear directory
$dotPosition = strrpos($file, ".");
return substr($file, 0, $dotPosition);
}
/*
* Determines if a string starts with specified substring
* @param string $haystack the string to check
* @param string $needle the substring to determines if it's the start
* @param boolean $case_sensitive determines if the search must be case sensitive
* @return boolean true if $haystack starts with $needle ; otherwise, false.
*/
function string_starts_with ($haystack, $needle, $case_sensitive = true) {
if (!$case_sensitive) {
$haystack = strtoupper($haystack);
$needle = strtoupper($needle);
}
if ($haystack == $needle) return true;
return strpos($haystack, $needle) === 0;
}
////////////////////////////////////////////////////////////////////////////////
/// ///
/// URL helpers functions ///
/// ///
////////////////////////////////////////////////////////////////////////////////
/*
* Gets URL
* @return string URL
*/
function get_url () {
global $Config;
if (func_num_args() > 0) {
$pieces = func_get_args();
return $Config['BaseURL'] . '/' . implode('/', $pieces);
} elseif ($Config['BaseURL'] == "" || $Config['BaseURL'] == "/index.php") {
return "/";
} else {
return $Config['BaseURL'];
}
}
/*
* Gets server URL
* @todo find a way to detect https:// on non standard port
* @return string the server URL
*/
function get_server_url () {
if (php_sapi_name() == 'cli') {
return '';
}
switch ($port = $_SERVER['SERVER_PORT']) {
case '80':
return "http://$_SERVER[SERVER_NAME]";
case '443':
return "https://$_SERVER[SERVER_NAME]";
default:
return "http://$_SERVER[SERVER_NAME]:$_SERVER[SERVER_PORT]";
}
}
/*
* Gets $_SERVER['PATH_INFO'] or computes the equivalent if not defined.
* @return string the relevant URL part
*/
function get_current_url () {
global $Config;
//Gets relevant URL part from relevant $_SERVER variables
if (array_key_exists('PATH_INFO', $_SERVER)) {
//Without mod_rewrite, and url like /index.php/controller
//we use PATH_INFO. It's the easiest case.
return $_SERVER["PATH_INFO"];
}
//In other cases, we'll need to get the relevant part of the URL
$current_url = get_server_url() . $_SERVER['REQUEST_URI'];
//Relevant URL part starts after the site URL
$len = strlen($Config['SiteURL']);
//We need to assert it's the correct site
if (substr($current_url, 0, $len) != $Config['SiteURL']) {
dieprint_r(GENERAL_ERROR, "Edit includes/config.php and specify the correct site URL<br /><strong>Current value:</strong> $Config[SiteURL]<br /><strong>Expected value:</strong> a string starting by " . get_server_url(), "Setup");
}
if (array_key_exists('REDIRECT_URL', $_SERVER)) {
//With mod_rewrite, we can use REDIRECT_URL
//We take the end of the URL, ie *FROM* $len position
return substr(get_server_url() . $_SERVER["REDIRECT_URL"], $len);
}
//Last possibility: use REQUEST_URI, but remove QUERY_STRING
//If you need to edit here, use $_SERVER['REQUEST_URI']
//but you need to discard $_SERVER['QUERY_STRING']
//We take the end of the URL, ie *FROM* $len position
$url = substr(get_server_url() . $_SERVER["REQUEST_URI"], $len);
//But if there are a query string (?action=... we need to discard it)
if ($_SERVER['QUERY_STRING']) {
return substr($url, 0, strlen($url) - strlen($_SERVER['QUERY_STRING']) - 1);
}
return $url;
}
/*
* Gets an array of url fragments to be processed by controller
* @return array an array containing URL fragments
*/
function get_current_url_fragments () {
$url_source = get_current_url();
if ($url_source == '/index.php') return array();
return explode('/', substr($url_source, 1));
}
diff --git a/workspaces/src/includes/objects/user.php b/workspaces/src/includes/objects/user.php
index bbc2d7c..cdfb665 100755
--- a/workspaces/src/includes/objects/user.php
+++ b/workspaces/src/includes/objects/user.php
@@ -1,419 +1,445 @@
<?php
/**
* _, __, _, _ __, _ _, _, _
* / \ |_) (_ | | \ | /_\ |\ |
* \ / |_) , ) | |_/ | | | | \|
* ~ ~ ~ ~ ~ ~ ~ ~ ~ ~
*
* User class
*
* @package ObsidianWorkspaces
* @subpackage Model
* @author Sébastien Santoro aka Dereckson <dereckson@espace-win.org>
* @license http://www.opensource.org/licenses/bsd-license.php BSD
* @filesource
*
*/
use Waystone\Workspaces\Engines\Errors\ErrorHandling;
use Waystone\Workspaces\Engines\Workspaces\Workspace;
+use Keruald\OmniTools\DataTypes\Option\None;
+use Keruald\OmniTools\DataTypes\Option\Option;
+use Keruald\OmniTools\DataTypes\Option\Some;
+
/**
* User class
*/
class User {
public $id;
public $name;
public $password;
public $active = 0;
public $email;
public $regdate;
public array $session = [];
public string $lastError;
/**
* @var Array An array of users already loaded, the username as user id
*/
public static $hashtableById = [];
/**
* @var array|null An array of the workspaces the user has access to, each element an instance of the Workspace object. As long as the field hasn't been initialized by get_workspaces, null.
*/
private $workspaces = null;
/*
* Initializes a new instance
*
* @param int $id the primary key
*/
function __construct ($id = null) {
if ($id) {
$this->id = $id;
$this->load_from_database();
}
}
/**
* Initializes a new User instance if needed or get already available one.
*
* @param iint $id the user ID
* @return User the user instance
*/
static function get ($id = NULL) {
if ($id && array_key_exists($id, User::$hashtableById)) {
return self::$hashtableById[$id];
}
$user = new self($id);
return $user;
}
/**
* Loads the object User (ie fill the properties) from the $_POST array
*/
function load_from_form () {
if (array_key_exists('name', $_POST)) $this->name = $_POST['name'];
if (array_key_exists('password', $_POST)) $this->password = $_POST['password'];
if (array_key_exists('active', $_POST)) $this->active = $_POST['active'];
if (array_key_exists('actkey', $_POST)) $this->actkey = $_POST['actkey'];
if (array_key_exists('email', $_POST)) $this->email = $_POST['email'];
if (array_key_exists('regdate', $_POST)) $this->regdate = $_POST['regdate'];
}
/**
* Loads the object User (ie fill the properties) from the database
*/
function load_from_database () {
global $db;
$sql = "SELECT * FROM " . TABLE_USERS . " WHERE user_id = '" . $this->id . "'";
if ( !($result = $db->query($sql)) ) ErrorHandling::messageAndDie(SQL_ERROR, "Unable to query users", '', __LINE__, __FILE__, $sql);
if (!$row = $db->fetchRow($result)) {
$this->lastError = "User unknown: " . $this->id;
return false;
}
$this->load_from_row($row);
return true;
}
/**
* Loads the object User (ie fill the properties) from the database row
*/
function load_from_row ($row) {
$this->id = $row['user_id'];
$this->name = $row['username'];
$this->password = $row['user_password'];
$this->active = $row['user_active'] ? true : false;
$this->email = $row['user_email'];
$this->regdate = $row['user_regdate'];
//Puts object in hashtable, so it's accessible in future call of
//this run through User::get($id).
self::$hashtableById[$this->id] = $this;
}
+ private static function fromRow (array $row) : User {
+ $user = new User();
+ $user->load_from_row($row);
+
+ return $user;
+ }
+
/**
* Saves to database
*/
function save_to_database () {
global $db;
$id = $this->id ? "'" . $db->escape($this->id) . "'" : 'NULL';
$name = $db->escape($this->name);
$password = $db->escape($this->password);
$active = $this->active ? 1 : 0;
$email = $db->escape($this->email);
$regdate = $this->regdate ? "'" . $db->escape($this->regdate) . "'" : 'NULL';
//Updates or inserts
$sql = "REPLACE INTO " . TABLE_USERS . " (`user_id`, `username`, `user_password`, `user_active`, `user_email`, `user_regdate`) VALUES ($id, '$name', '$password', $active, '$email', $regdate)";
if (!$db->query($sql)) {
ErrorHandling::messageAndDie(SQL_ERROR, "Unable to save user", '', __LINE__, __FILE__, $sql);
}
if (!$this->id) {
//Gets new record id value
$this->id = $db->nextId();
}
}
/**
* Updates the specified field in the database record
*/
function save_field ($field) {
global $db;
if (!$this->id) {
ErrorHandling::messageAndDie(GENERAL_ERROR, "You're trying to update a record not yet saved in the database");
}
$id = $db->escape($this->id);
$value = $db->escape($this->$field);
$sql = "UPDATE " . TABLE_USERS . " SET `$field` = '$value' WHERE user_id = '$id'";
if (!$db->query($sql)) {
ErrorHandling::messageAndDie(SQL_ERROR, "Unable to save $field field", '', __LINE__, __FILE__, $sql);
}
}
//
// USER MANAGEMENT FUNCTIONS
//
/**
* Generates a unique user id
*/
function generate_id () {
global $db;
do {
$this->id = mt_rand(2001, 9999);
$sql = "SELECT COUNT(*) FROM " . TABLE_USERS . " WHERE user_id = $this->id";
if (!$result = $db->query($sql)) {
ErrorHandling::messageAndDie(SQL_ERROR, "Can't check if a user id is free", '', __LINE__, __FILE__, $sql);
}
$row = $db->fetchRow($result);
} while ($row[0]);
}
/**
* Fills password field with encrypted version
* of the specified clear password
*/
public function set_password ($newpassword) {
$this->password = md5($newpassword);
}
/**
* Checks if a login is available
*
* @param string $login the login to check
* @return boolean true if the login is available; otherwise, false.
*/
public static function is_available_login ($login) {
global $db;
$sql = "SELECT COUNT(*) FROM " . TABLE_USERS . " WHERE username = '$login'";
if (!$result = $db->query($sql)) {
ErrorHandling::messageAndDie(SQL_ERROR, "Can't check if the specified login is available", '', __LINE__, __FILE__, $sql);
}
$row = $db->fetchRow($result);
return ($row[0] == 0);
}
/**
* Initializes a new User instance ready to have its property filled
*
* @return User the new user instance
*/
public static function create () {
$user = new User();
$user->generate_id();
$user->active = true;
$user->regdate = time();
return $user;
}
/**
- * Gets user from specified e-mail
- *
- * @return User the user matching the specified e-mail; null, if the mail were not found.
+ * @return Option<User>
*/
- public static function get_user_from_email ($mail) {
+ private static function getByProperty ($property, $value) : Option {
global $db;
- $sql = "SELECT * FROM " . TABLE_USERS . " WHERE user_email = '$mail'";
+
+ $value = $db->escape($value);
+ $sql = "SELECT * FROM " . TABLE_USERS . " WHERE $property = '$value'";
if (!$result = $db->query($sql)) {
ErrorHandling::messageAndDie(SQL_ERROR, "Can't get user", '', __LINE__, __FILE__, $sql);
}
if ($row = $db->fetchRow($result)) {
- //E-mail found.
- $user = new User();
- $user->load_from_row($row);
- return $user;
+ return new Some(User::fromRow($row));
}
- //E-mail not found.
- return null;
+ return new None;
+ }
+
+ /**
+ * Gets user from specified e-mail
+ *
+ * @return Option<User> the user matching the specified e-mail; None, if the mail were not found.
+ */
+ public static function get_user_from_email ($mail) : Option {
+ return self::getByProperty("user_email", $mail);
+ }
+
+ public static function get_user_from_username ($username) : Option {
+ return self::getByProperty("username", $username);
+ }
+
+ public static function resolveUserID ($expression) : Option {
+ return self::get_user_from_username($expression)
+ ->orElse(self::get_user_from_email($expression))
+ ->map(fn($user) => $user->id);
}
//
// REMOTE IDENTITY PROVIDERS
//
/**
* Gets user from remote identity provider identifiant
*
* @param $authType The authentication method type
* @param $remoteUserId The remote user identifier
* @return User the user matching the specified identity provider and identifiant; null if no user were found.
*/
public static function getUserFromRemoteIdentity ($authType, $remoteUserId) {
global $db;
$authType = $db->escape($authType);
$remoteUserId = $db->escape($remoteUserId);
$sql = "SELECT user_id FROM " . TABLE_USERS_AUTH . " WHERE "
. "auth_type = '$authType' AND auth_identity = '$remoteUserId'";
if (!$result = $db->query($sql)) {
ErrorHandling::messageAndDie(SQL_ERROR, "Can't get user", '', __LINE__, __FILE__, $sql);
}
if ($row = $db->fetchRow($result)) {
return User::get($row['user_id']);
}
return null;
}
/**
* Sets user's remote identity provider identifiant
*
* @param $authType The authentication method type
* @param $remoteUserId The remote user identifier
* */
public function setRemoteIdentity ($authType, $remoteUserId, $properties = null) {
global $db;
$authType = $db->escape($authType);
$remoteUserId = $db->escape($remoteUserId);
$properties = ($properties === NULL) ? 'NULL' : "'" . $db->escape($properties) . "'";
$sql = "INSERT INTO " . TABLE_USERS_AUTH . " (auth_type, auth_identity, auth_properties, user_id) "
. "VALUES ('$authType', '$remoteUserId', $properties, $this->id)";
if (!$db->query($sql)) {
ErrorHandling::messageAndDie(SQL_ERROR, "Can't set user remote identity provider information", '', __LINE__, __FILE__, $sql);
}
}
//
// INTERACTION WITH OTHER OBJECTS
//
/**
* Gets the groups where the current user has access to.
*
* @return array an array containing group_id, matching groups the current user has access to.
*/
public function get_groups () {
return self::get_groups_from_user_id($this->id);
}
/**
* Determines if the user is a member of the specified group
*
* @param UserGroup $group The group to check
*/
public function isMemberOfGroup (UserGroup $group) {
global $db;
$sql = "SELECT count(*) FROM users_groups_members WHERE group_id = $group->id AND user_id = $this->id";
if (!$result = $db->query($sql)) {
ErrorHandling::messageAndDie(SQL_ERROR, "Can't determine if the user belongs to the group", '', __LINE__, __FILE__, $sql);
}
$row = $db->fetchRow($result);
return $row[0] == 1;
}
/**
* Adds user to the specified group
*
* @param UserGroup $group The group where to add the user
* @parap boolean $isAdmin if true, set the user admin; otherwise, set it regular user.
*/
public function addToGroup (UserGroup $group, $isAdmin = false) {
global $db;
$isAdmin = $isAdmin ? 1 : 0;
$sql = "REPLACE INTO users_groups_members VALUES ($group->id, $this->id, $isAdmin)";
if (!$db->query($sql)) {
ErrorHandling::messageAndDie(SQL_ERROR, "Can't add user to group", '', __LINE__, __FILE__, $sql);
}
}
/**
* Gets the SQL permission clause to select resources where the user is the subject.
*
* @return string The SQL WHERE clause
*/
public function get_permissions_clause () {
return self::get_permissions_clause_from_user_id($this->id);
}
/**
* Gets workspaces this user has access to.
*
* @return Array A list of workspaces
*/
public function get_workspaces () {
if ($this->workspaces === null) {
$this->workspaces = Workspace::get_user_workspaces($this->id);
}
return $this->workspaces;
}
/**
* Sets user permission
*
* @param string $resourceType The target resource type
* @param int $resourceId The target resource ID
* @param string $permissionName The permission name
* @param int $permissionFlag The permission flag (facultative; by default, 1)
*/
public function setPermission ($resourceType, $resourceId, $permissionName, $permissionFlag = 1) {
global $db;
$resourceType = $db->escape($resourceType);
if (!is_numeric($resourceId)) {
throw new Exception("Resource ID must be a positive or null integer, and not $resourceId.");
}
$permissionName = $db->escape($permissionName);
if (!is_numeric($permissionFlag)) {
throw new Exception("Permission flag must be a positive or null integer, and not $permissionFlag.");
}
$sql = "REPLACE INTO permissions
(subject_resource_type, subject_resource_id,
target_resource_type, target_resource_id,
permission_name, permission_flag)
VALUES
('U', $this->id,
'$resourceType', $resourceId,
'$permissionName', $permissionFlag)";
if (!$db->query($sql)) {
ErrorHandling::messageAndDie(SQL_ERROR, "Can't set user permission", '', __LINE__, __FILE__, $sql);
}
}
/**
* Gets the groups where a user has access to.
*
* @param int $user_id the user to get the groups list
* @return array an array containing group_id, matching groups the specified user has access to.
*/
public static function get_groups_from_user_id ($user_id) {
global $db;
$sql = "SELECT group_id FROM " . TABLE_UGROUPS_MEMBERS . " WHERE user_id = " . $user_id;
if (!$result = $db->query($sql)) {
ErrorHandling::messageAndDie(SQL_ERROR, "Can't get user groups", '', __LINE__, __FILE__, $sql);
}
$gids = array();
while ($row = $db->fetchRow($result)) {
$gids[] = $row['group_id'];
}
return $gids;
}
/**
* Gets the SQL permission clause to select resources where the specified user is the subject.
*
* @param $user_id The user ID
* @return string The SQL WHERE clause
*/
public static function get_permissions_clause_from_user_id ($user_id) {
$clause = "subject_resource_type = 'U' AND subject_resource_id = $user_id";
if ($groups = self::get_groups_from_user_id ($user_id)) {
$clause = "($clause) OR (subject_resource_type = 'G' AND subject_resource_id = ";
$clause .= join(") OR (subject_resource_type = 'G' AND subject_resource_id = ", $groups);
$clause .= ')';
}
return $clause;
}
}

File Metadata

Mime Type
text/x-diff
Expires
Wed, Mar 18, 12:43 (1 d, 17 h)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
3539741
Default Alt Text
(38 KB)

Event Timeline