summaryrefslogtreecommitdiffstats
path: root/settings
diff options
context:
space:
mode:
authorRoeland Jago Douma <rullzer@users.noreply.github.com>2019-02-08 08:34:54 +0100
committerGitHub <noreply@github.com>2019-02-08 08:34:54 +0100
commitb40603d2501059752db43bafb74ef5c11eb57b99 (patch)
tree9e61588dea11c0278ccd7215625ca62dbdd9f69f /settings
parentdd9428047ecdb820b8b7171cbd1ae51a8a1411b8 (diff)
parent4532ed356d4815beba2db69b971e05708f9b33ee (diff)
downloadnextcloud-server-b40603d2501059752db43bafb74ef5c11eb57b99.tar.gz
nextcloud-server-b40603d2501059752db43bafb74ef5c11eb57b99.zip
Merge pull request #13702 from nextcloud/feature/6717/rename-app-passwords
Make it possible to rename app passwords
Diffstat (limited to 'settings')
-rw-r--r--settings/Controller/AuthSettingsController.php16
-rw-r--r--settings/css/settings.scss12
-rw-r--r--settings/js/authtoken_view.js67
-rw-r--r--settings/js/templates.js33
-rw-r--r--settings/js/templates/authtoken.handlebars10
5 files changed, 122 insertions, 16 deletions
diff --git a/settings/Controller/AuthSettingsController.php b/settings/Controller/AuthSettingsController.php
index 5f834b30134..5b2788bb0c1 100644
--- a/settings/Controller/AuthSettingsController.php
+++ b/settings/Controller/AuthSettingsController.php
@@ -31,10 +31,12 @@ use BadMethodCallException;
use OC\AppFramework\Http;
use OC\Authentication\Exceptions\InvalidTokenException;
use OC\Authentication\Exceptions\PasswordlessTokenException;
+use OC\Authentication\Token\INamedToken;
use OC\Authentication\Token\IProvider;
use OC\Authentication\Token\IToken;
use OC\Settings\Activity\Provider;
use OCP\Activity\IManager;
+use OC\Authentication\Token\PublicKeyToken;
use OCP\AppFramework\Controller;
use OCP\AppFramework\Http\JSONResponse;
use OCP\ILogger;
@@ -112,11 +114,12 @@ class AuthSettingsController extends Controller {
return array_map(function (IToken $token) use ($sessionToken) {
$data = $token->jsonSerialize();
+ $data['canDelete'] = true;
+ $data['canRename'] = $token instanceof INamedToken;
if ($sessionToken->getId() === $token->getId()) {
$data['canDelete'] = false;
+ $data['canRename'] = false;
$data['current'] = true;
- } else {
- $data['canDelete'] = true;
}
return $data;
}, $tokens);
@@ -153,6 +156,7 @@ class AuthSettingsController extends Controller {
$deviceToken = $this->tokenProvider->generateToken($token, $this->uid, $loginName, $password, $name, IToken::PERMANENT_TOKEN);
$tokenData = $deviceToken->jsonSerialize();
$tokenData['canDelete'] = true;
+ $tokenData['canRename'] = true;
$this->publishActivity(Provider::APP_TOKEN_CREATED, $deviceToken->getId(), $deviceToken->getName());
@@ -212,9 +216,10 @@ class AuthSettingsController extends Controller {
*
* @param int $id
* @param array $scope
+ * @param string $name
* @return array|JSONResponse
*/
- public function update($id, array $scope) {
+ public function update($id, array $scope, string $name) {
try {
$token = $this->findTokenByIdAndUser($id);
} catch (InvalidTokenException $e) {
@@ -225,6 +230,11 @@ class AuthSettingsController extends Controller {
'filesystem' => $scope['filesystem']
]);
+
+ if ($token instanceof INamedToken) {
+ $token->setName($name);
+ }
+
$this->tokenProvider->updateToken($token);
$this->publishActivity(Provider::APP_TOKEN_UPDATED, $token->getId(), $token->getName());
return [];
diff --git a/settings/css/settings.scss b/settings/css/settings.scss
index 5f1bc1af7e4..126d451fc66 100644
--- a/settings/css/settings.scss
+++ b/settings/css/settings.scss
@@ -440,7 +440,14 @@ table.nostyle {
}
&.token-name {
- padding: 10px 0;
+ padding: 10px 6px;
+ &.token-rename {
+ padding: 0;
+ }
+ input {
+ width: 100%;
+ margin: 0;
+ }
}
&.more {
@@ -456,6 +463,9 @@ table.nostyle {
}
}
}
+ tr > *:nth-child(2) {
+ padding-left: 6px;
+ }
tr > *:nth-child(3) {
text-align: right;
}
diff --git a/settings/js/authtoken_view.js b/settings/js/authtoken_view.js
index 9ad07e9cca5..3f88517d02b 100644
--- a/settings/js/authtoken_view.js
+++ b/settings/js/authtoken_view.js
@@ -35,6 +35,7 @@
data.revokeText = t('settings', 'Revoke');
data.settingsTitle = t('settings', 'Device settings');
data.allowFSAccess = t('settings', 'Allow filesystem access');
+ data.renameText = t('settings', 'Rename');
return OC.Settings.Templates['authtoken'](data);
},
@@ -106,7 +107,7 @@
iosTalkClient: /^Mozilla\/5\.0 \(iOS\) Nextcloud\-Talk.*$/,
androidTalkClient:/^Mozilla\/5\.0 \(Android\) Nextcloud\-Talk.*$/,
// DAVdroid/1.2 (2016/07/03; dav4android; okhttp3) Android/6.0.1
- davDroid: /DAVdroid\/([0-9.]+)/,
+ davDroid: /DAV(droid|x5)\/([0-9.]+)/,
// Mozilla/5.0 (U; Linux; Maemo; Jolla; Sailfish; like Android 4.3) AppleWebKit/538.1 (KHTML, like Gecko) WebPirate/2.0 like Mobile Safari/538.1 (compatible)
webPirate: /(Sailfish).*WebPirate\/(\d+)/,
// Mozilla/5.0 (Maemo; Linux; U; Jolla; Sailfish; Mobile; rv:31.0) Gecko/31.0 Firefox/31.0 SailfishBrowser/1.0
@@ -218,6 +219,9 @@
$el.on('click', 'a.icon-delete', _.bind(this._onDeleteToken, this));
$el.on('click', '.icon-more', _.bind(this._onConfigureToken, this));
$el.on('change', 'input.filesystem', _.bind(this._onSetTokenScope, this));
+ $el.on('click', '.icon-rename', _.bind(this._onRenameToken, this));
+ $el.on('dblclick', '.token-name > span', _.bind(this._onRenameToken, this));
+ $el.on('keyup', '.token-name > input', _.bind(this._onEnterTokenName, this));
this._form = $('#app-password-form');
this._tokenName = $('#app-password-name');
@@ -241,7 +245,7 @@
this._result.find('.clipboardButton').tooltip({placement: 'bottom', title: t('core', 'Copy'), trigger: 'hover'});
// Clipboard!
- var clipboard = new Clipboard('.clipboardButton');
+ var clipboard = new ClipboardJS('.clipboardButton');
clipboard.on('success', function(e) {
var $input = $(e.trigger);
$input.tooltip('hide')
@@ -414,6 +418,65 @@
token.save();
},
+ _onRenameToken: function (event) {
+ var $target = $(event.target);
+ var $row = $target.closest('tr');
+
+ var tokenId = $row.data('id');
+ var token = this.collection.get(tokenId);
+
+ if (_.isUndefined(token) || token.get('current') === true) {
+ // Ignore event
+ return;
+ }
+
+ var $tokenName = $row.find('.token-name');
+ var showTokenNameInput = !$tokenName.hasClass('token-rename'); // if class token-rename present input is already visible.
+
+ this._hideTokenNameInput();
+
+ if (showTokenNameInput) {
+ $tokenName.addClass('token-rename');
+ $tokenName.find('span').addClass('hidden');
+ $tokenName.find('input').removeClass('hidden').val(token.get('name')).focus();
+ }
+
+ this._hideConfigureToken();
+ },
+
+ _onEnterTokenName: function(event) {
+ var $target = $(event.target);
+ var $row = $target.closest('tr');
+
+ var tokenId = $row.data('id');
+ var token = this.collection.get(tokenId);
+
+ if (_.isUndefined(token) || token.get('current') === true) {
+ // Ignore event
+ return;
+ }
+
+ if (event.key === 'Enter') {
+ token.set('name', $target.context.value);
+
+ var _this = this;
+ $.when(token.save()).always(function () {
+ _this.render();
+ });
+ }
+
+ if (event.key === 'Escape') {
+ this._hideTokenNameInput();
+ }
+ },
+
+ _hideTokenNameInput: function () {
+ var $tokenList = $('.token-list td.token-name');
+ $tokenList.removeClass('token-rename');
+ $tokenList.find('span').removeClass('hidden');
+ $tokenList.find('input').addClass('hidden');
+ },
+
_toggleFormResult: function (showForm) {
if (showForm) {
this._result.slideUp();
diff --git a/settings/js/templates.js b/settings/js/templates.js
index c9931fed41b..e35f93d3cb9 100644
--- a/settings/js/templates.js
+++ b/settings/js/templates.js
@@ -3,24 +3,36 @@
templates['authtoken'] = template({"1":function(container,depth0,helpers,partials,data) {
var helper;
+ return " <input class=\"hidden\" type=\"text\" value=\""
+ + container.escapeExpression(((helper = (helper = helpers.name || (depth0 != null ? depth0.name : depth0)) != null ? helper : helpers.helperMissing),(typeof helper === "function" ? helper.call(depth0 != null ? depth0 : (container.nullContext || {}),{"name":"name","hash":{},"data":data}) : helper)))
+ + "\" />\n";
+},"3":function(container,depth0,helpers,partials,data) {
+ var helper;
+
return "<a class=\"icon icon-more has-tooltip\" tabindex=\"0\" title=\""
+ container.escapeExpression(((helper = (helper = helpers.settingsTitle || (depth0 != null ? depth0.settingsTitle : depth0)) != null ? helper : helpers.helperMissing),(typeof helper === "function" ? helper.call(depth0 != null ? depth0 : (container.nullContext || {}),{"name":"settingsTitle","hash":{},"data":data}) : helper)))
+ "\"/>";
-},"3":function(container,depth0,helpers,partials,data) {
+},"5":function(container,depth0,helpers,partials,data) {
var stack1, helper, alias1=depth0 != null ? depth0 : (container.nullContext || {}), alias2=helpers.helperMissing, alias3="function", alias4=container.escapeExpression;
return " <li><span class=\"menuitem\">\n <input class=\"filesystem checkbox\" type=\"checkbox\" id=\""
+ alias4(((helper = (helper = helpers.id || (depth0 != null ? depth0.id : depth0)) != null ? helper : alias2),(typeof helper === alias3 ? helper.call(alias1,{"name":"id","hash":{},"data":data}) : helper)))
+ "_filesystem\" "
- + ((stack1 = helpers["if"].call(alias1,((stack1 = (depth0 != null ? depth0.scope : depth0)) != null ? stack1.filesystem : stack1),{"name":"if","hash":{},"fn":container.program(4, data, 0),"inverse":container.noop,"data":data})) != null ? stack1 : "")
+ + ((stack1 = helpers["if"].call(alias1,((stack1 = (depth0 != null ? depth0.scope : depth0)) != null ? stack1.filesystem : stack1),{"name":"if","hash":{},"fn":container.program(6, data, 0),"inverse":container.noop,"data":data})) != null ? stack1 : "")
+ " tabindex=\"0\" />\n <label for=\""
+ alias4(((helper = (helper = helpers.id || (depth0 != null ? depth0.id : depth0)) != null ? helper : alias2),(typeof helper === alias3 ? helper.call(alias1,{"name":"id","hash":{},"data":data}) : helper)))
+ "_filesystem\">"
+ alias4(((helper = (helper = helpers.allowFSAccess || (depth0 != null ? depth0.allowFSAccess : depth0)) != null ? helper : alias2),(typeof helper === alias3 ? helper.call(alias1,{"name":"allowFSAccess","hash":{},"data":data}) : helper)))
+ "</label><br/>\n </span></li>\n";
-},"4":function(container,depth0,helpers,partials,data) {
- return "checked";
},"6":function(container,depth0,helpers,partials,data) {
+ return "checked";
+},"8":function(container,depth0,helpers,partials,data) {
+ var helper;
+
+ return " <li>\n <a class=\"icon icon-rename\" tabindex=\"0\">"
+ + container.escapeExpression(((helper = (helper = helpers.renameText || (depth0 != null ? depth0.renameText : depth0)) != null ? helper : helpers.helperMissing),(typeof helper === "function" ? helper.call(depth0 != null ? depth0 : (container.nullContext || {}),{"name":"renameText","hash":{},"data":data}) : helper)))
+ + "</a>\n </li>\n";
+},"10":function(container,depth0,helpers,partials,data) {
var helper;
return " <li>\n <a class=\"icon icon-delete\" tabindex=\"0\">"
@@ -33,17 +45,20 @@ templates['authtoken'] = template({"1":function(container,depth0,helpers,partial
+ alias4(((helper = (helper = helpers.id || (depth0 != null ? depth0.id : depth0)) != null ? helper : alias2),(typeof helper === alias3 ? helper.call(alias1,{"name":"id","hash":{},"data":data}) : helper)))
+ "\">\n <td class=\"client\">\n <div class=\""
+ alias4(((helper = (helper = helpers.icon || (depth0 != null ? depth0.icon : depth0)) != null ? helper : alias2),(typeof helper === alias3 ? helper.call(alias1,{"name":"icon","hash":{},"data":data}) : helper)))
- + "\" />\n </td>\n <td class=\"token-name\">\n "
+ + "\" />\n </td>\n <td class=\"token-name\">\n <span>"
+ alias4(((helper = (helper = helpers.name || (depth0 != null ? depth0.name : depth0)) != null ? helper : alias2),(typeof helper === alias3 ? helper.call(alias1,{"name":"name","hash":{},"data":data}) : helper)))
- + "\n </td>\n <td>\n <span class=\"last-activity has-tooltip\" title=\""
+ + "</span>\n"
+ + ((stack1 = helpers["if"].call(alias1,(depth0 != null ? depth0.canRename : depth0),{"name":"if","hash":{},"fn":container.program(1, data, 0),"inverse":container.noop,"data":data})) != null ? stack1 : "")
+ + " </td>\n <td>\n <span class=\"last-activity has-tooltip\" title=\""
+ alias4(((helper = (helper = helpers.lastActivityTime || (depth0 != null ? depth0.lastActivityTime : depth0)) != null ? helper : alias2),(typeof helper === alias3 ? helper.call(alias1,{"name":"lastActivityTime","hash":{},"data":data}) : helper)))
+ "\">"
+ alias4(((helper = (helper = helpers.lastActivity || (depth0 != null ? depth0.lastActivity : depth0)) != null ? helper : alias2),(typeof helper === alias3 ? helper.call(alias1,{"name":"lastActivity","hash":{},"data":data}) : helper)))
+ "</span></td>\n <td class=\"more\">\n "
- + ((stack1 = helpers["if"].call(alias1,(depth0 != null ? depth0.showMore : depth0),{"name":"if","hash":{},"fn":container.program(1, data, 0),"inverse":container.noop,"data":data})) != null ? stack1 : "")
+ + ((stack1 = helpers["if"].call(alias1,(depth0 != null ? depth0.showMore : depth0),{"name":"if","hash":{},"fn":container.program(3, data, 0),"inverse":container.noop,"data":data})) != null ? stack1 : "")
+ "\n <div class=\"popovermenu menu\">\n"
- + ((stack1 = helpers["if"].call(alias1,(depth0 != null ? depth0.canScope : depth0),{"name":"if","hash":{},"fn":container.program(3, data, 0),"inverse":container.noop,"data":data})) != null ? stack1 : "")
- + ((stack1 = helpers["if"].call(alias1,(depth0 != null ? depth0.canDelete : depth0),{"name":"if","hash":{},"fn":container.program(6, data, 0),"inverse":container.noop,"data":data})) != null ? stack1 : "")
+ + ((stack1 = helpers["if"].call(alias1,(depth0 != null ? depth0.canScope : depth0),{"name":"if","hash":{},"fn":container.program(5, data, 0),"inverse":container.noop,"data":data})) != null ? stack1 : "")
+ + ((stack1 = helpers["if"].call(alias1,(depth0 != null ? depth0.canRename : depth0),{"name":"if","hash":{},"fn":container.program(8, data, 0),"inverse":container.noop,"data":data})) != null ? stack1 : "")
+ + ((stack1 = helpers["if"].call(alias1,(depth0 != null ? depth0.canDelete : depth0),{"name":"if","hash":{},"fn":container.program(10, data, 0),"inverse":container.noop,"data":data})) != null ? stack1 : "")
+ " </div>\n </td>\n</tr>\n";
},"useData":true});
templates['federationscopemenu'] = template({"1":function(container,depth0,helpers,partials,data) {
diff --git a/settings/js/templates/authtoken.handlebars b/settings/js/templates/authtoken.handlebars
index b6d81780e80..37dc31f04c6 100644
--- a/settings/js/templates/authtoken.handlebars
+++ b/settings/js/templates/authtoken.handlebars
@@ -3,7 +3,10 @@
<div class="{{icon}}" />
</td>
<td class="token-name">
- {{name}}
+ <span>{{name}}</span>
+ {{#if canRename}}
+ <input class="hidden" type="text" value="{{name}}" />
+ {{/if}}
</td>
<td>
<span class="last-activity has-tooltip" title="{{lastActivityTime}}">{{lastActivity}}</span></td>
@@ -16,6 +19,11 @@
<label for="{{id}}_filesystem">{{allowFSAccess}}</label><br/>
</span></li>
{{/if}}
+ {{#if canRename}}
+ <li>
+ <a class="icon icon-rename" tabindex="0">{{renameText}}</a>
+ </li>
+ {{/if}}
{{#if canDelete}}
<li>
<a class="icon icon-delete" tabindex="0">{{revokeText}}</a>