]> www.vanbest.org Git - motioneye-debian/commitdiff
added a logout button
authorCalin Crisan <ccrisan@gmail.com>
Sun, 31 Aug 2014 13:09:01 +0000 (16:09 +0300)
committerCalin Crisan <ccrisan@gmail.com>
Sun, 31 Aug 2014 13:09:40 +0000 (16:09 +0300)
src/handlers.py
static/css/main.css
static/img/logout.svg [new file with mode: 0644]
static/js/main.js
templates/main.html

index d208de8af342d8896820f3281e6653ef18df6923..6603367e1245d8c68d35e97c26644cb278a0339a 100644 (file)
@@ -112,12 +112,10 @@ class BaseHandler(RequestHandler):
             def wrapper(self, *args, **kwargs):
                 user = self.current_user
                 if (user is None) or (user != 'admin' and admin):
-                    realm = 'motionEye admin authentication' if admin else 'motionEye authentication'
-                    
                     self.set_status(401)
                     if prompt:
                         self.set_header('WWW-Authenticate', 'basic realm="%(realm)s"' % {
-                                'realm': realm})
+                                'realm': 'motionEye authentication'})
                         
                     return self.finish('Authentication required.')
                 
@@ -145,6 +143,9 @@ class NotFoundHandler(BaseHandler):
 class MainHandler(BaseHandler):
     @BaseHandler.auth()
     def get(self):
+        if self.get_argument('logout', None):
+            return self.redirect('/')
+        
         timezones = []
         if settings.LOCAL_TIME_FILE:
             import pytz
index 1a8d24fa9aef8fa6a177cb513a6d21aacbb39712..33eff945d1c198f4f943d6767fc403ec47edcb4d 100644 (file)
@@ -125,6 +125,14 @@ div.button.settings-button {
     height: 48px;
 }
 
