From 3f330a219916083fa6c91ee7b83ee6caaa70b9c1 Mon Sep 17 00:00:00 2001 From: Nicolas Vazquez Date: Fri, 11 Aug 2017 07:24:50 -0300 Subject: [PATCH] CLOUDSTACK-10044: Update role permission (#2236) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This feature allows changing permission for existing role permissions, as those were static and could not be changed once created. It also provides the ability to change these permissions in the UI using a drop down menu for each permission rule, in which admin can select ‘Allow’ or ‘Deny’ permission. Changes in the API: This feature modifies behaviour of updateRolePermission API method: New optional parameters ‘ruleid’ and ‘permission’ are introduced, they are mutual exclusive to ‘ruleorder’ parameter. This defines two use cases: Update role permission: ‘ruleid’ and ‘permission’ parameters needed Update rules order: ‘ruleorder’ parameter needed Parameter ‘ruleorder’ is now optional updateRolePermission providing ‘ruleorder’ parameter should be sent via POST --- .../apache/cloudstack/acl/RoleService.java | 4 +- .../apache/cloudstack/api/ApiConstants.java | 1 + .../admin/acl/UpdateRolePermissionCmd.java | 58 ++++++++++++++++--- .../acl/dao/RolePermissionsDao.java | 10 ++++ .../acl/dao/RolePermissionsDaoImpl.java | 14 +++++ .../cloudstack/acl/RoleManagerImpl.java | 6 ++ test/integration/smoke/test_dynamicroles.py | 40 +++++++++++++ ui/l10n/ar.js | 1 + ui/l10n/ca.js | 1 + ui/l10n/de_DE.js | 1 + ui/l10n/en.js | 1 + ui/l10n/es.js | 1 + ui/l10n/fr_FR.js | 1 + ui/l10n/hu.js | 1 + ui/l10n/it_IT.js | 1 + ui/l10n/ja_JP.js | 1 + ui/l10n/ko_KR.js | 1 + ui/l10n/nb_NO.js | 1 + ui/l10n/nl_NL.js | 1 + ui/l10n/pl.js | 1 + ui/l10n/pt_BR.js | 1 + ui/l10n/ru_RU.js | 1 + ui/l10n/zh_CN.js | 1 + ui/scripts/roles.js | 23 ++++++++ ui/scripts/ui/widgets/multiEdit.js | 35 +++++++++-- 25 files changed, 193 insertions(+), 14 deletions(-) diff --git a/api/src/org/apache/cloudstack/acl/RoleService.java b/api/src/org/apache/cloudstack/acl/RoleService.java index 59eef51e782..98d170b5853 100644 --- a/api/src/org/apache/cloudstack/acl/RoleService.java +++ b/api/src/org/apache/cloudstack/acl/RoleService.java @@ -17,6 +17,7 @@ package org.apache.cloudstack.acl; +import org.apache.cloudstack.acl.RolePermission.Permission; import org.apache.cloudstack.framework.config.ConfigKey; import java.util.List; @@ -36,13 +37,14 @@ public interface RoleService { RolePermission findRolePermission(final Long id); RolePermission findRolePermissionByUuid(final String uuid); - RolePermission createRolePermission(final Role role, final Rule rule, final RolePermission.Permission permission, final String description); + RolePermission createRolePermission(final Role role, final Rule rule, final Permission permission, final String description); /** * updateRolePermission updates the order/position of an role permission * @param role The role whose permissions needs to be re-ordered * @param newOrder The new list of ordered role permissions */ boolean updateRolePermission(final Role role, final List newOrder); + boolean updateRolePermission(final Role role, final RolePermission rolePermission, final Permission permission); boolean deleteRolePermission(final RolePermission rolePermission); List listRoles(); diff --git a/api/src/org/apache/cloudstack/api/ApiConstants.java b/api/src/org/apache/cloudstack/api/ApiConstants.java index 10470b589be..6421fb3e66c 100644 --- a/api/src/org/apache/cloudstack/api/ApiConstants.java +++ b/api/src/org/apache/cloudstack/api/ApiConstants.java @@ -373,6 +373,7 @@ public class ApiConstants { public static final String ROLE_NAME = "rolename"; public static final String PERMISSION = "permission"; public static final String RULE = "rule"; + public static final String RULE_ID = "ruleid"; public static final String RULE_ORDER = "ruleorder"; public static final String USER = "user"; public static final String ACTIVE_ONLY = "activeonly"; diff --git a/api/src/org/apache/cloudstack/api/command/admin/acl/UpdateRolePermissionCmd.java b/api/src/org/apache/cloudstack/api/command/admin/acl/UpdateRolePermissionCmd.java index 055265c5ccc..045464eab79 100644 --- a/api/src/org/apache/cloudstack/api/command/admin/acl/UpdateRolePermissionCmd.java +++ b/api/src/org/apache/cloudstack/api/command/admin/acl/UpdateRolePermissionCmd.java @@ -20,6 +20,7 @@ package org.apache.cloudstack.api.command.admin.acl; import com.cloud.user.Account; import org.apache.cloudstack.acl.Role; import org.apache.cloudstack.acl.RolePermission; +import org.apache.cloudstack.acl.RolePermission.Permission; import org.apache.cloudstack.acl.RoleType; import org.apache.cloudstack.api.APICommand; import org.apache.cloudstack.api.ApiArgValidator; @@ -51,10 +52,18 @@ public class UpdateRolePermissionCmd extends BaseCmd { description = "ID of the role", validations = {ApiArgValidator.PositiveNumber}) private Long roleId; - @Parameter(name = ApiConstants.RULE_ORDER, type = CommandType.LIST, collectionType = CommandType.UUID, required = true, entityType = RolePermissionResponse.class, + @Parameter(name = ApiConstants.RULE_ORDER, type = CommandType.LIST, collectionType = CommandType.UUID, entityType = RolePermissionResponse.class, description = "The parent role permission uuid, use 0 to move this rule at the top of the list") private List rulePermissionOrder; + @Parameter(name = ApiConstants.RULE_ID, type = CommandType.UUID, entityType = RolePermissionResponse.class, + description = "Role permission rule id", since="4.11") + private Long ruleId; + + @Parameter(name = ApiConstants.PERMISSION, type = CommandType.STRING, + description = "Rule permission, can be: allow or deny", since="4.11") + private String rulePermission; + ///////////////////////////////////////////////////// /////////////////// Accessors /////////////////////// ///////////////////////////////////////////////////// @@ -67,6 +76,21 @@ public class UpdateRolePermissionCmd extends BaseCmd { return rulePermissionOrder; } + public Long getRuleId() { + return ruleId; + } + + public Permission getRulePermission() { + if (this.rulePermission == null) { + return null; + } + if (!this.rulePermission.equalsIgnoreCase(Permission.ALLOW.toString()) && + !this.rulePermission.equalsIgnoreCase(Permission.DENY.toString())) { + throw new ServerApiException(ApiErrorCode.PARAM_ERROR, "Values for permission parameter should be: allow or deny"); + } + return rulePermission.equalsIgnoreCase(Permission.ALLOW.toString()) ? Permission.ALLOW : Permission.DENY; + } + ///////////////////////////////////////////////////// /////////////// API Implementation/////////////////// ///////////////////////////////////////////////////// @@ -84,19 +108,35 @@ public class UpdateRolePermissionCmd extends BaseCmd { @Override public void execute() { final Role role = roleService.findRole(getRoleId()); + boolean result = false; if (role == null) { throw new ServerApiException(ApiErrorCode.PARAM_ERROR, "Invalid role id provided"); } - CallContext.current().setEventDetails("Reordering permissions for role id: " + role.getId()); - final List rolePermissionsOrder = new ArrayList<>(); - for (Long rolePermissionId : getRulePermissionOrder()) { - final RolePermission rolePermission = roleService.findRolePermission(rolePermissionId); - if (rolePermission == null) { - throw new ServerApiException(ApiErrorCode.PARAM_ERROR, "Provided role permission(s) do not exist"); + if (getRulePermissionOrder() != null) { + if (getRuleId() != null || getRulePermission() != null) { + throw new ServerApiException(ApiErrorCode.PARAM_ERROR, "Parameters permission and ruleid must be mutually exclusive with ruleorder"); } - rolePermissionsOrder.add(rolePermission); + CallContext.current().setEventDetails("Reordering permissions for role id: " + role.getId()); + final List rolePermissionsOrder = new ArrayList<>(); + for (Long rolePermissionId : getRulePermissionOrder()) { + final RolePermission rolePermission = roleService.findRolePermission(rolePermissionId); + if (rolePermission == null) { + throw new ServerApiException(ApiErrorCode.PARAM_ERROR, "Provided role permission(s) do not exist"); + } + rolePermissionsOrder.add(rolePermission); + } + result = roleService.updateRolePermission(role, rolePermissionsOrder); + } else if (getRuleId() != null && getRulePermission() != null) { + if (getRulePermissionOrder() != null) { + throw new ServerApiException(ApiErrorCode.PARAM_ERROR, "Parameters permission and ruleid must be mutually exclusive with ruleorder"); + } + RolePermission rolePermission = roleService.findRolePermission(getRuleId()); + if (rolePermission == null) { + throw new ServerApiException(ApiErrorCode.PARAM_ERROR, "Invalid rule id provided"); + } + CallContext.current().setEventDetails("Updating permission for rule id: " + getRuleId() + " to: " + getRulePermission().toString()); + result = roleService.updateRolePermission(role, rolePermission, getRulePermission()); } - boolean result = roleService.updateRolePermission(role, rolePermissionsOrder); SuccessResponse response = new SuccessResponse(getCommandName()); response.setSuccess(result); setResponseObject(response); diff --git a/engine/schema/src/org/apache/cloudstack/acl/dao/RolePermissionsDao.java b/engine/schema/src/org/apache/cloudstack/acl/dao/RolePermissionsDao.java index 37544919657..c9aeba1c599 100644 --- a/engine/schema/src/org/apache/cloudstack/acl/dao/RolePermissionsDao.java +++ b/engine/schema/src/org/apache/cloudstack/acl/dao/RolePermissionsDao.java @@ -20,6 +20,7 @@ package org.apache.cloudstack.acl.dao; import com.cloud.utils.db.GenericDao; import org.apache.cloudstack.acl.Role; import org.apache.cloudstack.acl.RolePermission; +import org.apache.cloudstack.acl.RolePermission.Permission; import org.apache.cloudstack.acl.RolePermissionVO; import java.util.List; @@ -40,6 +41,15 @@ public interface RolePermissionsDao extends GenericDao { */ boolean update(final Role role, final List newOrder); + /** + * Updates existing role permission + * @param role role of which rule belongs + * @param rolePermission role permission + * @param permission permission + * @return true on success, false if not + */ + boolean update(final Role role, final RolePermission rolePermission, final Permission permission); + /** * Returns ordered linked-list of role permission for a given role * @param roleId the ID of the role diff --git a/engine/schema/src/org/apache/cloudstack/acl/dao/RolePermissionsDaoImpl.java b/engine/schema/src/org/apache/cloudstack/acl/dao/RolePermissionsDaoImpl.java index 8f6fa83f012..32faf4e9a8c 100644 --- a/engine/schema/src/org/apache/cloudstack/acl/dao/RolePermissionsDaoImpl.java +++ b/engine/schema/src/org/apache/cloudstack/acl/dao/RolePermissionsDaoImpl.java @@ -29,6 +29,7 @@ import com.cloud.utils.db.UpdateBuilder; import com.cloud.utils.exception.CloudRuntimeException; import org.apache.cloudstack.acl.Role; import org.apache.cloudstack.acl.RolePermission; +import org.apache.cloudstack.acl.RolePermission.Permission; import org.apache.cloudstack.acl.RolePermissionVO; import org.apache.log4j.Logger; import org.springframework.stereotype.Component; @@ -149,6 +150,19 @@ public class RolePermissionsDaoImpl extends GenericDaoBase findAllByRoleIdSorted(final Long roleId) { final SearchCriteria sc = RolePermissionsSearch.create(); diff --git a/server/src/org/apache/cloudstack/acl/RoleManagerImpl.java b/server/src/org/apache/cloudstack/acl/RoleManagerImpl.java index 27cb3d0238a..6cf8f9711b3 100644 --- a/server/src/org/apache/cloudstack/acl/RoleManagerImpl.java +++ b/server/src/org/apache/cloudstack/acl/RoleManagerImpl.java @@ -204,6 +204,12 @@ public class RoleManagerImpl extends ManagerBase implements RoleService, Configu return role != null && newOrder != null && rolePermissionsDao.update(role, newOrder); } + @Override + public boolean updateRolePermission(Role role, RolePermission rolePermission, RolePermission.Permission permission) { + checkCallerAccess(); + return role != null && rolePermissionsDao.update(role, rolePermission, permission); + } + @Override @ActionEvent(eventType = EventTypes.EVENT_ROLE_PERMISSION_DELETE, eventDescription = "deleting Role Permission") public boolean deleteRolePermission(final RolePermission rolePermission) { diff --git a/test/integration/smoke/test_dynamicroles.py b/test/integration/smoke/test_dynamicroles.py index 99614374553..5d105f6a427 100644 --- a/test/integration/smoke/test_dynamicroles.py +++ b/test/integration/smoke/test_dynamicroles.py @@ -394,6 +394,46 @@ class TestDynamicRoles(cloudstackTestCase): rule.update(self.apiclient, ruleorder=",".join(map(lambda x: x.id, permissions))) validate_permissions_list(permissions) + @attr(tags=['advanced', 'simulator', 'basic', 'sg'], required_hardware=False) + def test_rolepermission_lifecycle_update_permission(self): + """ + Tests update of Allow to Deny permission of a rule + """ + permissions = [self.rolepermission] + + rule = permissions.pop(0) + rule.update(self.apiclient, ruleid=rule.id, permission='deny') + + list_rolepermissions = RolePermission.list(self.apiclient, roleid=self.role.id) + self.assertEqual( + list_rolepermissions[0].permission, + 'deny', + msg="List of role permissions do not match created list of permissions" + ) + + rule.update(self.apiclient, ruleid=rule.id, permission='allow') + + list_rolepermissions = RolePermission.list(self.apiclient, roleid=self.role.id) + self.assertEqual( + list_rolepermissions[0].permission, + 'allow', + msg="List of role permissions do not match created list of permissions" + ) + + @attr(tags=['advanced', 'simulator', 'basic', 'sg'], required_hardware=False) + def test_rolepermission_lifecycle_update_permission_negative(self): + """ + Tests negative test for setting incorrect value as permission + """ + permissions = [self.rolepermission] + + rule = permissions.pop(0) + try: + rule.update(self.apiclient, ruleid=rule.id, permission='some_other_value') + except Exception: + pass + else: + self.fail("Negative test: Setting permission to 'some_other_value' should not be successful, failing") @attr(tags=['advanced', 'simulator', 'basic', 'sg'], required_hardware=False) def test_rolepermission_lifecycle_concurrent_updates(self): diff --git a/ui/l10n/ar.js b/ui/l10n/ar.js index 599db00e573..538fd4b3608 100644 --- a/ui/l10n/ar.js +++ b/ui/l10n/ar.js @@ -2176,6 +2176,7 @@ var dictionary = { "message.restart.vpc": "يرجى تأكيد رغبتك في إعادة تشغيل الـVPN", "message.restart.vpc.remark": "Please confirm that you want to restart the VPC

Remark: making a non-redundant VPC redundant will force a clean up. The networks will not be available for a couple of minutes.

", "message.restoreVM": "Do you want to restore the VM ?", + "message.role.update.fail": "Failed updating rule permission", "message.role.ordering.fail": "Reordering of rule permissions aborted as the list has changed while you were making changes. Please try again.", "message.security.group.usage": "(Use Ctrl-click to select all applicable security groups)", "message.select.a.zone": "A zone typically corresponds to a single datacenter. Multiple zones help make the cloud more reliable by providing physical isolation and redundancy.", diff --git a/ui/l10n/ca.js b/ui/l10n/ca.js index a2f8fd4ce35..d97a948ef1b 100644 --- a/ui/l10n/ca.js +++ b/ui/l10n/ca.js @@ -2176,6 +2176,7 @@ var dictionary = { "message.restart.vpc": "Please confirm that you want to restart the VPC", "message.restart.vpc.remark": "Please confirm that you want to restart the VPC

Remark: making a non-redundant VPC redundant will force a clean up. The networks will not be available for a couple of minutes.

", "message.restoreVM": "Do you want to restore the VM ?", + "message.role.update.fail": "Failed updating rule permission", "message.role.ordering.fail": "Reordering of rule permissions aborted as the list has changed while you were making changes. Please try again.", "message.security.group.usage": "(Use Ctrl-click to select all applicable security groups)", "message.select.a.zone": "A zone typically corresponds to a single datacenter. Multiple zones help make the cloud more reliable by providing physical isolation and redundancy.", diff --git a/ui/l10n/de_DE.js b/ui/l10n/de_DE.js index 0df586116bf..f3d93bffec5 100644 --- a/ui/l10n/de_DE.js +++ b/ui/l10n/de_DE.js @@ -2176,6 +2176,7 @@ var dictionary = { "message.restart.vpc": "Bitte bestätigen Sie, dass Sie den VPC neu starten möchten", "message.restart.vpc.remark": "Bitte bestätigen Sie, dass Sie die VPC neu starten möchten

small>Hinweis: Ein nicht-redundante VPC redundant zu machen wird eine Bereinigung erzwingen. Die Netzwerke werden dadurch einige Minuten nicht verfügbar sein.

", "message.restoreVM": "Möchten Sie die VM wiederherstellen?", + "message.role.update.fail": "Failed updating rule permission", "message.role.ordering.fail": "Die Neuordnung der Regelberechtigungen wurde abgebrochen, es sind Änderungen eingetreten während Sie an der Liste Arbeiten durchgeführt haben. Bitte versuchen Sie es erneut.", "message.security.group.usage": "(Verwenden Sie Ctrl-click um alle passenden Sicherheits Gruppen auszuwählen)", "message.select.a.zone": "Eine Zone steht typischerweise für ein einzelnes Rechenzentrum. Mehrere Zonen helfen dabei, die Cloud zuverlässiger zu machen durch physikalische Isolation und Redundanz.", diff --git a/ui/l10n/en.js b/ui/l10n/en.js index 3503296c69f..8cfa419e9b2 100644 --- a/ui/l10n/en.js +++ b/ui/l10n/en.js @@ -2207,6 +2207,7 @@ var dictionary = {"ICMP.code":"ICMP Code", "message.restart.vpc":"Please confirm that you want to restart the VPC", "message.restart.vpc.remark":"Please confirm that you want to restart the VPC

Remark: making a non-redundant VPC redundant will force a clean up. The networks will not be available for a couple of minutes.

", "message.restoreVM":"Do you want to restore the VM ?", +"message.role.update.fail": "Failed updating rule permission", "message.role.ordering.fail":"Reordering of rule permissions aborted as the list has changed while you were making changes. Please try again.", "message.security.group.usage":"(Use Ctrl-click to select all applicable security groups)", "message.select.a.zone":"A zone typically corresponds to a single datacenter. Multiple zones help make the cloud more reliable by providing physical isolation and redundancy.", diff --git a/ui/l10n/es.js b/ui/l10n/es.js index eee421f41ed..38ec9c00ac2 100644 --- a/ui/l10n/es.js +++ b/ui/l10n/es.js @@ -2176,6 +2176,7 @@ var dictionary = { "message.restart.vpc": "Por favor confirme que usted quiere reiniciar el VPC", "message.restart.vpc.remark": "Por favor confirme que desea reiniciar el VPC

Atención: creando un VPC sin redundancia forzara la limpieza. Todas las redes dejaran de estar disponibles por unos minutos.

", "message.restoreVM": "¿Desea recuperar la MV?", + "message.role.update.fail": "Failed updating rule permission", "message.role.ordering.fail": "Reordenación de permisos de reglas abortada ya que la lista ha cambiado mientras realizaba los cambios. Por favor, intente de nuevo. ", "message.security.group.usage": "(Use Ctrl-click para seleccionar todos los grupos de seguridad pertinentes)", "message.select.a.zone": "Una zona normalmente se corresponde con un solo datacenter. Múltiples zonas pueden ayudar a aumentar la disponibilidad del cloud al proveer aislamiento físico y redundancia.", diff --git a/ui/l10n/fr_FR.js b/ui/l10n/fr_FR.js index 8a03fb0ea35..0bb6a0dc8c9 100644 --- a/ui/l10n/fr_FR.js +++ b/ui/l10n/fr_FR.js @@ -2176,6 +2176,7 @@ var dictionary = { "message.restart.vpc": "Confirmer le redémarrage du VPC", "message.restart.vpc.remark": "Veuillez confirmer que vous voulez redémarrer le VPC

Note : transformer un VPC non-redondant en VPC redondant va forcer un nettoyage du routeur. Le réseau associé ne sera pas disponible durant quelques minutes.

", "message.restoreVM": "Voulez-vous restaurer la VM ?", + "message.role.update.fail": "Failed updating rule permission", "message.role.ordering.fail": "La réorganisation des règles d'autorisations a été abandonnée car la liste a changé pendant que vous apportez des modifications. Veuillez réessayer.", "message.security.group.usage": "(Utilisez Ctrl-clic pour sélectionner les groupes de sécurité visés)", "message.select.a.zone": "Une zone correspond typiquement à un seul centre de données. Des zones multiples peuvent permettre de rendre votre cloud plus fiable en apportant une isolation physique et de la redondance.", diff --git a/ui/l10n/hu.js b/ui/l10n/hu.js index 726cab8cb28..3da69417fca 100644 --- a/ui/l10n/hu.js +++ b/ui/l10n/hu.js @@ -2176,6 +2176,7 @@ var dictionary = { "message.restart.vpc": "Erősítsd meg, hogy újra akarod indítani a VPC-t!", "message.restart.vpc.remark": "Erősítsd meg, hogy újra akarod indítani a VPC-t!

Megjegyzés: egy nem redundáns VPC redundánssá tétele takarítást tesz szükségessé. A hálózatok nem lesznek elérhetőek egy pár percig..

", "message.restoreVM": "Helyre akarod állítani a VM-et?", + "message.role.update.fail": "Failed updating rule permission", "message.role.ordering.fail": "Reordering of rule permissions aborted as the list has changed while you were making changes. Please try again.", "message.security.group.usage": "(A Ctrl-kattintás használatával tudod az összes alkalmazható biztonsági csoportot kiválasztani)", "message.select.a.zone": "Egy zóna tipikusan egy adatközpontnak felel meg. Több zóna segíthet a felhőt megbízhatóbbá tenni fizikai izolációval és redundanciával.", diff --git a/ui/l10n/it_IT.js b/ui/l10n/it_IT.js index 71875a3d30d..247b8e04a73 100644 --- a/ui/l10n/it_IT.js +++ b/ui/l10n/it_IT.js @@ -2176,6 +2176,7 @@ var dictionary = { "message.restart.vpc": "Si prega di confermare di voler riavviare VPC", "message.restart.vpc.remark": "Please confirm that you want to restart the VPC

Remark: making a non-redundant VPC redundant will force a clean up. The networks will not be available for a couple of minutes.

", "message.restoreVM": "Do you want to restore the VM ?", + "message.role.update.fail": "Failed updating rule permission", "message.role.ordering.fail": "Reordering of rule permissions aborted as the list has changed while you were making changes. Please try again.", "message.security.group.usage": "(Use Ctrl-click to select all applicable security groups)", "message.select.a.zone": "Una zona corrisponde tipicamente ad un singolo datacenter. Zone multiple consentono di aumentare l'affidabilità creando isolamento fisico e ridondanza.", diff --git a/ui/l10n/ja_JP.js b/ui/l10n/ja_JP.js index 5a55e870d76..a5da1a37d77 100644 --- a/ui/l10n/ja_JP.js +++ b/ui/l10n/ja_JP.js @@ -2180,6 +2180,7 @@ var dictionary = { "message.restart.vpc": "VPC を再起動してもよろしいですか?", "message.restart.vpc.remark": "VPC を再起動してもよろしいですか?

注意: 非冗長 VPC の冗長化は強制的にクリーンアップされます. また、ネットワークは数分間利用出来なくなります.

", "message.restoreVM": "VM を復元してもよろしいですか?", + "message.role.update.fail": "Failed updating rule permission", "message.role.ordering.fail": "Reordering of rule permissions aborted as the list has changed while you were making changes. Please try again.", "message.security.group.usage": "(該当するセキュリティ グループをすべて選択するには、Ctrl キーを押しながらクリックしてください)", "message.select.a.zone": "ゾーンは通常、単一のデータセンターに相当します。複数のゾーンを設定し、物理的に分離して冗長性を持たせることにより、クラウドの信頼性を高めます。", diff --git a/ui/l10n/ko_KR.js b/ui/l10n/ko_KR.js index ca222386602..f592a7c1c87 100644 --- a/ui/l10n/ko_KR.js +++ b/ui/l10n/ko_KR.js @@ -2176,6 +2176,7 @@ var dictionary = { "message.restart.vpc": "VPC를 재시작하시겠습니까?", "message.restart.vpc.remark": "Please confirm that you want to restart the VPC

Remark: making a non-redundant VPC redundant will force a clean up. The networks will not be available for a couple of minutes.

", "message.restoreVM": "Do you want to restore the VM ?", + "message.role.update.fail": "Failed updating rule permission", "message.role.ordering.fail": "Reordering of rule permissions aborted as the list has changed while you were making changes. Please try again.", "message.security.group.usage": "(해당하는 보안 그룹을 모두 선택하려면 Ctrl 키를 누르면서 클릭해 주십시오)", "message.select.a.zone": "Zone은 원래 단일 데이터 센터에 해당합니다. 복수 Zone을 설정하고 물리적으로 분리하는 방법으로 클라우드의 신뢰성을 높일 수 있습니다.", diff --git a/ui/l10n/nb_NO.js b/ui/l10n/nb_NO.js index 801ce7fa458..1ef414572c4 100644 --- a/ui/l10n/nb_NO.js +++ b/ui/l10n/nb_NO.js @@ -2176,6 +2176,7 @@ var dictionary = { "message.restart.vpc": "Vennligst bekreft at du ønsker å restarte VPC", "message.restart.vpc.remark": "Vennligst bekreft du at du vil restarte VPC

Merk: Å gjøre en ikke reduntant VPC redundant vil tvinge en opprydning. Nettverkene vil ikke være tilgjengelig i noen minutter.

", "message.restoreVM": "Vil du gjenopprette denne VMen?", + "message.role.update.fail": "Failed updating rule permission", "message.role.ordering.fail": "Reordering of rule permissions aborted as the list has changed while you were making changes. Please try again.", "message.security.group.usage": "(Bruk Ctrl-klikk for å velge alle aktuelle sikkerhetsgrupper)", "message.select.a.zone": "En sone er typisk sett på som et datasenter. Multiple soner gir CloudStack bedre pålitelighet gjennom isolasjon og redundans.", diff --git a/ui/l10n/nl_NL.js b/ui/l10n/nl_NL.js index 10456e86839..58465f377d4 100644 --- a/ui/l10n/nl_NL.js +++ b/ui/l10n/nl_NL.js @@ -2176,6 +2176,7 @@ var dictionary = { "message.restart.vpc": "Bevestig dat u deze VPC wilt herstarten", "message.restart.vpc.remark": "Bevestig altublieft dat U de VPC wilt herstarten

Opmerking: Een niet-redundante VPC redundant maken zal opschonen forceren. De netwerken zullen enige tijd niet beschikbaar zijn.

", "message.restoreVM": "Wilt u de VM herstellen?", + "message.role.update.fail": "Failed updating rule permission", "message.role.ordering.fail": "Reordering of rule permissions aborted as the list has changed while you were making changes. Please try again.", "message.security.group.usage": "(Gebruik Ctrl-klik om meerdere security groups te selecteren)", "message.select.a.zone": "Een zone correspondeert meestal met een enkel datacenter. Meerdere zones maken de cloud betrouwbaarder door fysiek isolatie en redunatie te verzorgen.", diff --git a/ui/l10n/pl.js b/ui/l10n/pl.js index 80bc1f334d6..1ba89b25cc1 100644 --- a/ui/l10n/pl.js +++ b/ui/l10n/pl.js @@ -2176,6 +2176,7 @@ var dictionary = { "message.restart.vpc": "Please confirm that you want to restart the VPC", "message.restart.vpc.remark": "Please confirm that you want to restart the VPC

Remark: making a non-redundant VPC redundant will force a clean up. The networks will not be available for a couple of minutes.

", "message.restoreVM": "Do you want to restore the VM ?", + "message.role.update.fail": "Failed updating rule permission", "message.role.ordering.fail": "Reordering of rule permissions aborted as the list has changed while you were making changes. Please try again.", "message.security.group.usage": "(Use Ctrl-click to select all applicable security groups)", "message.select.a.zone": "A zone typically corresponds to a single datacenter. Multiple zones help make the cloud more reliable by providing physical isolation and redundancy.", diff --git a/ui/l10n/pt_BR.js b/ui/l10n/pt_BR.js index bc34f156d88..77bfe53eed1 100644 --- a/ui/l10n/pt_BR.js +++ b/ui/l10n/pt_BR.js @@ -2176,6 +2176,7 @@ var dictionary = { "message.restart.vpc": "Favor confirmar que você deseja reiniciar a VPC", "message.restart.vpc.remark": "Por favor, confirme a reinicialização do VPC

Observação: fazendo um VPC redundante não redundante irá forçar uma limpeza. As redes não estarão disponíveis por alguns minutos.

", "message.restoreVM": "Quer restaurar a VM?", + "message.role.update.fail": "Failed updating rule permission", "message.role.ordering.fail": "Reordering of rule permissions aborted as the list has changed while you were making changes. Please try again.", "message.security.group.usage": "(Use Ctrl-clique para selecionar todos os Security Groups)", "message.select.a.zone": "A zone tipicamente corresponde a um único datacenter. Múltiplas zonas auxiliam a cloud a ser mais confiável provendo isolamento físico e redundância.", diff --git a/ui/l10n/ru_RU.js b/ui/l10n/ru_RU.js index f9fd5db64ce..aaa40b8f9a3 100644 --- a/ui/l10n/ru_RU.js +++ b/ui/l10n/ru_RU.js @@ -2176,6 +2176,7 @@ var dictionary = { "message.restart.vpc": "Подтвердите, что вы действительно хотите перезапустить VPC", "message.restart.vpc.remark": "Please confirm that you want to restart the VPC

Remark: making a non-redundant VPC redundant will force a clean up. The networks will not be available for a couple of minutes.

", "message.restoreVM": "Do you want to restore the VM ?", + "message.role.update.fail": "Failed updating rule permission", "message.role.ordering.fail": "Reordering of rule permissions aborted as the list has changed while you were making changes. Please try again.", "message.security.group.usage": "(Используйте Ctrl-click для выбора всех применимых security groups)", "message.select.a.zone": "Зона обычно соответствует единичному центру обработки данных. Несколько зон помогают создавать более надежные облака, обеспечивая физическую изоляцию и избыточность.", diff --git a/ui/l10n/zh_CN.js b/ui/l10n/zh_CN.js index 54646b02488..2131c985cff 100644 --- a/ui/l10n/zh_CN.js +++ b/ui/l10n/zh_CN.js @@ -2180,6 +2180,7 @@ var dictionary = { "message.restart.vpc": "请确认您确实要重新启动 VPC", "message.restart.vpc.remark": "请确定您要重启VPC

警告: 重启非冗余的VPC将会导致网络中断,直至VPC重启完成.

", "message.restoreVM": "是否要还原此 VM?", + "message.role.update.fail": "Failed updating rule permission", "message.role.ordering.fail": "Reordering of rule permissions aborted as the list has changed while you were making changes. Please try again.", "message.security.group.usage": "(按住 Ctrl 键并单击鼠标可选择所有适用的安全组)", "message.select.a.zone": "一个资源域通常与一个数据中心相对应。多个资源域可以提供物理隔离和冗余,有助于使云更加可靠。", diff --git a/ui/scripts/roles.js b/ui/scripts/roles.js index eae088fafa8..01700dfc9a5 100644 --- a/ui/scripts/roles.js +++ b/ui/scripts/roles.js @@ -171,6 +171,28 @@ context: context, noSelect: true, noHeaderActionsColumn: true, + selectPermission: { + action: function(args){ + $.ajax({ + url: createURL("updateRolePermission"), + data: { + roleid: args.roleid, + ruleid: args.ruleid, + permission: args.permission + }, + dataType: "json", + async: true, + success: function(json) { + $(window).trigger('cloudStack.fullRefresh'); + }, + error: function(json) { + cloudStack.dialog.notice({ + message: 'message.role.update.fail' + }); + } + }); + } + }, reorder: { moveDrag: { action: function(args) { @@ -193,6 +215,7 @@ }); $.ajax({ + type: 'POST', url: createURL('updateRolePermission'), data: { roleid: rule.roleid, diff --git a/ui/scripts/ui/widgets/multiEdit.js b/ui/scripts/ui/widgets/multiEdit.js index 3e88b929394..48d597e6859 100755 --- a/ui/scripts/ui/widgets/multiEdit.js +++ b/ui/scripts/ui/widgets/multiEdit.js @@ -31,6 +31,7 @@ var $item = $('
').addClass('data-item'); var multiRule = data; var reorder = options.reorder; + var selectPermission = options.selectPermission; $item.append($('').append($(''))); $tr = $('').appendTo($item.find('tbody')); @@ -189,10 +190,34 @@ return $(this).val() == data[fieldName]; }); - var matchingValue = $matchingOption.size() ? - $matchingOption.html() : data[fieldName]; + if (selectPermission) { + // Wrap div to get its html code + selectedOptionHtml = $matchingOption.clone().wrap('
').parent().html(); + // Get html code from not matching option + $matchingSelect.find('option').each( + function() { + if ($(this).val() != data[fieldName]){ + selectedOptionHtml += $(this).clone().wrap('
').parent().html(); + } + } + ); + $select = $('
').appendTo( $('').appendTo($inputTable) @@ -1197,7 +1223,8 @@ preFilter: actionPreFilter, listView: listView, tags: tags, - reorder: reorder + reorder: reorder, + selectPermission: selectPermission } ).appendTo($dataBody); });