From 042748e044f2c4cca452e4a750629ed1d37e8c90 Mon Sep 17 00:00:00 2001 From: Nicolas Le Goff Date: Mon, 4 Aug 2014 11:25:59 +0200 Subject: [PATCH] Apply user rights on sub-definition --- lib/classes/API/V1/adapter.php | 29 ++++++-- lib/classes/Feed/Entry/Adapter.php | 11 +-- lib/classes/caption/record.php | 15 +++-- .../Tests/Phrasea/Application/ApiAbstract.php | 67 +++++++++++++++++-- .../Phrasea/Application/OverviewTest.php | 8 +-- .../Phrasea/Controller/Root/RSSFeedTest.php | 6 +- 6 files changed, 109 insertions(+), 27 deletions(-) diff --git a/lib/classes/API/V1/adapter.php b/lib/classes/API/V1/adapter.php index 5e470d9ee3..eecc531b62 100644 --- a/lib/classes/API/V1/adapter.php +++ b/lib/classes/API/V1/adapter.php @@ -1039,7 +1039,6 @@ class API_V1_adapter extends API_V1_Abstract */ public function get_record_embed(Request $request, $databox_id, $record_id) { - $result = new API_V1_result($this->app, $request, $this); $record = $this->app['phraseanet.appbox']->get_databox($databox_id)->get_record($record_id); @@ -1050,7 +1049,9 @@ class API_V1_adapter extends API_V1_Abstract $mimes = $request->get('mimes', array()); foreach ($record->get_embedable_medias($devices, $mimes) as $name => $media) { - $ret[] = $this->list_embedable_media($media, $this->app['phraseanet.registry']); + if (null !== $subdef = $this->list_embedable_media($record, $media, $this->app['phraseanet.registry'])) { + $ret[] = $subdef; + } } $result->set_datas(array("embed" => $ret)); @@ -1082,7 +1083,9 @@ class API_V1_adapter extends API_V1_Abstract $mimes = $request->get('mimes', array()); foreach ($record->get_embedable_medias($devices, $mimes) as $name => $media) { - $ret[] = $this->list_embedable_media($media, $this->app['phraseanet.registry']); + if (null !== $subdef = $this->list_embedable_media($record, $media, $this->app['phraseanet.registry'])) { + $ret[] = $subdef; + } } $result->set_datas(array("embed" => $ret)); @@ -1705,12 +1708,22 @@ class API_V1_adapter extends API_V1_Abstract * @param media_subdef $media * @return array */ - protected function list_embedable_media(media_subdef $media, registryInterface $registry) + protected function list_embedable_media(\record_adapter $record, media_subdef $media, registryInterface $registry) { if (!$media->is_physically_present()) { return null; } + if ($this->app['authentication']->isAuthenticated()) { + if ($media->get_name() !== 'document' && false === $this->app['authentication']->getUser()->ACL()->has_access_to_subdef($record, $media->get_name())) { + return null; + } else if ($media->get_name() === 'document' + && !$this->app['authentication']->getUser()->ACL()->has_right_on_base($record->get_base_id(), 'candwnldhd') + && !$this->app['authentication']->getUser()->ACL()->has_hd_grant($record)) { + return null; + } + } + if ($media->get_permalink() instanceof media_Permalink_Adapter) { $permalink = $this->list_permalink($media->get_permalink(), $registry); } else { @@ -1897,7 +1910,7 @@ class API_V1_adapter extends API_V1_Abstract 'created_on' => $record->get_creation_date()->format(DATE_ATOM), 'collection_id' => phrasea::collFromBas($this->app, $record->get_base_id()), 'sha256' => $record->get_sha256(), - 'thumbnail' => $this->list_embedable_media($record->get_thumbnail(), $this->app['phraseanet.registry']), + 'thumbnail' => $this->list_embedable_media($record, $record->get_thumbnail(), $this->app['phraseanet.registry']), 'technical_informations' => $technicalInformation, 'phrasea_type' => $record->get_type(), 'uuid' => $record->get_uuid(), @@ -1907,7 +1920,9 @@ class API_V1_adapter extends API_V1_Abstract $subdefs = $caption = array(); foreach ($record->get_embedable_medias(array(), array()) as $name => $media) { - $subdefs[] = $this->list_embedable_media($media, $this->app['phraseanet.registry']); + if (null !== $subdef = $this->list_embedable_media($record, $media, $this->app['phraseanet.registry'])) { + $subdefs[] = $subdef; + } } foreach ($record->get_caption()->get_fields() as $field) { @@ -1969,7 +1984,7 @@ class API_V1_adapter extends API_V1_Abstract 'updated_on' => $story->get_modification_date()->format(DATE_ATOM), 'created_on' => $story->get_creation_date()->format(DATE_ATOM), 'collection_id' => phrasea::collFromBas($this->app, $story->get_base_id()), - 'thumbnail' => $this->list_embedable_media($story->get_thumbnail(), $this->app['phraseanet.registry']), + 'thumbnail' => $this->list_embedable_media($story, $story->get_thumbnail(), $this->app['phraseanet.registry']), 'uuid' => $story->get_uuid(), 'metadatas' => array( '@entity@' => self::OBJECT_TYPE_STORY_METADATA_BAG, diff --git a/lib/classes/Feed/Entry/Adapter.php b/lib/classes/Feed/Entry/Adapter.php index c5ff25fe72..8d65d25c57 100644 --- a/lib/classes/Feed/Entry/Adapter.php +++ b/lib/classes/Feed/Entry/Adapter.php @@ -450,11 +450,14 @@ class Feed_Entry_Adapter implements Feed_Entry_Interface, cache_cacheableInterfa $rs = $this->retrieve_elements(); $items = array(); - foreach ($rs as $item_id) { - try { - $items[] = new Feed_Entry_Item($this->app['phraseanet.appbox'], $this, $item_id); - } catch (NotFoundHttpException $e) { + if ($rs) { + foreach ($rs as $item_id) { + try { + $items[] = new Feed_Entry_Item($this->app['phraseanet.appbox'], $this, $item_id); + } catch (NotFoundHttpException $e) { + + } } } diff --git a/lib/classes/caption/record.php b/lib/classes/caption/record.php index 48a53ce204..62ecef8c95 100644 --- a/lib/classes/caption/record.php +++ b/lib/classes/caption/record.php @@ -205,15 +205,20 @@ class caption_record implements caption_interface, cache_cacheableInterface $stmt->execute(array(':record_id' => $this->record->get_record_id())); $fields = $stmt->fetchAll(PDO::FETCH_ASSOC); $stmt->closeCursor(); - $this->set_data_to_cache($fields); + if ($fields) { + $this->set_data_to_cache($fields); + } } $rec_fields = array(); - foreach ($fields as $row) { - $databox_meta_struct = databox_field::get_instance($this->app, $this->databox, $row['structure_id']); - $metadata = new caption_field($this->app, $databox_meta_struct, $this->record); - $rec_fields[$databox_meta_struct->get_id()] = $metadata; + if ($fields) { + foreach ($fields as $row) { + $databox_meta_struct = databox_field::get_instance($this->app, $this->databox, $row['structure_id']); + $metadata = new caption_field($this->app, $databox_meta_struct, $this->record); + + $rec_fields[$databox_meta_struct->get_id()] = $metadata; + } } $this->fields = $rec_fields; diff --git a/tests/Alchemy/Tests/Phrasea/Application/ApiAbstract.php b/tests/Alchemy/Tests/Phrasea/Application/ApiAbstract.php index d934c8f7fd..0a94f0b39f 100644 --- a/tests/Alchemy/Tests/Phrasea/Application/ApiAbstract.php +++ b/tests/Alchemy/Tests/Phrasea/Application/ApiAbstract.php @@ -85,6 +85,7 @@ abstract class ApiAbstract extends \PhraseanetWebTestCaseAbstract if (!static::$APIrecord) { $file = new File(self::$DI['app'], self::$DI['app']['mediavorus']->guess(__DIR__ . '/../../../../files/test024.jpg'), self::$DI['collection']); + static::$APIrecord = \record_adapter::createFromFile($file, self::$DI['app']); static::$APIrecord->generate_subdefs(static::$APIrecord->get_databox(), self::$DI['app']); } @@ -121,8 +122,10 @@ abstract class ApiAbstract extends \PhraseanetWebTestCaseAbstract self::$adminApplication->delete(); } - static::$APIrecord->delete(); - static::$APIrecord = null; + if (static::$APIrecord) { + static::$APIrecord->delete(); + static::$APIrecord = null; + } parent::tearDownAfterClass(); } @@ -1045,7 +1048,10 @@ abstract class ApiAbstract extends \PhraseanetWebTestCaseAbstract { $this->setToken(self::$token); - $keys = array_keys($this->record->get_subdefs()); + self::$DI['user_notAdmin']->ACL()->update_rights_to_base(self::$DI['collection']->get_base_id(), array( + 'candwnldpreview' => 1, + 'candwnldhd' => 1 + )); $route = '/api/v1/records/' . $this->record->get_sbas_id() . '/' . $this->record->get_record_id() . '/embed/'; $this->evaluateMethodNotAllowedRoute($route, array('POST', 'PUT', 'DELETE')); @@ -1058,6 +1064,13 @@ abstract class ApiAbstract extends \PhraseanetWebTestCaseAbstract $this->assertArrayHasKey('embed', $content['response']); + $embedTypes = array_flip(array_map(function($subdef) {return $subdef['name'];},$content['response']['embed'])); + + //access to all subdefs + $this->assertArrayHasKey('document', $embedTypes); + $this->assertArrayHasKey('preview', $embedTypes); + $this->assertArrayHasKey('thumbnail', $embedTypes); + foreach ($content['response']['embed'] as $embed) { $this->checkEmbed($embed, $this->record); } @@ -1069,6 +1082,52 @@ abstract class ApiAbstract extends \PhraseanetWebTestCaseAbstract $this->evaluateMethodNotAllowedRoute($route, array('POST', 'PUT', 'DELETE')); } + public function testRecordsEmbedRouteNoHdRights() + { + $this->setToken(self::$token); + + self::$DI['user_notAdmin']->ACL()->update_rights_to_base(self::$DI['collection']->get_base_id(), array( + 'candwnldhd' => 0, + 'candwnldpreview' => 1 + )); + + $route = '/api/v1/records/' . $this->record->get_sbas_id() . '/' . $this->record->get_record_id() . '/embed/'; + + self::$DI['client']->request('GET', $route, $this->getParameters(), array(), array('HTTP_Accept' => $this->getAcceptMimeType())); + $content = $this->unserialize(self::$DI['client']->getResponse()->getContent()); + + $this->evaluateResponse200(self::$DI['client']->getResponse()); + $this->evaluateMeta200($content); + $this->assertArrayHasKey('embed', $content['response']); + // no hd subdef + $embedTypes = array_flip(array_map(function($subdef) {return $subdef['name'];},$content['response']['embed'])); + $this->assertArrayHasKey('preview', $embedTypes); + $this->assertArrayNotHasKey('document', $embedTypes); + } + + + public function testRecordsEmbedRouteNoPreviewAndHdRights() + { + $this->setToken(self::$token); + + self::$DI['user_notAdmin']->ACL()->update_rights_to_base(self::$DI['collection']->get_base_id(), array( + 'candwnldpreview' => 0, + 'candwnldhd' => 0 + )); + + $route = '/api/v1/records/' . $this->record->get_sbas_id() . '/' . $this->record->get_record_id() . '/embed/'; + + self::$DI['client']->request('GET', $route, $this->getParameters(), array(), array('HTTP_Accept' => $this->getAcceptMimeType())); + $content = $this->unserialize(self::$DI['client']->getResponse()->getContent()); + + $this->evaluateResponse200(self::$DI['client']->getResponse()); + $this->evaluateMeta200($content); + $this->assertArrayHasKey('embed', $content['response']); + // no preview + $this->assertArrayNotHasKey('document', array_flip(array_map(function($subdef) {return $subdef['name'];},$content['response']['embed']))); + $this->assertArrayNotHasKey('preview', array_flip(array_map(function($subdef) {return $subdef['name'];},$content['response']['embed']))); + } + /** * @covers \API_V1_adapter::get_record_embed * @covers \API_V1_adapter::list_embedable_media @@ -2019,7 +2078,7 @@ abstract class ApiAbstract extends \PhraseanetWebTestCaseAbstract $lazaretSession = new \Entities\LazaretSession(); self::$DI['app']['EM']->persist($lazaretSession); - $quarantineItem; + $quarantineItem = null; $callback = function ($element, $visa, $code) use (&$quarantineItem) { $quarantineItem = $element; }; diff --git a/tests/Alchemy/Tests/Phrasea/Application/OverviewTest.php b/tests/Alchemy/Tests/Phrasea/Application/OverviewTest.php index 4b3077588b..65687508b7 100644 --- a/tests/Alchemy/Tests/Phrasea/Application/OverviewTest.php +++ b/tests/Alchemy/Tests/Phrasea/Application/OverviewTest.php @@ -104,7 +104,7 @@ class OverviewTest extends \PhraseanetWebTestCaseAuthenticatedAbstract $this->assertRegExp('/^attachment;/', $response->headers->get('content-disposition')); - $this->assertEquals(rtrim(self::$DI['app']['phraseanet.configuration']['main']['servername'], '/') . "/permalink/v1/1/". self::$DI['record_1']->get_record_id()."/caption/?token=".$token, $response->headers->get("Link")); + $this->assertContains(self::$DI['record_1']->get_record_id()."/caption/?token=".$token, $response->headers->get("Link")); $this->assertEquals(200, $response->getStatusCode()); } @@ -221,7 +221,7 @@ class OverviewTest extends \PhraseanetWebTestCaseAuthenticatedAbstract $this->assertEquals($value, $response->headers->get($name)); } - $this->assertEquals(rtrim(self::$DI['app']['phraseanet.configuration']['main']['servername'], '/') . "/permalink/v1/1/". self::$DI['record_1']->get_record_id()."/caption/?token=".$token, $response->headers->get("Link")); + $this->assertContains(self::$DI['record_1']->get_record_id()."/caption/?token=".$token, $response->headers->get("Link")); $this->assertEquals(200, $response->getStatusCode()); } @@ -253,7 +253,7 @@ class OverviewTest extends \PhraseanetWebTestCaseAuthenticatedAbstract $this->assertEquals($value, $response->headers->get($name)); } - $this->assertEquals(200, $response->getStatusCode()); + $this->assertTrue($response->isOk(), $response); } protected function get_a_permalink(array $headers = array()) @@ -269,7 +269,7 @@ class OverviewTest extends \PhraseanetWebTestCaseAuthenticatedAbstract $this->assertEquals($value, $response->headers->get($name)); } - $this->assertEquals(rtrim(self::$DI['app']['phraseanet.configuration']['main']['servername'], '/') . "/permalink/v1/1/". self::$DI['record_1']->get_record_id()."/caption/?token=".$token, $response->headers->get("Link")); + $this->assertContains(self::$DI['record_1']->get_record_id()."/caption/?token=".$token, $response->headers->get("Link")); $this->assertEquals(200, $response->getStatusCode()); self::$DI['client']->request('OPTIONS', $url); diff --git a/tests/Alchemy/Tests/Phrasea/Controller/Root/RSSFeedTest.php b/tests/Alchemy/Tests/Phrasea/Controller/Root/RSSFeedTest.php index d08e5dd8cb..3fba951ff9 100644 --- a/tests/Alchemy/Tests/Phrasea/Controller/Root/RSSFeedTest.php +++ b/tests/Alchemy/Tests/Phrasea/Controller/Root/RSSFeedTest.php @@ -226,8 +226,8 @@ class RSSFeedTest extends \PhraseanetWebTestCaseAbstract protected function evaluateResponse200(Response $response) { - $this->assertEquals(200, $response->getStatusCode(), 'Test status code '); - $this->assertEquals('UTF-8', $response->getCharset(), 'Test charset response'); + $this->assertEquals(200, $response->getStatusCode(), $response); + $this->assertEquals('UTF-8', $response->getCharset(), $response); } public function testPublicFeed() @@ -321,7 +321,7 @@ class RSSFeedTest extends \PhraseanetWebTestCaseAbstract $this->assertTrue($feed->is_public()); } $crawler = self::$DI['client']->request("GET", "/feeds/aggregated/rss/"); - $this->assertTrue(self::$DI['client']->getResponse()->isOk()); + $this->assertTrue(self::$DI['client']->getResponse()->isOk(), self::$DI['client']->getResponse()); $this->assertEquals("application/rss+xml", self::$DI['client']->getResponse()->headers->get("content-type")); $xml = self::$DI['client']->getResponse()->getContent(); $this->verifyXML($xml);