Customer portal : Edit profile picture

SVN:trunk[4231]
This commit is contained in:
Guillaume Lajarige
2016-06-21 10:19:28 +00:00
parent 2773419faa
commit a0d16b868e
5 changed files with 183 additions and 14 deletions

View File

@@ -21,6 +21,7 @@ namespace Combodo\iTop\Portal\Controller;
use \Exception;
use \IssueLog;
use \utils;
use \MetaModel;
use \UserRights;
use \Silex\Application;
@@ -34,6 +35,7 @@ use \Combodo\iTop\Renderer\Bootstrap\BsFormRenderer;
class UserProfileBrickController extends BrickController
{
const ENUM_FORM_TYPE_PICTURE = 'picture';
public function DisplayAction(Request $oRequest, Application $oApp, $sBrickId)
{
@@ -79,6 +81,10 @@ class UserProfileBrickController extends BrickController
{
$aData['form'] = $this->HandlePasswordForm($oRequest, $oApp);
}
elseif ($sFormType === static::ENUM_FORM_TYPE_PICTURE)
{
$aData['form'] = $this->HandlePictureForm($oRequest, $oApp, $sFormMode);
}
else
{
throw new Exception('Unknown form type.');
@@ -235,6 +241,66 @@ class UserProfileBrickController extends BrickController
return $aFormData;
}
public function HandlePictureForm(Request $oRequest, Application $oApp, $sFormMode)
{
$aFormData = array();
$oRequestParams = $oRequest->request;
$sPictureAttCode = 'picture';
// Handling form
$sOperation = $oRequestParams->get('operation');
// - No operation specified
if ($sOperation === null)
{
IssueLog::Error(__METHOD__ . ' at line ' . __LINE__ . ' : Operation parameter must be specified.');
$oApp->abort(500, 'Operation parameter must be specified.');
}
// - Submit
else if ($sOperation === 'submit')
{
$oRequestFiles = $oRequest->files;
$oPictureFile = $oRequestFiles->get($sPictureAttCode);
if ($oPictureFile === null)
{
IssueLog::Error(__METHOD__ . ' at line ' . __LINE__ . ' : Parameter picture must be defined.');
$oApp->abort(500, 'Parameter picture must be defined.');
}
try
{
// Retrieving image as an ORMDocument
$oImage = utils::ReadPostedDocument($sPictureAttCode);
// Retrieving current contact
$oCurContact = UserRights::GetContactObject();
// Resizing image
$oAttDef = MetaModel::GetAttributeDef(get_class($oCurContact), $sPictureAttCode);
$aSize = utils::GetImageSize($oImage->GetData());
$oImage = utils::ResizeImageToFit($oImage, $aSize[0], $aSize[1], $oAttDef->Get('storage_max_width'), $oAttDef->Get('storage_max_height'));
// Setting it to the contact
$oCurContact->Set($sPictureAttCode, $oImage);
// Forcing allowed writing on the object if necessary.
$oCurContact->AllowWrite(true);
$oCurContact->DBUpdate();
}
catch (FileUploadException $e)
{
$aFormData['error'] = $e->GetMessage();
}
$aFormData['picture_url'] = $oImage->GetDownloadURL(get_class($oCurContact), $oCurContact->GetKey(), $sPictureAttCode);
$aFormData['validation'] = array(
'valid' => true,
'messages' => array()
);
}
else
{
// Else, submit from another form
}
return $aFormData;
}
}
?>

View File

@@ -29,7 +29,8 @@ class UserProfileRouter extends AbstractRouter
'bind' => 'p_user_profile_brick',
'values' => array(
'sBrickId' => null
))
)
)
);
}

View File

