webcam support

This commit is contained in:
Roland Gruber 2020-07-24 10:06:22 +02:00
parent 3ad5dcf65a
commit 75120fc25d
7 changed files with 146 additions and 28 deletions

View File

@ -3,6 +3,7 @@ September 2020
- Configuration export and import - Configuration export and import
- Show password prompt when a user with expired password logs into LAM admin interface (requires PHP 7.2) - Show password prompt when a user with expired password logs into LAM admin interface (requires PHP 7.2)
- Better error messages on login when account is expired/deactivated/... - Better error messages on login when account is expired/deactivated/...
- Personal: photo can be uploaded via webcam
- Windows users: group display format can be configured (cn/dn) - Windows users: group display format can be configured (cn/dn)
- LAM Pro: - LAM Pro:
-> Windows: new cron job to send users a summary of their managed groups -> Windows: new cron job to send users a summary of their managed groups

BIN
lam/graphics/webcam.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.4 KiB

View File

@ -3350,6 +3350,8 @@ class htmlLink extends htmlElement {
private $onClick = null; private $onClick = null;
/** show as button */ /** show as button */
private $showAsButton = false; private $showAsButton = false;
/** link id */
private $id;
/** /**
* Constructor. * Constructor.
@ -3399,8 +3401,8 @@ class htmlLink extends htmlElement {
$onClick = ' onclick="' . $this->onClick . '"'; $onClick = ' onclick="' . $this->onClick . '"';
} }
$idAttr = ''; $idAttr = '';
if ($this->showAsButton) { if ($this->showAsButton || !empty($this->id)) {
$id = 'a_' . preg_replace('/[^a-zA-Z0-9_]+/', '_', $this->target); $id = !empty($this->id) ? $this->id : 'a_' . preg_replace('/[^a-zA-Z0-9_]+/', '_', $this->target);
$idAttr = ' id="' . $id . '"'; $idAttr = ' id="' . $id . '"';
} }
$classAttr = ''; $classAttr = '';
@ -3463,6 +3465,15 @@ class htmlLink extends htmlElement {
$this->onClick = htmlspecialchars($event); $this->onClick = htmlspecialchars($event);
} }
/**
* Sets the element id.
*
* @param string $id unique id
*/
public function setId($id) {
$this->id = $id;
}
} }
/** /**

View File

@ -1715,12 +1715,12 @@ class inetOrgPerson extends baseModule implements passwordService {
$container->addField(new htmlAccountPageButton(get_class($this), 'photo', 'upload', _('Upload'))); $container->addField(new htmlAccountPageButton(get_class($this), 'photo', 'upload', _('Upload')));
$container->addVerticalSpacer('1rem'); $container->addVerticalSpacer('1rem');
$webcamContent = new htmlResponsiveRow(); $webcamContent = new htmlResponsiveRow();
$webcamContent->add(new htmlSubTitle(_('Get from webcam')), 12); $webcamContent->add(new htmlSubTitle(_('Use webcam')), 12);
$errorMessage = new htmlStatusMessage('ERROR', ''); $errorMessage = new htmlStatusMessage('ERROR', '');
$errorMessage->setCSSClasses(array('hidden', 'lam-webcam-message')); $errorMessage->setCSSClasses(array('hidden', 'lam-webcam-message'));
$webcamContent->add($errorMessage, 12); $webcamContent->add($errorMessage, 12);
$captureButton = new htmlButton('lam-webcam-capture', _('Start capture')); $captureButton = new htmlButton('lam-webcam-capture', _('Start capture'));
$captureButton->setOnClick('window.lam.tools.startWebcamCapture(event);'); $captureButton->setOnClick('window.lam.tools.webcam.capture(event);');
$webcamContent->add($captureButton, 12, 12, 12, 'text-center'); $webcamContent->add($captureButton, 12, 12, 12, 'text-center');
$video = new htmlVideo('lam-webcam-video'); $video = new htmlVideo('lam-webcam-video');
$video->setCSSClasses(array('hidden')); $video->setCSSClasses(array('hidden'));
@ -1728,7 +1728,7 @@ class inetOrgPerson extends baseModule implements passwordService {
$webcamContent->addVerticalSpacer('0.5rem'); $webcamContent->addVerticalSpacer('0.5rem');
$webcamUploadButton = new htmlButton('uploadWebcam', _('Upload')); $webcamUploadButton = new htmlButton('uploadWebcam', _('Upload'));
$webcamUploadButton->setCSSClasses(array('btn-lam-webcam-upload', 'hidden')); $webcamUploadButton->setCSSClasses(array('btn-lam-webcam-upload', 'hidden'));
$webcamUploadButton->setOnClick('window.lam.tools.startWebcamUpload();'); $webcamUploadButton->setOnClick('window.lam.tools.webcam.upload();');
$webcamContent->add($webcamUploadButton, 12, 12, 12, 'text-center'); $webcamContent->add($webcamUploadButton, 12, 12, 12, 'text-center');
$canvas = new htmlCanvas('lam-webcam-canvas'); $canvas = new htmlCanvas('lam-webcam-canvas');
$canvas->setCSSClasses(array('hidden')); $canvas->setCSSClasses(array('hidden'));
@ -3092,6 +3092,33 @@ class inetOrgPerson extends baseModule implements passwordService {
$uploadStatus = new htmlDiv('inetOrgPersonPhotoUploadStatus', new htmlOutputText('')); $uploadStatus = new htmlDiv('inetOrgPersonPhotoUploadStatus', new htmlOutputText(''));
$uploadStatus->setCSSClasses(array('qq-upload-list')); $uploadStatus->setCSSClasses(array('qq-upload-list'));
$row->add($uploadStatus, 12); $row->add($uploadStatus, 12);
// webcam button
$webcamContent = new htmlResponsiveRow();
$webcamContent->addVerticalSpacer('0.5rem');
$errorMessage = new htmlStatusMessage('ERROR', '');
$errorMessage->setCSSClasses(array('hidden', 'lam-webcam-message'));
$webcamContent->add($errorMessage, 12);
$webcamContent->addVerticalSpacer('0.5rem');
$captureButton = new htmlLink(_('Use webcam'), '#', '../../graphics/webcam.png', true);
$captureButton->setId('btn_lam-webcam-capture');
$captureButton->setOnClick('window.lam.tools.webcam.capture(event);');
$webcamContent->add($captureButton, 12, 12, 12);
$video = new htmlVideo('lam-webcam-video');
$video->setCSSClasses(array('hidden'));
$webcamContent->add($video, 12, 12, 12, 'text-center');
$webcamContent->addVerticalSpacer('1rem');
$webcamUploadButton = new htmlLink(_('Upload'), '#', '../../graphics/up.gif', true);
$webcamUploadButton->setId('btn-lam-webcam-upload');
$webcamUploadButton->setCSSClasses(array('btn-lam-webcam-upload', 'hidden'));
$webcamUploadButton->setOnClick('window.lam.tools.webcam.uploadSelfService(event, "' . getSecurityTokenName()
. '", "' . getSecurityTokenValue() . '", "inetOrgPerson", "user", "' . _('File upload failed!') . '", "inetOrgPersonPhotoUploadContent");');
$webcamContent->add($webcamUploadButton, 12, 12, 12);
$canvas = new htmlCanvas('lam-webcam-canvas');
$canvas->setCSSClasses(array('hidden'));
$webcamContent->add($canvas, 12);
$webcamDiv = new htmlDiv('lam_webcam_div', $webcamContent, array('hidden'));
$webcamContent->addVerticalSpacer('1rem');
$row->add($webcamDiv, 12);
return $row; return $row;
} }
@ -3125,6 +3152,7 @@ class inetOrgPerson extends baseModule implements passwordService {
if (data.success) { if (data.success) {
if (data.html) { if (data.html) {
jQuery(\'#inetOrgPersonPhotoUploadContent\').html(data.html); jQuery(\'#inetOrgPersonPhotoUploadContent\').html(data.html);
window.lam.tools.webcam.init();
} }
} }
else { else {
@ -3149,6 +3177,7 @@ class inetOrgPerson extends baseModule implements passwordService {
function inetOrgPersonDeletePhotoHandleReply(data) { function inetOrgPersonDeletePhotoHandleReply(data) {
if (data.errorsOccured == "false") { if (data.errorsOccured == "false") {
jQuery(\'#inetOrgPersonPhotoUploadContent\').html(data.html); jQuery(\'#inetOrgPersonPhotoUploadContent\').html(data.html);
window.lam.tools.webcam.init();
} }
else { else {
alert(data.errormessage); alert(data.errormessage);
@ -3820,13 +3849,20 @@ class inetOrgPerson extends baseModule implements passwordService {
*/ */
private function ajaxUploadPhoto() { private function ajaxUploadPhoto() {
$result = array('success' => true); $result = array('success' => true);
if (!isset($_FILES['qqfile']) || ($_FILES['qqfile']['size'] < 100)) { if ((!isset($_FILES['qqfile']) || ($_FILES['qqfile']['size'] < 100)) && empty($_POST['webcamData'])) {
$result = array('error' => _('No file received.')); $result = array('error' => _('No file received.'));
} }
else { else {
$handle = fopen($_FILES['qqfile']['tmp_name'], "r"); if (empty($_POST['webcamData'])) {
$data = fread($handle, 100000000); $handle = fopen($_FILES['qqfile']['tmp_name'], "r");
fclose($handle); $data = fread($handle, 100000000);
fclose($handle);
}
else {
$data = $_POST['webcamData'];
$data = str_replace('data:image/png;base64,', '', $data);
$data = base64_decode($data);
}
try { try {
include_once dirname(__FILE__) . '/../imageutils.inc'; include_once dirname(__FILE__) . '/../imageutils.inc';
$imageManipulator = ImageManipulationFactory::getImageManipulator($data); $imageManipulator = ImageManipulationFactory::getImageManipulator($data);

View File

@ -314,11 +314,6 @@ table.collapse {
font-weight: bold; font-weight: bold;
} }
#lam-webcam-video {
max-width: 200px;
max-height: 200px;
}
/** buttons */ /** buttons */
.saveButton { .saveButton {
background-image: url(../graphics/save.png) !important; background-image: url(../graphics/save.png) !important;

View File

@ -193,6 +193,11 @@ table.responsive-table td {
padding: 5px 5px 5px 5px; padding: 5px 5px 5px 5px;
} }
#lam-webcam-video {
max-width: 200px;
max-height: 200px;
}
} }
/* tablet */ /* tablet */
@ -222,6 +227,11 @@ table.responsive-table td {
padding: 5px 20px 5px 20px; padding: 5px 20px 5px 20px;
} }
#lam-webcam-video {
max-width: 300px;
max-height: 300px;
}
} }
/* desktop */ /* desktop */
@ -255,4 +265,9 @@ table.responsive-table td {
padding: 5px 20px 5px 20px; padding: 5px 20px 5px 20px;
} }
#lam-webcam-video {
max-width: 400px;
max-height: 400px;
}
} }

