Unverified Commit 3ba6dc62 authored by Adrien Clairembault's avatar Adrien Clairembault Committed by GitHub
Browse files

API: enable access to user pictures and inline images (#6963)

* API: add userPicture endpoint

* Allow access to inline images using an API session

* Compare file content instead of hash

* Use i flag for regex
parent 4414b1cf
......@@ -1288,6 +1288,33 @@ $ curl -X GET \
The body of the answer contains the raw file attached to the document.
### Get a user's profile picture
* **URL**: apirest.php/User/:id/Picture
* **Description**: Get a user's profile picture.
* **Method**: GET
* **Parameters**: (Headers)
* *Session-Token*: session var provided by [initSession](#init-session) endpoint. Mandatory.
* *App-Token*: authorization string provided by the GLPI API configuration. Optional.
* **Returns**:
* 200 (OK) with the raw image in the request body.
* 204 (No content) if the request is correct but the specified user doesn't have a profile picture.
* 400 (Bad Request) with a message indicating an error in input parameter.
Example usage (CURL):
```bash
$ curl -X GET \
-H 'Content-Type: application/json' \
-H "Session-Token: 83af7e620c83a50a18d3eac2f6ed05a3ca0bea62" \
-H "App-Token: f7g3csp8mgatg5ebc5elnazakw20i9fyev1qopya7" \
'http://path/to/glpi/apirest.php/User/2/Picture/'
< 200 OK
```
The body of the answer contains the raw image.
## Errors
### ERROR_ITEM_NOT_FOUND
......
......@@ -2684,4 +2684,31 @@ abstract class API extends CommonGLPI {
return $_names;
}
/**
* Get the profile picture of the given user
*
* @since 9.5
*
* @param int|boolean $user_id
*/
public function userPicture($user_id) {
$this->initEndpoint();
// Try to load target user
$user = new \User();
if (!$user->getFromDB($user_id)) {
$this->returnError("Bad request: user with id '$user_id' not found");
}
if (!empty($user->fields['picture'])) {
// Send file
$file = GLPI_PICTURE_DIR . '/' . $user->fields['picture'];
Toolbox::sendFile($file, $user->fields['picture']);
} else {
// No content
http_response_code(204);
}
die;
}
}
......@@ -215,6 +215,8 @@ class APIRest extends API {
}
return $this->returnResponse($this->lostPassword($this->parameters));
} else if (preg_match('%user/(\d+)/picture%i', $path_info, $matches)) {
$this->userPicture($matches[1]);
} else {
// commonDBTM manipulation
$itemtype = $this->getItemtype(0);
......
......@@ -617,6 +617,9 @@ class Document extends CommonDBTM {
return true;
}
// The following case should be reachable from the API
self::loadAPISessionIfExist();
if (isset($options["tickets_id"])
&& $this->canViewFileFromItilObject('Ticket', $options["tickets_id"])) {
return true;
......@@ -625,6 +628,31 @@ class Document extends CommonDBTM {
return false;
}
/**
* Try to load the session from the API Tolen
*
* @since 9.5
*/
private static function loadAPISessionIfExist() {
$session_token = \Toolbox::getHeader('Session-Token');
// No api token found
if ($session_token === null) {
return;
}
$current_session = session_id();
// Clean current session
if (!empty($current_session) && $current_session !== $session_token) {
session_destroy();
}
// Load API session
session_id($session_token);
Session::start();
}
/**
* Check if file of current instance can be viewed from a Reminder.
*
......
......@@ -3218,4 +3218,20 @@ HTML;
return "#".$fg_color;
}
/**
* Get an HTTP header value
*
* @since 9.5
*
* @param string $name
*
* @return mixed The header value or null if not found
*/
public static function getHeader(string $name) {
// Format expected header name
$name = "HTTP_" . str_replace("-", "_", strtoupper($name));
return $_SERVER[$name] ?? null;
}
}
......@@ -31,5 +31,6 @@
*/
define('GLPI_CONFIG_DIR', __DIR__);
define('GLPI_PICTURE_DIR', __DIR__ . '/files/_pictures');
return false;
......@@ -71,7 +71,13 @@ class APIRest extends APIBaseClass {
}
}
protected function query($resource = "", $params = [], $expected_code = 200, $expected_symbol = '') {
protected function query(
$resource = "",
$params = [],
$expected_code = 200,
$expected_symbol = '',
bool $file = false
) {
$verb = isset($params['verb'])
? $params['verb']
: 'GET';
......@@ -110,14 +116,21 @@ class APIRest extends APIBaseClass {
$this->array($body)
->hasKey('0')
->string[0]->isIdenticalTo($expected_symbol);
return;
return $body;
}
//retrieve data
$body = $res->getBody();
$data = json_decode($body, true);
if (is_array($data)) {
$data['headers'] = $res->getHeaders();
// retrieve data
$body = $res->getBody();
if ($file) {
$data = $body;
} else {
$data = json_decode($body, true);
if (is_array($data)) {
$data['headers'] = $res->getHeaders();
}
}
// common tests
$this->variable($res)->isNotNull();
$this->variable($res->getStatusCode())->isEqualTo($expected_code);
......@@ -371,4 +384,69 @@ class APIRest extends APIBaseClass {
}
$this->integer(count($data))->isEqualTo(1);
}
/**
* @tags api
* @covers API::userPicture
*/
public function testUserPicture() {
$pic = "test_picture.png";
$params = ['headers' => ['Session-Token' => $this->session_token]];
$id = getItemByTypeName('User', 'glpi', true);
$user = new \User();
/**
* Case 1: normal execution
*/
// Copy pic to tmp folder so it can be set to a user
copy("tests/$pic", "files/_tmp/$pic");
// Load GLPI user
$this->boolean($user->getFromDB($id))->isTrue();
// Set a pic URL
$success = $user->update([
'id' => $id,
'_picture' => [$pic],
]);
$this->boolean($success)->isTrue();
// Get updated pic url
$pic = $user->fields['picture'];
$this->string($pic)->isNotEmpty();
// Check pic was moved correctly into _picture folder
$this->boolean(file_exists(GLPI_PICTURE_DIR . "/$pic"))->isTrue();
$file_content = file_get_contents(GLPI_PICTURE_DIR . "/$pic");
$this->string($file_content)->isNotEmpty();
// Request
$response = $this->query("User/$id/Picture", $params, 200, '', true);
$this->string($response->__toString())->isEqualTo($file_content);
/**
* Case 2: user doens't exist
*/
// Request
$response = $this->query("User/99999999/Picture", $params, 400, "ERROR");
$this->array($response)->hasSize(2);
$this->string($response[1])->contains("Bad request: user with id '99999999' not found");
/**
* Case 3: user with no pictures
*/
// Remove pic URL
$success = $user->update([
'id' => $id,
'_blank_picture' => true,
]);
$this->boolean($success)->isTrue();
// Request
$response = $this->query("User/$id/Picture", $params, 204);
$this->variable($response)->isNull();
}
}
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment