mirror of
https://github.com/ceph/ceph
synced 2024-12-28 06:23:08 +00:00
Merge pull request #24757 from votdev/issue_36480
mgr/dashboard: Can't handle user editing when tenants are specified Reviewed-by: Ernesto Puerta <epuertat@redhat.com> Reviewed-by: Tatjana Dehler <tdehler@suse.com> Reviewed-by: Tiago Melo <tmelo@suse.com>
This commit is contained in:
commit
dc8237e94d
@ -1,8 +1,11 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
from __future__ import absolute_import
|
||||
import logging
|
||||
|
||||
from .helper import DashboardTestCase
|
||||
import logging
|
||||
import urllib
|
||||
import six
|
||||
|
||||
from .helper import DashboardTestCase, JObj, JList, JLeaf
|
||||
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
@ -124,6 +127,16 @@ class RgwBucketTest(RgwTestCase):
|
||||
def setUpClass(cls):
|
||||
cls.create_test_user = True
|
||||
super(RgwBucketTest, cls).setUpClass()
|
||||
# Create a tenanted user.
|
||||
cls._radosgw_admin_cmd([
|
||||
'user', 'create', '--tenant', 'testx', '--uid', 'teuth-test-user',
|
||||
'--display-name', 'tenanted teuth-test-user'
|
||||
])
|
||||
|
||||
@classmethod
|
||||
def tearDownClass(cls):
|
||||
cls._radosgw_admin_cmd(['user', 'rm', '--tenant', 'testx', '--uid=teuth-test-user'])
|
||||
super(RgwBucketTest, cls).tearDownClass()
|
||||
|
||||
def test_all(self):
|
||||
# Create a new bucket.
|
||||
@ -135,14 +148,20 @@ class RgwBucketTest(RgwTestCase):
|
||||
})
|
||||
self.assertStatus(201)
|
||||
data = self.jsonBody()
|
||||
self.assertIn('bucket_info', data)
|
||||
data = data['bucket_info']
|
||||
self.assertIn('bucket', data)
|
||||
self.assertIn('quota', data)
|
||||
self.assertIn('creation_time', data)
|
||||
self.assertIn('name', data['bucket'])
|
||||
self.assertIn('bucket_id', data['bucket'])
|
||||
self.assertEqual(data['bucket']['name'], 'teuth-test-bucket')
|
||||
self.assertSchema(data, JObj(sub_elems={
|
||||
'bucket_info': JObj(sub_elems={
|
||||
'bucket': JObj(allow_unknown=True, sub_elems={
|
||||
'name': JLeaf(str),
|
||||
'bucket_id': JLeaf(str),
|
||||
'tenant': JLeaf(str)
|
||||
}),
|
||||
'quota': JObj(sub_elems={}, allow_unknown=True),
|
||||
'creation_time': JLeaf(str)
|
||||
}, allow_unknown=True)
|
||||
}, allow_unknown=True))
|
||||
data = data['bucket_info']['bucket']
|
||||
self.assertEqual(data['name'], 'teuth-test-bucket')
|
||||
self.assertEqual(data['tenant'], '')
|
||||
|
||||
# List all buckets.
|
||||
data = self._get('/api/rgw/bucket')
|
||||
@ -153,10 +172,14 @@ class RgwBucketTest(RgwTestCase):
|
||||
# Get the bucket.
|
||||
data = self._get('/api/rgw/bucket/teuth-test-bucket')
|
||||
self.assertStatus(200)
|
||||
self.assertIn('id', data)
|
||||
self.assertIn('bucket', data)
|
||||
self.assertIn('bucket_quota', data)
|
||||
self.assertIn('owner', data)
|
||||
self.assertSchema(data, JObj(sub_elems={
|
||||
'id': JLeaf(str),
|
||||
'bid': JLeaf(str),
|
||||
'tenant': JLeaf(str),
|
||||
'bucket': JLeaf(str),
|
||||
'bucket_quota': JObj(sub_elems={}, allow_unknown=True),
|
||||
'owner': JLeaf(str)
|
||||
}, allow_unknown=True))
|
||||
self.assertEqual(data['bucket'], 'teuth-test-bucket')
|
||||
self.assertEqual(data['owner'], 'admin')
|
||||
|
||||
@ -170,6 +193,11 @@ class RgwBucketTest(RgwTestCase):
|
||||
self.assertStatus(200)
|
||||
data = self._get('/api/rgw/bucket/teuth-test-bucket')
|
||||
self.assertStatus(200)
|
||||
self.assertSchema(data, JObj(sub_elems={
|
||||
'owner': JLeaf(str),
|
||||
'bid': JLeaf(str),
|
||||
'tenant': JLeaf(str)
|
||||
}, allow_unknown=True))
|
||||
self.assertEqual(data['owner'], 'teuth-test-user')
|
||||
|
||||
# Delete the bucket.
|
||||
@ -179,6 +207,65 @@ class RgwBucketTest(RgwTestCase):
|
||||
self.assertStatus(200)
|
||||
self.assertEqual(len(data), 0)
|
||||
|
||||
def test_create_get_update_delete_w_tenant(self):
|
||||
# Create a new bucket. The tenant of the user is used when
|
||||
# the bucket is created.
|
||||
self._post(
|
||||
'/api/rgw/bucket',
|
||||
params={
|
||||
'bucket': 'teuth-test-bucket',
|
||||
'uid': 'testx$teuth-test-user'
|
||||
})
|
||||
self.assertStatus(201)
|
||||
# It's not possible to validate the result because there
|
||||
# IS NO result object returned by the RGW Admin OPS API
|
||||
# when a tenanted bucket is created.
|
||||
data = self.jsonBody()
|
||||
self.assertIsNone(data)
|
||||
|
||||
# List all buckets.
|
||||
data = self._get('/api/rgw/bucket')
|
||||
self.assertStatus(200)
|
||||
self.assertEqual(len(data), 1)
|
||||
self.assertIn('testx/teuth-test-bucket', data)
|
||||
|
||||
# Get the bucket.
|
||||
data = self._get('/api/rgw/bucket/{}'.format(urllib.quote_plus(
|
||||
'testx/teuth-test-bucket')))
|
||||
self.assertStatus(200)
|
||||
self.assertSchema(data, JObj(sub_elems={
|
||||
'owner': JLeaf(str),
|
||||
'bucket': JLeaf(str),
|
||||
'tenant': JLeaf(str),
|
||||
'bid': JLeaf(str)
|
||||
}, allow_unknown=True))
|
||||
self.assertEqual(data['owner'], 'testx$teuth-test-user')
|
||||
self.assertEqual(data['bucket'], 'teuth-test-bucket')
|
||||
self.assertEqual(data['tenant'], 'testx')
|
||||
self.assertEqual(data['bid'], 'testx/teuth-test-bucket')
|
||||
|
||||
# Update the bucket.
|
||||
self._put(
|
||||
'/api/rgw/bucket/{}'.format(urllib.quote_plus('testx/teuth-test-bucket')),
|
||||
params={
|
||||
'bucket_id': data['id'],
|
||||
'uid': 'admin'
|
||||
})
|
||||
self.assertStatus(200)
|
||||
data = self._get('/api/rgw/bucket/{}'.format(urllib.quote_plus(
|
||||
'testx/teuth-test-bucket')))
|
||||
self.assertStatus(200)
|
||||
self.assertIn('owner', data)
|
||||
self.assertEqual(data['owner'], 'admin')
|
||||
|
||||
# Delete the bucket.
|
||||
self._delete('/api/rgw/bucket/{}'.format(urllib.quote_plus(
|
||||
'testx/teuth-test-bucket')))
|
||||
self.assertStatus(204)
|
||||
data = self._get('/api/rgw/bucket')
|
||||
self.assertStatus(200)
|
||||
self.assertEqual(len(data), 0)
|
||||
|
||||
|
||||
class RgwDaemonTest(DashboardTestCase):
|
||||
|
||||
@ -237,17 +324,20 @@ class RgwUserTest(RgwTestCase):
|
||||
super(RgwUserTest, cls).setUpClass()
|
||||
|
||||
def _assert_user_data(self, data):
|
||||
self.assertIn('caps', data)
|
||||
self.assertIn('display_name', data)
|
||||
self.assertIn('email', data)
|
||||
self.assertIn('keys', data)
|
||||
self.assertSchema(data, JObj(sub_elems={
|
||||
'caps': JList(JObj(sub_elems={}, allow_unknown=True)),
|
||||
'display_name': JLeaf(str),
|
||||
'email': JLeaf(str),
|
||||
'keys': JList(JObj(sub_elems={}, allow_unknown=True)),
|
||||
'max_buckets': JLeaf(int),
|
||||
'subusers': JList(JLeaf(str)),
|
||||
'suspended': JLeaf(int),
|
||||
'swift_keys': JList(JObj(sub_elems={}, allow_unknown=True)),
|
||||
'tenant': JLeaf(str),
|
||||
'user_id': JLeaf(str),
|
||||
'uid': JLeaf(str)
|
||||
}, allow_unknown=True))
|
||||
self.assertGreaterEqual(len(data['keys']), 1)
|
||||
self.assertIn('max_buckets', data)
|
||||
self.assertIn('subusers', data)
|
||||
self.assertIn('suspended', data)
|
||||
self.assertIn('swift_keys', data)
|
||||
self.assertIn('tenant', data)
|
||||
self.assertIn('user_id', data)
|
||||
|
||||
def test_get(self):
|
||||
data = self.get_rgw_user('admin')
|
||||
@ -261,7 +351,7 @@ class RgwUserTest(RgwTestCase):
|
||||
self.assertGreaterEqual(len(data), 1)
|
||||
self.assertIn('admin', data)
|
||||
|
||||
def test_create_update_delete(self):
|
||||
def test_create_get_update_delete(self):
|
||||
# Create a new user.
|
||||
self._post('/api/rgw/user', params={
|
||||
'uid': 'teuth-test-user',
|
||||
@ -277,7 +367,9 @@ class RgwUserTest(RgwTestCase):
|
||||
data = self.get_rgw_user('teuth-test-user')
|
||||
self.assertStatus(200)
|
||||
self._assert_user_data(data)
|
||||
self.assertEqual(data['tenant'], '')
|
||||
self.assertEqual(data['user_id'], 'teuth-test-user')
|
||||
self.assertEqual(data['uid'], 'teuth-test-user')
|
||||
|
||||
# Update the user.
|
||||
self._put(
|
||||
@ -302,6 +394,49 @@ class RgwUserTest(RgwTestCase):
|
||||
self.assertIn('"HostId"', resp['detail'])
|
||||
self.assertIn('"RequestId"', resp['detail'])
|
||||
|
||||
def test_create_get_update_delete_w_tenant(self):
|
||||
# Create a new user.
|
||||
self._post('/api/rgw/user', params={
|
||||
'uid': 'test01$teuth-test-user',
|
||||
'display_name': 'display name'
|
||||
})
|
||||
self.assertStatus(201)
|
||||
data = self.jsonBody()
|
||||
self._assert_user_data(data)
|
||||
self.assertEqual(data['user_id'], 'teuth-test-user')
|
||||
self.assertEqual(data['display_name'], 'display name')
|
||||
|
||||
# Get the user.
|
||||
data = self.get_rgw_user('test01$teuth-test-user')
|
||||
self.assertStatus(200)
|
||||
self._assert_user_data(data)
|
||||
self.assertEqual(data['tenant'], 'test01')
|
||||
self.assertEqual(data['user_id'], 'teuth-test-user')
|
||||
self.assertEqual(data['uid'], 'test01$teuth-test-user')
|
||||
|
||||
# Update the user.
|
||||
self._put(
|
||||
'/api/rgw/user/test01$teuth-test-user',
|
||||
params={
|
||||
'display_name': 'new name'
|
||||
})
|
||||
self.assertStatus(200)
|
||||
data = self.jsonBody()
|
||||
self._assert_user_data(data)
|
||||
self.assertEqual(data['display_name'], 'new name')
|
||||
|
||||
# Delete the user.
|
||||
self._delete('/api/rgw/user/test01$teuth-test-user')
|
||||
self.assertStatus(204)
|
||||
self.get_rgw_user('test01$teuth-test-user')
|
||||
self.assertStatus(500)
|
||||
resp = self.jsonBody()
|
||||
self.assertIn('detail', resp)
|
||||
self.assertIn('failed request with status code 404', resp['detail'])
|
||||
self.assertIn('"Code":"NoSuchUser"', resp['detail'])
|
||||
self.assertIn('"HostId"', resp['detail'])
|
||||
self.assertIn('"RequestId"', resp['detail'])
|
||||
|
||||
|
||||
class RgwUserCapabilityTest(RgwTestCase):
|
||||
|
||||
|
@ -105,11 +105,27 @@ class RgwRESTController(RESTController):
|
||||
@ApiController('/rgw/bucket', Scope.RGW)
|
||||
class RgwBucket(RgwRESTController):
|
||||
|
||||
def _append_bid(self, bucket):
|
||||
"""
|
||||
Append the bucket identifier that looks like [<tenant>/]<bucket>.
|
||||
See http://docs.ceph.com/docs/nautilus/radosgw/multitenancy/ for
|
||||
more information.
|
||||
:param bucket: The bucket parameters.
|
||||
:type bucket: dict
|
||||
:return: The modified bucket parameters including the 'bid' parameter.
|
||||
:rtype: dict
|
||||
"""
|
||||
if isinstance(bucket, dict):
|
||||
bucket['bid'] = '{}/{}'.format(bucket['tenant'], bucket['bucket']) \
|
||||
if bucket['tenant'] else bucket['bucket']
|
||||
return bucket
|
||||
|
||||
def list(self):
|
||||
return self.proxy('GET', 'bucket')
|
||||
|
||||
def get(self, bucket):
|
||||
return self.proxy('GET', 'bucket', {'bucket': bucket})
|
||||
result = self.proxy('GET', 'bucket', {'bucket': bucket})
|
||||
return self._append_bid(result)
|
||||
|
||||
def create(self, bucket, uid):
|
||||
try:
|
||||
@ -119,11 +135,12 @@ class RgwBucket(RgwRESTController):
|
||||
raise DashboardException(e, http_status_code=500, component='rgw')
|
||||
|
||||
def set(self, bucket, bucket_id, uid):
|
||||
return self.proxy('PUT', 'bucket', {
|
||||
result = self.proxy('PUT', 'bucket', {
|
||||
'bucket': bucket,
|
||||
'bucket-id': bucket_id,
|
||||
'uid': uid
|
||||
}, json_response=False)
|
||||
return self._append_bid(result)
|
||||
|
||||
def delete(self, bucket, purge_objects='true'):
|
||||
return self.proxy('DELETE', 'bucket', {
|
||||
@ -135,11 +152,27 @@ class RgwBucket(RgwRESTController):
|
||||
@ApiController('/rgw/user', Scope.RGW)
|
||||
class RgwUser(RgwRESTController):
|
||||
|
||||
def _append_uid(self, user):
|
||||
"""
|
||||
Append the user identifier that looks like [<tenant>$]<user>.
|
||||
See http://docs.ceph.com/docs/jewel/radosgw/multitenancy/ for
|
||||
more information.
|
||||
:param user: The user parameters.
|
||||
:type user: dict
|
||||
:return: The modified user parameters including the 'uid' parameter.
|
||||
:rtype: dict
|
||||
"""
|
||||
if isinstance(user, dict):
|
||||
user['uid'] = '{}${}'.format(user['tenant'], user['user_id']) \
|
||||
if user['tenant'] else user['user_id']
|
||||
return user
|
||||
|
||||
def list(self):
|
||||
return self.proxy('GET', 'metadata/user')
|
||||
|
||||
def get(self, uid):
|
||||
return self.proxy('GET', 'user', {'uid': uid})
|
||||
result = self.proxy('GET', 'user', {'uid': uid})
|
||||
return self._append_uid(result)
|
||||
|
||||
def create(self, uid, display_name, email=None, max_buckets=None,
|
||||
suspended=None, generate_key=None, access_key=None,
|
||||
@ -159,7 +192,8 @@ class RgwUser(RgwRESTController):
|
||||
params['access-key'] = access_key
|
||||
if secret_key is not None:
|
||||
params['secret-key'] = secret_key
|
||||
return self.proxy('PUT', 'user', params)
|
||||
result = self.proxy('PUT', 'user', params)
|
||||
return self._append_uid(result)
|
||||
|
||||
def set(self, uid, display_name=None, email=None, max_buckets=None,
|
||||
suspended=None):
|
||||
@ -172,7 +206,8 @@ class RgwUser(RgwRESTController):
|
||||
params['max-buckets'] = max_buckets
|
||||
if suspended is not None:
|
||||
params['suspended'] = suspended
|
||||
return self.proxy('POST', 'user', params)
|
||||
result = self.proxy('POST', 'user', params)
|
||||
return self._append_uid(result)
|
||||
|
||||
def delete(self, uid):
|
||||
try:
|
||||
|
@ -205,7 +205,7 @@ const routes: Routes = [
|
||||
children: [
|
||||
{ path: '', component: RgwBucketListComponent },
|
||||
{ path: 'add', component: RgwBucketFormComponent, data: { breadcrumbs: 'Add' } },
|
||||
{ path: 'edit/:bucket', component: RgwBucketFormComponent, data: { breadcrumbs: 'Edit' } }
|
||||
{ path: 'edit/:bid', component: RgwBucketFormComponent, data: { breadcrumbs: 'Edit' } }
|
||||
]
|
||||
}
|
||||
]
|
||||
|
@ -6,7 +6,7 @@
|
||||
<tr>
|
||||
<td i18n
|
||||
class="bold col-sm-1">Name</td>
|
||||
<td class="col-sm-3">{{ bucket.bucket }}</td>
|
||||
<td class="col-sm-3">{{ bucket.bid }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td i18n
|
||||
|
@ -36,31 +36,31 @@
|
||||
|
||||
<!-- Name -->
|
||||
<div class="form-group"
|
||||
[ngClass]="{'has-error': bucketForm.showError('bucket', frm)}">
|
||||
[ngClass]="{'has-error': bucketForm.showError('bid', frm)}">
|
||||
<label class="control-label col-sm-3"
|
||||
for="bucket">
|
||||
for="bid">
|
||||
<ng-container i18n>Name</ng-container>
|
||||
<span class="required"
|
||||
*ngIf="!editing"></span>
|
||||
</label>
|
||||
<div class="col-sm-9">
|
||||
<input id="bucket"
|
||||
name="bucket"
|
||||
<input id="bid"
|
||||
name="bid"
|
||||
class="form-control"
|
||||
type="text"
|
||||
i18n-placeholder
|
||||
placeholder="Name..."
|
||||
formControlName="bucket"
|
||||
formControlName="bid"
|
||||
[readonly]="editing"
|
||||
autofocus>
|
||||
<span class="help-block"
|
||||
*ngIf="bucketForm.showError('bucket', frm, 'required')"
|
||||
*ngIf="bucketForm.showError('bid', frm, 'required')"
|
||||
i18n>This field is required.</span>
|
||||
<span class="help-block"
|
||||
*ngIf="bucketForm.showError('bucket', frm, 'bucketNameInvalid')"
|
||||
*ngIf="bucketForm.showError('bid', frm, 'bucketNameInvalid')"
|
||||
i18n>The value is not valid.</span>
|
||||
<span class="help-block"
|
||||
*ngIf="bucketForm.showError('bucket', frm, 'bucketNameExists')"
|
||||
*ngIf="bucketForm.showError('bid', frm, 'bucketNameExists')"
|
||||
i18n>The chosen name is already in use.</span>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -34,7 +34,7 @@ export class RgwBucketFormComponent implements OnInit {
|
||||
createForm() {
|
||||
this.bucketForm = this.formBuilder.group({
|
||||
id: [null],
|
||||
bucket: [null, [Validators.required], [this.bucketNameValidator()]],
|
||||
bid: [null, [Validators.required], [this.bucketNameValidator()]],
|
||||
owner: [null, [Validators.required]]
|
||||
});
|
||||
}
|
||||
@ -47,15 +47,15 @@ export class RgwBucketFormComponent implements OnInit {
|
||||
|
||||
// Process route parameters.
|
||||
this.route.params.subscribe(
|
||||
(params: { bucket: string }) => {
|
||||
if (!params.hasOwnProperty('bucket')) {
|
||||
(params: { bid: string }) => {
|
||||
if (!params.hasOwnProperty('bid')) {
|
||||
return;
|
||||
}
|
||||
params.bucket = decodeURIComponent(params.bucket);
|
||||
const bid = decodeURIComponent(params.bid);
|
||||
this.loading = true;
|
||||
// Load the bucket data in 'edit' mode.
|
||||
this.editing = true;
|
||||
this.rgwBucketService.get(params.bucket).subscribe((resp: object) => {
|
||||
this.rgwBucketService.get(bid).subscribe((resp: object) => {
|
||||
this.loading = false;
|
||||
// Get the default values.
|
||||
const defaults = _.clone(this.bucketForm.value);
|
||||
@ -82,12 +82,12 @@ export class RgwBucketFormComponent implements OnInit {
|
||||
if (this.bucketForm.pristine) {
|
||||
this.goToListView();
|
||||
}
|
||||
const bucketCtl = this.bucketForm.get('bucket');
|
||||
const bidCtl = this.bucketForm.get('bid');
|
||||
const ownerCtl = this.bucketForm.get('owner');
|
||||
if (this.editing) {
|
||||
// Edit
|
||||
const idCtl = this.bucketForm.get('id');
|
||||
this.rgwBucketService.update(bucketCtl.value, idCtl.value, ownerCtl.value).subscribe(
|
||||
this.rgwBucketService.update(bidCtl.value, idCtl.value, ownerCtl.value).subscribe(
|
||||
() => {
|
||||
this.goToListView();
|
||||
},
|
||||
@ -98,7 +98,7 @@ export class RgwBucketFormComponent implements OnInit {
|
||||
);
|
||||
} else {
|
||||
// Add
|
||||
this.rgwBucketService.create(bucketCtl.value, ownerCtl.value).subscribe(
|
||||
this.rgwBucketService.create(bidCtl.value, ownerCtl.value).subscribe(
|
||||
() => {
|
||||
this.goToListView();
|
||||
},
|
||||
|
@ -39,7 +39,7 @@ export class RgwBucketListComponent {
|
||||
this.columns = [
|
||||
{
|
||||
name: this.i18n('Name'),
|
||||
prop: 'bucket',
|
||||
prop: 'bid',
|
||||
flexGrow: 1
|
||||
},
|
||||
{
|
||||
@ -49,7 +49,7 @@ export class RgwBucketListComponent {
|
||||
}
|
||||
];
|
||||
const getBucketUri = () =>
|
||||
this.selection.first() && `${encodeURI(this.selection.first().bucket)}`;
|
||||
this.selection.first() && `${encodeURIComponent(this.selection.first().bid)}`;
|
||||
const addAction: CdTableAction = {
|
||||
permission: 'create',
|
||||
icon: 'fa-plus',
|
||||
@ -97,7 +97,7 @@ export class RgwBucketListComponent {
|
||||
// Delete all selected data table rows.
|
||||
observableForkJoin(
|
||||
this.selection.selected.map((bucket: any) => {
|
||||
return this.rgwBucketService.delete(bucket.bucket);
|
||||
return this.rgwBucketService.delete(bucket.bid);
|
||||
})
|
||||
).subscribe(
|
||||
null,
|
||||
|
@ -7,7 +7,7 @@
|
||||
<tr>
|
||||
<td i18n
|
||||
class="bold col-sm-1">Username</td>
|
||||
<td class="col-sm-3">{{ user.user_id }}</td>
|
||||
<td class="col-sm-3">{{ user.uid }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td i18n
|
||||
@ -24,6 +24,11 @@
|
||||
class="bold col-sm-1">Suspended</td>
|
||||
<td class="col-sm-3">{{ user.suspended ? "Yes" : "No" }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td i18n
|
||||
class="bold col-sm-1">System</td>
|
||||
<td class="col-sm-3">{{ user.system ? "Yes" : "No" }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td i18n
|
||||
class="bold col-sm-1">Maximum buckets</td>
|
||||
|
@ -64,11 +64,9 @@ export class RgwUserDetailsComponent implements OnChanges, OnInit {
|
||||
this.user.caps = _.sortBy(this.user.caps, 'type');
|
||||
|
||||
// Load the user/bucket quota of the selected user.
|
||||
if (this.user.tenant === '') {
|
||||
this.rgwUserService.getQuota(this.user.user_id).subscribe((resp: object) => {
|
||||
_.extend(this.user, resp);
|
||||
});
|
||||
}
|
||||
this.rgwUserService.getQuota(this.user.uid).subscribe((resp: object) => {
|
||||
_.extend(this.user, resp);
|
||||
});
|
||||
|
||||
// Process the keys.
|
||||
this.keys = [];
|
||||
|
@ -18,26 +18,26 @@
|
||||
|
||||
<!-- Username -->
|
||||
<div class="form-group"
|
||||
[ngClass]="{'has-error': userForm.showError('user_id', frm)}">
|
||||
[ngClass]="{'has-error': userForm.showError('uid', frm)}">
|
||||
<label class="control-label col-sm-3"
|
||||
for="user_id">
|
||||
for="uid">
|
||||
<ng-container i18n>Username</ng-container>
|
||||
<span class="required"
|
||||
*ngIf="!editing">
|
||||
</span>
|
||||
</label>
|
||||
<div class="col-sm-9">
|
||||
<input id="user_id"
|
||||
<input id="uid"
|
||||
class="form-control"
|
||||
type="text"
|
||||
formControlName="user_id"
|
||||
formControlName="uid"
|
||||
[readonly]="editing"
|
||||
autofocus>
|
||||
<span class="help-block"
|
||||
*ngIf="userForm.showError('user_id', frm, 'required')"
|
||||
*ngIf="userForm.showError('uid', frm, 'required')"
|
||||
i18n>This field is required.</span>
|
||||
<span class="help-block"
|
||||
*ngIf="userForm.showError('user_id', frm, 'notUnique')"
|
||||
*ngIf="userForm.showError('uid', frm, 'notUnique')"
|
||||
i18n>The chosen user ID is already in use.</span>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -119,19 +119,19 @@ describe('RgwUserFormComponent', () => {
|
||||
});
|
||||
|
||||
it('should validate that username is required', () => {
|
||||
formHelper.expectErrorChange('user_id', '', 'required', true);
|
||||
formHelper.expectErrorChange('uid', '', 'required', true);
|
||||
});
|
||||
|
||||
it('should validate that username is valid', fakeAsync(() => {
|
||||
formHelper.setValue('user_id', 'ab', true);
|
||||
formHelper.setValue('uid', 'ab', true);
|
||||
tick(500);
|
||||
formHelper.expectValid('user_id');
|
||||
formHelper.expectValid('uid');
|
||||
}));
|
||||
|
||||
it('should validate that username is invalid', fakeAsync(() => {
|
||||
formHelper.setValue('user_id', 'abc', true);
|
||||
formHelper.setValue('uid', 'abc', true);
|
||||
tick(500);
|
||||
formHelper.expectError('user_id', 'notUnique');
|
||||
formHelper.expectError('uid', 'notUnique');
|
||||
}));
|
||||
});
|
||||
|
||||
|
@ -51,7 +51,7 @@ export class RgwUserFormComponent implements OnInit {
|
||||
createForm() {
|
||||
this.userForm = this.formBuilder.group({
|
||||
// General
|
||||
user_id: [
|
||||
uid: [
|
||||
null,
|
||||
[Validators.required],
|
||||
[CdValidators.unique(this.rgwUserService.exists, this.rgwUserService)]
|
||||
@ -154,13 +154,14 @@ export class RgwUserFormComponent implements OnInit {
|
||||
if (!params.hasOwnProperty('uid')) {
|
||||
return;
|
||||
}
|
||||
const uid = decodeURIComponent(params.uid);
|
||||
this.loading = true;
|
||||
// Load the user data in 'edit' mode.
|
||||
this.editing = true;
|
||||
// Load the user and quota information.
|
||||
const observables = [];
|
||||
observables.push(this.rgwUserService.get(params.uid));
|
||||
observables.push(this.rgwUserService.getQuota(params.uid));
|
||||
observables.push(this.rgwUserService.get(uid));
|
||||
observables.push(this.rgwUserService.getQuota(uid));
|
||||
observableForkJoin(observables).subscribe(
|
||||
(resp: any[]) => {
|
||||
this.loading = false;
|
||||
@ -224,7 +225,7 @@ export class RgwUserFormComponent implements OnInit {
|
||||
if (this.userForm.pristine) {
|
||||
this.goToListView();
|
||||
}
|
||||
const uid = this.userForm.getValue('user_id');
|
||||
const uid = this.userForm.getValue('uid');
|
||||
if (this.editing) {
|
||||
// Edit
|
||||
if (this._isGeneralDirty()) {
|
||||
@ -284,7 +285,7 @@ export class RgwUserFormComponent implements OnInit {
|
||||
'full-control': 'full',
|
||||
'read-write': 'readwrite'
|
||||
};
|
||||
const uid = this.userForm.getValue('user_id');
|
||||
const uid = this.userForm.getValue('uid');
|
||||
const args = {
|
||||
subuser: subuser.id,
|
||||
access:
|
||||
@ -323,7 +324,7 @@ export class RgwUserFormComponent implements OnInit {
|
||||
const subuser = this.subusers[index];
|
||||
// Create an observable to delete the subuser when the form is submitted.
|
||||
this.submitObservables.push(
|
||||
this.rgwUserService.deleteSubuser(this.userForm.getValue('user_id'), subuser.id)
|
||||
this.rgwUserService.deleteSubuser(this.userForm.getValue('uid'), subuser.id)
|
||||
);
|
||||
// Remove the associated S3 keys.
|
||||
this.s3Keys = this.s3Keys.filter((key) => {
|
||||
@ -343,7 +344,7 @@ export class RgwUserFormComponent implements OnInit {
|
||||
* Add/Update a capability.
|
||||
*/
|
||||
setCapability(cap: RgwUserCapability, index?: number) {
|
||||
const uid = this.userForm.getValue('user_id');
|
||||
const uid = this.userForm.getValue('uid');
|
||||
if (_.isNumber(index)) {
|
||||
// Modify
|
||||
const oldCap = this.capabilities[index];
|
||||
@ -375,7 +376,7 @@ export class RgwUserFormComponent implements OnInit {
|
||||
const cap = this.capabilities[index];
|
||||
// Create an observable to delete the capability when the form is submitted.
|
||||
this.submitObservables.push(
|
||||
this.rgwUserService.deleteCapability(this.userForm.getValue('user_id'), cap.type, cap.perm)
|
||||
this.rgwUserService.deleteCapability(this.userForm.getValue('uid'), cap.type, cap.perm)
|
||||
);
|
||||
// Remove the capability to update the UI.
|
||||
this.capabilities.splice(index, 1);
|
||||
@ -423,7 +424,7 @@ export class RgwUserFormComponent implements OnInit {
|
||||
const key = this.s3Keys[index];
|
||||
// Create an observable to delete the S3 key when the form is submitted.
|
||||
this.submitObservables.push(
|
||||
this.rgwUserService.deleteS3Key(this.userForm.getValue('user_id'), key.access_key)
|
||||
this.rgwUserService.deleteS3Key(this.userForm.getValue('uid'), key.access_key)
|
||||
);
|
||||
// Remove the S3 key to update the UI.
|
||||
this.s3Keys.splice(index, 1);
|
||||
@ -436,7 +437,7 @@ export class RgwUserFormComponent implements OnInit {
|
||||
* @param {number | undefined} index The subuser to show.
|
||||
*/
|
||||
showSubuserModal(index?: number) {
|
||||
const uid = this.userForm.getValue('user_id');
|
||||
const uid = this.userForm.getValue('uid');
|
||||
const modalRef = this.bsModalService.show(RgwUserSubuserModalComponent);
|
||||
if (_.isNumber(index)) {
|
||||
// Edit
|
||||
@ -555,7 +556,7 @@ export class RgwUserFormComponent implements OnInit {
|
||||
*/
|
||||
private _getCreateArgs() {
|
||||
const result = {
|
||||
uid: this.userForm.getValue('user_id'),
|
||||
uid: this.userForm.getValue('uid'),
|
||||
display_name: this.userForm.getValue('display_name'),
|
||||
suspended: this.userForm.getValue('suspended'),
|
||||
email: '',
|
||||
@ -645,9 +646,9 @@ export class RgwUserFormComponent implements OnInit {
|
||||
private _getS3KeyUserCandidates() {
|
||||
let result = [];
|
||||
// Add the current user id.
|
||||
const user_id = this.userForm.getValue('user_id');
|
||||
if (_.isString(user_id) && !_.isEmpty(user_id)) {
|
||||
result.push(user_id);
|
||||
const uid = this.userForm.getValue('uid');
|
||||
if (_.isString(uid) && !_.isEmpty(uid)) {
|
||||
result.push(uid);
|
||||
}
|
||||
// Append the subusers.
|
||||
this.subusers.forEach((subUser) => {
|
||||
|
@ -40,7 +40,7 @@ export class RgwUserListComponent {
|
||||
this.columns = [
|
||||
{
|
||||
name: this.i18n('Username'),
|
||||
prop: 'user_id',
|
||||
prop: 'uid',
|
||||
flexGrow: 1
|
||||
},
|
||||
{
|
||||
@ -65,7 +65,8 @@ export class RgwUserListComponent {
|
||||
flexGrow: 1
|
||||
}
|
||||
];
|
||||
const getUserUri = () => this.selection.first() && this.selection.first().user_id;
|
||||
const getUserUri = () =>
|
||||
this.selection.first() && `${encodeURIComponent(this.selection.first().uid)}`;
|
||||
const addAction: CdTableAction = {
|
||||
permission: 'create',
|
||||
icon: 'fa-plus',
|
||||
@ -111,7 +112,7 @@ export class RgwUserListComponent {
|
||||
// Delete all selected data table rows.
|
||||
observableForkJoin(
|
||||
this.selection.selected.map((user: any) => {
|
||||
return this.rgwUserService.delete(user.user_id);
|
||||
return this.rgwUserService.delete(user.uid);
|
||||
})
|
||||
).subscribe(
|
||||
null,
|
||||
|
Loading…
Reference in New Issue
Block a user