Skip to content
This repository has been archived by the owner on Jan 30, 2020. It is now read-only.

feat(account): add menu for managing API credentials #191

Closed
wants to merge 3 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
"use strict";
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No need for this if you use a class

angular.module("UserAccount.controllers")
.controller("UserAccount.controllers.credentials.delete", class UserAccountCredentialsDeleteController {

constructor ($scope, UseraccountCredentialsService, Alerter) {
this.$scope = $scope;
this.UseraccountCredentialsService = UseraccountCredentialsService;
this.Alerter = Alerter;
this.credential = $scope.currentActionData;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You can move this to $onInit

this.loader = false;
}

$onInit () {
this.$scope.deleteCredential = this.deleteCredential.bind(this);
}

deleteCredential () {
this.loader = true;

this.UseraccountCredentialsService.deleteCredential(this.credential.credentialId)
.then(() => {
this.Alerter.success(this.$scope.tr("user_credentials_delete_success_message"), "userCredentials");
})
.catch((err) => {
this.Alerter.error(`${this.$scope.tr("user_credentials_delete_error_message")} ${_.get(err, "message") || err}`, "userCredentials");
})
.finally(() => {
this.loader = false;
this.$scope.resetAction();
});
}

});
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
<div data-ng-controller="UserAccount.controllers.credentials.delete as $ctrl">

<div data-wizard
data-wizard-on-cancel="resetAction"
data-wizard-on-finish="deleteCredential"
data-wizard-title="i18n.user_credentials_delete_modal_title">

<div data-wizard-step>

<p data-ng-bind-html="tr('user_credentials_delete_modal_step1_question', [$ctrl.credential.name])"></p>
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

tr? Should be $translate now :)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes I need to rebase on develop branch.


</div>

