[test-only][full-ci] Api tests. get notification on different languages (#6254)
* get notification on different languages * set default english if no configured * fix * fix after review * fix after rebase * after review
This commit is contained in:
@@ -13,7 +13,7 @@ default:
|
|||||||
ldapGroupsOU: TestGroups
|
ldapGroupsOU: TestGroups
|
||||||
ldapInitialUserFilePath: /../../config/ldap-users.ldif
|
ldapInitialUserFilePath: /../../config/ldap-users.ldif
|
||||||
contexts:
|
contexts:
|
||||||
- RoleAssignmentContext:
|
- SettingsContext:
|
||||||
- GraphContext:
|
- GraphContext:
|
||||||
- SpacesContext:
|
- SpacesContext:
|
||||||
- FeatureContext: &common_feature_context_params
|
- FeatureContext: &common_feature_context_params
|
||||||
@@ -37,7 +37,7 @@ default:
|
|||||||
- '%paths.base%/../features/apiSpaces'
|
- '%paths.base%/../features/apiSpaces'
|
||||||
context: *common_ldap_suite_context
|
context: *common_ldap_suite_context
|
||||||
contexts:
|
contexts:
|
||||||
- RoleAssignmentContext:
|
- SettingsContext:
|
||||||
- SpacesContext:
|
- SpacesContext:
|
||||||
- FeatureContext: *common_feature_context_params
|
- FeatureContext: *common_feature_context_params
|
||||||
- CapabilitiesContext:
|
- CapabilitiesContext:
|
||||||
@@ -60,7 +60,7 @@ default:
|
|||||||
- '%paths.base%/../features/apiSpacesShares'
|
- '%paths.base%/../features/apiSpacesShares'
|
||||||
context: *common_ldap_suite_context
|
context: *common_ldap_suite_context
|
||||||
contexts:
|
contexts:
|
||||||
- RoleAssignmentContext:
|
- SettingsContext:
|
||||||
- SpacesContext:
|
- SpacesContext:
|
||||||
- FeatureContext: *common_feature_context_params
|
- FeatureContext: *common_feature_context_params
|
||||||
- CapabilitiesContext:
|
- CapabilitiesContext:
|
||||||
@@ -82,7 +82,7 @@ default:
|
|||||||
- '%paths.base%/../features/apiContract'
|
- '%paths.base%/../features/apiContract'
|
||||||
context: *common_ldap_suite_context
|
context: *common_ldap_suite_context
|
||||||
contexts:
|
contexts:
|
||||||
- RoleAssignmentContext:
|
- SettingsContext:
|
||||||
- SpacesContext:
|
- SpacesContext:
|
||||||
- FeatureContext: *common_feature_context_params
|
- FeatureContext: *common_feature_context_params
|
||||||
- CapabilitiesContext:
|
- CapabilitiesContext:
|
||||||
@@ -103,7 +103,7 @@ default:
|
|||||||
- '%paths.base%/../features/apiArchiver'
|
- '%paths.base%/../features/apiArchiver'
|
||||||
context: *common_ldap_suite_context
|
context: *common_ldap_suite_context
|
||||||
contexts:
|
contexts:
|
||||||
- RoleAssignmentContext:
|
- SettingsContext:
|
||||||
- ArchiverContext:
|
- ArchiverContext:
|
||||||
- SpacesContext:
|
- SpacesContext:
|
||||||
- FeatureContext: *common_feature_context_params
|
- FeatureContext: *common_feature_context_params
|
||||||
@@ -122,7 +122,7 @@ default:
|
|||||||
- '%paths.base%/../features/apiGraph'
|
- '%paths.base%/../features/apiGraph'
|
||||||
context: *common_ldap_suite_context
|
context: *common_ldap_suite_context
|
||||||
contexts:
|
contexts:
|
||||||
- RoleAssignmentContext:
|
- SettingsContext:
|
||||||
- GraphContext:
|
- GraphContext:
|
||||||
- SpacesContext:
|
- SpacesContext:
|
||||||
- FeatureContext: *common_feature_context_params
|
- FeatureContext: *common_feature_context_params
|
||||||
@@ -185,7 +185,7 @@ default:
|
|||||||
- FavoritesContext:
|
- FavoritesContext:
|
||||||
- ChecksumContext:
|
- ChecksumContext:
|
||||||
- FilesVersionsContext:
|
- FilesVersionsContext:
|
||||||
- RoleAssignmentContext:
|
- SettingsContext:
|
||||||
|
|
||||||
extensions:
|
extensions:
|
||||||
rdx\behatvars\BehatVariablesExtension: ~
|
rdx\behatvars\BehatVariablesExtension: ~
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
@api
|
@api
|
||||||
Feature: Notification
|
Feature: Notification
|
||||||
As a user
|
As a user
|
||||||
I want to be notified of actions related to me
|
I want to be notified of actions related to me
|
||||||
@@ -21,108 +21,160 @@ Feature: Notification
|
|||||||
When user "Brian" lists all notifications
|
When user "Brian" lists all notifications
|
||||||
Then the HTTP status code should be "200"
|
Then the HTTP status code should be "200"
|
||||||
And the JSON response should contain a notification message with the subject "Space shared" and the message-details should match
|
And the JSON response should contain a notification message with the subject "Space shared" and the message-details should match
|
||||||
"""
|
"""
|
||||||
{
|
{
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"required": [
|
"required": [
|
||||||
"app",
|
"app",
|
||||||
"datetime",
|
"datetime",
|
||||||
"message",
|
"message",
|
||||||
"messageRich",
|
"messageRich",
|
||||||
"messageRichParameters",
|
"messageRichParameters",
|
||||||
"notification_id",
|
"notification_id",
|
||||||
"object_id",
|
"object_id",
|
||||||
"object_type",
|
"object_type",
|
||||||
"subject",
|
"subject",
|
||||||
"subjectRich",
|
"subjectRich",
|
||||||
"user"
|
"user"
|
||||||
],
|
],
|
||||||
"properties": {
|
"properties": {
|
||||||
"app": {
|
"app": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"enum": ["userlog"]
|
"enum": [
|
||||||
},
|
"userlog"
|
||||||
"message": {
|
]
|
||||||
"type": "string",
|
},
|
||||||
"enum": ["Alice Hansen added you to Space notification checking"]
|
"message": {
|
||||||
},
|
"type": "string",
|
||||||
"messageRich": {
|
"enum": [
|
||||||
"type": "string",
|
"Alice Hansen added you to Space notification checking"
|
||||||
"enum": ["{user} added you to Space {space}"]
|
]
|
||||||
},
|
},
|
||||||
"messageRichParameters": {
|
"messageRich": {
|
||||||
"type": "object",
|
"type": "string",
|
||||||
"required": [
|
"enum": [
|
||||||
"space",
|
"{user} added you to Space {space}"
|
||||||
"user"
|
]
|
||||||
],
|
},
|
||||||
"properties": {
|
"messageRichParameters": {
|
||||||
"space": {
|
"type": "object",
|
||||||
"type": "object",
|
"required": [
|
||||||
"required": [
|
"space",
|
||||||
"id",
|
"user"
|
||||||
"name"
|
],
|
||||||
],
|
"properties": {
|
||||||
"properties": {
|
"space": {
|
||||||
"id": {
|
"type": "object",
|
||||||
"type": "string",
|
"required": [
|
||||||
"pattern": "^[a-fA-F0-9]{8}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{12}\\$[a-fA-F0-9]{8}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{12}![a-fA-F0-9]{8}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{12}$"
|
"id",
|
||||||
},
|
"name"
|
||||||
"name": {
|
],
|
||||||
"type": "string",
|
"properties": {
|
||||||
"enum": ["notification checking"]
|
"id": {
|
||||||
|
"type": "string",
|
||||||
|
"pattern": "^[a-fA-F0-9]{8}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{12}\\$[a-fA-F0-9]{8}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{12}![a-fA-F0-9]{8}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{12}$"
|
||||||
|
},
|
||||||
|
"name": {
|
||||||
|
"type": "string",
|
||||||
|
"enum": [
|
||||||
|
"notification checking"
|
||||||
|
]
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
},
|
"user": {
|
||||||
"user": {
|
"type": "object",
|
||||||
"type": "object",
|
"required": [
|
||||||
"required": [
|
"displayname",
|
||||||
"displayname",
|
"id",
|
||||||
"id",
|
"name"
|
||||||
"name"
|
],
|
||||||
],
|
"properties": {
|
||||||
"properties": {
|
"displayname": {
|
||||||
"displayname": {
|
"type": "string",
|
||||||
"type": "string",
|
"enum": [
|
||||||
"enum": ["Alice Hansen"]
|
"Alice Hansen"
|
||||||
},
|
]
|
||||||
"id": {
|
},
|
||||||
"type": "string",
|
"id": {
|
||||||
"enim": ["%user_id%"]
|
"type": "string",
|
||||||
},
|
"enim": [
|
||||||
"name": {
|
"%user_id%"
|
||||||
"type": "string",
|
]
|
||||||
"enum": ["Alice"]
|
},
|
||||||
|
"name": {
|
||||||
|
"type": "string",
|
||||||
|
"enum": [
|
||||||
|
"Alice"
|
||||||
|
]
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
"notification_id": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"object_id": {
|
||||||
|
"type": "string",
|
||||||
|
"pattern": "^%space_id_pattern%$"
|
||||||
|
},
|
||||||
|
"object_type": {
|
||||||
|
"type": "string",
|
||||||
|
"enum": [
|
||||||
|
"storagespace"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"subject": {
|
||||||
|
"type": "string",
|
||||||
|
"enum": [
|
||||||
|
"Space shared"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"subjectRich": {
|
||||||
|
"type": "string",
|
||||||
|
"enum": [
|
||||||
|
"Space shared"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"user": {
|
||||||
|
"type": "string",
|
||||||
|
"enum": [
|
||||||
|
"Alice"
|
||||||
|
]
|
||||||
}
|
}
|
||||||
},
|
|
||||||
"notification_id": {
|
|
||||||
"type": "string"
|
|
||||||
|
|
||||||
},
|
|
||||||
"object_id": {
|
|
||||||
"type": "string"
|
|
||||||
|
|
||||||
},
|
|
||||||
"object_type": {
|
|
||||||
"type": "string",
|
|
||||||
"enum": ["storagespace"]
|
|
||||||
},
|
|
||||||
"subject": {
|
|
||||||
"type": "string",
|
|
||||||
"enum": ["Space shared"]
|
|
||||||
},
|
|
||||||
"subjectRich": {
|
|
||||||
"type": "string",
|
|
||||||
"enum": ["Space shared"]
|
|
||||||
},
|
|
||||||
"user": {
|
|
||||||
"type": "string",
|
|
||||||
"enum": ["Alice"]
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
"""
|
||||||
"""
|
|
||||||
|
|
||||||
|
|
||||||
|
Scenario Outline: user gets a notification of space sharing in different languages
|
||||||
|
Given user "Alice" has created a space "notification checking" with the default quota using the GraphApi
|
||||||
|
And user "Brian" has switched the system language to "<language>"
|
||||||
|
And user "Alice" has shared a space "notification checking" with settings:
|
||||||
|
| shareWith | Brian |
|
||||||
|
| role | editor |
|
||||||
|
When user "Brian" lists all notifications
|
||||||
|
Then the HTTP status code should be "200"
|
||||||
|
And the JSON response should contain a notification message with the subject "<subject>" and the message-details should match
|
||||||
|
"""
|
||||||
|
{
|
||||||
|
"type": "object",
|
||||||
|
"required": [
|
||||||
|
"message"
|
||||||
|
],
|
||||||
|
"properties": {
|
||||||
|
"message": {
|
||||||
|
"type": "string",
|
||||||
|
"enum": [
|
||||||
|
"<message>"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
"""
|
||||||
|
Examples:
|
||||||
|
| language | subject | message |
|
||||||
|
| de | Space freigegeben | Alice Hansen hat Sie zu Space notification checking hinzugefügt |
|
||||||
|
| en | Space shared | Alice Hansen added you to Space notification checking |
|
||||||
|
| es | Space compartido | Alice Hansen te añadió al Space notification checking |
|
||||||
|
|||||||
@@ -22,9 +22,8 @@ require_once 'bootstrap.php';
|
|||||||
*/
|
*/
|
||||||
class NotificationContext implements Context {
|
class NotificationContext implements Context {
|
||||||
private FeatureContext $featureContext;
|
private FeatureContext $featureContext;
|
||||||
|
|
||||||
private SpacesContext $spacesContext;
|
private SpacesContext $spacesContext;
|
||||||
|
private SettingsContext $settingsContext;
|
||||||
private string $notificationEndpointPath = '/apps/notifications/api/v1/notifications?format=json';
|
private string $notificationEndpointPath = '/apps/notifications/api/v1/notifications?format=json';
|
||||||
|
|
||||||
private array $notificationIds;
|
private array $notificationIds;
|
||||||
@@ -78,6 +77,7 @@ class NotificationContext implements Context {
|
|||||||
// Get all the contexts you need in this context
|
// Get all the contexts you need in this context
|
||||||
$this->featureContext = $environment->getContext('FeatureContext');
|
$this->featureContext = $environment->getContext('FeatureContext');
|
||||||
$this->spacesContext = $environment->getContext('SpacesContext');
|
$this->spacesContext = $environment->getContext('SpacesContext');
|
||||||
|
$this->settingsContext = $environment->getContext('SettingsContext');
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -89,13 +89,17 @@ class NotificationContext implements Context {
|
|||||||
*/
|
*/
|
||||||
public function userListAllNotifications(string $user):void {
|
public function userListAllNotifications(string $user):void {
|
||||||
$this->setUserRecipient($user);
|
$this->setUserRecipient($user);
|
||||||
|
$headers = ["accept-language" => $this->settingsContext->getSettingLanguageValue($user)];
|
||||||
$response = OcsApiHelper::sendRequest(
|
$response = OcsApiHelper::sendRequest(
|
||||||
$this->featureContext->getBaseUrl(),
|
$this->featureContext->getBaseUrl(),
|
||||||
$this->featureContext->getActualUsername($user),
|
$this->featureContext->getActualUsername($user),
|
||||||
$this->featureContext->getPasswordForUser($user),
|
$this->featureContext->getPasswordForUser($user),
|
||||||
'GET',
|
'GET',
|
||||||
$this->notificationEndpointPath,
|
$this->notificationEndpointPath,
|
||||||
$this->featureContext->getStepLineRef()
|
$this->featureContext->getStepLineRef(),
|
||||||
|
[],
|
||||||
|
2,
|
||||||
|
$headers
|
||||||
);
|
);
|
||||||
$this->featureContext->setResponse($response);
|
$this->featureContext->setResponse($response);
|
||||||
}
|
}
|
||||||
|
|||||||
+155
-1
@@ -1,4 +1,5 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
declare(strict_types=1);
|
declare(strict_types=1);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -18,7 +19,7 @@ require_once 'bootstrap.php';
|
|||||||
/**
|
/**
|
||||||
* Context for the TUS-specific steps using the Graph API
|
* Context for the TUS-specific steps using the Graph API
|
||||||
*/
|
*/
|
||||||
class RoleAssignmentContext implements Context {
|
class SettingsContext implements Context {
|
||||||
private FeatureContext $featureContext;
|
private FeatureContext $featureContext;
|
||||||
private SpacesContext $spacesContext;
|
private SpacesContext $spacesContext;
|
||||||
private string $baseUrl;
|
private string $baseUrl;
|
||||||
@@ -256,4 +257,157 @@ class RoleAssignmentContext implements Context {
|
|||||||
$assignmentRoleId = $this->featureContext->getJsonDecodedResponse($this->featureContext->getResponse())["assignments"][0]["roleId"];
|
$assignmentRoleId = $this->featureContext->getJsonDecodedResponse($this->featureContext->getResponse())["assignments"][0]["roleId"];
|
||||||
Assert::assertEquals($this->userGetRoleIdByRoleName($this->featureContext->getAdminUserName(), $role), $assignmentRoleId, "user has no role $role");
|
Assert::assertEquals($this->userGetRoleIdByRoleName($this->featureContext->getAdminUserName(), $role), $assignmentRoleId, "user has no role $role");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param string $user
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*
|
||||||
|
* @throws GuzzleException
|
||||||
|
* @throws Exception
|
||||||
|
*/
|
||||||
|
public function sendRequestGetBundlesList(string $user): void {
|
||||||
|
$fullUrl = $this->baseUrl . $this->settingsUrl . "bundles-list";
|
||||||
|
$this->featureContext->setResponse(
|
||||||
|
$this->spacesContext->sendPostRequestToUrl($fullUrl, $user, $this->featureContext->getPasswordForUser($user), '{}')
|
||||||
|
);
|
||||||
|
|
||||||
|
$this->featureContext->theHTTPStatusCodeShouldBe(
|
||||||
|
201,
|
||||||
|
"Expected response status code should be 201"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param string $user
|
||||||
|
* @param string $bundleName
|
||||||
|
*
|
||||||
|
* @return array
|
||||||
|
*
|
||||||
|
* @throws GuzzleException
|
||||||
|
* @throws Exception
|
||||||
|
*/
|
||||||
|
public function getBundlesList(string $user, string $bundleName): array {
|
||||||
|
$this->sendRequestGetBundlesList($user);
|
||||||
|
$body = json_decode((string)$this->featureContext->getResponse()->getBody(), true, 512, JSON_THROW_ON_ERROR);
|
||||||
|
foreach ($body["bundles"] as $value) {
|
||||||
|
if ($value["displayName"] === $bundleName) {
|
||||||
|
return $value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param string $user
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*
|
||||||
|
* @throws GuzzleException
|
||||||
|
* @throws Exception
|
||||||
|
*/
|
||||||
|
public function sendRequestGetSettingsValuesList(string $user): void {
|
||||||
|
$fullUrl = $this->baseUrl . $this->settingsUrl . "values-list";
|
||||||
|
$body = json_encode(["account_uuid" => "me"], JSON_THROW_ON_ERROR);
|
||||||
|
$this->featureContext->setResponse(
|
||||||
|
$this->spacesContext->sendPostRequestToUrl($fullUrl, $user, $this->featureContext->getPasswordForUser($user), $body)
|
||||||
|
);
|
||||||
|
|
||||||
|
$this->featureContext->theHTTPStatusCodeShouldBe(
|
||||||
|
201,
|
||||||
|
"Expected response status code should be 201"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param string $user
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*
|
||||||
|
* @throws GuzzleException
|
||||||
|
* @throws Exception
|
||||||
|
*/
|
||||||
|
public function getSettingLanguageValue(string $user): string {
|
||||||
|
$this->sendRequestGetSettingsValuesList($user);
|
||||||
|
$body = json_decode((string)$this->featureContext->getResponse()->getBody(), true, 512, JSON_THROW_ON_ERROR);
|
||||||
|
|
||||||
|
// if no language is set, the request body is empty return English as the default language
|
||||||
|
if (empty($body)) {
|
||||||
|
return "en";
|
||||||
|
}
|
||||||
|
foreach ($body["values"] as $value) {
|
||||||
|
if ($value["identifier"]["setting"] === "language") {
|
||||||
|
return $value["value"]["listValue"]["values"][0]["stringValue"];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param string $user
|
||||||
|
* @param string $language
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*
|
||||||
|
* @throws GuzzleException
|
||||||
|
* @throws Exception
|
||||||
|
*/
|
||||||
|
public function sendRequestToSwitchSystemLanguage(string $user, string $language): void {
|
||||||
|
$profileBundlesList = $this->getBundlesList($user, "Profile");
|
||||||
|
Assert::assertNotEmpty($profileBundlesList, "bundles list is empty");
|
||||||
|
|
||||||
|
$settingId = '';
|
||||||
|
foreach ($profileBundlesList["settings"] as $value) {
|
||||||
|
if ($value["name"] === "language") {
|
||||||
|
$settingId = $value["id"];
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Assert::assertNotEmpty($settingId, "settingId is empty");
|
||||||
|
|
||||||
|
$fullUrl = $this->baseUrl . $this->settingsUrl . "values-save";
|
||||||
|
$userId = $this->featureContext->getAttributeOfCreatedUser($user, 'id');
|
||||||
|
$body = json_encode(
|
||||||
|
[
|
||||||
|
"value" => [
|
||||||
|
"account_uuid" => "me",
|
||||||
|
"bundleId" => $profileBundlesList["id"],
|
||||||
|
"id" => $userId,
|
||||||
|
"listValue" => [
|
||||||
|
"values" => [
|
||||||
|
[
|
||||||
|
"stringValue" => $language
|
||||||
|
]
|
||||||
|
]
|
||||||
|
],
|
||||||
|
"resource" => [
|
||||||
|
"type" => "TYPE_USER"
|
||||||
|
],
|
||||||
|
"settingId" => $settingId
|
||||||
|
]
|
||||||
|
],
|
||||||
|
JSON_THROW_ON_ERROR
|
||||||
|
);
|
||||||
|
|
||||||
|
$this->featureContext->setResponse(
|
||||||
|
$this->spacesContext->sendPostRequestToUrl($fullUrl, $user, $this->featureContext->getPasswordForUser($user), $body)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Given /^user "([^"]*)" has switched the system language to "([^"]*)"$/
|
||||||
|
*
|
||||||
|
* @param string $user
|
||||||
|
* @param string $language
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*
|
||||||
|
* @throws Exception
|
||||||
|
*/
|
||||||
|
public function theUserHasSwitchedSysemLanguage(string $user, string $language): void {
|
||||||
|
$this->sendRequestToSwitchSystemLanguage($user, $language);
|
||||||
|
$this->featureContext->theHTTPStatusCodeShouldBe(
|
||||||
|
201,
|
||||||
|
"Expected response status code should be 201"
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user