diff options
Diffstat (limited to 'settings')
-rw-r--r-- | settings/Controller/AuthSettingsController.php | 19 | ||||
-rw-r--r-- | settings/css/settings.css | 12 | ||||
-rw-r--r-- | settings/js/authtoken_collection.js | 18 | ||||
-rw-r--r-- | settings/js/authtoken_view.js | 104 | ||||
-rw-r--r-- | settings/templates/personal.php | 20 |
5 files changed, 146 insertions, 27 deletions
diff --git a/settings/Controller/AuthSettingsController.php b/settings/Controller/AuthSettingsController.php index 71868b7688d..75311920d2a 100644 --- a/settings/Controller/AuthSettingsController.php +++ b/settings/Controller/AuthSettingsController.php @@ -60,7 +60,8 @@ class AuthSettingsController extends Controller { * @param ISecureRandom $random * @param string $uid */ - public function __construct($appName, IRequest $request, IProvider $tokenProvider, IUserManager $userManager, ISession $session, ISecureRandom $random, $uid) { + public function __construct($appName, IRequest $request, IProvider $tokenProvider, IUserManager $userManager, + ISession $session, ISecureRandom $random, $uid) { parent::__construct($appName, $request); $this->tokenProvider = $tokenProvider; $this->userManager = $userManager; @@ -131,4 +132,20 @@ class AuthSettingsController extends Controller { return implode('-', $groups); } + /** + * @NoAdminRequired + * @NoSubadminRequired + * + * @return JSONResponse + */ + public function destroy($id) { + $user = $this->userManager->get($this->uid); + if (is_null($user)) { + return []; + } + + $this->tokenProvider->invalidateTokenById($user, $id); + return []; + } + } diff --git a/settings/css/settings.css b/settings/css/settings.css index 418c5f95517..5fc96343502 100644 --- a/settings/css/settings.css +++ b/settings/css/settings.css @@ -114,18 +114,22 @@ table.nostyle td { padding: 0.2em 0; } #sessions table td, #devices table th, #devices table td { - padding: 10px; + padding: 10px; } #sessions .token-list td, #devices .token-list td { - border-top: 1px solid #DDD; + border-top: 1px solid #DDD; +} +#sessions .token-list td a.icon-delete, +#devices .token-list td a.icon-delete { + display: block; + opacity: 0.6; } #device-new-token { - padding: 10px; + width: 186px; font-family: monospace; - font-size: 1.4em; background-color: lightyellow; } diff --git a/settings/js/authtoken_collection.js b/settings/js/authtoken_collection.js index dd964356d06..a78e053995f 100644 --- a/settings/js/authtoken_collection.js +++ b/settings/js/authtoken_collection.js @@ -26,9 +26,25 @@ OC.Settings = OC.Settings || {}; var AuthTokenCollection = Backbone.Collection.extend({ + model: OC.Settings.AuthToken, + + /** + * Show recently used sessions/devices first + * + * @param {OC.Settigns.AuthToken} t1 + * @param {OC.Settigns.AuthToken} t2 + * @returns {Boolean} + */ + comparator: function (t1, t2) { + var ts1 = parseInt(t1.get('lastActivity'), 10); + var ts2 = parseInt(t2.get('lastActivity'), 10); + return ts1 < ts2; + }, + tokenType: null, - url: OC.generateUrl('/settings/personal/authtokens'), + + url: OC.generateUrl('/settings/personal/authtokens') }); OC.Settings.AuthTokenCollection = AuthTokenCollection; diff --git a/settings/js/authtoken_view.js b/settings/js/authtoken_view.js index 8ca38d80d84..a165a465247 100644 --- a/settings/js/authtoken_view.js +++ b/settings/js/authtoken_view.js @@ -26,62 +26,110 @@ OC.Settings = OC.Settings || {}; var TEMPLATE_TOKEN = - '<tr>' + '<tr data-id="{{id}}">' + '<td>{{name}}</td>' - + '<td>{{lastActivity}}</td>' + + '<td><span class="last-activity" title="{{lastActivityTime}}">{{lastActivity}}</span></td>' + + '<td><a class="icon-delete" title="' + t('core', 'Disconnect') + '"></a></td>' + '<tr>'; var SubView = Backbone.View.extend({ collection: null, + + /** + * token type + * - 0: browser + * - 1: device + * + * @see OC\Authentication\Token\IToken + */ type: 0, - template: Handlebars.compile(TEMPLATE_TOKEN), + + _template: undefined, + + template: function(data) { + if (_.isUndefined(this._template)) { + this._template = Handlebars.compile(TEMPLATE_TOKEN); + } + + return this._template(data); + }, + initialize: function(options) { this.type = options.type; this.collection = options.collection; + + this.on(this.collection, 'change', this.render); }, + render: function() { var _this = this; - var list = this.$el.find('.token-list'); + var list = this.$('.token-list'); var tokens = this.collection.filter(function(token) { - return parseInt(token.get('type')) === _this.type; + return parseInt(token.get('type'), 10) === _this.type; }); list.html(''); + // Show header only if there are tokens to show + console.log(tokens.length > 0); + this._toggleHeader(tokens.length > 0); + tokens.forEach(function(token) { var viewData = token.toJSON(); - viewData.lastActivity = moment(viewData.lastActivity, 'X'). - format('LLL'); + var ts = viewData.lastActivity * 1000; + viewData.lastActivity = OC.Util.relativeModifiedDate(ts); + viewData.lastActivityTime = OC.Util.formatDate(ts, 'LLL'); var html = _this.template(viewData); - list.append(html); + var $html = $(html); + $html.find('.last-activity').tooltip(); + $html.find('.icon-delete').tooltip(); + list.append($html); }); }, + toggleLoading: function(state) { - this.$el.find('.token-list').toggleClass('icon-loading', state); + this.$('.token-list').toggleClass('icon-loading', state); + }, + + _toggleHeader: function(show) { + this.$('.hidden-when-empty').toggleClass('hidden', !show); } }); var AuthTokenView = Backbone.View.extend({ collection: null, + _views: [], + _form: undefined, + _tokenName: undefined, + _addTokenBtn: undefined, + _result: undefined, + _newToken: undefined, + _hideTokenBtn: undefined, + _addingToken: false, + initialize: function(options) { this.collection = options.collection; var tokenTypes = [0, 1]; var _this = this; _.each(tokenTypes, function(type) { + var el = type === 0 ? '#sessions' : '#devices'; _this._views.push(new SubView({ - el: type === 0 ? '#sessions' : '#devices', + el: el, type: type, collection: _this.collection })); + + var $el = $(el); + $el.on('click', 'a.icon-delete', _.bind(_this._onDeleteToken, _this)); }); this._form = $('#device-token-form'); @@ -91,15 +139,18 @@ this._result = $('#device-token-result'); this._newToken = $('#device-new-token'); + this._newToken.on('focus', _.bind(this._onNewTokenFocus, this)); this._hideTokenBtn = $('#device-token-hide'); this._hideTokenBtn.click(_.bind(this._hideToken, this)); }, + render: function() { _.each(this._views, function(view) { view.render(); view.toggleLoading(false); }); }, + reload: function() { var _this = this; @@ -116,6 +167,7 @@ OC.Notification.showTemporary(t('core', 'Error while loading browser sessions and device tokens')); }); }, + _addDeviceToken: function() { var _this = this; this._toggleAddingToken(true); @@ -131,8 +183,9 @@ $.when(creatingToken).done(function(resp) { _this.collection.add(resp.deviceToken); _this.render(); - _this._newToken.text(resp.token); + _this._newToken.val(resp.token); _this._toggleFormResult(false); + _this._newToken.select(); _this._tokenName.val(''); }); $.when(creatingToken).fail(function() { @@ -142,13 +195,42 @@ _this._toggleAddingToken(false); }); }, + + _onNewTokenFocus: function() { + this._newToken.select(); + }, + _hideToken: function() { this._toggleFormResult(true); }, + _toggleAddingToken: function(state) { this._addingToken = state; this._addTokenBtn.toggleClass('icon-loading-small', state); }, + + _onDeleteToken: function(event) { + var $target = $(event.target); + var $row = $target.closest('tr'); + var id = $row.data('id'); + + var token = this.collection.get(id); + if (_.isUndefined(token)) { + // Ignore event + return; + } + + var destroyingToken = token.destroy(); + + var _this = this; + $.when(destroyingToken).fail(function() { + OC.Notification.showTemporary(t('core', 'Error while deleting the token')); + }); + $.when(destroyingToken).always(function() { + _this.render(); + }); + }, + _toggleFormResult: function(showForm) { this._form.toggleClass('hidden', !showForm); this._result.toggleClass('hidden', showForm); diff --git a/settings/templates/personal.php b/settings/templates/personal.php index 4f8d564f549..dcc83b3e99e 100644 --- a/settings/templates/personal.php +++ b/settings/templates/personal.php @@ -141,12 +141,12 @@ if($_['passwordChangeSupported']) { <div id="sessions" class="section"> <h2><?php p($l->t('Sessions'));?></h2> - <?php p($l->t('These are the web browsers currently logged in to your ownCloud.'));?> + <span class="hidden-when-empty"><?php p($l->t('These are the web browsers currently logged in to your ownCloud.'));?></span> <table> - <thead> + <thead class="token-list-header"> <tr> - <th>Browser</th> - <th>Most recent activity</th> + <th><?php p($l->t('Browser'));?></th> + <th><?php p($l->t('Most recent activity'));?></th> <th></th> </tr> </thead> @@ -157,13 +157,13 @@ if($_['passwordChangeSupported']) { <div id="devices" class="section"> <h2><?php p($l->t('Devices'));?></h2> - <?php p($l->t("You've linked these devices."));?> + <span class="hidden-when-empty"><?php p($l->t("You've linked these devices."));?></span> <table> - <thead> + <thead class="hidden-when-empty"> <tr> - <th>Name</th> - <th>Most recent activity</th> - <th><a class="icon-delete"></a></th> + <th><?php p($l->t('Name'));?></th> + <th><?php p($l->t('Most recent activity'));?></th> + <th></th> </tr> </thead> <tbody class="token-list icon-loading"> @@ -175,7 +175,7 @@ if($_['passwordChangeSupported']) { <button id="device-add-token" class="button">Create new device password</button> </div> <div id="device-token-result" class="hidden"> - <span id="device-new-token"></span> + <input id="device-new-token" type="text" readonly="readonly"/> <button id="device-token-hide" class="button">Done</button> </div> </div> |