CLOUDSTACK-10044: Update role permission (#2236)

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
This commit is contained in:
Nicolas Vazquez 2017-08-11 07:24:50 -03:00 committed by Rohit Yadav
parent c13af1e85a
commit 3f330a2199
25 changed files with 193 additions and 14 deletions

View File

@ -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<RolePermission> newOrder);
boolean updateRolePermission(final Role role, final RolePermission rolePermission, final Permission permission);
boolean deleteRolePermission(final RolePermission rolePermission);
List<Role> listRoles();

View File

@ -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";

View File

@ -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<Long> 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<RolePermission> 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<RolePermission> 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);

View File

@ -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<RolePermissionVO, Long> {
*/
boolean update(final Role role, final List<RolePermission> 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

View File

@ -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<RolePermissionVO, Lon
});
}
@Override
public boolean update(Role role, RolePermission rolePermission, Permission permission) {
if (role == null || rolePermission == null || permission == null) {
return false;
}
RolePermissionVO rolePermissionVO = findById(rolePermission.getId());
if (rolePermissionVO == null || role.getId() != rolePermission.getRoleId() || rolePermissionVO.getId() != rolePermission.getId()) {
return false;
}
rolePermissionVO.setPermission(permission);
return update(rolePermission.getId(), rolePermissionVO);
}
@Override
public List<RolePermissionVO> findAllByRoleIdSorted(final Long roleId) {
final SearchCriteria<RolePermissionVO> sc = RolePermissionsSearch.create();

View File

@ -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) {

View File

@ -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):

View File