</div>
</div>
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
angular.module("UserAccount.controllers")
.controller("UserAccount.controllers.credentials.read", class UserAccountCredentialsReadController {
constructor ($scope) {
this.$scope = $scope;
this.credential = $scope.currentActionData;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You can move this to $onInit

}
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
<div data-ng-controller="UserAccount.controllers.credentials.read as $ctrl">

<div data-wizard
data-wizard-on-cancel="resetAction"
data-wizard-on-finish="resetAction"
data-wizard-title="i18n.user_credentials_read_modal_title">

<div data-wizard-step>

<p data-ng-bind="$ctrl.credential.name"></p>
<table class="table table-hover">
<thead>
<tr>
<th scope="col"
data-i18n-static="user_credentials_permissions_method">
</th>
<th scope="col"
data-i18n-static="user_credentials_permissions_path">
</th>
</tr>
</thead>
<tbody>
<tr data-ng-repeat="rule in $ctrl.credential.rules track by $index">
<td>
<span class="label"
data-ng-class="{
'label-danger': rule.method === 'DELETE',
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why is DELETE considered a "danger" ? I understand it's only a matter of color but it's a bit weird, was this CX validated ?

'label-success': rule.method === 'POST',
'label-info': rule.method === 'GET',
'label-warning': rule.method === 'PUT'
}"
data-ng-bind="rule.method">
</span>
</td>
<th scope="row"
data-ng-bind="rule.path">
</th>
</tr>
</tbody>
</table>

</div>

</div>

</div>
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
angular.module("UserAccount.controllers")
.controller("UserAccount.controllers.credentials", class UserAccountCredentialsController {

constructor ($q, $scope, Alerter, UseraccountCredentialsService) {
this.$q = $q;
this.$scope = $scope;
this.Alerter = Alerter;
this.UseraccountCredentialsService = UseraccountCredentialsService;

this.$scope.$on("useraccount.credentials.refresh", () => {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Move to $onInit ?

this.$onInit();
});
}

$onInit () {
this.credentialsIds = [];

return this.getCredentials();
}

/**
* Get the list of your Api Credentials IDs.
* @return {Promise}
*/
getCredentials () {
return this.UseraccountCredentialsService.getCredentials()
.then((credentialsIds) => {
this.credentialsIds = credentialsIds;
return credentialsIds;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this needed ? You already have this.credentialsIds at this point

})
.catch((err) => {
this.Alerter.error(`${this.$scope.tr("user_credentials_error")} ${_.get(err, "message", "")}`, "userCredentials");
});
}

loadDatagridCredentials ({ offset, pageSize }) {
return this.getCredentials()
.then(() => {
const part = this.credentialsIds.slice(offset - 1, offset - 1 + pageSize);
return {
data: part.map((id) => ({ id })),
meta: {
totalCount: this.credentialsIds.length
}
};
});
}

transformItem (credential) {
return this.UseraccountCredentialsService
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

return this.UseraccountCredentialsService
	.getCredential(credential.id)
    .then((credentialInfo) => this.UseraccountCredentialsService
    	.getApplication(credentialInfo.credentialId)
        .then((applicationInfo) => _.assign(credentialInfo, applicationInfo)));

to

return this.UseraccountCredentialsService
	.getCredential(credential.id)
    .then((credentialInfo) => this.UseraccountCredentialsService.getApplication(credentialInfo.credentialId))
    .then((applicationInfo) => _.assign(credentialInfo, applicationInfo));

.getCredential(credential.id)
.then((credentialInfo) => this.UseraccountCredentialsService
.getApplication(credentialInfo.credentialId)
.then((applicationInfo) => _.assign(credentialInfo, applicationInfo)));
}
});
50 changes: 50 additions & 0 deletions client/app/account/user/credentials/user-credentials.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
<div class="module-useraccount-sections-credentials-container">

<div class="page-header">
<h1 data-i18n-static="user_credentials_title"></h1>
</div>

<div class="tab-content">

<div data-ovh-alert="userCredentials"></div>

<!-- CREDENTIALS EXPLAIN -->
<oui-message class="d-block mb-4"
data-type="info">
<span data-i18n-static="user_credentials_info"></span>
</oui-message>

<!-- CREDENTIALS LIST -->
<oui-datagrid data-rows-loader="$ctrl.loadDatagridCredentials($config)"
data-row-loader="$ctrl.transformItem($row)">
<oui-column data-title=":: i18n.user_credentials_name"
data-property="name">
</oui-column>
<oui-column data-title=":: i18n.user_credentials_desc">
<span data-ng-if="$row.description.length > 20"
data-ng-bind="($row.description | limitTo:'15') + '…'"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍

data-uib-tooltip="{{ $row.description }}">
</span>
<span data-ng-if="$row.description.length <= 20"
data-ng-bind="$row.description">
</span>
</oui-column>
<oui-column data-title=":: i18n.user_credentials_creation_date">
<span data-ng-bind="$row.creation | date"></span>
</oui-column>
<oui-column data-title=":: i18n.user_credentials_expiration_date">
<span data-ng-bind="($row.expiration | date) || '-'"></span>
</oui-column>
<oui-action-menu data-align="end"
data-compact>
<oui-action-menu-item data-text="{{:: i18n.user_credentials_read }}"
data-ng-click="setAction('credentials/read/user-credentials-read', $row)">
</oui-action-menu-item>
<oui-action-menu-item data-text="{{:: i18n.user_credentials_delete }}"
data-ng-click="setAction('credentials/delete/user-credentials-delete', $row)">
</oui-action-menu-item>
</oui-action-menu>
</oui-datagrid>
</div>

</div>
10 changes: 10 additions & 0 deletions client/app/account/user/credentials/user-credentials.routes.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
angular
.module("UserAccount")
.config(["$stateProvider", function ($stateProvider) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No need to inject $stateProvider before the function, grunt ng-annotate task do it for you :)

$stateProvider.state("app.account.useraccount.credentials", {
url: "/credentials",
templateUrl: "account/user/credentials/user-credentials.html",
controller: "UserAccount.controllers.credentials",
controllerAs: "$ctrl"
});
}]);
40 changes: 40 additions & 0 deletions client/app/account/user/credentials/user-credentials.service.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
angular.module("UserAccount.services")
.service("UseraccountCredentialsService", class UseraccountCredentialsService {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It should be in ovh-api-services :)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You're right! I'll have to merge and release this pull request first.

constructor (OvhHttp) {
this.OvhHttp = OvhHttp;
}

getCredentials () {
return this.OvhHttp.get("/me/api/credential", {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

you should use a variable for the pattern: "/me/api/credential" and use it across your methods :)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

OvhApiMe will be used.

rootPath: "apiv6"
});
}