@@ -41,17 +41,37 @@
</div>
</div>
<div class="col-sm-6">
<div class="panel panel-default">
<div class="panel panel-default user_profile_picture">
<div class="panel-heading">
<h3 class="panel-title">Photo</h3>
</div>
<div class="panel-body" style="position: relative;">
<div class="text-center">
<img src="{{ sUserPhotoUrl }}" style="max-width: 175px;"/>
<!--<input type="file" id="xx" name="xx" />-->
<div style="position: absolute; top: 0px; left: 0px; width: 100%; height: 100%; background-color: #000000; opacity: 0.5;"></div>
<div style="position: absolute; bottom: 0.5em; left: 0px; width: 100%; color: #FFFFFF; font-size: 1.5em; font-style: italic;">Picture edition not available in beta</div>
<div class="form_alerts">
<div class="alert alert-success" role="alert" style="display: none;"></div>
<div class="alert alert-warning" role="alert" style="display: none;"></div>
<div class="alert alert-error alert-danger" role="alert" style="display: none;"></div>
</div>
<form id="picture-form" method="POST" action="{{ app['url_generator'].generate('p_user_profile_brick') }}">
<input type="hidden" name="current_values[form_type]" value="{{ constant('\\Combodo\\iTop\\Portal\\Controller\\UserProfileBrickController::ENUM_FORM_TYPE_PICTURE') }}" />
<input type="hidden" name="operation" value="submit" />
<div class="text-center">
<span class="preview">
<img src="{{ sUserPhotoUrl }}"/>
</span>
<span class="actions">
<button type="button" class="btn btn-default btn_edit">
<span class="fa fa-pencil fa-fw"></span>
<input id="picture" type="file" name="picture" />
</button>
{#<button type="button" class="btn btn-default btn_undo" title="{{ 'UI:Button:ResetImage'|dict_s }}" disabled>
<span class="fa fa-undo fa-fw"></span>
</button>
<button type="button" class="btn btn-default btn_reset" title="{{ 'UI:Button:RemoveImage'|dict_s }}">
<span class="fa fa-trash-o fa-fw"></span>
</button>#}
</span>
</div>
</form>
</div>
</div>
<div class="panel panel-default">
@@ -136,6 +156,46 @@
});
{% endif %}
// Picture form
// - JQuery upload widget
$('#picture-form #picture').fileupload({
dataType: 'json',
acceptFileTypes: /(\.|\/)(gif|jpe?g|png)$/i,
disableImageResize: /Android(?!.*Chrome)|Opera/.test(window.navigator.userAgent)
})
.on('fileuploadsend', function(oEvent, oData){
$('.user_profile_picture .form_alerts .alert-error').hide()
$('#page_overlay .overlay_content .content_loader').clone().prependTo('.user_profile_picture .panel-body');
})
.on('fileuploadalways', function(oEvent, oData){
$('.user_profile_picture .content_loader').remove();
})
.on('fileuploaddone', function(oEvent, oData){
if( (oData._response.result.form !== undefined) && (oData._response.result.form.validation.valid === true) )
{
// Retrieving picture url
var sPictureUrl = oData._response.result.form.picture_url;
// Replacing form preview image
$('#picture-form .preview img').attr('src', sPictureUrl);
// Replacing menu image
$('#topbar .user_photo, #sidebar .user_photo').css('background-image', 'url("' + sPictureUrl + '")');
}
})
.on('fileuploadfail', function(oEvent, oData){
if( (oData._response.jqXHR.responseJSON !== undefined) && (oData._response.jqXHR.responseJSON.error_message !== undefined) )
{
$('.user_profile_picture .form_alerts .alert-error').show().text(oData._response.jqXHR.responseJSON.error_message);
}
});
// - Undo button
/*$('#user-profile-wrapper .actions .btn_undo').on('click', function(oEvent){
console.log('Picture undo trigger');
});*/
// - Reset button
$('#user-profile-wrapper .actions .btn_reset').on('click', function(oEvent){
console.log('Picture reset trigger');
});
// Submit button
$('#user-profile-wrapper .form_buttons .form_btn_submit').off('click').on('click', function(oEvent){
oEvent.preventDefault();
@@ -168,6 +228,6 @@
return false;
}
});
{% endif %}
{% endif %}
});
{% endblock %}

View File

@@ -1617,8 +1617,8 @@ output {
.form-control:focus {
border-color: $brand-primary;
outline: 0;
-webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 8px rgba(102, 175, 233, 0.6);
box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 8px rgba(102, 175, 233, 0.6)
-webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 8px rgba(234, 125, 30, 0.6); /* Last rgb color is $brand-primary */
box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 8px rgba(234, 125, 30, 0.6)
}
.form-control::-moz-placeholder {
color: #dddddd;
@@ -2160,8 +2160,8 @@ fieldset[disabled] .btn-default:active,
.btn-default.disabled.active,
.btn-default[disabled].active,
fieldset[disabled] .btn-default.active {
background-color: #474949;
border-color: #474949
background-color: #BBBBBB;
border-color: $gray-light;
}
.btn-default .badge {
color: #474949;

View File

@@ -495,8 +495,50 @@ footer{
/**********************/
/* Brick user profile */
/**********************/
.home .userprofile-brick{
background-color: #E8E7E7;
#user-profile-wrapper .user_profile_picture .content_loader{
position: absolute;
z-index: 1;
top: 0;
left: 0;
padding-top: 4em;
width: 100%;
height: 100%;
text-align: center;
color: white;
background-color: black;
opacity: 0.5;
}
#user-profile-wrapper .user_profile_picture .preview{
display: inline-block;
position: relative;
max-width: 175px;
max-height: 175px;
overflow: hidden;
}
#user-profile-wrapper .user_profile_picture .actions{
display: inline-block;
vertical-align: top; /*middle;*/
margin-left: 5px;
}
#user-profile-wrapper .user_profile_picture .actions .btn{
display: block;
position: relative;
margin-bottom: 10px;
}
#user-profile-wrapper .user_profile_picture .actions .btn:last-child{
margin-bottom: 0px;
}
#user-profile-wrapper .user_profile_picture .actions .btn.btn_edit{
overflow: hidden;
}
#user-profile-wrapper .user_profile_picture .actions .btn.btn_edit input{
position: absolute;
top: 0px;
left: 0px;
width: 100%;
height: 100%;
opacity: 0;
cursor: pointer;
}
/****************/