@ -2176,6 +2176,7 @@ var dictionary = {
"message.restart.vpc": "يرجى تأكيد رغبتك في إعادة تشغيل الـVPN",
"message.restart.vpc.remark": "Please confirm that you want to restart the VPC <p><small><i>Remark: making a non-redundant VPC redundant will force a clean up. The networks will not be available for a couple of minutes</i>.</small></p>",
"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 <strong>Ctrl-click</strong> 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.",

View File

@ -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 <p><small><i>Remark: making a non-redundant VPC redundant will force a clean up. The networks will not be available for a couple of minutes</i>.</small></p>",
"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 <strong>Ctrl-click</strong> 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.",

View File

@ -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 <p>small><i>Hinweis: Ein nicht-redundante VPC redundant zu machen wird eine Bereinigung erzwingen. Die Netzwerke werden dadurch einige Minuten nicht verfügbar sein</i>.</small></p>",
"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 <strong>Ctrl-click</strong> 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.",

View File

@ -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 <p><small><i>Remark: making a non-redundant VPC redundant will force a clean up. The networks will not be available for a couple of minutes</i>.</small></p>",
"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 <strong>Ctrl-click</strong> 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.",

View File

@ -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 <p><small><i>Atención: creando un VPC sin redundancia forzara la limpieza. Todas las redes dejaran de estar disponibles por unos minutos</i>.</small></p>",
"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 <strong> Ctrl-click </strong> 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.",

View File

@ -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 <p><small><i>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</i>.</small></p>",
"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 <strong>Ctrl-clic</strong> 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.",

View File

@ -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! <p><small><i>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.</i>.</small></p>",
"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 <strong>Ctrl-kattintás</strong> 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.",

View File

@ -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 <p><small><i>Remark: making a non-redundant VPC redundant will force a clean up. The networks will not be available for a couple of minutes</i>.</small></p>",
"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 <strong>Ctrl-click</strong> 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.",

View File

@ -2180,6 +2180,7 @@ var dictionary = {
"message.restart.vpc": "VPC を再起動してもよろしいですか?",
"message.restart.vpc.remark": "VPC を再起動してもよろしいですか? <p><small><i>注意: 非冗長 VPC の冗長化は強制的にクリーンアップされます. また、ネットワークは数分間利用出来なくなります</i>.</small></p>",
"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": "(該当するセキュリティ グループをすべて選択するには、<strong>Ctrl キーを押しながらクリック</strong>してください)",
"message.select.a.zone": "ゾーンは通常、単一のデータセンターに相当します。複数のゾーンを設定し、物理的に分離して冗長性を持たせることにより、クラウドの信頼性を高めます。",

View File

@ -2176,6 +2176,7 @@ var dictionary = {
"message.restart.vpc": "VPC를 재시작하시겠습니까?",
"message.restart.vpc.remark": "Please confirm that you want to restart the VPC <p><small><i>Remark: making a non-redundant VPC redundant will force a clean up. The networks will not be available for a couple of minutes</i>.</small></p>",
"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": "(해당하는 보안 그룹을 모두 선택하려면 <strong>Ctrl 키를 누르면서 클릭</strong>해 주십시오)",
"message.select.a.zone": "Zone은 원래 단일 데이터 센터에 해당합니다. 복수 Zone을 설정하고 물리적으로 분리하는 방법으로 클라우드의 신뢰성을 높일 수 있습니다.",

View File

@ -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 <p><small><i>Merk: Å gjøre en ikke reduntant VPC redundant vil tvinge en opprydning. Nettverkene vil ikke være tilgjengelig i noen minutter</i>.</small></p>",
"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 <strong>Ctrl-klikk</strong> 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.",

View File

@ -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 <p><small><i>Opmerking: Een niet-redundante VPC redundant maken zal opschonen forceren. De netwerken zullen enige tijd niet beschikbaar zijn</i>.</small></p>",
"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 <strong>Ctrl-klik</strong> 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.",

View File

@ -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 <p><small><i>Remark: making a non-redundant VPC redundant will force a clean up. The networks will not be available for a couple of minutes</i>.</small></p>",
"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 <strong>Ctrl-click</strong> 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.",

View File

@ -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 <p><small><i>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</i>.</small></p>",
"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 <strong>Ctrl-clique</strong> 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.",

View File

@ -2176,6 +2176,7 @@ var dictionary = {
"message.restart.vpc": "Подтвердите, что вы действительно хотите перезапустить VPC",
"message.restart.vpc.remark": "Please confirm that you want to restart the VPC <p><small><i>Remark: making a non-redundant VPC redundant will force a clean up. The networks will not be available for a couple of minutes</i>.</small></p>",
"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": "(Используйте <strong>Ctrl-click</strong> для выбора всех применимых security groups)",
"message.select.a.zone": "Зона обычно соответствует единичному центру обработки данных. Несколько зон помогают создавать более надежные облака, обеспечивая физическую изоляцию и избыточность.",

View File

@ -2180,6 +2180,7 @@ var dictionary = {
"message.restart.vpc": "请确认您确实要重新启动 VPC",
"message.restart.vpc.remark": "请确定您要重启VPC <p><small><i> 警告: 重启非冗余的VPC将会导致网络中断,直至VPC重启完成</i>.</small></p>",
"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": "(<strong>按住 Ctrl 键并单击鼠标</strong>可选择所有适用的安全组)",
"message.select.a.zone": "一个资源域通常与一个数据中心相对应。多个资源域可以提供物理隔离和冗余,有助于使云更加可靠。",

View File

@ -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,

View File

@ -31,6 +31,7 @@
var $item = $('<div>').addClass('data-item');
var multiRule = data;
var reorder = options.reorder;
var selectPermission = options.selectPermission;
$item.append($('<table>').append($('<tbody>')));
$tr = $('<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('<div>').parent().html();
// Get html code from not matching option
$matchingSelect.find('option').each(
function() {
if ($(this).val() != data[fieldName]){
selectedOptionHtml += $(this).clone().wrap('<div>').parent().html();
}
}
);
$select = $('<select>');
$select.html(selectedOptionHtml);
$select.change(function(event) {
selectPermission.action({
roleid: data['roleid'],
ruleid: data['id'],
permission: $(this).val()
});
});
$td.append($select);
}
else {
var matchingValue = $matchingOption.size() ?
$matchingOption.html() : data[fieldName];
$td.append($('<span>').html(_s(matchingValue)));
$td.append($('<span>').html(_s(matchingValue)));
}
} else if (field.addButton && !options.noSelect) {
if (options.multipleAdd) {
$addButton.click(function() {
@ -862,6 +887,7 @@
var actionPreFilter = args.actionPreFilter;
var readOnlyCheck = args.readOnlyCheck;
var reorder = args.reorder;
var selectPermission = args.selectPermission;
var $thead = $('<tr>').appendTo(
$('<thead>').appendTo($inputTable)
@ -1197,7 +1223,8 @@
preFilter: actionPreFilter,
listView: listView,
tags: tags,
reorder: reorder
reorder: reorder,
selectPermission: selectPermission
}
).appendTo($dataBody);
});