mirror of
https://github.com/alchemy-fr/Phraseanet.git
synced 2025-10-13 21:13:26 +00:00
Port PHRAS-1593
This commit is contained in:
3
.bowerrc
3
.bowerrc
@@ -1,3 +1,4 @@
|
||||
{
|
||||
"directory" : "www/bower_components"
|
||||
"directory" : "www/bower_components",
|
||||
"timeout": 1200000
|
||||
}
|
||||
|
@@ -23,43 +23,70 @@ class ShareController extends Controller
|
||||
*/
|
||||
public function shareRecord($base_id, $record_id)
|
||||
{
|
||||
$outputVars = [
|
||||
'isAvailable' => false,
|
||||
'preview' => [
|
||||
'permalinkUrl' => '',
|
||||
'permaviewUrl' => '',
|
||||
'embedUrl' => '',
|
||||
'width' => '',
|
||||
'height' => ''
|
||||
]
|
||||
];
|
||||
$record = new \record_adapter($this->app, \phrasea::sbasFromBas($this->app, $base_id), $record_id);
|
||||
|
||||
if (!$this->getAclForUser()->has_access_to_subdef($record, 'preview')) {
|
||||
$this->app->abort(403);
|
||||
//get list of subdefs
|
||||
$subdefs = $record->get_subdefs();
|
||||
|
||||
$databoxSubdefs = $record->getDatabox()->get_subdef_structure()->getSubdefGroup($record->getType());
|
||||
$acl = $this->getAclForUser();
|
||||
$subdefList = [];
|
||||
$defaultKey = null;
|
||||
foreach ($subdefs as $subdef) {
|
||||
$subdefName = $subdef->get_name();
|
||||
if ($subdefName == 'document') {
|
||||
if (!$acl->has_right_on_base($record->getBaseId(), \ACL::CANDWNLDHD)) {
|
||||
continue;
|
||||
}
|
||||
$label = $this->app->trans('prod::tools: document');
|
||||
}
|
||||
elseif ($databoxSubdefs->hasSubdef($subdefName)) {
|
||||
if (!$acl->has_access_to_subdef($record, $subdefName)) {
|
||||
continue;
|
||||
}
|
||||
$label = $databoxSubdefs->getSubdef($subdefName)->get_label($this->app['locale']);
|
||||
}
|
||||
else {
|
||||
// this subdef does no exists anymore in databox structure ?
|
||||
continue; // don't publish it
|
||||
}
|
||||
$value = $subdef->get_name();
|
||||
$preview = $record->get_subdef($value);
|
||||
$defaultKey = $value; // will set a default option if neither preview,thumbnail or document is present
|
||||
|
||||
$preview = $record->get_preview();
|
||||
|
||||
if (null !== $previewLink = $preview->get_permalink()) {
|
||||
$permalinkUrl = $previewLink->get_url();
|
||||
if ( ($previewLink = $preview->get_permalink()) !== null ) {
|
||||
$permalinkUrl = $previewLink->get_url()->__toString();
|
||||
$permaviewUrl = $previewLink->get_page();
|
||||
$previewWidth = $preview->get_width();
|
||||
$previewHeight = $preview->get_height();
|
||||
|
||||
$embedUrl = $this->app->url('alchemy_embed_view', ['url' => (string)$permalinkUrl]);
|
||||
|
||||
$outputVars = [
|
||||
'isAvailable' => true,
|
||||
'preview' => [
|
||||
$previewData = [
|
||||
'label' => $label,
|
||||
'permalinkUrl' => $permalinkUrl,
|
||||
'permaviewUrl' => $permaviewUrl,
|
||||
'embedUrl' => $embedUrl,
|
||||
'width' => $previewWidth,
|
||||
'height' => $previewHeight
|
||||
]
|
||||
];
|
||||
$subdefList[$value] = $previewData;
|
||||
}
|
||||
}
|
||||
|
||||
// candidates as best default selected option
|
||||
foreach(["preview", "thumbnail", "document"] as $k) {
|
||||
if (array_key_exists($k, $subdefList)) {
|
||||
$defaultKey = $k;
|
||||
break;
|
||||
}
|
||||
}
|
||||
// if no subdef was sharable, subdefList is empty and defaultKey is null
|
||||
// the twig MUST handle that
|
||||
$outputVars = [
|
||||
'isAvailable' => !empty($subdefList),
|
||||
'subdefList' => $subdefList,
|
||||
'defaultKey' => $defaultKey
|
||||
];
|
||||
|
||||
return $this->renderResponse('prod/Share/record.html.twig', $outputVars);
|
||||
}
|
||||
|
@@ -47,10 +47,22 @@ class Share implements ControllerProviderInterface, ServiceProviderInterface
|
||||
|
||||
$controllers->get('/record/{base_id}/{record_id}/', 'controller.prod.share:shareRecord')
|
||||
->before(function (Request $request) use ($app, $firewall) {
|
||||
$socialTools = $app['conf']->get(['registry', 'actions', 'social-tools']);
|
||||
if($socialTools === "all") {
|
||||
return;
|
||||
}
|
||||
elseif($socialTools === "none") {
|
||||
$app->abort(403, 'social tools disabled');
|
||||
}
|
||||
elseif($socialTools === "publishers") {
|
||||
$firewall->requireRightOnSbas(
|
||||
\phrasea::sbasFromBas($app, $request->attributes->get('base_id')),
|
||||
\ACL::BAS_CHUPUB
|
||||
);
|
||||
}
|
||||
else {
|
||||
throw new \Exception("bad value \"" . $socialTools . "\" for social tools");
|
||||
}
|
||||
})
|
||||
->bind('share_record');
|
||||
|
||||
|
@@ -1,17 +1,29 @@
|
||||
{% if not isAvailable %}
|
||||
<p>{{ 'No permalink available.' | trans }}</p>
|
||||
{% else %}
|
||||
{% if preview.permalinkUrl is not empty %}
|
||||
{% if subdefList is not empty %}
|
||||
{% set defKey = defaultKey %}
|
||||
<div id="share">
|
||||
<div id="tweet" class="well-large">
|
||||
<p>
|
||||
<a href="http://www.twitter.com/home/?status={{ preview.permaviewUrl }}" target="_blank">
|
||||
<a href="#" id="advance-share">{{ 'share::share-record: advance' | trans }}</a>
|
||||
<span id="shared-def">
|
||||
{{ 'share::share-record: select-shared-def' | trans }}
|
||||
<select name="resource_type" id="resource_type_sel" class="input-small">
|
||||
{% for key,value in subdefList %}
|
||||
<option value={{ key }} {% if key == defKey %}selected{% endif %}>{{ value.label }}</option>
|
||||
{% endfor %}
|
||||
</select>
|
||||
</span>
|
||||
</p>
|
||||
<p>
|
||||
<a id="twitter-link" href="http://www.twitter.com/home/?status={{ subdefList[defKey].permaviewUrl }}" target="_blank">
|
||||
<img src="/assets/common/images/icons/twitter.png" title="share this on twitter" style="width:25px;vertical-align:middle;padding:0 5px;"/>
|
||||
{% trans %}Send to Twitter{% endtrans %}
|
||||
</a>
|
||||
</p>
|
||||
<p>
|
||||
<a href="http://www.facebook.com/sharer.php?u={{ preview.permaviewUrl }}" target="_blank">
|
||||
<a id="facebook-link" href="http://www.facebook.com/sharer.php?u={{ subdefList[defKey].permaviewUrl }}" target="_blank">
|
||||
<img src="/assets/common/images/icons/facebook.png" title="share on facebook" style="width:25px;vertical-align:middle;padding:0 5px;"/>
|
||||
{% trans %}Send to Facebook{% endtrans %}
|
||||
</a>
|
||||
@@ -19,20 +31,20 @@
|
||||
|
||||
<form action="#">
|
||||
<div class="form-group clearfix">
|
||||
<label>{% trans %}Resource URL{% endtrans %}</label>
|
||||
<input class="input-block-level" readonly="readonly" type="text" value="{{ preview.permalinkUrl }}"
|
||||
<label style="display:inline-block;">{% trans %}Resource URL{% endtrans %}</label>
|
||||
<input class="input-block-level" readonly="readonly" type="text" value="{{ subdefList[defKey].permalinkUrl }}"
|
||||
id="permalinkUrl"/>
|
||||
|
||||
<p class="pull-right">
|
||||
<a href="{{ preview.permalinkUrl }}" target="_blank">{{ 'previewLinkLabel' | trans }}</a>
|
||||
<a id="permalinkUrl-link" href="{{ subdefList[defKey].permalinkUrl }}" target="_blank">{{ 'previewLinkLabel' | trans }}</a>
|
||||
<a href="#" class="" id="permalinkUrlCopy">{{ 'copyClipboardLabel' | trans }}</a>
|
||||
</p>
|
||||
</div>
|
||||
<div class="form-group clearfix">
|
||||
<label>{% trans %}Detailed view URL{% endtrans %}</label>
|
||||
<input class="input-block-level" readonly="readonly" type="text" value="{{ preview.permaviewUrl }}" id="permaviewUrl"/>
|
||||
<input class="input-block-level" readonly="readonly" type="text" value="{{ subdefList[defKey].permaviewUrl }}" id="permaviewUrl"/>
|
||||
<p class="pull-right">
|
||||
<a href="{{ preview.permaviewUrl }}" target="_blank">{{ 'previewLinkLabel' | trans }}</a>
|
||||
<a id="permaviewUrl-link" href="{{ subdefList[defKey].permaviewUrl }}" target="_blank">{{ 'previewLinkLabel' | trans }}</a>
|
||||
<a href="#" class="" id="permaviewUrlCopy">{{ 'copyClipboardLabel' | trans }}</a>
|
||||
</p>
|
||||
</div>
|
||||
@@ -41,18 +53,69 @@
|
||||
<label>{% trans %}Embed code{% endtrans %}</label>
|
||||
{% spaceless %}
|
||||
<textarea class="input-block-level" rows="4" readonly="true" id="embedRecordUrl">
|
||||
<iframe width="{{ preview.width }}" height="{{ preview.height }}" src="{{ preview.embedUrl }}" frameborder="0" allowfullscreen></iframe>
|
||||
<iframe width="{{ subdefList[defKey].width }}" height="{{ subdefList[defKey].height }}" src="{{ subdefList[defKey].embedUrl }}" frameborder="0" allowfullscreen></iframe>
|
||||
</textarea>
|
||||
{% endspaceless %}
|
||||
<p class="pull-right">
|
||||
<a href="{{ preview.embedUrl }}" target="_blank">{{ 'previewLinkLabel' | trans }}</a>
|
||||
<a id="embedRecordUrl-link" href="{{ subdefList[defKey].embedUrl }}" target="_blank">{{ 'previewLinkLabel' | trans }}</a>
|
||||
<a href="#" class="" id="embedCopy">{{ 'copyClipboardLabel' | trans }}</a>
|
||||
</p>
|
||||
</div>
|
||||
{#{% endif %}#}
|
||||
</form>
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<script language="javascript">
|
||||
// var subdefListObj = JSON.parse(subdefList); // to convert json into a javascript object
|
||||
$(document).ready(function(){
|
||||
var subdefList = JSON.parse('{{ subdefList | json_encode | escape('js') }}');
|
||||
$('#resource_type_sel').on('change', function() {
|
||||
assignPermalinks(this.value);
|
||||
});
|
||||
$('input.ui-state-default').hover(
|
||||
function(){$(this).addClass('ui-state-hover');},
|
||||
function(){$(this).removeClass('ui-state-hover');}
|
||||
);
|
||||
$('#permalinkUrlCopy').on('click', function(event) {
|
||||
event.preventDefault();
|
||||
return copyElContentClipboard('permalinkUrl');
|
||||
});
|
||||
$('#permaviewUrlCopy').on('click', function(event) {
|
||||
event.preventDefault();
|
||||
return copyElContentClipboard('permaviewUrl');
|
||||
});
|
||||
$('#embedCopy').on('click', function(event) {
|
||||
event.preventDefault();
|
||||
return copyElContentClipboard('embedRecordUrl');
|
||||
});
|
||||
$('#advance-share').on('click', function() {
|
||||
$('#shared-def').show();
|
||||
});
|
||||
var copyElContentClipboard = function(elId) {
|
||||
var copyEl = document.getElementById(elId);
|
||||
copyEl.select();
|
||||
try {
|
||||
var successful = document.execCommand('copy');
|
||||
var msg = successful ? 'successful' : 'unsuccessful';
|
||||
console.log('Copying text command was ' + msg);
|
||||
} catch (err) {
|
||||
console.log('unable to copy');
|
||||
}
|
||||
}
|
||||
var assignPermalinks = function(resourceType) {
|
||||
$('#twitter-link').attr('href', 'http://www.twitter.com/home/?status=' + subdefList[resourceType].permaviewUrl);
|
||||
$('#facebook-link').attr('href', 'http://www.facebook.com/sharer.php?u=' + subdefList[resourceType].permaviewUrl);
|
||||
$('#permalinkUrl').val(subdefList[resourceType].permalinkUrl);
|
||||
$('#permalinkUrl-link').attr('href', subdefList[resourceType].permalinkUrl);
|
||||
$('#permaviewUrl').val(subdefList[resourceType].permaviewUrl);
|
||||
$('#permaviewUrl-link').attr('href', subdefList[resourceType].permaviewUrl);
|
||||
var html = '<iframe width="' + subdefList[resourceType].width
|
||||
+ '" height="' + subdefList[resourceType].height + '" src="' + subdefList[resourceType].embedUrl + '" frameborder="0" allowfullscreen></iframe>';
|
||||
$('#embedRecordUrl').val(html);
|
||||
$('#embedRecordUrl-link').attr('href', subdefList[resourceType].embedUrl);
|
||||
}
|
||||
});
|
||||
</script>
|
||||
{% else %}
|
||||
<div>{{ 'No URL available' | trans }}</div>
|
||||
{% endif %}
|
||||
|
@@ -2,6 +2,7 @@
|
||||
|
||||
namespace Alchemy\Tests\Phrasea\Controller\Prod;
|
||||
|
||||
use Alchemy\Phrasea\Application;
|
||||
use Alchemy\Phrasea\Controller\Prod\ShareController;
|
||||
use Alchemy\Phrasea\ControllerProvider\Prod\Share;
|
||||
use Symfony\Component\HttpKernel\Exception\HttpException;
|
||||
@@ -19,86 +20,63 @@ class ShareTest extends \PhraseanetAuthenticatedWebTestCase
|
||||
/**
|
||||
* @covers Alchemy\Phrasea\Controller\Prod\Share::shareRecord
|
||||
* @covers Alchemy\Phrasea\Controller\Prod\Share::connect
|
||||
* @covers Alchemy\Phrasea\Controller\Prod\Share::call
|
||||
*/
|
||||
public function testMountedRouteSlash()
|
||||
public function testRouteSlashALL()
|
||||
{
|
||||
$url = sprintf('/prod/share/record/%d/%d/', self::$DI['record_1']->get_base_id(), self::$DI['record_1']->get_record_id());
|
||||
self::$DI['client']->request('GET', $url);
|
||||
$this->assertTrue(self::$DI['client']->getResponse()->isOk());
|
||||
$this->_RouteSlash("all", [0=>true, 1=>true, 2=>true, 3=>true]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers Alchemy\Phrasea\Controller\Prod\Share::shareRecord
|
||||
* @covers Alchemy\Phrasea\Controller\Prod\Share::connect
|
||||
*/
|
||||
public function testRouteSlash()
|
||||
public function testRouteSlashPublishers()
|
||||
{
|
||||
$this->_RouteSlash("publishers", [0=>false, 1=>true, 2=>false, 3=>true]);
|
||||
}
|
||||
public function testRouteSlashNone()
|
||||
{
|
||||
$this->_RouteSlash("none", [0=>false, 1=>false, 2=>false, 3=>false]);
|
||||
}
|
||||
private function _RouteSlash($setting, $expected)
|
||||
{
|
||||
$app = $this->getApplication();
|
||||
$_conf = $app['conf'];
|
||||
$app['conf'] = $this->getMockBuilder('Alchemy\Phrasea\Core\Configuration\PropertyAccess')
|
||||
->disableOriginalConstructor()
|
||||
->getMock();
|
||||
$app['conf']
|
||||
->expects($this->any())
|
||||
->method('get')
|
||||
->will($this->returnCallback(function ($param, $default) use ($_conf, $setting) {
|
||||
switch ($param) {
|
||||
case ['registry', 'actions', 'social-tools']:
|
||||
return $setting;
|
||||
}
|
||||
return $_conf->get($param, $default);
|
||||
}));
|
||||
$result = [];
|
||||
foreach($expected as $flags=>$v) {
|
||||
$stubbedACL = $this->stubACL();
|
||||
|
||||
//has_right_on_base return true
|
||||
$stubbedACL->expects($this->once())
|
||||
// "has_right_on_sbas" IS checked by the route->before(), the url will return 403
|
||||
$stubbedACL->expects($this->any())
|
||||
->method('has_right_on_sbas')
|
||||
->will($this->returnValue(true));
|
||||
|
||||
//has_access_to_subdef return true
|
||||
$stubbedACL->expects($this->once())
|
||||
->will($this->returnValue(($flags & 1) ? true:false));
|
||||
// but "has_access_to_subdef" IS NOT checked (the url will return a 200 with a message "no subdef to share")
|
||||
$stubbedACL->expects($this->any())
|
||||
->method('has_access_to_subdef')
|
||||
->will($this->returnValue(true));
|
||||
|
||||
|
||||
->will($this->returnValue(($flags & 2) ? true:false));
|
||||
$url = sprintf('/prod/share/record/%d/%d/', self::$DI['record_1']->get_base_id(), self::$DI['record_1']->get_record_id());
|
||||
self::$DI['client']->request('GET', $url);
|
||||
$this->assertTrue(self::$DI['client']->getResponse()->isOk());
|
||||
$result[$flags] = self::$DI['client']->getResponse()->isOk();
|
||||
}
|
||||
$this->assertEquals($expected, $result);
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers Alchemy\Phrasea\Controller\Prod\Share::shareRecord
|
||||
*/
|
||||
public function testShareRecord()
|
||||
{
|
||||
$share = new ShareController(self::$DI['app']);
|
||||
|
||||
/** @var \record_adapter $record_1 */
|
||||
$record_1 = self::$DI['record_1'];
|
||||
|
||||
$response = $share->shareRecord($record_1->getBaseId(), $record_1->getRecordId());
|
||||
$this->assertTrue($response->isOk());
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers Alchemy\Phrasea\Controller\Prod\Share::shareRecord
|
||||
*/
|
||||
public function testShareRecordBadAccess()
|
||||
{
|
||||
$share = new ShareController(self::$DI['app']);
|
||||
|
||||
$stubbedACL = $this->getMockBuilder('\ACL')
|
||||
->disableOriginalConstructor()
|
||||
->getMock();
|
||||
|
||||
//has_access_to_subdef return false
|
||||
$stubbedACL->expects($this->once())
|
||||
->method('has_access_to_subdef')
|
||||
->will($this->returnValue(false));
|
||||
|
||||
$aclProvider = $this->getMockBuilder('Alchemy\Phrasea\Authentication\ACLProvider')
|
||||
->disableOriginalConstructor()
|
||||
->getMock();
|
||||
$aclProvider->expects($this->any())
|
||||
->method('get')
|
||||
->will($this->returnValue($stubbedACL));
|
||||
|
||||
self::$DI['app']['acl'] = $aclProvider;
|
||||
|
||||
try {
|
||||
$share->shareRecord(self::$DI['record_1']->get_base_id(), self::$DI['record_1']->get_record_id());
|
||||
} catch (HttpException $exception) {
|
||||
$this->assertEquals(403, $exception->getStatusCode());
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
$this->fail('An access denied exception should have been thrown.');
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user