getCredential (credentialId) {
return this.OvhHttp.get("/me/api/credential/{credentialId}", {
rootPath: "apiv6",
urlParams: {
credentialId
}
});
}

getApplication (credentialId) {
return this.OvhHttp.get("/me/api/credential/{credentialId}/application", {
rootPath: "apiv6",
urlParams: {
credentialId
}
});
}

deleteCredential (credentialId) {
return this.OvhHttp.delete("/me/api/credential/{credentialId}", {
rootPath: "apiv6",
urlParams: {
credentialId
},
broadcast: "useraccount.credentials.refresh"
});
}
});
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,11 @@ angular.module("App").run(($q, $translatePartialLoader, $translate, SidebarMenu,
state: "app.account.useraccount.ssh"
}, myAccountMenu);

SidebarMenu.addMenuItem({
title: $translate.instant("menu_credentials"),
state: "app.account.useraccount.credentials"
}, myAccountMenu);

if (constants.target === "EU" || constants.target === "CA") {
SidebarMenu.addMenuItem({
title: $translate.instant("menu_advanced"),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
<translation id="menu_subscriptions" qtlid="144708">Mes abonnements</translation>
<translation id="menu_ssh" qtlid="165897">Mes clés SSH</translation>
<translation id="menu_infos" qtlid="405499">Mon profil</translation>
<translation id="menu_credentials">Applications</translation>
<translation id="menu_advanced" qtlid="39958">Paramètres avancés</translation>
<translation id="menu_services" qtlid="229658">Mes services</translation>
<translation id="menu_account_title" qtlid="157642">Mon compte</translation>
Expand Down
3 changes: 3 additions & 0 deletions client/app/components/user/session/user-session.service.js
Original file line number Diff line number Diff line change
Expand Up @@ -375,6 +375,9 @@ class SessionService {
}, {
title: this.$translate.instant("menu_ssh"),
state: "app.account.useraccount.ssh"
}, {
title: this.$translate.instant("menu_credentials"),
state: "app.account.useraccount.credentials"
}, {
title: this.$translate.instant("menu_advanced"),
state: "app.account.useraccount.advanced"
Expand Down
20 changes: 20 additions & 0 deletions client/app/resources/i18n/useraccount/Messages_fr_FR.xml
Original file line number Diff line number Diff line change
Expand Up @@ -152,6 +152,26 @@
<translation id="user_agreement_details_success" qtlid="410598">Votre contrat a bien été validé.</translation>
<translation id="user_agreement_details_error" qtlid="410611">Une erreur s'est produite lors de l'acceptation de votre contrat.</translation>

<translation id="user_credentials_title">Applications autorisées</translation>
<translation id="user_credentials_info">Les applications ci-dessous ont accès à votre espace client.</translation>
<translation id="user_credentials_error">Une erreur est survenue lors du chargement de la liste de vos applications.</translation>
<translation id="user_credentials_table_empty">Aucune application</translation>
<translation id="user_credentials_name">Nom</translation>
<translation id="user_credentials_desc">Description</translation>
<translation id="user_credentials_creation_date">Date de création</translation>
<translation id="user_credentials_expiration_date">Date d'expiration</translation>
<translation id="user_credentials_show_permissions">Afficher les permissions</translation>
<translation id="user_credentials_hide_permissions">Masquer</translation>
<translation id="user_credentials_permissions_method">Méthode</translation>
<translation id="user_credentials_permissions_path">Chemin</translation>
<translation id="user_credentials_read">Détails</translation>
<translation id="user_credentials_read_modal_title">Détails de l'application</translation>
<translation id="user_credentials_delete">Révoquer</translation>
<translation id="user_credentials_delete_modal_title">Supprimer une application</translation>
<translation id="user_credentials_delete_modal_step1_question">Êtes-vous sûr de vouloir supprimer l'application <strong>{0}</strong> ?</translation>
<translation id="user_credentials_delete_success_message">L'application a été supprimée.</translation>
<translation id="user_credentials_delete_error_message">Une erreur s'est produite lors de la suppression de l'application.</translation>

<translation id="user_ipRestrictions_title" qtlid="225486">Restriction d'accès par IP</translation>
<translation id="user_ipRestrictions_activate" qtlid="76734">Activer</translation>
<translation id="user_ipRestrictions_default_rule" qtlid="229710">Règle par défaut</translation>
Expand Down