+div.button.logout-button {
+    margin: 1px;
+    vertical-align: middle;
+    background-image: url(../img/logout.svg);
+    width: 48px;
+    height: 48px;
+}
+
 div.button.rem-camera-button {
     display: none;
     margin: 1px;
@@ -287,7 +295,7 @@ div.settings-item-separator {
     margin: 5px 0px;
 }
 
-select.video-device {
+#cameraSelect {
     display: none;
     padding: 4px 1.5em 4px 4px;
     vertical-align: middle;
@@ -352,10 +360,14 @@ div.update-button:ACTIVE {
     background-color: #317CAD;
 }
 
-div.settings-top-bar.open select.video-device {
+div.settings-top-bar.open #cameraSelect {
     display: inline;
 }
 
+div.settings-top-bar.open div.logout-button {
+    display: none;
+}
+
 div.check-box.section {
     margin: 0px;
     float: left;
diff --git a/static/img/logout.svg b/static/img/logout.svg
new file mode 100644 (file)
index 0000000..cda383d
--- /dev/null
@@ -0,0 +1,56 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+
+<svg
+   xmlns:dc="http://purl.org/dc/elements/1.1/"
+   xmlns:cc="http://creativecommons.org/ns#"
+   xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+   xmlns:svg="http://www.w3.org/2000/svg"
+   xmlns="http://www.w3.org/2000/svg"
+   xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+   xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+   id="svg2"
+   xml:space="preserve"
+   viewBox="0 0 64 64"
+   version="1.1"
+   inkscape:version="0.48.5 r10040"
+   width="100%"
+   height="100%"
+   sodipodi:docname="logout.svg"><defs
+     id="defs8" /><sodipodi:namedview
+     pagecolor="#666666"
+     bordercolor="#666666"
+     borderopacity="1"
+     objecttolerance="10"
+     gridtolerance="10"
+     guidetolerance="10"
+     inkscape:pageopacity="0"
+     inkscape:pageshadow="2"
+     inkscape:window-width="1077"
+     inkscape:window-height="782"
+     id="namedview6"
+     showgrid="false"
+     inkscape:zoom="5.1943359"
+     inkscape:cx="24.357877"
+     inkscape:cy="26.948648"
+     inkscape:window-x="258"
+     inkscape:window-y="33"
+     inkscape:window-maximized="0"
+     inkscape:current-layer="svg2" /><metadata
+     id="metadata8"><rdf:RDF><cc:Work
+         rdf:about=""><dc:format>image/svg+xml</dc:format><dc:type
+           rdf:resource="http://purl.org/dc/dcmitype/StillImage" /><dc:title /></cc:Work></rdf:RDF></metadata><path
+     sodipodi:nodetypes="ssccccccsccccc"
+     style="fill:#3498db;fill-opacity:1"
+     id="path3"
+     d="m 21.267338,42.732446 c 3.741665,3.741354 9.807034,3.741354 13.548699,0 2.776803,-2.77657 3.490747,-6.8354 2.144089,-10.273324 l 5.763494,-5.763661 c 1.49694,-1.496847 1.496489,-3.922567 0,-5.419481 -1.496034,-1.496525 -3.922182,-1.496525 -5.419118,0 l -5.763946,5.764034 c -3.437493,-1.346908 -7.495965,-0.633431 -10.27367,2.144832 -3.740312,3.740676 -3.740765,9.806754 4.52e-4,13.5476 z m 6.435428,-6.434662 c 0.898073,0.897093 0.898073,2.353493 0,3.2516 -0.897621,0.897939 -2.35394,0.897939 -3.251561,0 -0.89717,-0.898107 -0.89717,-2.354507 0,-3.2516 0.897621,-0.898107 2.353489,-0.898107 3.251561,0 z"
+     inkscape:connector-curvature="0" /><path
+     sodipodi:type="arc"
+     style="fill:none;stroke:#3498db;stroke-width:1.80392128;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
+     id="path4097"
+     sodipodi:cx="16"
+     sodipodi:cy="16.5"
+     sodipodi:rx="14"
+     sodipodi:ry="12.5"
+     d="m 30,16.5 a 14,12.5 0 1 1 -28,0 14,12.5 0 1 1 28,0 z"
+     transform="matrix(1.5714286,0,0,1.7600001,6.8571426,2.9599978)" /></svg>
\ No newline at end of file
index 0dfcd8600b6880d5f732b37228e176ab27807c39..7cabcd067251ef3cd79ce5128d0b6feb3e6003a3 100644 (file)
@@ -38,6 +38,28 @@ function showErrorMessage(message) {
     showPopupMessage(message, 'error');
 }
 
+function doLogout() {
+    $.ajax({
+        url: '/',
+        username: ' ',
+        password: 'logout' + new Date().getTime(),
+        complete: function () {
+            window.location.href = '/?logout=true';
+        }
+    });
+    
+    /* IE is always a breed apart */
+    if (document.execCommand) {
+        try {
+            document.execCommand('ClearAuthenticationCache');
+        }
+        catch (e) {
+        }
+
+        window.location.href = '/?logout=true';
+    }
+}
+
 Object.keys = Object.keys || (function () {
     var hasOwnProperty = Object.prototype.hasOwnProperty;
     var hasDontEnumBug = !({toString: null}).propertyIsEnumerable('toString');
@@ -302,12 +324,12 @@ function initUI() {
     });
     
     /* fetch & push handlers */
-    $('#videoDeviceSelect').focus(function () {
+    $('#cameraSelect').focus(function () {
         /* remember the previously selected index */
         this._prevSelectedIndex = this.selectedIndex;
     
     }).change(function () {
-        if ($('#videoDeviceSelect').val() === 'add') {
+        if ($('#cameraSelect').val() === 'add') {
             runAddCameraDialog();
             this.selectedIndex = this._prevSelectedIndex;
         }
@@ -350,6 +372,9 @@ function initUI() {
     
     /* remove camera button */
     $('div.button.rem-camera-button').click(doRemCamera);
+    
+    /* logout button */
+    $('div.button.logout-button').click(doLogout);
 }
 
 
@@ -357,7 +382,7 @@ function initUI() {
 
 function openSettings(cameraId) {
     if (cameraId != null) {
-        $('#videoDeviceSelect').val(cameraId).change();
+        $('#cameraSelect').val(cameraId).change();
     }
     
     $('div.settings').addClass('open').removeClass('closed');
@@ -380,7 +405,7 @@ function isSettingsOpen() {
 }
 
 function updateConfigUi() {
-    var objs = $('tr.settings-item, div.advanced-setting, table.advanced-setting, div.settings-section-title, table.settings').not('.rpi');
+    var objs = $('tr.settings-item, div.advanced-setting, table.advanced-setting, div.settings-section-title, table.settings');
     
     function markHide() {
         this._hide = true;
@@ -410,7 +435,7 @@ function updateConfigUi() {
         $('#wifiSwitch').parent().next('table.settings').find('tr.settings-item').each(markHide);
     }
     
-    if ($('#videoDeviceSelect').find('option').length < 2) { /* no camera configured */
+    if ($('#cameraSelect').find('option').length < 2) { /* no camera configured */
         $('#videoDeviceSwitch').parent().each(markHide);
         $('#videoDeviceSwitch').parent().nextAll('div.settings-section-title, table.settings').each(markHide);
     }
@@ -577,7 +602,7 @@ function updateConfigUi() {
     });
     
     /* select the first option for the selects with no current selection */
-    $('div.settings').find('select').each(function () {
+    $('div.settings').find('select').not('#cameraSelect').each(function () {
         if (this.selectedIndex === -1) {
             this.selectedIndex = 0;
         }
@@ -1153,7 +1178,7 @@ function doApply() {
         Object.keys(pushConfigs).forEach(function (key) {
             var config = pushConfigs[key];
             if (config.key !== 'main') {
-                $('#videoDeviceSelect').find('option[value=' + key + ']').html(config.name);
+                $('#cameraSelect').find('option[value=' + key + ']').html(config.name);
             }
             
             $('#camera' + key).find('span.camera-name').html(config.name);
@@ -1170,13 +1195,13 @@ function doRemCamera() {
         return runAlertDialog('Please apply the modified settings first!');
     }
     
-    var cameraId = $('#videoDeviceSelect').val();
+    var cameraId = $('#cameraSelect').val();
     if (cameraId == null || cameraId === 'add') {
         runAlertDialog('No camera to remove!');
         return;
     }
 
-    var deviceName = $('#videoDeviceSelect').find('option[value=' + cameraId + ']').text();
+    var deviceName = $('#cameraSelect').find('option[value=' + cameraId + ']').text();
     
     runConfirmDialog('Remove camera ' + deviceName + '?', function () {
         /* disable further refreshing of this camera */
@@ -1263,25 +1288,25 @@ function fetchCurrentConfig(onFetch) {
             var i, cameras = data.cameras;
             
             if (user === 'admin') {
-                var videoDeviceSelect = $('#videoDeviceSelect');
-                videoDeviceSelect.html('');
+                var cameraSelect = $('#cameraSelect');
+                cameraSelect.html('');
                 for (i = 0; i < cameras.length; i++) {
                     var camera = cameras[i];
-                    videoDeviceSelect.append('<option value="' + camera['id'] + '">' + camera['name'] + '</option>');
+                    cameraSelect.append('<option value="' + camera['id'] + '">' + camera['name'] + '</option>');
                 }
-                videoDeviceSelect.append('<option value="add">add camera...</option>');
+                cameraSelect.append('<option value="add">add camera...</option>');
                 
                 var enabledCameras = cameras.filter(function (camera) {return camera['enabled'];});
                 if (enabledCameras.length > 0) { /* prefer the first enabled camera */
-                    videoDeviceSelect[0].selectedIndex = cameras.indexOf(enabledCameras[0]);
+                    cameraSelect[0].selectedIndex = cameras.indexOf(enabledCameras[0]);
                     fetchCurrentCameraConfig();
                 }
                 else if (cameras.length) { /* a disabled camera */
-                    videoDeviceSelect[0].selectedIndex = 0;
+                    cameraSelect[0].selectedIndex = 0;
                     fetchCurrentCameraConfig();
                 }
                 else { /* no camera at all */
-                    videoDeviceSelect[0].selectedIndex = -1;
+                    cameraSelect[0].selectedIndex = -1;
                 }
 
                 updateConfigUi();
@@ -1322,7 +1347,7 @@ function fetchCurrentConfig(onFetch) {
 }
 
 function fetchCurrentCameraConfig(onFetch) {
-    var cameraId = $('#videoDeviceSelect').val();
+    var cameraId = $('#cameraSelect').val();
     if (cameraId != null) {
         ajax('GET', '/config/' + cameraId + '/get/', null, function (data) {
             if (data == null || data.error) {
@@ -1356,7 +1381,7 @@ function pushMainConfig() {
 
 function pushCameraConfig() {
     var cameraConfig = cameraUi2Dict();
-    var cameraId = $('#videoDeviceSelect').val();
+    var cameraId = $('#cameraSelect').val();
 
     pushConfigs[cameraId] = cameraConfig;
     if (!isApplyVisible()) {
@@ -1371,7 +1396,7 @@ function pushCameraConfig() {
 }
 
 function pushPreview(control) {
-    var cameraId = $('#videoDeviceSelect').val();
+    var cameraId = $('#cameraSelect').val();
     
     var brightness = $('#brightnessSlider').val();
     var contrast= $('#contrastSlider').val();
@@ -1566,7 +1591,7 @@ function runAddCameraDialog() {
                 '</tr>' +
                 '<tr class="motioneye netcam">' +
                     '<td class="dialog-item-label"><span class="dialog-item-label">Camera</span></td>' +
-                    '<td class="dialog-item-value"><select class="styled" id="cameraSelect"></select><span id="cameraMsgLabel"></span></td>' +
+                    '<td class="dialog-item-value"><select class="styled" id="addCameraSelect"></select><span id="cameraMsgLabel"></span></td>' +
                     '<td><span class="help-mark" title="the camera you wish to add to motionEye">?</span></td>' +
                 '</tr>' +
             '</table>');
@@ -1576,14 +1601,14 @@ function runAddCameraDialog() {
     var urlEntry = content.find('#urlEntry');
     var usernameEntry = content.find('#usernameEntry');
     var passwordEntry = content.find('#passwordEntry');
-    var cameraSelect = content.find('#cameraSelect');
+    var addCameraSelect = content.find('#addCameraSelect');
     var cameraMsgLabel = content.find('#cameraMsgLabel');
     
     /* make validators */
     makeUrlValidator(urlEntry, true);
     makeTextValidator(usernameEntry, false);
     makeTextValidator(deviceSelect, false);
-    makeComboValidator(cameraSelect, true);
+    makeComboValidator(addCameraSelect, true);
     
     /* ui interaction */
     content.find('tr.motioneye, tr.netcam').css('display', 'none');
@@ -1592,15 +1617,15 @@ function runAddCameraDialog() {
         content.find('tr.motioneye, tr.netcam').css('display', 'none');
         if (deviceSelect.val() == 'motioneye') {
             content.find('tr.motioneye').css('display', 'table-row');
-            cameraSelect.hide();
+            addCameraSelect.hide();
         }
         else if (deviceSelect.val() == 'netcam') {
             content.find('tr.netcam').css('display', 'table-row');
-            cameraSelect.hide();
+            addCameraSelect.hide();
         }
         
         updateModalDialogPosition();
-        cameraSelect.html('');
+        addCameraSelect.html('');
         
         /* re-validate all the validators */
         content.find('.validator').each(function () {
@@ -1621,7 +1646,7 @@ function runAddCameraDialog() {
         var valid = true;
         var query = content.find('input, select');
         if (!includeCameraSelect) {
-            query = query.not('#cameraSelect');
+            query = query.not('#addCameraSelect');
         }
         query.each(function () {
             if (this.invalid) {
@@ -1669,9 +1694,9 @@ function runAddCameraDialog() {
     function fetchRemoteCameras() {
         var progress = $('<div style="text-align: center; margin: 2px;"><img src="' + staticUrl + 'img/small-progress.gif"></div>');
         
-        cameraSelect.hide();
-        cameraSelect.parent().find('div').remove(); /* remove any previous progress div */
-        cameraSelect.before(progress);
+        addCameraSelect.hide();
+        addCameraSelect.parent().find('div').remove(); /* remove any previous progress div */
+        addCameraSelect.before(progress);
         
         var data = splitUrl(urlEntry.val());
         data.username = usernameEntry.val();
@@ -1690,17 +1715,17 @@ function runAddCameraDialog() {
                 return;
             }
             
-            cameraSelect.html('');
+            addCameraSelect.html('');
             
             if (data.error || !data.cameras) {
                 return;
             }
 
             data.cameras.forEach(function (info) {
-                cameraSelect.append('<option value="' + info.id + '">' + info.name + '</option>');
+                addCameraSelect.append('<option value="' + info.id + '">' + info.name + '</option>');
             });
             
-            cameraSelect.show();
+            addCameraSelect.show();
         });
     }
     
@@ -1749,7 +1774,7 @@ function runAddCameraDialog() {
                     data.proto = 'motioneye';
                     data.username = usernameEntry.val();
                     data.password = passwordEntry.val();
-                    data.remote_camera_id = cameraSelect.val();
+                    data.remote_camera_id = addCameraSelect.val();
                 }
                 else if (deviceSelect.val() == 'netcam') {
                     data = splitUrl(urlEntry.val());
@@ -1770,9 +1795,9 @@ function runAddCameraDialog() {
                     }
                     
                     endProgress();
-                    var addCameraOption = $('#videoDeviceSelect').find('option[value=add]');
+                    var addCameraOption = $('#addCameraSelect').find('option[value=add]');
                     addCameraOption.before('<option value="' + data.id + '">' + data.name + '</option>');
-                    $('#videoDeviceSelect').val(data.id).change();
+                    $('#addCameraSelect').val(data.id).change();
                     recreateCameraFrames();
                 });
             }
@@ -2181,7 +2206,7 @@ function recreateCameraFrames(cameras) {
             addCameraFrameUi(camera);
         }
         
-        if ($('#videoDeviceSelect').find('option').length < 2 && user === 'admin' && $('#motionEyeSwitch')[0].checked) {
+        if ($('#cameraSelect').find('option').length < 2 && user === 'admin' && $('#motionEyeSwitch')[0].checked) {
             /* invite the user to add a camera */
             var addCameraLink = $('<div class="add-camera-message">' + 
                     '<a href="javascript:runAddCameraDialog()">You have not configured any camera yet. Click here to add one...</a></div>');
index 0debe616c89dfc3aa519900b79159a4b842a5ed3..e9431d3b97e5906c184556ade9a95988404a88f0 100644 (file)
             {% if USER == 'admin' %}
             <div class="settings-top-bar closed">
                 <div class="button settings-button mouse-effect" title="settings"></div>
-                <select class="video-device styled" id="videoDeviceSelect"></select>
+                <div class="button logout-button mouse-effect" title="logout"></div>
+                <select class="styled" id="cameraSelect"></select>
                 <div class="button rem-camera-button mouse-effect" id="remCameraButton" title="remove camera"></div>
                 <div class="button apply-button" id="applyButton">Apply</div>
                 {% if hostname %}<div class="hostname">{{hostname}}</div>{% endif %}
             </div>
+            {% else %}
+                <div class="button logout-button mouse-effect" title="logout"></div>
+                {% if hostname %}<div class="hostname">{{hostname}}</div>{% endif %}
             {% endif %}
             <div class="logo">
                 <a href="/">