From 06a1119bf50c1d813df77223b5327f61c42021ae Mon Sep 17 00:00:00 2001 From: Jared Hancock <jared@osticket.com> Date: Fri, 27 Feb 2015 16:48:32 -0600 Subject: [PATCH] lock: Sync lockCode input with lock renew Also, add warning popup when lock is about to expire and allow the user to attempt to renew the lock. Also, connect the keyup callback for redactor to the autoLock.handleEvent for greater update of the lock, and also deadband the lock to every 10 seconds. --- include/ajax.tickets.php | 5 +- include/class.lock.php | 15 ++--- include/staff/footer.inc.php | 2 +- include/staff/ticket-view.inc.php | 4 +- js/redactor-osticket.js | 12 +++- scp/js/scp.js | 2 + scp/js/ticket.js | 106 ++++++++++++++++++------------ scp/tickets.php | 5 +- 8 files changed, 91 insertions(+), 60 deletions(-) diff --git a/include/ajax.tickets.php b/include/ajax.tickets.php index e13128529..721da4403 100644 --- a/include/ajax.tickets.php +++ b/include/ajax.tickets.php @@ -122,7 +122,10 @@ class TicketsAjaxAPI extends AjaxController { return $this->json_encode(array('id'=>0, 'retry'=>true)); } - return $this->json_encode(array('id'=>$lock->getId(), 'time'=>$lock->getTime())); + return $this->json_encode(array( + 'id'=>$lock->getId(), 'time'=>$lock->getTime(), + 'code' => $lock->getCode() + )); } function renewLock($tid, $id) { diff --git a/include/class.lock.php b/include/class.lock.php index e4870d465..acbe1365e 100644 --- a/include/class.lock.php +++ b/include/class.lock.php @@ -38,13 +38,6 @@ class Lock extends VerySimpleModel { ), ); - var $expiretime; - - function __onload() { - if (isset($this->expire)) - $this->expiretime = strtotime($this->expire); - } - function getId() { return $this->lock_id; } @@ -62,16 +55,16 @@ class Lock extends VerySimpleModel { } function getExpireTime() { - return $this->expire; + return strtotime($this->expire); } //Get remaiming time before the lock expires function getTime() { - return $this->isExpired()?0:($this->expiretime-time()); + return $this->isExpired()?0:($this->getExpireTime()-time()); } //Should we be doing realtime check here? (Ans: not really....expiretime is local & based on loadtime) function isExpired() { - return (time()>$this->expiretime); + return (time()>$this->getExpireTime()); } function getCode() { @@ -89,7 +82,7 @@ class Lock extends VerySimpleModel { SqlFunction::NOW(), SqlInterval::MINUTE($lockTime) ); - return $this->save(); + return $this->save(true); } //release aka delete a lock. diff --git a/include/staff/footer.inc.php b/include/staff/footer.inc.php index 5abc09973..778fbd045 100644 --- a/include/staff/footer.inc.php +++ b/include/staff/footer.inc.php @@ -34,7 +34,7 @@ if(is_object($thisstaff) && $thisstaff->isStaff()) { ?> <hr style="margin-top:3em"/> <p class="full-width"> <span class="buttons pull-right"> - <input type="button" value="<?php echo __('OK');?>" class="close"> + <input type="button" value="<?php echo __('OK');?>" class="close ok"> </span> </p> <div class="clear"></div> diff --git a/include/staff/ticket-view.inc.php b/include/staff/ticket-view.inc.php index 0560eaf00..572fc90c6 100644 --- a/include/staff/ticket-view.inc.php +++ b/include/staff/ticket-view.inc.php @@ -701,7 +701,7 @@ $tcount = $ticket->getThreadEntries($types)->count(); echo $ticket->getId(); ?>#note" name="note" method="post" enctype="multipart/form-data"> <?php csrf_token(); ?> <input type="hidden" name="id" value="<?php echo $ticket->getId(); ?>"> - <input type="hidden" name="locktime" value="<?php echo $cfg->getLockTime(); ?>"> + <input type="hidden" name="locktime" value="<?php echo $cfg->getLockTime() * 60; ?>"> <input type="hidden" name="a" value="postnote"> <input type="hidden" name="lockCode" value="<?php echo $ticket->getLock()->getCode(); ?>"> <table width="100%" border="0" cellspacing="0" cellpadding="3"> @@ -1065,7 +1065,7 @@ $(function() { clearInterval(setLock); autoLock.setLock({ id:<?php echo $lock->getId(); ?>, - time: <?php echo $cfg->getLockTime(); ?>}, 'acquire'); + time: <?php echo $cfg->getLockTime() * 60; ?>}, 'acquire'); }, 50); }(); <?php } ?> diff --git a/js/redactor-osticket.js b/js/redactor-osticket.js index 39ffaad30..ac1ca3bef 100644 --- a/js/redactor-osticket.js +++ b/js/redactor-osticket.js @@ -209,6 +209,16 @@ RedactorPlugins.signature = function() { } }; +RedactorPlugins.autolock = function() { + return { + init: function() { + var code = this.$box.closest('form').find('[name=lockCode]'); + if ($.autoLock && code.length) + this.opts.keydownCallback = $.autoLock.handleEvent; + } + }; +} + /* Redactor richtext init */ $(function() { var captureImageSizes = function(html) { @@ -245,7 +255,7 @@ $(function() { 'focus': false, 'plugins': el.hasClass('no-bar') ? ['imagepaste','imagemanager','definedlinks'] - : ['imagepaste','imagemanager','imageannotate','table','video','definedlinks'], + : ['imagepaste','imagemanager','imageannotate','table','video','definedlinks','autolock'], 'imageUpload': 'tbd', 'imageManagerJson': 'ajax.php/draft/images/browse', 'syncBeforeCallback': captureImageSizes, diff --git a/scp/js/scp.js b/scp/js/scp.js index edb2cf0c0..44a995235 100644 --- a/scp/js/scp.js +++ b/scp/js/scp.js @@ -617,6 +617,8 @@ $.sysAlert = function (title, msg, cb) { $('#title', $dialog).html(title); $('#body', $dialog).html(msg); $dialog.show(); + if (cb) + $dialog.find('input.ok.close').click(cb); } else { alert(msg); } diff --git a/scp/js/ticket.js b/scp/js/ticket.js index 37b828a17..708267996 100644 --- a/scp/js/ticket.js +++ b/scp/js/ticket.js @@ -17,12 +17,14 @@ var autoLock = { // Defaults lockId: 0, + lockCode: '', timerId: 0, lasteventTime: 0, + lastcheckTime: 0, lastattemptTime: 0, acquireTime: 0, renewTime: 0, - renewFreq: 0, //renewal frequency in seconds...based on returned lock time. + renewFreq: 10000, //renewal frequency in seconds...based on returned lock time. time: 0, lockAttempts: 0, //Consecutive lock attempt errors maxattempts: 2, //Maximum failed lock attempts before giving up. @@ -53,16 +55,6 @@ var autoLock = { //Incoming event... handleEvent: function(e) { - if(!autoLock.lockId) { - var now = new Date().getTime(); - //Retry every 5 seconds?? - if(autoLock.retry && (!autoLock.lastattemptTime || (now-autoLock.lastattemptTime)>5000)) { - autoLock.acquireLock(e,autoLock.warn); - autoLock.lastattemptTime=new Date().getTime(); - } - }else{ - autoLock.renewLock(e); - } if(!autoLock.lasteventTime) { //I hate nav away warnings..but $(document).on('pjax:beforeSend.changed', function(e) { @@ -72,8 +64,23 @@ var autoLock = { return __("Any changes or info you've entered will be discarded!"); }); } + // Handle events only every few seconds + var now = new Date().getTime(), + renewFreq = autoLock.renewFreq; + + if (autoLock.lasteventTime && now - autoLock.lasteventTime < renewFreq) + return; + + autoLock.lasteventTime = now; + + if (!autoLock.lockId) { + // Retry every 5 seconds?? + if (autoLock.retry) + autoLock.acquireLock(e,autoLock.warn); + } else { + autoLock.renewLock(e); + } - autoLock.lasteventTime=new Date().getTime(); }, //Watch activity on individual form. @@ -126,7 +133,6 @@ var autoLock = { void(autoLock.lockTime=parseInt($(':input[name=locktime]',fObj).val())); autoLock.watchDocument(); - autoLock.resetTimer(); autoLock.addEvent(window,'unload',autoLock.releaseLock,true); //Release lock regardless of any activity. }, @@ -168,9 +174,7 @@ var autoLock = { success: function(lock){ autoLock.setLock(lock,'acquire',warn); } - }) - .done(function() { }) - .fail(function() { }); + }); } return autoLock.lockId; @@ -179,22 +183,25 @@ var autoLock = { //Renewal only happens on form activity.. renewLock: function(e) { - if(!autoLock.lockId) { return false; } + if (!autoLock.lockId) + return false; - var now= new Date().getTime(); - if(!autoLock.lastcheckTime || (now-autoLock.lastcheckTime)>=(autoLock.renewFreq*1000)){ - $.ajax({ - type: 'POST', - url: 'ajax.php/tickets/'+autoLock.tid+'/lock/'+autoLock.lockId+'/renew', - dataType: 'json', - cache: false, - success: function(lock){ - autoLock.setLock(lock,'renew',autoLock.warn); - } - }) - .done(function() { }) - .fail(function() { }); - } + var now = new Date().getTime(), + renewFreq = autoLock.renewFreq; + + if (autoLock.lastcheckTime && now - autoLock.lastcheckTime < renewFreq) + return; + + autoLock.lastcheckTime = now; + $.ajax({ + type: 'POST', + url: 'ajax.php/tickets/'+autoLock.tid+'/lock/'+autoLock.lockId+'/renew', + dataType: 'json', + cache: false, + success: function(lock){ + autoLock.setLock(lock,'renew',autoLock.warn); + } + }); }, releaseLock: function(e) { @@ -209,22 +216,23 @@ var autoLock = { success: function() { autoLock.lockId = 0; } - }) - .done(function() { }) - .fail(function() { }); + }); }, setLock: function(lock, action, warn) { var warn = warn || false; - if(!lock) return false; + if (!lock) + return false; - if(lock.id) { - autoLock.renewFreq=lock.time?(lock.time/2):30; - autoLock.lastcheckTime=new Date().getTime(); - } autoLock.lockId=lock.id; //override the lockid. + if (lock.code) { + autoLock.lockCode = lock.code; + // Update the lock code for the upcoming POST + var el = $('input[name=lockCode]').val(lock.code); + } + switch(action){ case 'renew': if(!lock.id && lock.retry) { @@ -242,6 +250,10 @@ var autoLock = { } break; } + + if (lock.id && lock.time) { + autoLock.resetTimer((lock.time - 10) * 1000); + } }, discardWarning: function(e) { @@ -250,17 +262,25 @@ var autoLock = { //TODO: Monitor events and elapsed time and warn user when the lock is about to expire. monitorEvents: function() { - // warn user when lock is about to expire??; - //autoLock.resetTimer(); + $.sysAlert( + __('Your lock is expiring soon'), + __('The lock you hold on this ticket will expire soon. Would you like to renew the lock?'), + function() { + autoLock.renewLock(); + } + ); }, clearTimer: function() { clearTimeout(autoLock.timerId); }, - resetTimer: function() { + resetTimer: function(time) { clearTimeout(autoLock.timerId); - autoLock.timerId=setTimeout(function () { autoLock.monitorEvents() },30000); + autoLock.timerId = setTimeout( + function () { autoLock.monitorEvents(); }, + time || 30000 + ); } }; $.autoLock = autoLock; diff --git a/scp/tickets.php b/scp/tickets.php index 0a57e94c5..620f8cfc4 100644 --- a/scp/tickets.php +++ b/scp/tickets.php @@ -76,7 +76,10 @@ if($_POST && !$errors): elseif ($lock->getStaffId()!=$thisstaff->getId()) { $errors['err'] = __('Action Denied. Ticket is locked by someone else!'); } - elseif ($lock->getCode() != $_POST['lockCode']) { + // Attempt to renew the lock if possible + elseif (($lock->isExpired() && !$lock->renew()) + ||($lock->getCode() != $_POST['lockCode']) + ) { $errors['err'] = __('Your lock has expired. Please try again'); } -- GitLab