View File

@ -934,10 +934,12 @@ window.lam.tools.setInitialFocus = function() {
jQuery('.lam-initial-focus').focus(); jQuery('.lam-initial-focus').focus();
}; };
window.lam.tools.webcam = window.lam.tools.webcam || {};
/** /**
* Initializes the webcam capture. * Initializes the webcam capture.
*/ */
window.lam.tools.initWebcamCapture = function() { window.lam.tools.webcam.init = function() {
var contentDiv = jQuery('#lam_webcam_div'); var contentDiv = jQuery('#lam_webcam_div');
if (contentDiv.length === 0) { if (contentDiv.length === 0) {
return; return;
@ -957,7 +959,7 @@ window.lam.tools.initWebcamCapture = function() {
/** /**
* Starts the webcam capture. * Starts the webcam capture.
*/ */
window.lam.tools.startWebcamCapture = function(event) { window.lam.tools.webcam.capture = function(event) {
event.preventDefault(); event.preventDefault();
var video = document.getElementById('lam-webcam-video'); var video = document.getElementById('lam-webcam-video');
var msg = jQuery('.lam-webcam-message'); var msg = jQuery('.lam-webcam-message');
@ -988,28 +990,86 @@ window.lam.tools.startWebcamCapture = function(event) {
/** /**
* Starts the webcam upload. * Starts the webcam upload.
*/ */
window.lam.tools.startWebcamUpload = function() { window.lam.tools.webcam.upload = function() {
var form = jQuery('#lam-webcam-canvas').closest('form');
canvasData = window.lam.tools.webcam.prepareData();
var canvasDataInput = jQuery("<input></input>");
canvasDataInput.attr('name', 'webcamData');
canvasDataInput.attr('id', 'webcamData');
canvasDataInput.attr('type', 'hidden');
canvasDataInput.attr('value', canvasData);
form.append(canvasDataInput);
form.submit();
return true;
}
/**
* Starts the webcam upload.
*
* @param event click event
* @param tokenName security token name
* @param tokenValue security token value
* @param moduleName module name
* @param scope account type
* @param uploadErrorMessage error message if upload fails
* @param contentId id of content to replace
*/
window.lam.tools.webcam.uploadSelfService = function(event, tokenName, tokenValue, moduleName, scope, uploadErrorMessage, contentId) {
event.preventDefault();
var msg = jQuery('.lam-webcam-message');
canvasData = window.lam.tools.webcam.prepareData();
var data = {
webcamData: canvasData
};
data[tokenName] = tokenValue;
jQuery.ajax({
url: '../misc/ajax.php?selfservice=1&action=ajaxPhotoUpload'
+ '&module=' + moduleName + '&scope=' + scope,
method: 'POST',
data: data
})
.done(function(jsonData) {
if (jsonData.success) {
if (jsonData.html) {
jQuery('#' + contentId).html(jsonData.html);
window.lam.tools.webcam.init();
}
return false;
}
else if (jsonData.error) {
msg.find('.statusTitle').text(jsonData.error);
msg.show();
}
})
.fail(function() {
msg.find('.statusTitle').text(errorMessage);
msg.show();
});
jQuery('#btn_lam-webcam-capture').show();
jQuery('.btn-lam-webcam-upload').hide();
return false;
}
/**
* Starts the webcam upload.
*
* @return webcam data as string
*/
window.lam.tools.webcam.prepareData = function() {
var canvas = document.getElementById('lam-webcam-canvas'); var canvas = document.getElementById('lam-webcam-canvas');
var video = document.getElementById('lam-webcam-video'); var video = document.getElementById('lam-webcam-video');
var form = jQuery('#lam-webcam-canvas').closest('form');
canvas.setAttribute('width', video.videoWidth); canvas.setAttribute('width', video.videoWidth);
canvas.setAttribute('height', video.videoHeight); canvas.setAttribute('height', video.videoHeight);
var context = canvas.getContext('2d'); var context = canvas.getContext('2d');
context.drawImage(video, 0, 0, video.videoWidth, video.videoHeight); context.drawImage(video, 0, 0, video.videoWidth, video.videoHeight);
var canvasData = canvas.toDataURL("image/png"); var canvasData = canvas.toDataURL("image/png");
var canvasDataInput = jQuery("<input></input>");
canvasDataInput.attr('name', 'webcamData');
canvasDataInput.attr('type', 'hidden');
canvasDataInput.attr('value', canvasData);
video.pause(); video.pause();
window.lam.tools.webcamStream.getTracks().forEach(function(track) { window.lam.tools.webcamStream.getTracks().forEach(function(track) {
track.stop(); track.stop();
}); });
form.append(canvasDataInput); jQuery(canvas).hide();
jQuery(canvas).remove(); jQuery(video).hide();
jQuery(video).remove(); return canvasData;
form.submit();
return true;
} }
window.lam.tools.schema = window.lam.tools.schema || {}; window.lam.tools.schema = window.lam.tools.schema || {};
@ -1866,7 +1926,7 @@ jQuery(document).ready(function() {
window.lam.tools.addSavedSelectListener(); window.lam.tools.addSavedSelectListener();
window.lam.tools.activateTab(); window.lam.tools.activateTab();
window.lam.tools.setInitialFocus(); window.lam.tools.setInitialFocus();
window.lam.tools.initWebcamCapture(); window.lam.tools.webcam.init();
window.lam.tools.schema.select(); window.lam.tools.schema.select();
window.lam.html.activateLightboxes(); window.lam.html.activateLightboxes();
window.lam.html.preventEnter(); window.lam.html.preventEnter();