Version Description
Download this release
Release Info
Developer | vasyltech |
Plugin | Advanced Access Manager |
Version | 6.0.0-alpha.2 |
Comparing to | |
See all releases |
Code changes from version 6.0.0-alpha.1 to 6.0.0-alpha.2
- aam.php +2 -5
- application/Backend/Feature.php +77 -28
- application/Backend/Feature/Abstract.php +1 -1
- application/Backend/Feature/Main/404Redirect.php +1 -1
- application/Backend/Feature/Main/Capability.php +21 -6
- application/Backend/Feature/Main/Jwt.php +1 -1
- application/Backend/Feature/Main/LoginRedirect.php +1 -1
- application/Backend/Feature/Main/LogoutRedirect.php +1 -1
- application/Backend/Feature/Main/Menu.php +1 -1
- application/Backend/Feature/Main/Metabox.php +1 -1
- application/Backend/Feature/Main/Policy.php +195 -111
- application/Backend/Feature/Main/Post.php +32 -22
- application/Backend/Feature/Main/Redirect.php +1 -1
- application/Backend/Feature/Main/Route.php +1 -1
- application/Backend/Feature/Main/Toolbar.php +1 -1
- application/Backend/Feature/Main/Uri.php +14 -20
- application/Backend/Feature/Main/Welcome.php +1 -1
- application/Backend/Feature/Settings/ConfigPress.php +1 -1
- application/Backend/Feature/Settings/Content.php +1 -1
- application/Backend/Feature/Settings/Core.php +1 -1
- application/Backend/Feature/Settings/Manager.php +19 -2
- application/Backend/Feature/Settings/Security.php +1 -1
- application/Backend/Feature/Settings/Service.php +1 -1
- application/Backend/Feature/Subject/Role.php +23 -9
- application/Backend/Feature/Subject/User.php +30 -8
- application/Backend/Manager.php +1 -1
- application/Backend/Subject.php +2 -2
- application/Backend/View.php +104 -41
- application/Backend/View/Localization.php +2 -0
- application/Backend/Widget/Login.php +2 -2
- application/Backend/phtml/metabox/policy-metabox.phtml +0 -427
- application/Backend/phtml/metabox/policy-principal-metabox.phtml +0 -3
- application/Backend/{phtml/index.phtml → tmpl/index.php} +4 -6
- application/Backend/{phtml/metabox/iframe-footer.phtml → tmpl/metabox/iframe-footer.php} +0 -0
- application/Backend/{phtml/metabox/iframe-header.phtml → tmpl/metabox/iframe-header.php} +1 -1
- application/Backend/tmpl/metabox/policy-metabox.php +59 -0
- application/Backend/tmpl/metabox/policy-principal-metabox.php +3 -0
- application/Backend/{phtml/metabox/post-iframe.phtml → tmpl/metabox/post-iframe.php} +3 -3
- application/Backend/{phtml/metabox/post-metabox.phtml → tmpl/metabox/post-metabox.php} +0 -0
- application/Backend/tmpl/metabox/principal-iframe.php +12 -0
- application/Backend/{phtml/metabox/term-metabox.phtml → tmpl/metabox/term-metabox.php} +0 -0
- application/Backend/tmpl/metabox/user-iframe.php +21 -0
- application/Backend/tmpl/metabox/user-metabox.php +5 -0
- application/Backend/{phtml/page/addon-panel.phtml → tmpl/page/addon-panel.php} +0 -0
- application/Backend/{phtml/page/current-subject.phtml → tmpl/page/current-subject.php} +0 -0
- application/Backend/{phtml/page/main-panel.phtml → tmpl/page/main-panel.php} +0 -0
- application/Backend/{phtml/page/subject-panel-advanced.phtml → tmpl/page/subject-panel-advanced.php} +0 -0
- application/Backend/{phtml/page/subject-panel.phtml → tmpl/page/subject-panel.php} +7 -13
- application/Backend/tmpl/partial/default-principal-subject-tab.php +9 -0
- application/Backend/tmpl/partial/default-subject-tab.php +8 -0
- application/Backend/{phtml/partial/jwt-login-url.phtml → tmpl/partial/jwt-login-url.php} +0 -0
- application/Backend/tmpl/partial/loading-content.php +7 -0
- application/Backend/{phtml/partial/post-access-form.phtml → tmpl/partial/post-access-form.php} +10 -1
- application/Backend/{phtml/partial/posts-terms-help-tips.phtml → tmpl/partial/posts-terms-help-tips.php} +0 -0
- application/Backend/{phtml/partial/role-inheritance.phtml → tmpl/partial/role-inheritance.php} +0 -0
- application/Backend/{phtml/partial/taxonomy-access-form.phtml → tmpl/partial/taxonomy-access-form.php} +0 -0
- application/Backend/{phtml/partial/term-access-form.phtml → tmpl/partial/term-access-form.php} +0 -0
- application/Backend/{phtml/partial/type-access-form.phtml → tmpl/partial/type-access-form.php} +0 -0
- application/Backend/tmpl/partial/visitor-principal-subject-tab.php +17 -0
- application/Backend/tmpl/partial/visitor-subject-tab.php +8 -0
- application/Backend/tmpl/policy/default-policy.php +27 -0
- application/Backend/{phtml/service/404redirect.phtml → tmpl/service/404redirect.php} +0 -0
- application/Backend/{phtml/service/capability.phtml → tmpl/service/capability.php} +0 -0
- application/Backend/{phtml/service/jwt.phtml → tmpl/service/jwt.php} +0 -0
- application/Backend/{phtml/service/login-redirect.phtml → tmpl/service/login-redirect.php} +0 -0
- application/Backend/{phtml/service/logout-redirect.phtml → tmpl/service/logout-redirect.php} +0 -0
- application/Backend/{phtml/service/menu.phtml → tmpl/service/menu.php} +5 -1
- application/Backend/{phtml/service/metabox.phtml → tmpl/service/metabox.php} +7 -3
- application/Backend/{phtml/service/policy.phtml → tmpl/service/policy.php} +1 -1
- application/Backend/{phtml/service/post.phtml → tmpl/service/post.php} +0 -0
- application/Backend/{phtml/service/redirect.phtml → tmpl/service/redirect.php} +0 -0
- application/Backend/{phtml/service/route.phtml → tmpl/service/route.php} +0 -0
- application/Backend/{phtml/service/toolbar.phtml → tmpl/service/toolbar.php} +5 -5
- application/Backend/{phtml/service/uri.phtml → tmpl/service/uri.php} +0 -1
- application/Backend/{phtml/service/welcome.phtml → tmpl/service/welcome.php} +0 -0
- application/Backend/{phtml/settings/configpress.phtml → tmpl/settings/configpress.php} +0 -0
- application/Backend/{phtml/settings/content.phtml → tmpl/settings/content.php} +0 -0
- application/Backend/{phtml/settings/core.phtml → tmpl/settings/core.php} +0 -0
- application/Backend/{phtml/settings/security.phtml → tmpl/settings/security.php} +0 -0
- application/Backend/{phtml/settings/service.phtml → tmpl/settings/service.php} +1 -1
- application/Backend/{phtml/user/multiple-roles.phtml → tmpl/user/multiple-roles.php} +0 -0
- application/Backend/{phtml/widget/login-backend.phtml → tmpl/widget/login-backend.php} +0 -0
- application/Backend/{phtml/widget/login-frontend.phtml → tmpl/widget/login-frontend.php} +0 -0
- application/Core/API.php +11 -72
- application/Core/ConfigPress/Reader.php +4 -4
- application/Core/Contract/RequestTrait.php +62 -5
- application/Core/Gateway.php +5 -5
- application/Core/Jwt/Issuer.php +2 -2
- application/Core/Migration/2019_06_30-migrate-settings-to-6.0.0.php +4 -1
- application/Core/Object.php +65 -4
- application/Core/Object/LoginRedirect.php +1 -3
- application/Core/Object/LogoutRedirect.php +1 -3
- application/Core/Object/Menu.php +2 -6
- application/Core/Object/Metabox.php +4 -17
- application/Core/Object/Policy.php +16 -32
- application/Core/Object/Post.php +11 -46
- application/Core/Object/Redirect.php +1 -4
- application/Core/Object/Route.php +1 -3
- application/Core/Object/Toolbar.php +3 -5
- application/Core/Object/Uri.php +19 -23
- application/Core/Object/Visibility.php +47 -6
- application/Core/Policy/Condition.php +91 -87
- application/Core/Policy/Factory.php +39 -21
- application/Core/Policy/Manager.php +319 -284
- application/Core/Policy/Resource.php +82 -0
- application/Core/Policy/Token.php +50 -41
- application/Core/Policy/Validator.php +116 -62
- application/Core/Subject.php +2 -2
- application/Core/Subject/Role.php +19 -10
- application/Core/Subject/User.php +16 -8
- application/Service/AccessPolicy.php +434 -489
- application/Service/Content.php +38 -11
- application/Service/Core.php +28 -0
- application/Service/ExtendedCapabilities.php +3 -2
- application/Service/Jwt.php +46 -9
- application/Service/Metabox.php +2 -2
- application/Service/Route.php +1 -1
- application/Service/SecureLogin.php +4 -5
- application/Service/Settings.php +1 -0
- application/Service/Toolbar.php +2 -2
- application/Service/UserLevelFilter.php +42 -18
- application/Shortcode/Factory.php +2 -2
- lang/advanced-access-manager-en_US.po +1068 -989
- media/css/aam.css +16 -0
- media/css/vendor.min.css +6 -6
- media/js/aam.js +79 -49
- tests/Addon/IpCheck/IpCheckTest.php +343 -0
- tests/Addon/PlusPackage/ContentAccessTest.php +451 -0
- tests/Addon/PlusPackage/ContentVisibilityTest.php +204 -0
- tests/Addon/PlusPackage/DefaultCategoryTest.php +226 -0
- tests/Addon/PlusPackage/TermRESTfulAccessTest.php +221 -0
- tests/Addon/PlusPackage/UriAccessTest.php +101 -0
- tests/Addon/RoleHierarchy/RoleHierarchyTest.php +58 -0
- tests/Core/GatewayTest.php +90 -0
- tests/Core/SubjectLoadTest.php +32 -0
- tests/Libs/AuthManagerUserTrait.php +36 -0
- tests/Libs/AuthMultiRoleUserTrait.php +57 -0
- tests/Libs/AuthUserTrait.php +37 -0
- tests/Libs/MultiRoleOptionInterface.php +17 -0
- tests/Libs/ResetTrait.php +92 -0
- tests/Service/AccessPolicy/PolicyConditionTest.php +543 -0
- tests/Service/AccessPolicy/PolicyManagerTest.php +170 -0
- tests/Service/AccessPolicy/PolicyServiceIntegrationTest.php +413 -0
- tests/Service/AccessPolicy/PolicyTokenTest.php +236 -0
- tests/Service/AccessPolicy/PolicyUserRoleIntegrationTest.php +143 -0
- tests/Service/AccessPolicy/PolicyValidationTest.php +125 -0
- tests/Service/AccessPolicy/policies/admin-menu.json +11 -0
- tests/Service/AccessPolicy/policies/capability-changes.json +17 -0
- tests/Service/AccessPolicy/policies/dynamic-param.json +9 -0
- tests/Service/AccessPolicy/policies/dynamic-resource.json +12 -0
- tests/Service/AccessPolicy/policies/metabox.json +12 -0
- tests/Service/AccessPolicy/policies/option-override-policy.json +9 -0
- tests/Service/AccessPolicy/policies/plugins.json +8 -0
- tests/Service/AccessPolicy/policies/post-complex-actions.json +18 -0
- tests/Service/AccessPolicy/policies/post-hidden.json +10 -0
- tests/Service/AccessPolicy/policies/post-redirect-callback.json +16 -0
- tests/Service/AccessPolicy/policies/post-redirect-page-id.json +17 -0
- tests/Service/AccessPolicy/policies/post-redirect-page-slug.json +17 -0
- tests/Service/AccessPolicy/policies/post-redirect-url.json +14 -0
- tests/Service/AccessPolicy/policies/post-restricted.json +10 -0
- tests/Service/AccessPolicy/policies/post-simple-actions.json +10 -0
- tests/Service/AccessPolicy/policies/role-add.json +11 -0
- tests/Service/AccessPolicy/policies/role-remove.json +11 -0
- tests/Service/AccessPolicy/policies/simple-policy-with-action.json +12 -0
- tests/Service/AccessPolicy/policies/simple-policy.json +9 -0
- tests/Service/AccessPolicy/policies/single-plugin.json +10 -0
- tests/Service/AccessPolicy/policies/toolbar.json +11 -0
- tests/Service/AccessPolicy/policies/uri.json +57 -0
- tests/Service/AdminMenu/MultipleRoleInheritanceTest.php +182 -0
- tests/Service/AdminMenu/SingleRoleInheritanceTest.php +226 -0
- tests/Service/Capabilities/CapabilityManagerTest.php +345 -0
- tests/Service/Content/Callback.php +13 -0
- tests/Service/Content/MultipleRoleInheritanceTest.php +190 -0
- tests/Service/Content/RESTfulSingleRoleAccessControlTest.php +579 -0
- tests/Service/Content/SingleRoleAccessControlTest.php +602 -0
- tests/Service/Content/SingleRoleInheritanceTest.php +221 -0
- tests/Service/Content/VisitorAccessControlTest.php +432 -0
- tests/Service/Core/CoreServiceTest.php +43 -0
- tests/Service/DeniedRedirect/Callback.php +14 -0
- tests/Service/DeniedRedirect/DeniedRedirectTest.php +189 -0
- tests/Service/Jwt/JwtTest.php +360 -0
- tests/Service/LoginRedirect/Callback.php +14 -0
- tests/Service/LoginRedirect/LoginRedirectTest.php +215 -0
- tests/Service/LogoutRedirect/Callback.php +14 -0
- tests/Service/LogoutRedirect/LogoutRedirectTest.php +115 -0
- tests/Service/Metabox/MultipleRoleInheritanceTest.php +192 -0
- tests/Service/Metabox/SingleRoleInheritanceTest.php +231 -0
- tests/Service/Metabox/VisitorInheritanceTest.php +187 -0
- tests/Service/NotFoundRedirect/Callback.php +14 -0
- tests/Service/NotFoundRedirect/NotFoundRedirectTest.php +141 -0
- tests/Service/Route/RouteTest.php +99 -0
- tests/Service/SecureLogin/SecureLoginTest.php +151 -0
- tests/Service/Toolbar/MultipleRoleInheritanceTest.php +179 -0
- tests/Service/Toolbar/SingleRoleInheritanceTest.php +225 -0
- tests/Service/Uri/Callback.php +14 -0
- tests/Service/Uri/UriTest.php +177 -0
- tests/Service/UserLevelFilter/UserLevelFilterTest.php +151 -0
- tests/bootstrap.php +27 -0
- vendor/composer/VersionParser.php +10 -0
- vendor/firebase/JWT.php +2 -0
aam.php
CHANGED
@@ -3,7 +3,7 @@
|
|
3 |
/**
|
4 |
* Plugin Name: Advanced Access Manager
|
5 |
* Description: Collection of features to manage your WordPress website authentication, authorization and monitoring
|
6 |
-
* Version: 6.0.0-alpha.
|
7 |
* Author: Vasyl Martyniuk <vasyl@vasyltech.com>
|
8 |
* Author URI: https://vasyltech.com
|
9 |
* Text Domain: advanced-access-manager
|
@@ -118,7 +118,7 @@ class AAM
|
|
118 |
|
119 |
// Change current user
|
120 |
if ($id) {
|
121 |
-
$this->setUser(
|
122 |
} else {
|
123 |
$this->setUser(new AAM_Core_Subject_Visitor());
|
124 |
}
|
@@ -246,9 +246,6 @@ class AAM
|
|
246 |
|
247 |
//clear all AAM settings
|
248 |
AAM_Core_API::clearSettings();
|
249 |
-
|
250 |
-
//clear schedules
|
251 |
-
wp_clear_scheduled_hook('aam-cron');
|
252 |
}
|
253 |
|
254 |
}
|
3 |
/**
|
4 |
* Plugin Name: Advanced Access Manager
|
5 |
* Description: Collection of features to manage your WordPress website authentication, authorization and monitoring
|
6 |
+
* Version: 6.0.0-alpha.2
|
7 |
* Author: Vasyl Martyniuk <vasyl@vasyltech.com>
|
8 |
* Author URI: https://vasyltech.com
|
9 |
* Text Domain: advanced-access-manager
|
118 |
|
119 |
// Change current user
|
120 |
if ($id) {
|
121 |
+
$this->setUser(self::api()->getUser($id));
|
122 |
} else {
|
123 |
$this->setUser(new AAM_Core_Subject_Visitor());
|
124 |
}
|
246 |
|
247 |
//clear all AAM settings
|
248 |
AAM_Core_API::clearSettings();
|
|
|
|
|
|
|
249 |
}
|
250 |
|
251 |
}
|
application/Backend/Feature.php
CHANGED
@@ -44,6 +44,7 @@ class AAM_Backend_Feature
|
|
44 |
public static function registerFeature($feature)
|
45 |
{
|
46 |
$response = false;
|
|
|
47 |
|
48 |
// Determine correct AAM UI capability
|
49 |
if (empty($feature->capability)) {
|
@@ -60,13 +61,25 @@ class AAM_Backend_Feature
|
|
60 |
}
|
61 |
|
62 |
// Determine that current user has enough user level to manage
|
63 |
-
// requested subject
|
64 |
-
|
65 |
-
|
66 |
-
|
|
|
|
|
|
|
|
|
|
|
67 |
|
68 |
if ($show && $allowed && current_user_can($cap)) {
|
69 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
70 |
$response = true;
|
71 |
}
|
72 |
|
@@ -74,46 +87,39 @@ class AAM_Backend_Feature
|
|
74 |
}
|
75 |
|
76 |
/**
|
77 |
-
*
|
78 |
*
|
79 |
-
*
|
80 |
-
* features should be visible only when Backend Access options is enabled.
|
81 |
-
*
|
82 |
-
* @param string $options
|
83 |
*
|
84 |
-
* @return
|
85 |
*
|
86 |
-
* @access
|
87 |
* @version 6.0.0
|
88 |
*/
|
89 |
-
|
90 |
{
|
91 |
-
$
|
92 |
-
|
93 |
-
|
94 |
-
$
|
95 |
}
|
96 |
|
97 |
-
return
|
98 |
}
|
99 |
|
100 |
/**
|
101 |
-
*
|
102 |
*
|
103 |
-
* @param
|
104 |
*
|
105 |
-
* @return
|
106 |
*
|
107 |
* @access public
|
108 |
* @version 6.0.0
|
109 |
*/
|
110 |
-
public static function
|
111 |
{
|
112 |
-
|
113 |
-
$feature->view = new $feature->view(AAM_Backend_Subject::getInstance());
|
114 |
-
}
|
115 |
-
|
116 |
-
return $feature;
|
117 |
}
|
118 |
|
119 |
/**
|
@@ -131,8 +137,8 @@ class AAM_Backend_Feature
|
|
131 |
public static function retrieveList($type)
|
132 |
{
|
133 |
$response = array();
|
|
|
134 |
|
135 |
-
$subject = AAM_Backend_Subject::getInstance()->getSubjectType();
|
136 |
foreach (self::$_features as $feature) {
|
137 |
if (
|
138 |
$feature->type === $type
|
@@ -158,4 +164,47 @@ class AAM_Backend_Feature
|
|
158 |
return $response;
|
159 |
}
|
160 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
161 |
}
|
44 |
public static function registerFeature($feature)
|
45 |
{
|
46 |
$response = false;
|
47 |
+
$subject = AAM_Backend_Subject::getInstance();
|
48 |
|
49 |
// Determine correct AAM UI capability
|
50 |
if (empty($feature->capability)) {
|
61 |
}
|
62 |
|
63 |
// Determine that current user has enough user level to manage
|
64 |
+
// requested subject but only if it is manages settings for individual
|
65 |
+
// subjects
|
66 |
+
if (!empty($feature->subjects)) {
|
67 |
+
$allowed = apply_filters(
|
68 |
+
'aam_user_can_manage_level_filter', true, $subject->getSubject()->getMaxLevel()
|
69 |
+
);
|
70 |
+
} else { // Other allow because access to the feature is managed with cap
|
71 |
+
$allowed = true;
|
72 |
+
}
|
73 |
|
74 |
if ($show && $allowed && current_user_can($cap)) {
|
75 |
+
if (is_object($feature->view)) {
|
76 |
+
self::$_features[get_class($feature->view)] = $feature;
|
77 |
+
} else {
|
78 |
+
self::$_features[$feature->view] = $feature;
|
79 |
+
// Initialize view manage so it can register any necessary hooks
|
80 |
+
$feature->view = new $feature->view($subject);
|
81 |
+
}
|
82 |
+
|
83 |
$response = true;
|
84 |
}
|
85 |
|
87 |
}
|
88 |
|
89 |
/**
|
90 |
+
* Get feature view manager
|
91 |
*
|
92 |
+
* @param string $id
|
|
|
|
|
|
|
93 |
*
|
94 |
+
* @return object
|
95 |
*
|
96 |
+
* @access public
|
97 |
* @version 6.0.0
|
98 |
*/
|
99 |
+
public static function getFeatureView($id)
|
100 |
{
|
101 |
+
if (self::isFeatureRegistered($id)) {
|
102 |
+
$view = self::$_features[$id]->view;
|
103 |
+
} else {
|
104 |
+
$view = null;
|
105 |
}
|
106 |
|
107 |
+
return $view;
|
108 |
}
|
109 |
|
110 |
/**
|
111 |
+
* Check if feature is registered
|
112 |
*
|
113 |
+
* @param string $id
|
114 |
*
|
115 |
+
* @return boolean
|
116 |
*
|
117 |
* @access public
|
118 |
* @version 6.0.0
|
119 |
*/
|
120 |
+
public static function isFeatureRegistered($id)
|
121 |
{
|
122 |
+
return array_key_exists($id, self::$_features);
|
|
|
|
|
|
|
|
|
123 |
}
|
124 |
|
125 |
/**
|
137 |
public static function retrieveList($type)
|
138 |
{
|
139 |
$response = array();
|
140 |
+
$subject = AAM_Backend_Subject::getInstance()->getSubjectType();
|
141 |
|
|
|
142 |
foreach (self::$_features as $feature) {
|
143 |
if (
|
144 |
$feature->type === $type
|
164 |
return $response;
|
165 |
}
|
166 |
|
167 |
+
/**
|
168 |
+
* Check if feature is visible
|
169 |
+
*
|
170 |
+
* There is a way to show/hide feature based on the option. For example some
|
171 |
+
* features should be visible only when Backend Access options is enabled.
|
172 |
+
*
|
173 |
+
* @param string $options
|
174 |
+
*
|
175 |
+
* @return boolean
|
176 |
+
*
|
177 |
+
* @access protected
|
178 |
+
* @version 6.0.0
|
179 |
+
*/
|
180 |
+
protected static function isVisible($options)
|
181 |
+
{
|
182 |
+
$count = 0;
|
183 |
+
|
184 |
+
foreach (explode(',', $options) as $option) {
|
185 |
+
$count += AAM_Core_Config::get($option, true);
|
186 |
+
}
|
187 |
+
|
188 |
+
return ($count > 0);
|
189 |
+
}
|
190 |
+
|
191 |
+
/**
|
192 |
+
* Initiate the view controller
|
193 |
+
*
|
194 |
+
* @param object $feature
|
195 |
+
*
|
196 |
+
* @return array
|
197 |
+
*
|
198 |
+
* @access protected
|
199 |
+
* @version 6.0.0
|
200 |
+
*/
|
201 |
+
protected static function initView($feature)
|
202 |
+
{
|
203 |
+
if (is_string($feature->view)) {
|
204 |
+
$feature->view = new $feature->view(AAM_Backend_Subject::getInstance());
|
205 |
+
}
|
206 |
+
|
207 |
+
return $feature;
|
208 |
+
}
|
209 |
+
|
210 |
}
|
application/Backend/Feature/Abstract.php
CHANGED
@@ -104,7 +104,7 @@ abstract class AAM_Backend_Feature_Abstract
|
|
104 |
public function getContent()
|
105 |
{
|
106 |
ob_start();
|
107 |
-
require_once(dirname(__DIR__) . '/
|
108 |
$content = ob_get_contents();
|
109 |
ob_end_clean();
|
110 |
|
104 |
public function getContent()
|
105 |
{
|
106 |
ob_start();
|
107 |
+
require_once(dirname(__DIR__) . '/tmpl/' . static::TEMPLATE);
|
108 |
$content = ob_get_contents();
|
109 |
ob_end_clean();
|
110 |
|
application/Backend/Feature/Main/404Redirect.php
CHANGED
@@ -33,7 +33,7 @@ class AAM_Backend_Feature_Main_404Redirect
|
|
33 |
*
|
34 |
* @version 6.0.0
|
35 |
*/
|
36 |
-
const TEMPLATE = 'service/404redirect.
|
37 |
|
38 |
/**
|
39 |
* Save 404 redirect options
|
33 |
*
|
34 |
* @version 6.0.0
|
35 |
*/
|
36 |
+
const TEMPLATE = 'service/404redirect.php';
|
37 |
|
38 |
/**
|
39 |
* Save 404 redirect options
|
application/Backend/Feature/Main/Capability.php
CHANGED
@@ -31,7 +31,7 @@ class AAM_Backend_Feature_Main_Capability
|
|
31 |
*
|
32 |
* @version 6.0.0
|
33 |
*/
|
34 |
-
const TEMPLATE = 'service/capability.
|
35 |
|
36 |
/**
|
37 |
* Capability groups
|
@@ -83,7 +83,7 @@ class AAM_Backend_Feature_Main_Capability
|
|
83 |
$effect = $this->getFromPost('effect', FILTER_VALIDATE_BOOLEAN);
|
84 |
$assign = $this->getFromPost('assignToMe', FILTER_VALIDATE_BOOLEAN);
|
85 |
|
86 |
-
if ($cap) {
|
87 |
// Add capability to current user if checkbox checked
|
88 |
if ($assign === true) {
|
89 |
AAM::getUser()->addCapability($cap);
|
@@ -186,7 +186,7 @@ class AAM_Backend_Feature_Main_Capability
|
|
186 |
$caps = array_merge($caps, $this->getSubject()->getCapabilities());
|
187 |
|
188 |
foreach (array_keys($caps) as $cap) {
|
189 |
-
if (apply_filters('
|
190 |
$data[] = array(
|
191 |
$cap,
|
192 |
$this->getGroup($cap),
|
@@ -219,7 +219,7 @@ class AAM_Backend_Feature_Main_Capability
|
|
219 |
|
220 |
$toggle = ($subject->hasCapability($cap) ? 'checked' : 'unchecked');
|
221 |
|
222 |
-
if (
|
223 |
$toggle = 'no-' . $toggle;
|
224 |
}
|
225 |
|
@@ -242,6 +242,21 @@ class AAM_Backend_Feature_Main_Capability
|
|
242 |
return implode(',', $actions);
|
243 |
}
|
244 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
245 |
/**
|
246 |
* Check if current user can edit capability
|
247 |
*
|
@@ -261,7 +276,7 @@ class AAM_Backend_Feature_Main_Capability
|
|
261 |
}
|
262 |
|
263 |
// Access & Security policy has higher priority
|
264 |
-
if (apply_filters('
|
265 |
$allowed = false;
|
266 |
}
|
267 |
|
@@ -293,7 +308,7 @@ class AAM_Backend_Feature_Main_Capability
|
|
293 |
}
|
294 |
|
295 |
// Access & Security policy has higher priority
|
296 |
-
if (apply_filters('
|
297 |
$allowed = false;
|
298 |
}
|
299 |
|
31 |
*
|
32 |
* @version 6.0.0
|
33 |
*/
|
34 |
+
const TEMPLATE = 'service/capability.php';
|
35 |
|
36 |
/**
|
37 |
* Capability groups
|
83 |
$effect = $this->getFromPost('effect', FILTER_VALIDATE_BOOLEAN);
|
84 |
$assign = $this->getFromPost('assignToMe', FILTER_VALIDATE_BOOLEAN);
|
85 |
|
86 |
+
if ($cap && $this->isAllowedToToggle($cap)) {
|
87 |
// Add capability to current user if checkbox checked
|
88 |
if ($assign === true) {
|
89 |
AAM::getUser()->addCapability($cap);
|
186 |
$caps = array_merge($caps, $this->getSubject()->getCapabilities());
|
187 |
|
188 |
foreach (array_keys($caps) as $cap) {
|
189 |
+
if (apply_filters('aam_cap_can_filter', true, $cap, 'list') !== false) {
|
190 |
$data[] = array(
|
191 |
$cap,
|
192 |
$this->getGroup($cap),
|
219 |
|
220 |
$toggle = ($subject->hasCapability($cap) ? 'checked' : 'unchecked');
|
221 |
|
222 |
+
if ($this->isAllowedToToggle($cap) === false) {
|
223 |
$toggle = 'no-' . $toggle;
|
224 |
}
|
225 |
|
242 |
return implode(',', $actions);
|
243 |
}
|
244 |
|
245 |
+
/**
|
246 |
+
* Check if current user is allowed to toggle capability
|
247 |
+
*
|
248 |
+
* @param string $cap
|
249 |
+
*
|
250 |
+
* @return boolean
|
251 |
+
*
|
252 |
+
* @access protected
|
253 |
+
* @version 6.0.0
|
254 |
+
*/
|
255 |
+
protected function isAllowedToToggle($cap)
|
256 |
+
{
|
257 |
+
return apply_filters('aam_cap_can_filter', true, $cap, 'toggle');
|
258 |
+
}
|
259 |
+
|
260 |
/**
|
261 |
* Check if current user can edit capability
|
262 |
*
|
276 |
}
|
277 |
|
278 |
// Access & Security policy has higher priority
|
279 |
+
if (apply_filters('aam_cap_can_filter', true, $cap, 'update') === false) {
|
280 |
$allowed = false;
|
281 |
}
|
282 |
|
308 |
}
|
309 |
|
310 |
// Access & Security policy has higher priority
|
311 |
+
if (apply_filters('aam_cap_can_filter', true, $cap, 'delete') === false) {
|
312 |
$allowed = false;
|
313 |
}
|
314 |
|
application/Backend/Feature/Main/Jwt.php
CHANGED
@@ -33,7 +33,7 @@ class AAM_Backend_Feature_Main_Jwt
|
|
33 |
*
|
34 |
* @version 6.0.0
|
35 |
*/
|
36 |
-
const TEMPLATE = 'service/jwt.
|
37 |
|
38 |
/**
|
39 |
* Get list of tokens
|
33 |
*
|
34 |
* @version 6.0.0
|
35 |
*/
|
36 |
+
const TEMPLATE = 'service/jwt.php';
|
37 |
|
38 |
/**
|
39 |
* Get list of tokens
|
application/Backend/Feature/Main/LoginRedirect.php
CHANGED
@@ -38,7 +38,7 @@ class AAM_Backend_Feature_Main_LoginRedirect
|
|
38 |
*
|
39 |
* @version 6.0.0
|
40 |
*/
|
41 |
-
const TEMPLATE = 'service/login-redirect.
|
42 |
|
43 |
/**
|
44 |
* Get option value
|
38 |
*
|
39 |
* @version 6.0.0
|
40 |
*/
|
41 |
+
const TEMPLATE = 'service/login-redirect.php';
|
42 |
|
43 |
/**
|
44 |
* Get option value
|
application/Backend/Feature/Main/LogoutRedirect.php
CHANGED
@@ -38,7 +38,7 @@ class AAM_Backend_Feature_Main_LogoutRedirect
|
|
38 |
*
|
39 |
* @version 6.0.0
|
40 |
*/
|
41 |
-
const TEMPLATE = 'service/logout-redirect.
|
42 |
|
43 |
/**
|
44 |
* Get option value
|
38 |
*
|
39 |
* @version 6.0.0
|
40 |
*/
|
41 |
+
const TEMPLATE = 'service/logout-redirect.php';
|
42 |
|
43 |
/**
|
44 |
* Get option value
|
application/Backend/Feature/Main/Menu.php
CHANGED
@@ -38,7 +38,7 @@ class AAM_Backend_Feature_Main_Menu
|
|
38 |
*
|
39 |
* @version 6.0.0
|
40 |
*/
|
41 |
-
const TEMPLATE = 'service/menu.
|
42 |
|
43 |
/**
|
44 |
* Save menu settings
|
38 |
*
|
39 |
* @version 6.0.0
|
40 |
*/
|
41 |
+
const TEMPLATE = 'service/menu.php';
|
42 |
|
43 |
/**
|
44 |
* Save menu settings
|
application/Backend/Feature/Main/Metabox.php
CHANGED
@@ -45,7 +45,7 @@ class AAM_Backend_Feature_Main_Metabox
|
|
45 |
*
|
46 |
* @version 6.0.0
|
47 |
*/
|
48 |
-
const TEMPLATE = 'service/metabox.
|
49 |
|
50 |
/**
|
51 |
* Save metabox access settings
|
45 |
*
|
46 |
* @version 6.0.0
|
47 |
*/
|
48 |
+
const TEMPLATE = 'service/metabox.php';
|
49 |
|
50 |
/**
|
51 |
* Save metabox access settings
|
application/Backend/Feature/Main/Policy.php
CHANGED
@@ -5,143 +5,170 @@
|
|
5 |
* LICENSE: This file is subject to the terms and conditions defined in *
|
6 |
* file 'license.txt', which is part of this source code package. *
|
7 |
* ======================================================================
|
|
|
|
|
8 |
*/
|
9 |
|
10 |
/**
|
11 |
-
*
|
12 |
-
*
|
13 |
* @package AAM
|
14 |
-
* @
|
15 |
*/
|
16 |
-
class AAM_Backend_Feature_Main_Policy
|
|
|
17 |
{
|
18 |
|
|
|
|
|
19 |
/**
|
20 |
* Default access capability to the feature
|
|
|
|
|
21 |
*/
|
22 |
const ACCESS_CAPABILITY = 'aam_manage_policy';
|
23 |
|
24 |
/**
|
25 |
-
*
|
26 |
-
*
|
|
|
27 |
*/
|
28 |
-
|
29 |
-
{
|
30 |
-
return wp_json_encode($this->retrievePolicies());
|
31 |
-
}
|
32 |
|
33 |
/**
|
34 |
-
*
|
35 |
-
*
|
36 |
-
* @
|
37 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
38 |
* @access public
|
39 |
-
* @
|
40 |
*/
|
41 |
-
public function
|
42 |
{
|
43 |
-
$
|
44 |
-
|
45 |
-
|
46 |
-
|
47 |
-
|
48 |
-
$
|
49 |
-
|
50 |
-
|
51 |
-
|
52 |
-
|
53 |
-
|
54 |
-
|
55 |
-
));
|
56 |
-
|
57 |
-
if (!is_wp_error($result)) {
|
58 |
-
$response = array('status' => 'success');
|
59 |
-
} else {
|
60 |
-
$response = array(
|
61 |
-
'status' => 'failure', 'reason' => $result->get_error_message()
|
62 |
);
|
63 |
}
|
64 |
-
} else {
|
65 |
-
$response = array(
|
66 |
-
'status' => 'failure',
|
67 |
-
'reason' => __('Failed to fetch policy. Please try again.', AAM_KEY)
|
68 |
-
);
|
69 |
-
}
|
70 |
|
71 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
72 |
}
|
73 |
|
74 |
/**
|
75 |
-
*
|
76 |
-
*
|
|
|
|
|
|
|
|
|
77 |
* @return string
|
78 |
-
*
|
79 |
* @access public
|
|
|
80 |
*/
|
81 |
-
public function
|
82 |
{
|
83 |
-
$
|
84 |
-
|
85 |
-
|
86 |
-
|
87 |
-
|
88 |
-
|
89 |
-
|
90 |
-
if (AAM_Core_Policy_Factory::get()->canTogglePolicy($id, $action)) {
|
91 |
-
$object = $subject->getObject('policy', null, true);
|
92 |
-
$result = $object->updateOptionItem($id, $effect)->save();
|
93 |
-
} else {
|
94 |
-
$result = false;
|
95 |
}
|
96 |
|
97 |
-
return
|
98 |
-
'status' => ($result ? 'success' : 'failure')
|
99 |
-
));
|
100 |
}
|
101 |
|
102 |
/**
|
103 |
-
*
|
104 |
-
*
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
105 |
*/
|
106 |
-
public function
|
107 |
{
|
108 |
-
|
109 |
-
|
110 |
-
|
111 |
-
|
|
|
|
|
|
|
112 |
|
113 |
-
|
114 |
-
* @inheritdoc
|
115 |
-
*/
|
116 |
-
public static function getTemplate()
|
117 |
-
{
|
118 |
-
return 'service/policy.phtml';
|
119 |
}
|
120 |
|
121 |
/**
|
122 |
-
*
|
123 |
-
*
|
124 |
-
*
|
125 |
-
*
|
126 |
-
*
|
127 |
-
*
|
128 |
-
*
|
|
|
|
|
129 |
*/
|
130 |
-
|
131 |
{
|
132 |
-
|
|
|
|
|
|
|
|
|
133 |
|
134 |
-
return $
|
135 |
}
|
136 |
|
137 |
/**
|
138 |
-
*
|
139 |
-
*
|
|
|
|
|
|
|
|
|
140 |
*/
|
141 |
-
|
142 |
{
|
143 |
$list = get_posts(array(
|
144 |
-
'post_type' =>
|
145 |
'numberposts' => -1,
|
146 |
'post_status' => 'publish'
|
147 |
));
|
@@ -149,7 +176,7 @@ class AAM_Backend_Feature_Main_Policy extends AAM_Backend_Feature_Abstract imple
|
|
149 |
$response = array(
|
150 |
'recordsTotal' => count($list),
|
151 |
'recordsFiltered' => count($list),
|
152 |
-
'draw' =>
|
153 |
'data' => array(),
|
154 |
);
|
155 |
|
@@ -159,24 +186,34 @@ class AAM_Backend_Feature_Main_Policy extends AAM_Backend_Feature_Abstract imple
|
|
159 |
if ($policy) {
|
160 |
$response['data'][] = array(
|
161 |
$record->ID,
|
162 |
-
$this->
|
163 |
-
$this->
|
164 |
get_edit_post_link($record->ID, 'link')
|
165 |
);
|
166 |
}
|
167 |
}
|
168 |
|
169 |
-
return $response;
|
170 |
}
|
171 |
|
172 |
/**
|
173 |
-
*
|
174 |
-
*
|
|
|
|
|
175 |
* @return string
|
|
|
|
|
|
|
176 |
*/
|
177 |
-
protected function
|
178 |
{
|
179 |
-
|
|
|
|
|
|
|
|
|
|
|
180 |
$title .= '<br/>';
|
181 |
|
182 |
if (isset($record->post_excerpt)) {
|
@@ -187,22 +224,24 @@ class AAM_Backend_Feature_Main_Policy extends AAM_Backend_Feature_Abstract imple
|
|
187 |
}
|
188 |
|
189 |
/**
|
190 |
-
*
|
191 |
-
*
|
192 |
-
* @
|
|
|
|
|
|
|
|
|
|
|
193 |
*/
|
194 |
-
protected function
|
195 |
{
|
196 |
-
//'assign,edit,clone,delete'
|
197 |
$subject = AAM_Backend_Subject::getInstance();
|
198 |
-
$policy = $subject->getObject('policy');
|
199 |
-
$post = $subject->getObject('post', $record->ID);
|
200 |
|
201 |
-
$
|
202 |
-
$
|
203 |
|
204 |
$actions = array(
|
205 |
-
$policy->has($record->ID) ? "
|
206 |
$post->isAllowedTo('edit') ? 'edit' : 'no-edit'
|
207 |
);
|
208 |
|
@@ -210,15 +249,59 @@ class AAM_Backend_Feature_Main_Policy extends AAM_Backend_Feature_Abstract imple
|
|
210 |
}
|
211 |
|
212 |
/**
|
213 |
-
*
|
214 |
-
*
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
215 |
* @return void
|
216 |
-
*
|
217 |
* @access public
|
|
|
218 |
*/
|
219 |
public static function register()
|
220 |
{
|
221 |
-
AAM_Backend_Feature::registerFeature((object)array(
|
222 |
'uid' => 'policy',
|
223 |
'position' => 2,
|
224 |
'title' => __('Access Policies', AAM_KEY),
|
@@ -233,4 +316,5 @@ class AAM_Backend_Feature_Main_Policy extends AAM_Backend_Feature_Abstract imple
|
|
233 |
'view' => __CLASS__
|
234 |
));
|
235 |
}
|
236 |
-
|
|
5 |
* LICENSE: This file is subject to the terms and conditions defined in *
|
6 |
* file 'license.txt', which is part of this source code package. *
|
7 |
* ======================================================================
|
8 |
+
*
|
9 |
+
* @version 6.0.0
|
10 |
*/
|
11 |
|
12 |
/**
|
13 |
+
* Access Policy UI manager
|
14 |
+
*
|
15 |
* @package AAM
|
16 |
+
* @version 6.0.0
|
17 |
*/
|
18 |
+
class AAM_Backend_Feature_Main_Policy
|
19 |
+
extends AAM_Backend_Feature_Abstract implements AAM_Backend_Feature_ISubjectAware
|
20 |
{
|
21 |
|
22 |
+
use AAM_Core_Contract_RequestTrait;
|
23 |
+
|
24 |
/**
|
25 |
* Default access capability to the feature
|
26 |
+
*
|
27 |
+
* @version 6.0.0
|
28 |
*/
|
29 |
const ACCESS_CAPABILITY = 'aam_manage_policy';
|
30 |
|
31 |
/**
|
32 |
+
* Type of AAM core object
|
33 |
+
*
|
34 |
+
* @version 6.0.0
|
35 |
*/
|
36 |
+
const OBJECT_TYPE = AAM_Core_Object_Policy::OBJECT_TYPE;
|
|
|
|
|
|
|
37 |
|
38 |
/**
|
39 |
+
* HTML template to render
|
40 |
+
*
|
41 |
+
* @version 6.0.0
|
42 |
+
*/
|
43 |
+
const TEMPLATE = 'service/policy.php';
|
44 |
+
|
45 |
+
/**
|
46 |
+
* Constructor
|
47 |
+
*
|
48 |
+
* @return void
|
49 |
+
*
|
50 |
* @access public
|
51 |
+
* @version 6.0.0
|
52 |
*/
|
53 |
+
public function __construct()
|
54 |
{
|
55 |
+
add_filter('aam_iframe_content_filter', array($this, 'renderPrincipalIframe'), 1, 3);
|
56 |
+
add_filter('aam_role_row_actions_filter', array($this, 'renderRoleActions'), 1, 2);
|
57 |
+
add_filter('aam_user_row_actions_filter', array($this, 'renderUserActions'), 1, 2);
|
58 |
+
|
59 |
+
add_filter('aam_visitor_subject_tab_filter', function ($content, $params) {
|
60 |
+
global $post;
|
61 |
+
|
62 |
+
if (is_a($post, 'WP_Post')
|
63 |
+
&& ($post->post_type === AAM_Service_AccessPolicy::POLICY_CPT)) {
|
64 |
+
$content = AAM_Backend_View::getInstance()->loadPartial(
|
65 |
+
'visitor-principal-subject-tab',
|
66 |
+
$params
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
67 |
);
|
68 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
69 |
|
70 |
+
return $content;
|
71 |
+
}, 10, 2);
|
72 |
+
|
73 |
+
add_filter('aam_default_subject_tab_filter', function ($content, $params) {
|
74 |
+
global $post;
|
75 |
+
|
76 |
+
if (is_a($post, 'WP_Post')
|
77 |
+
&& ($post->post_type === AAM_Service_AccessPolicy::POLICY_CPT)) {
|
78 |
+
$content = AAM_Backend_View::getInstance()->loadPartial(
|
79 |
+
'default-principal-subject-tab',
|
80 |
+
$params
|
81 |
+
);
|
82 |
+
}
|
83 |
+
|
84 |
+
return $content;
|
85 |
+
}, 10, 2);
|
86 |
}
|
87 |
|
88 |
/**
|
89 |
+
* Render access policy principal metabox
|
90 |
+
*
|
91 |
+
* @param null|string $content
|
92 |
+
* @param string $type
|
93 |
+
* @param AAM_Backend_View $view
|
94 |
+
*
|
95 |
* @return string
|
96 |
+
*
|
97 |
* @access public
|
98 |
+
* @version 6.0.0
|
99 |
*/
|
100 |
+
public function renderPrincipalIframe($content, $type, $view)
|
101 |
{
|
102 |
+
if ($type === 'principal') {
|
103 |
+
$content = $view->loadTemplate(
|
104 |
+
dirname(__DIR__) . '/../tmpl/metabox/principal-iframe.php',
|
105 |
+
(object) array(
|
106 |
+
'policyId' => $this->getFromQuery('id', FILTER_VALIDATE_INT)
|
107 |
+
)
|
108 |
+
);
|
|
|
|
|
|
|
|
|
|
|
109 |
}
|
110 |
|
111 |
+
return $content;
|
|
|
|
|
112 |
}
|
113 |
|
114 |
/**
|
115 |
+
* Render role actions
|
116 |
+
*
|
117 |
+
* @param array $actions
|
118 |
+
* @param string $id
|
119 |
+
*
|
120 |
+
* @return array
|
121 |
+
*
|
122 |
+
* @access public
|
123 |
+
* @version 6.0.0
|
124 |
*/
|
125 |
+
public function renderRoleActions($actions, $id)
|
126 |
{
|
127 |
+
if ($this->getFromPost('ui') === 'principal') {
|
128 |
+
$object = AAM::api()->getRole($id)->getObject(
|
129 |
+
AAM_Core_Object_Policy::OBJECT_TYPE
|
130 |
+
);
|
131 |
+
$policyId = $this->getFromPost('policyId', FILTER_VALIDATE_INT);
|
132 |
+
$actions = array($object->has($policyId) ? 'detach' : 'attach');
|
133 |
+
}
|
134 |
|
135 |
+
return $actions;
|
|
|
|
|
|
|
|
|
|
|
136 |
}
|
137 |
|
138 |
/**
|
139 |
+
* Render user actions
|
140 |
+
*
|
141 |
+
* @param array $actions
|
142 |
+
* @param AAM_Core_Subject_User $user
|
143 |
+
*
|
144 |
+
* @return array
|
145 |
+
*
|
146 |
+
* @access public
|
147 |
+
* @version 6.0.0
|
148 |
*/
|
149 |
+
public function renderUserActions($actions, $user)
|
150 |
{
|
151 |
+
if ($this->getFromPost('ui') === 'principal') {
|
152 |
+
$object = $user->getObject(AAM_Core_Object_Policy::OBJECT_TYPE);
|
153 |
+
$policyId = $this->getFromPost('policyId', FILTER_VALIDATE_INT);
|
154 |
+
$actions = array($object->has($policyId) ? 'detach' : 'attach');
|
155 |
+
}
|
156 |
|
157 |
+
return $actions;
|
158 |
}
|
159 |
|
160 |
/**
|
161 |
+
* Get list of access policies
|
162 |
+
*
|
163 |
+
* @return string
|
164 |
+
*
|
165 |
+
* @access public
|
166 |
+
* @version 6.0.0
|
167 |
*/
|
168 |
+
public function getTable()
|
169 |
{
|
170 |
$list = get_posts(array(
|
171 |
+
'post_type' => AAM_Service_AccessPolicy::POLICY_CPT,
|
172 |
'numberposts' => -1,
|
173 |
'post_status' => 'publish'
|
174 |
));
|
176 |
$response = array(
|
177 |
'recordsTotal' => count($list),
|
178 |
'recordsFiltered' => count($list),
|
179 |
+
'draw' => $this->getFromRequest('draw'),
|
180 |
'data' => array(),
|
181 |
);
|
182 |
|
186 |
if ($policy) {
|
187 |
$response['data'][] = array(
|
188 |
$record->ID,
|
189 |
+
$this->preparePolicyTitle($record),
|
190 |
+
$this->preparePolicyActionList($record),
|
191 |
get_edit_post_link($record->ID, 'link')
|
192 |
);
|
193 |
}
|
194 |
}
|
195 |
|
196 |
+
return wp_json_encode($response);
|
197 |
}
|
198 |
|
199 |
/**
|
200 |
+
* Prepare policy title
|
201 |
+
*
|
202 |
+
* @param WP_Post $record
|
203 |
+
*
|
204 |
* @return string
|
205 |
+
*
|
206 |
+
* @access protected
|
207 |
+
* @version 6.0.0
|
208 |
*/
|
209 |
+
protected function preparePolicyTitle($record)
|
210 |
{
|
211 |
+
if (!empty($record->post_title)) {
|
212 |
+
$title = $record->post_title;
|
213 |
+
} else {
|
214 |
+
$title = __('(no title)', AAM_KEY);
|
215 |
+
}
|
216 |
+
|
217 |
$title .= '<br/>';
|
218 |
|
219 |
if (isset($record->post_excerpt)) {
|
224 |
}
|
225 |
|
226 |
/**
|
227 |
+
* Prepare the list of policy actions
|
228 |
+
*
|
229 |
+
* @param WP_Post $record
|
230 |
+
*
|
231 |
+
* @return string
|
232 |
+
*
|
233 |
+
* @access protected
|
234 |
+
* @version 6.0.0
|
235 |
*/
|
236 |
+
protected function preparePolicyActionList($record)
|
237 |
{
|
|
|
238 |
$subject = AAM_Backend_Subject::getInstance();
|
|
|
|
|
239 |
|
240 |
+
$policy = $subject->getObject(AAM_Core_Object_Policy::OBJECT_TYPE);
|
241 |
+
$post = $subject->getObject(AAM_Core_Object_Post::OBJECT_TYPE, $record->ID);
|
242 |
|
243 |
$actions = array(
|
244 |
+
$policy->has($record->ID) ? "detach" : "attach",
|
245 |
$post->isAllowedTo('edit') ? 'edit' : 'no-edit'
|
246 |
);
|
247 |
|
249 |
}
|
250 |
|
251 |
/**
|
252 |
+
* Save access policy effect
|
253 |
+
*
|
254 |
+
* @return string
|
255 |
+
*
|
256 |
+
* @access public
|
257 |
+
* @version 6.0.0
|
258 |
+
*/
|
259 |
+
public function save()
|
260 |
+
{
|
261 |
+
$subject = AAM_Backend_Subject::getInstance();
|
262 |
+
|
263 |
+
$id = $this->getFromPost('id');
|
264 |
+
$effect = $this->getFromPost('effect', FILTER_VALIDATE_BOOLEAN);
|
265 |
+
|
266 |
+
// Verify that current user can perform following action
|
267 |
+
if (current_user_can('read_post', $id)) {
|
268 |
+
$object = $subject->getObject(self::OBJECT_TYPE, null, true);
|
269 |
+
$result = $object->updateOptionItem($id, $effect)->save();
|
270 |
+
} else {
|
271 |
+
$result = false;
|
272 |
+
}
|
273 |
+
|
274 |
+
return wp_json_encode(array(
|
275 |
+
'status' => ($result ? 'success' : 'failure')
|
276 |
+
));
|
277 |
+
}
|
278 |
+
|
279 |
+
/**
|
280 |
+
* Get default Access Policy
|
281 |
+
*
|
282 |
+
* @global string $wp_version
|
283 |
+
*
|
284 |
+
* @return string
|
285 |
+
*
|
286 |
+
* @access public
|
287 |
+
* @version 6.0.0
|
288 |
+
*/
|
289 |
+
public static function getDefaultPolicy()
|
290 |
+
{
|
291 |
+
return include dirname(__DIR__) . '/../tmpl/policy/default-policy.php';
|
292 |
+
}
|
293 |
+
|
294 |
+
/**
|
295 |
+
* Register Access Policy UI feature
|
296 |
+
*
|
297 |
* @return void
|
298 |
+
*
|
299 |
* @access public
|
300 |
+
* @version 6.0.0
|
301 |
*/
|
302 |
public static function register()
|
303 |
{
|
304 |
+
AAM_Backend_Feature::registerFeature((object) array(
|
305 |
'uid' => 'policy',
|
306 |
'position' => 2,
|
307 |
'title' => __('Access Policies', AAM_KEY),
|
316 |
'view' => __CLASS__
|
317 |
));
|
318 |
}
|
319 |
+
|
320 |
+
}
|
application/Backend/Feature/Main/Post.php
CHANGED
@@ -41,7 +41,7 @@ class AAM_Backend_Feature_Main_Post
|
|
41 |
*
|
42 |
* @version 6.0.0
|
43 |
*/
|
44 |
-
const TEMPLATE = 'service/post.
|
45 |
|
46 |
/**
|
47 |
* Get posts & terms list
|
@@ -71,7 +71,7 @@ class AAM_Backend_Feature_Main_Post
|
|
71 |
|
72 |
// Extend the response with some required props and return JSON
|
73 |
// response.
|
74 |
-
$response['draw'] =
|
75 |
|
76 |
return wp_json_encode($response);
|
77 |
}
|
@@ -244,7 +244,7 @@ class AAM_Backend_Feature_Main_Post
|
|
244 |
break;
|
245 |
|
246 |
case 'protected':
|
247 |
-
$preview = $
|
248 |
break;
|
249 |
|
250 |
case 'ceased':
|
@@ -355,21 +355,6 @@ class AAM_Backend_Feature_Main_Post
|
|
355 |
return $preview;
|
356 |
}
|
357 |
|
358 |
-
/**
|
359 |
-
* Prepare password protected option preview
|
360 |
-
*
|
361 |
-
* @param array $protected
|
362 |
-
*
|
363 |
-
* @return string
|
364 |
-
*
|
365 |
-
* @access protected
|
366 |
-
* @version 6.0.0
|
367 |
-
*/
|
368 |
-
protected function prepareProtectedPreview($protected)
|
369 |
-
{
|
370 |
-
return AAM_Core_API::crypt($protected['password'], 'decrypt');
|
371 |
-
}
|
372 |
-
|
373 |
/**
|
374 |
* Prepare ceased option preview
|
375 |
*
|
@@ -408,6 +393,35 @@ class AAM_Backend_Feature_Main_Post
|
|
408 |
));
|
409 |
}
|
410 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
411 |
/**
|
412 |
* Reset the object access settings
|
413 |
*
|
@@ -440,10 +454,6 @@ class AAM_Backend_Feature_Main_Post
|
|
440 |
*/
|
441 |
protected function sanitizeOption($option, $value)
|
442 |
{
|
443 |
-
if ($option === 'protected') {
|
444 |
-
$value['password'] = AAM_Core_API::crypt($value['password']);
|
445 |
-
}
|
446 |
-
|
447 |
if (is_array($value)) {
|
448 |
$value['enabled'] = filter_var($value['enabled'], FILTER_VALIDATE_BOOLEAN);
|
449 |
} else { // Any scalar value has to be boolean
|
41 |
*
|
42 |
* @version 6.0.0
|
43 |
*/
|
44 |
+
const TEMPLATE = 'service/post.php';
|
45 |
|
46 |
/**
|
47 |
* Get posts & terms list
|
71 |
|
72 |
// Extend the response with some required props and return JSON
|
73 |
// response.
|
74 |
+
$response['draw'] = $this->getFromRequest('draw');
|
75 |
|
76 |
return wp_json_encode($response);
|
77 |
}
|
244 |
break;
|
245 |
|
246 |
case 'protected':
|
247 |
+
$preview = $value['password'];
|
248 |
break;
|
249 |
|
250 |
case 'ceased':
|
355 |
return $preview;
|
356 |
}
|
357 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
358 |
/**
|
359 |
* Prepare ceased option preview
|
360 |
*
|
393 |
));
|
394 |
}
|
395 |
|
396 |
+
/**
|
397 |
+
* Reset view counter
|
398 |
+
*
|
399 |
+
* @return string
|
400 |
+
*
|
401 |
+
* @access public
|
402 |
+
* @version 6.0.0
|
403 |
+
*/
|
404 |
+
public function resetCounter()
|
405 |
+
{
|
406 |
+
$type = $this->getFromPost('object');
|
407 |
+
$id = $this->getFromPost('objectId');
|
408 |
+
|
409 |
+
if ($type === 'post') {
|
410 |
+
$result = delete_user_meta(
|
411 |
+
$this->getSubject()->getId(),
|
412 |
+
sprintf(AAM_Service_Content::POST_COUNTER_DB_OPTION, $id)
|
413 |
+
);
|
414 |
+
} else {
|
415 |
+
$result = apply_filters(
|
416 |
+
'aam_ajax_filter', false, $this->getSubject(), 'Main_Post.resetCounter'
|
417 |
+
);
|
418 |
+
}
|
419 |
+
|
420 |
+
return wp_json_encode(array(
|
421 |
+
'status' => ($result ? 'success' : 'failure')
|
422 |
+
));
|
423 |
+
}
|
424 |
+
|
425 |
/**
|
426 |
* Reset the object access settings
|
427 |
*
|
454 |
*/
|
455 |
protected function sanitizeOption($option, $value)
|
456 |
{
|
|
|
|
|
|
|
|
|
457 |
if (is_array($value)) {
|
458 |
$value['enabled'] = filter_var($value['enabled'], FILTER_VALIDATE_BOOLEAN);
|
459 |
} else { // Any scalar value has to be boolean
|
application/Backend/Feature/Main/Redirect.php
CHANGED
@@ -38,7 +38,7 @@ class AAM_Backend_Feature_Main_Redirect
|
|
38 |
*
|
39 |
* @version 6.0.0
|
40 |
*/
|
41 |
-
const TEMPLATE = 'service/redirect.
|
42 |
|
43 |
/**
|
44 |
* Get access denied redirect option
|
38 |
*
|
39 |
* @version 6.0.0
|
40 |
*/
|
41 |
+
const TEMPLATE = 'service/redirect.php';
|
42 |
|
43 |
/**
|
44 |
* Get access denied redirect option
|
application/Backend/Feature/Main/Route.php
CHANGED
@@ -40,7 +40,7 @@ class AAM_Backend_Feature_Main_Route
|
|
40 |
*
|
41 |
* @version 6.0.0
|
42 |
*/
|
43 |
-
const TEMPLATE = 'service/route.
|
44 |
|
45 |
/**
|
46 |
* Get list of API routes
|
40 |
*
|
41 |
* @version 6.0.0
|
42 |
*/
|
43 |
+
const TEMPLATE = 'service/route.php';
|
44 |
|
45 |
/**
|
46 |
* Get list of API routes
|
application/Backend/Feature/Main/Toolbar.php
CHANGED
@@ -40,7 +40,7 @@ class AAM_Backend_Feature_Main_Toolbar
|
|
40 |
*
|
41 |
* @version 6.0.0
|
42 |
*/
|
43 |
-
const TEMPLATE = 'service/toolbar.
|
44 |
|
45 |
/**
|
46 |
* Save toolbar settings
|
40 |
*
|
41 |
* @version 6.0.0
|
42 |
*/
|
43 |
+
const TEMPLATE = 'service/toolbar.php';
|
44 |
|
45 |
/**
|
46 |
* Save toolbar settings
|
application/Backend/Feature/Main/Uri.php
CHANGED
@@ -19,6 +19,8 @@ class AAM_Backend_Feature_Main_Uri
|
|
19 |
extends AAM_Backend_Feature_Abstract implements AAM_Backend_Feature_ISubjectAware
|
20 |
{
|
21 |
|
|
|
|
|
22 |
/**
|
23 |
* Default access capability to the feature
|
24 |
*
|
@@ -38,7 +40,7 @@ class AAM_Backend_Feature_Main_Uri
|
|
38 |
*
|
39 |
* @version 6.0.0
|
40 |
*/
|
41 |
-
const TEMPLATE = 'service/uri.
|
42 |
|
43 |
/**
|
44 |
* Get list of all rules
|
@@ -56,14 +58,13 @@ class AAM_Backend_Feature_Main_Uri
|
|
56 |
$response = array(
|
57 |
'recordsTotal' => count($rules),
|
58 |
'recordsFiltered' => count($rules),
|
59 |
-
'draw' =>
|
60 |
'data' => array(),
|
61 |
);
|
62 |
|
63 |
-
foreach ($rules as $
|
64 |
$response['data'][] = array(
|
65 |
-
$
|
66 |
-
$rule['uri'],
|
67 |
$rule['type'],
|
68 |
$rule['action'],
|
69 |
isset($rule['code']) ? $rule['code'] : 307,
|
@@ -84,27 +85,20 @@ class AAM_Backend_Feature_Main_Uri
|
|
84 |
*/
|
85 |
public function save()
|
86 |
{
|
87 |
-
$uri =
|
88 |
-
$
|
89 |
-
$
|
90 |
-
$
|
91 |
-
$code = filter_input(INPUT_POST, 'code');
|
92 |
|
93 |
$object = AAM_Backend_Subject::getInstance()->getObject(self::OBJECT_TYPE);
|
94 |
|
95 |
-
|
96 |
-
if (empty($id)) {
|
97 |
-
$id = uniqid();
|
98 |
-
}
|
99 |
-
|
100 |
-
$object->updateOptionItem($id, array(
|
101 |
-
'uri' => str_replace(site_url(), '', $uri),
|
102 |
'type' => $type,
|
103 |
'action' => $value,
|
104 |
'code' => $code
|
105 |
))->save();
|
106 |
|
107 |
-
return wp_json_encode(array('status' => 'success'));
|
108 |
}
|
109 |
|
110 |
/**
|
@@ -117,11 +111,11 @@ class AAM_Backend_Feature_Main_Uri
|
|
117 |
*/
|
118 |
public function delete()
|
119 |
{
|
120 |
-
$
|
121 |
$object = AAM_Backend_Subject::getInstance()->getObject(self::OBJECT_TYPE);
|
122 |
|
123 |
return wp_json_encode(
|
124 |
-
array('status' => ($object->delete($
|
125 |
);
|
126 |
}
|
127 |
|
19 |
extends AAM_Backend_Feature_Abstract implements AAM_Backend_Feature_ISubjectAware
|
20 |
{
|
21 |
|
22 |
+
use AAM_Core_Contract_RequestTrait;
|
23 |
+
|
24 |
/**
|
25 |
* Default access capability to the feature
|
26 |
*
|
40 |
*
|
41 |
* @version 6.0.0
|
42 |
*/
|
43 |
+
const TEMPLATE = 'service/uri.php';
|
44 |
|
45 |
/**
|
46 |
* Get list of all rules
|
58 |
$response = array(
|
59 |
'recordsTotal' => count($rules),
|
60 |
'recordsFiltered' => count($rules),
|
61 |
+
'draw' => $this->getFromRequest('draw'),
|
62 |
'data' => array(),
|
63 |
);
|
64 |
|
65 |
+
foreach ($rules as $uri => $rule) {
|
66 |
$response['data'][] = array(
|
67 |
+
$uri,
|
|
|
68 |
$rule['type'],
|
69 |
$rule['action'],
|
70 |
isset($rule['code']) ? $rule['code'] : 307,
|
85 |
*/
|
86 |
public function save()
|
87 |
{
|
88 |
+
$uri = str_replace(site_url(), '', $this->getFromPost('uri'));
|
89 |
+
$type = $this->getFromPost('type');
|
90 |
+
$value = $this->getFromPost('value');
|
91 |
+
$code = $this->getFromPost('code');
|
|
|
92 |
|
93 |
$object = AAM_Backend_Subject::getInstance()->getObject(self::OBJECT_TYPE);
|
94 |
|
95 |
+
$result = $object->updateOptionItem($uri, array(
|
|
|
|
|
|
|
|
|
|
|
|
|
96 |
'type' => $type,
|
97 |
'action' => $value,
|
98 |
'code' => $code
|
99 |
))->save();
|
100 |
|
101 |
+
return wp_json_encode(array('status' => ($result ? 'success' : 'failure')));
|
102 |
}
|
103 |
|
104 |
/**
|
111 |
*/
|
112 |
public function delete()
|
113 |
{
|
114 |
+
$uri = filter_input(INPUT_POST, 'uri');
|
115 |
$object = AAM_Backend_Subject::getInstance()->getObject(self::OBJECT_TYPE);
|
116 |
|
117 |
return wp_json_encode(
|
118 |
+
array('status' => ($object->delete($uri) ? 'success' : 'failure'))
|
119 |
);
|
120 |
}
|
121 |
|
application/Backend/Feature/Main/Welcome.php
CHANGED
@@ -23,7 +23,7 @@ class AAM_Backend_Feature_Main_Welcome extends AAM_Backend_Feature_Abstract
|
|
23 |
*
|
24 |
* @version 6.0.0
|
25 |
*/
|
26 |
-
const TEMPLATE = 'service/welcome.
|
27 |
|
28 |
/**
|
29 |
* Register welcome service
|
23 |
*
|
24 |
* @version 6.0.0
|
25 |
*/
|
26 |
+
const TEMPLATE = 'service/welcome.php';
|
27 |
|
28 |
/**
|
29 |
* Register welcome service
|
application/Backend/Feature/Settings/ConfigPress.php
CHANGED
@@ -32,7 +32,7 @@ class AAM_Backend_Feature_Settings_ConfigPress extends AAM_Backend_Feature_Abstr
|
|
32 |
*
|
33 |
* @version 6.0.0
|
34 |
*/
|
35 |
-
const TEMPLATE = 'settings/configpress.
|
36 |
|
37 |
/**
|
38 |
* Save config
|
32 |
*
|
33 |
* @version 6.0.0
|
34 |
*/
|
35 |
+
const TEMPLATE = 'settings/configpress.php';
|
36 |
|
37 |
/**
|
38 |
* Save config
|
application/Backend/Feature/Settings/Content.php
CHANGED
@@ -30,7 +30,7 @@ class AAM_Backend_Feature_Settings_Content extends AAM_Backend_Feature_Abstract
|
|
30 |
*
|
31 |
* @version 6.0.0
|
32 |
*/
|
33 |
-
const TEMPLATE = 'settings/content.
|
34 |
|
35 |
/**
|
36 |
* Get list of content options
|
30 |
*
|
31 |
* @version 6.0.0
|
32 |
*/
|
33 |
+
const TEMPLATE = 'settings/content.php';
|
34 |
|
35 |
/**
|
36 |
* Get list of content options
|
application/Backend/Feature/Settings/Core.php
CHANGED
@@ -30,7 +30,7 @@ class AAM_Backend_Feature_Settings_Core extends AAM_Backend_Feature_Abstract
|
|
30 |
*
|
31 |
* @version 6.0.0
|
32 |
*/
|
33 |
-
const TEMPLATE = 'settings/core.
|
34 |
|
35 |
/**
|
36 |
* Get list of core options
|
30 |
*
|
31 |
* @version 6.0.0
|
32 |
*/
|
33 |
+
const TEMPLATE = 'settings/core.php';
|
34 |
|
35 |
/**
|
36 |
* Get list of core options
|
application/Backend/Feature/Settings/Manager.php
CHANGED
@@ -10,12 +10,12 @@
|
|
10 |
*/
|
11 |
|
12 |
/**
|
13 |
-
* Backend Settings area manager
|
14 |
*
|
15 |
* @package AAM
|
16 |
* @version 6.0.0
|
17 |
*/
|
18 |
-
class AAM_Backend_Feature_Settings_Manager
|
19 |
{
|
20 |
|
21 |
use AAM_Core_Contract_RequestTrait;
|
@@ -60,4 +60,21 @@ class AAM_Backend_Feature_Settings_Manager extends AAM_Backend_Feature_Abstract
|
|
60 |
return wp_json_encode(array('status' => 'success'));
|
61 |
}
|
62 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
63 |
}
|
10 |
*/
|
11 |
|
12 |
/**
|
13 |
+
* Backend Settings area abstract manager
|
14 |
*
|
15 |
* @package AAM
|
16 |
* @version 6.0.0
|
17 |
*/
|
18 |
+
class AAM_Backend_Feature_Settings_Manager extends AAM_Backend_Feature_Abstract
|
19 |
{
|
20 |
|
21 |
use AAM_Core_Contract_RequestTrait;
|
60 |
return wp_json_encode(array('status' => 'success'));
|
61 |
}
|
62 |
|
63 |
+
/**
|
64 |
+
* Register settings UI manager
|
65 |
+
*
|
66 |
+
* @return void
|
67 |
+
*
|
68 |
+
* @access public
|
69 |
+
* @version 6.0.0
|
70 |
+
*/
|
71 |
+
public static function register()
|
72 |
+
{
|
73 |
+
AAM_Backend_Feature::registerFeature((object) array(
|
74 |
+
'capability' => self::ACCESS_CAPABILITY,
|
75 |
+
'type' => 'core',
|
76 |
+
'view' => __CLASS__
|
77 |
+
));
|
78 |
+
}
|
79 |
+
|
80 |
}
|
application/Backend/Feature/Settings/Security.php
CHANGED
@@ -30,7 +30,7 @@ class AAM_Backend_Feature_Settings_Security extends AAM_Backend_Feature_Abstract
|
|
30 |
*
|
31 |
* @version 6.0.0
|
32 |
*/
|
33 |
-
const TEMPLATE = 'settings/security.
|
34 |
|
35 |
/**
|
36 |
* Get list of security options
|
30 |
*
|
31 |
* @version 6.0.0
|
32 |
*/
|
33 |
+
const TEMPLATE = 'settings/security.php';
|
34 |
|
35 |
/**
|
36 |
* Get list of security options
|
application/Backend/Feature/Settings/Service.php
CHANGED
@@ -30,7 +30,7 @@ class AAM_Backend_Feature_Settings_Service extends AAM_Backend_Feature_Abstract
|
|
30 |
*
|
31 |
* @version 6.0.0
|
32 |
*/
|
33 |
-
const TEMPLATE = 'settings/service.
|
34 |
|
35 |
/**
|
36 |
* Get list of services
|
30 |
*
|
31 |
* @version 6.0.0
|
32 |
*/
|
33 |
+
const TEMPLATE = 'settings/service.php';
|
34 |
|
35 |
/**
|
36 |
* Get list of services
|
application/Backend/Feature/Subject/Role.php
CHANGED
@@ -57,11 +57,7 @@ class AAM_Backend_Feature_Subject_Role
|
|
57 |
$id,
|
58 |
$user_count,
|
59 |
translate_user_role($data['name']),
|
60 |
-
|
61 |
-
'aam_role_row_actions_filter',
|
62 |
-
implode(',', $this->prepareRowActions($user_count)),
|
63 |
-
$data
|
64 |
-
),
|
65 |
AAM_Core_API::maxLevel($data['capabilities'])
|
66 |
);
|
67 |
}
|
@@ -72,14 +68,15 @@ class AAM_Backend_Feature_Subject_Role
|
|
72 |
/**
|
73 |
* Prepare the list of role actions
|
74 |
*
|
75 |
-
* @param int
|
|
|
76 |
*
|
77 |
* @return array
|
78 |
*
|
79 |
* @access protected
|
80 |
* @version 6.0.0
|
81 |
*/
|
82 |
-
protected function prepareRowActions($user_count)
|
83 |
{
|
84 |
$actions = array('manage');
|
85 |
|
@@ -99,7 +96,7 @@ class AAM_Backend_Feature_Subject_Role
|
|
99 |
$actions[] = 'no-delete';
|
100 |
}
|
101 |
|
102 |
-
return $actions;
|
103 |
}
|
104 |
|
105 |
/**
|
@@ -127,7 +124,7 @@ class AAM_Backend_Feature_Subject_Role
|
|
127 |
_doing_it_wrong(
|
128 |
__CLASS__ . '::' . $method,
|
129 |
'User Manager does not have this method defined',
|
130 |
-
|
131 |
);
|
132 |
}
|
133 |
|
@@ -303,4 +300,21 @@ class AAM_Backend_Feature_Subject_Role
|
|
303 |
return $response;
|
304 |
}
|
305 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
306 |
}
|
57 |
$id,
|
58 |
$user_count,
|
59 |
translate_user_role($data['name']),
|
60 |
+
implode(',', $this->prepareRowActions($user_count, $id)),
|
|
|
|
|
|
|
|
|
61 |
AAM_Core_API::maxLevel($data['capabilities'])
|
62 |
);
|
63 |
}
|
68 |
/**
|
69 |
* Prepare the list of role actions
|
70 |
*
|
71 |
+
* @param int $user_count
|
72 |
+
* @param string $roleId
|
73 |
*
|
74 |
* @return array
|
75 |
*
|
76 |
* @access protected
|
77 |
* @version 6.0.0
|
78 |
*/
|
79 |
+
protected function prepareRowActions($user_count, $roleId)
|
80 |
{
|
81 |
$actions = array('manage');
|
82 |
|
96 |
$actions[] = 'no-delete';
|
97 |
}
|
98 |
|
99 |
+
return apply_filters('aam_role_row_actions_filter', $actions, $roleId);
|
100 |
}
|
101 |
|
102 |
/**
|
124 |
_doing_it_wrong(
|
125 |
__CLASS__ . '::' . $method,
|
126 |
'User Manager does not have this method defined',
|
127 |
+
AAM_VERSION
|
128 |
);
|
129 |
}
|
130 |
|
300 |
return $response;
|
301 |
}
|
302 |
|
303 |
+
/**
|
304 |
+
* Register Role UI feature
|
305 |
+
*
|
306 |
+
* @return void
|
307 |
+
*
|
308 |
+
* @access public
|
309 |
+
* @version 6.0.0
|
310 |
+
*/
|
311 |
+
public static function register()
|
312 |
+
{
|
313 |
+
AAM_Backend_Feature::registerFeature((object) array(
|
314 |
+
'capability' => self::ACCESS_CAPABILITY,
|
315 |
+
'type' => 'subject',
|
316 |
+
'view' => __CLASS__
|
317 |
+
));
|
318 |
+
}
|
319 |
+
|
320 |
}
|
application/Backend/Feature/Subject/User.php
CHANGED
@@ -53,7 +53,7 @@ class AAM_Backend_Feature_Subject_User
|
|
53 |
|
54 |
foreach ($result->get_results() as $row) {
|
55 |
$response['data'][] = $this->prepareRow(
|
56 |
-
|
57 |
);
|
58 |
}
|
59 |
|
@@ -96,7 +96,7 @@ class AAM_Backend_Feature_Subject_User
|
|
96 |
_doing_it_wrong(
|
97 |
__CLASS__ . '::' . $method,
|
98 |
'User Manager does not have this method defined',
|
99 |
-
|
100 |
);
|
101 |
}
|
102 |
|
@@ -168,14 +168,17 @@ class AAM_Backend_Feature_Subject_User
|
|
168 |
$actions = array();
|
169 |
|
170 |
if ($allowed) {
|
171 |
-
$actions =
|
172 |
-
'
|
173 |
-
|
174 |
-
|
|
|
|
|
|
|
175 |
);
|
176 |
}
|
177 |
|
178 |
-
return
|
179 |
}
|
180 |
|
181 |
/**
|
@@ -307,7 +310,26 @@ class AAM_Backend_Feature_Subject_User
|
|
307 |
$user = AAM::api()->getUser($user);
|
308 |
}
|
309 |
|
310 |
-
return
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
311 |
}
|
312 |
|
313 |
}
|
53 |
|
54 |
foreach ($result->get_results() as $row) {
|
55 |
$response['data'][] = $this->prepareRow(
|
56 |
+
AAM::api()->getUser($row->ID)
|
57 |
);
|
58 |
}
|
59 |
|
96 |
_doing_it_wrong(
|
97 |
__CLASS__ . '::' . $method,
|
98 |
'User Manager does not have this method defined',
|
99 |
+
AAM_VERSION
|
100 |
);
|
101 |
}
|
102 |
|
168 |
$actions = array();
|
169 |
|
170 |
if ($allowed) {
|
171 |
+
$actions = apply_filters(
|
172 |
+
'aam_user_row_actions_filter',
|
173 |
+
array(
|
174 |
+
'manage',
|
175 |
+
current_user_can('edit_users') ? 'edit' : 'no-edit'
|
176 |
+
),
|
177 |
+
$user
|
178 |
);
|
179 |
}
|
180 |
|
181 |
+
return $actions;
|
182 |
}
|
183 |
|
184 |
/**
|
310 |
$user = AAM::api()->getUser($user);
|
311 |
}
|
312 |
|
313 |
+
return apply_filters(
|
314 |
+
'aam_user_can_manage_level_filter', true, $user->getMaxLevel()
|
315 |
+
);
|
316 |
+
}
|
317 |
+
|
318 |
+
/**
|
319 |
+
* Register User UI feature
|
320 |
+
*
|
321 |
+
* @return void
|
322 |
+
*
|
323 |
+
* @access public
|
324 |
+
* @version 6.0.0
|
325 |
+
*/
|
326 |
+
public static function register()
|
327 |
+
{
|
328 |
+
AAM_Backend_Feature::registerFeature((object) array(
|
329 |
+
'capability' => self::ACCESS_CAPABILITY,
|
330 |
+
'type' => 'subject',
|
331 |
+
'view' => __CLASS__
|
332 |
+
));
|
333 |
}
|
334 |
|
335 |
}
|
application/Backend/Manager.php
CHANGED
@@ -148,7 +148,7 @@ class AAM_Backend_Manager
|
|
148 |
*/
|
149 |
public function addMultiRoleSupport($param)
|
150 |
{
|
151 |
-
require_once dirname(__FILE__) . '/
|
152 |
}
|
153 |
|
154 |
/**
|
148 |
*/
|
149 |
public function addMultiRoleSupport($param)
|
150 |
{
|
151 |
+
require_once dirname(__FILE__) . '/tmpl/user/multiple-roles.php';
|
152 |
}
|
153 |
|
154 |
/**
|
application/Backend/Subject.php
CHANGED
@@ -134,7 +134,7 @@ class AAM_Backend_Subject
|
|
134 |
protected function initRequestedSubject($type, $id)
|
135 |
{
|
136 |
if ($type === AAM_Core_Subject_User::UID) {
|
137 |
-
$subject =
|
138 |
} elseif ($type === AAM_Core_Subject_Default::UID) {
|
139 |
$subject = AAM_Core_Subject_Default::getInstance();
|
140 |
} else {
|
@@ -225,7 +225,7 @@ class AAM_Backend_Subject
|
|
225 |
_doing_it_wrong(
|
226 |
static::class . '::' . $name,
|
227 |
'Backend Subject does not have method defined',
|
228 |
-
|
229 |
);
|
230 |
}
|
231 |
|
134 |
protected function initRequestedSubject($type, $id)
|
135 |
{
|
136 |
if ($type === AAM_Core_Subject_User::UID) {
|
137 |
+
$subject = AAM::api()->getUser(intval($id));
|
138 |
} elseif ($type === AAM_Core_Subject_Default::UID) {
|
139 |
$subject = AAM_Core_Subject_Default::getInstance();
|
140 |
} else {
|
225 |
_doing_it_wrong(
|
226 |
static::class . '::' . $name,
|
227 |
'Backend Subject does not have method defined',
|
228 |
+
AAM_VERSION
|
229 |
);
|
230 |
}
|
231 |
|
application/Backend/View.php
CHANGED
@@ -46,23 +46,22 @@ class AAM_Backend_View
|
|
46 |
/**
|
47 |
* Load partial template
|
48 |
*
|
49 |
-
* The specified template has to be located inside the ./
|
50 |
*
|
51 |
* @param string $tmpl
|
52 |
-
* @param array $
|
53 |
*
|
54 |
* @return string|null
|
55 |
*
|
56 |
* @access public
|
57 |
* @version 6.0.0
|
58 |
*/
|
59 |
-
public function loadPartial($tmpl, $
|
60 |
{
|
61 |
if (preg_match('/^[a-z-]+$/i', $tmpl)) {
|
62 |
-
$
|
63 |
-
|
64 |
-
|
65 |
-
$params
|
66 |
);
|
67 |
} else {
|
68 |
$html = null;
|
@@ -79,10 +78,10 @@ class AAM_Backend_View
|
|
79 |
*
|
80 |
* @return string
|
81 |
*
|
82 |
-
* @access
|
83 |
* @version 6.0.0
|
84 |
*/
|
85 |
-
|
86 |
{
|
87 |
ob_start();
|
88 |
|
@@ -146,34 +145,18 @@ class AAM_Backend_View
|
|
146 |
$parts = explode('.', $action);
|
147 |
$subject = AAM_Backend_Subject::getInstance();
|
148 |
|
149 |
-
// Check if subject is allowed to be managed based on user level
|
150 |
-
$allowed = AAM_Core_API::isUserLevelAllowed(
|
151 |
-
$subject->getSubject()->getMaxLevel()
|
152 |
-
);
|
153 |
-
|
154 |
if (count($parts) === 2) {
|
155 |
-
$
|
156 |
|
157 |
-
if (
|
158 |
-
|
159 |
-
|
160 |
-
$isSubjectAware = class_implements(
|
161 |
-
$class_name, 'AAM_Backend_Feature_ISubjectAware'
|
162 |
);
|
163 |
-
|
164 |
-
// Check if service is allowed based on capability
|
165 |
-
$isServiceAllowed = current_user_can($class_name::ACCESS_CAPABILITY);
|
166 |
-
|
167 |
-
if (($isSubjectAware && !$allowed) || !$isServiceAllowed) {
|
168 |
-
wp_die(__('Access denied', AAM_KEY), 'aam_access_denied');
|
169 |
-
}
|
170 |
-
|
171 |
-
$response = call_user_func(array(new $class_name, $parts[1]));
|
172 |
}
|
173 |
}
|
174 |
|
175 |
return apply_filters(
|
176 |
-
'aam_ajax_filter', $response, $subject->getSubject(), $action
|
177 |
);
|
178 |
}
|
179 |
|
@@ -189,7 +172,7 @@ class AAM_Backend_View
|
|
189 |
*/
|
190 |
public function renderPage()
|
191 |
{
|
192 |
-
return $this->loadTemplate(dirname(__FILE__) . '/
|
193 |
}
|
194 |
|
195 |
/**
|
@@ -202,18 +185,28 @@ class AAM_Backend_View
|
|
202 |
*/
|
203 |
public function renderIFrame($type)
|
204 |
{
|
205 |
-
$basedir = dirname(__FILE__) . '/
|
206 |
|
207 |
-
if (current_user_can('aam_manager')
|
208 |
-
if (current_user_can('aam_manage_posts')) {
|
209 |
echo $this->loadTemplate(
|
210 |
-
$basedir . 'post-iframe.
|
211 |
(object) array(
|
212 |
'objectId' => filter_input(INPUT_GET, 'id'),
|
213 |
'objectType' => filter_input(INPUT_GET, 'type'),
|
214 |
'postManager' => new AAM_Backend_Feature_Main_Post()
|
215 |
)
|
216 |
);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
217 |
}
|
218 |
}
|
219 |
|
@@ -233,7 +226,7 @@ class AAM_Backend_View
|
|
233 |
public function renderPostMetabox($post)
|
234 |
{
|
235 |
return $this->loadTemplate(
|
236 |
-
dirname(__FILE__) . '/
|
237 |
(object) array('post' => $post)
|
238 |
);
|
239 |
}
|
@@ -251,7 +244,7 @@ class AAM_Backend_View
|
|
251 |
public function renderTermMetabox($term)
|
252 |
{
|
253 |
return $this->loadTemplate(
|
254 |
-
dirname(__FILE__) . '/
|
255 |
(object) array(
|
256 |
'term' => $term,
|
257 |
'postType' => filter_input(INPUT_GET, 'post_type')
|
@@ -259,6 +252,76 @@ class AAM_Backend_View
|
|
259 |
);
|
260 |
}
|
261 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
262 |
/**
|
263 |
* Render the AAM HTML content
|
264 |
*
|
@@ -274,14 +337,14 @@ class AAM_Backend_View
|
|
274 |
*/
|
275 |
public function renderContent($type = 'main')
|
276 |
{
|
277 |
-
$basedir = __DIR__ . '/
|
278 |
|
279 |
switch ($type) {
|
280 |
case 'main':
|
281 |
// No need to do the authorization as this is already done in the
|
282 |
// AAM_Backend_Manager class
|
283 |
$content = $this->loadTemplate(
|
284 |
-
$basedir . 'main-panel.
|
285 |
(object) array('type' => 'main')
|
286 |
);
|
287 |
break;
|
@@ -289,7 +352,7 @@ class AAM_Backend_View
|
|
289 |
case 'settings':
|
290 |
if (current_user_can('aam_manage_settings')) {
|
291 |
$content = $this->loadTemplate(
|
292 |
-
$basedir . 'main-panel.
|
293 |
(object) array('type' => 'settings')
|
294 |
);
|
295 |
}
|
@@ -297,7 +360,7 @@ class AAM_Backend_View
|
|
297 |
|
298 |
case 'extensions':
|
299 |
if (current_user_can('aam_manage_extensions')) {
|
300 |
-
$content = $this->loadTemplate($basedir . 'addon-panel.
|
301 |
}
|
302 |
break;
|
303 |
|
46 |
/**
|
47 |
* Load partial template
|
48 |
*
|
49 |
+
* The specified template has to be located inside the ./tmpl/partial folder
|
50 |
*
|
51 |
* @param string $tmpl
|
52 |
+
* @param array $params
|
53 |
*
|
54 |
* @return string|null
|
55 |
*
|
56 |
* @access public
|
57 |
* @version 6.0.0
|
58 |
*/
|
59 |
+
public function loadPartial($tmpl, $params = array())
|
60 |
{
|
61 |
if (preg_match('/^[a-z-]+$/i', $tmpl)) {
|
62 |
+
$html = $this->loadTemplate(
|
63 |
+
__DIR__ . "/tmpl/partial/{$tmpl}.php",
|
64 |
+
(is_object($params) ? $params : (object) $params)
|
|
|
65 |
);
|
66 |
} else {
|
67 |
$html = null;
|
78 |
*
|
79 |
* @return string
|
80 |
*
|
81 |
+
* @access public
|
82 |
* @version 6.0.0
|
83 |
*/
|
84 |
+
public function loadTemplate($file_path, $params = null)
|
85 |
{
|
86 |
ob_start();
|
87 |
|
145 |
$parts = explode('.', $action);
|
146 |
$subject = AAM_Backend_Subject::getInstance();
|
147 |
|
|
|
|
|
|
|
|
|
|
|
148 |
if (count($parts) === 2) {
|
149 |
+
$id = 'AAM_Backend_Feature_' . $parts[0];
|
150 |
|
151 |
+
if (AAM_Backend_Feature::isFeatureRegistered($id)) {
|
152 |
+
$response = call_user_func(
|
153 |
+
array(AAM_Backend_Feature::getFeatureView($id), $parts[1])
|
|
|
|
|
154 |
);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
155 |
}
|
156 |
}
|
157 |
|
158 |
return apply_filters(
|
159 |
+
'aam_ajax_filter', $response, $subject->getSubject(), $action
|
160 |
);
|
161 |
}
|
162 |
|
172 |
*/
|
173 |
public function renderPage()
|
174 |
{
|
175 |
+
return $this->loadTemplate(dirname(__FILE__) . '/tmpl/index.php');
|
176 |
}
|
177 |
|
178 |
/**
|
185 |
*/
|
186 |
public function renderIFrame($type)
|
187 |
{
|
188 |
+
$basedir = dirname(__FILE__) . '/tmpl/metabox/';
|
189 |
|
190 |
+
if (current_user_can('aam_manager')) {
|
191 |
+
if (($type === 'post') && current_user_can('aam_manage_posts')) {
|
192 |
echo $this->loadTemplate(
|
193 |
+
$basedir . 'post-iframe.php',
|
194 |
(object) array(
|
195 |
'objectId' => filter_input(INPUT_GET, 'id'),
|
196 |
'objectType' => filter_input(INPUT_GET, 'type'),
|
197 |
'postManager' => new AAM_Backend_Feature_Main_Post()
|
198 |
)
|
199 |
);
|
200 |
+
} elseif ($type === 'user' && current_user_can('aam_manage_users')) {
|
201 |
+
echo $this->loadTemplate(
|
202 |
+
$basedir . 'user-iframe.php',
|
203 |
+
(object) array(
|
204 |
+
'user' => new WP_User(filter_input(INPUT_GET, 'id')),
|
205 |
+
'type' => 'main'
|
206 |
+
)
|
207 |
+
);
|
208 |
+
} else {
|
209 |
+
echo apply_filters('aam_iframe_content_filter', null, $type, $this);
|
210 |
}
|
211 |
}
|
212 |
|
226 |
public function renderPostMetabox($post)
|
227 |
{
|
228 |
return $this->loadTemplate(
|
229 |
+
dirname(__FILE__) . '/tmpl/metabox/post-metabox.php',
|
230 |
(object) array('post' => $post)
|
231 |
);
|
232 |
}
|
244 |
public function renderTermMetabox($term)
|
245 |
{
|
246 |
return $this->loadTemplate(
|
247 |
+
dirname(__FILE__) . '/tmpl/metabox/term-metabox.php',
|
248 |
(object) array(
|
249 |
'term' => $term,
|
250 |
'postType' => filter_input(INPUT_GET, 'post_type')
|
252 |
);
|
253 |
}
|
254 |
|
255 |
+
/**
|
256 |
+
* Render Access Manager metabox iFrame element for user
|
257 |
+
*
|
258 |
+
* @param WP_User $term
|
259 |
+
*
|
260 |
+
* @return string
|
261 |
+
*
|
262 |
+
* @access public
|
263 |
+
* @version 6.0.0
|
264 |
+
*/
|
265 |
+
public function renderUserMetabox($user)
|
266 |
+
{
|
267 |
+
return $this->loadTemplate(
|
268 |
+
dirname(__FILE__) . '/tmpl/metabox/user-metabox.php',
|
269 |
+
(object) array(
|
270 |
+
'user' => $user
|
271 |
+
)
|
272 |
+
);
|
273 |
+
}
|
274 |
+
|
275 |
+
/**
|
276 |
+
* Render Access Policy editor
|
277 |
+
*
|
278 |
+
* @return string
|
279 |
+
*
|
280 |
+
* @access public
|
281 |
+
* @global WP_Post $post
|
282 |
+
* @version 6.0.0
|
283 |
+
*/
|
284 |
+
public function renderPolicyMetabox()
|
285 |
+
{
|
286 |
+
global $post;
|
287 |
+
|
288 |
+
if (is_a($post, 'WP_Post')) {
|
289 |
+
$content = $this->loadTemplate(
|
290 |
+
dirname(__FILE__) . '/tmpl/metabox/policy-metabox.php',
|
291 |
+
(object) array('post' => $post)
|
292 |
+
);
|
293 |
+
} else {
|
294 |
+
$content = null;
|
295 |
+
}
|
296 |
+
|
297 |
+
return $content;
|
298 |
+
}
|
299 |
+
|
300 |
+
/**
|
301 |
+
* Render policy principal metabox
|
302 |
+
*
|
303 |
+
* @return string
|
304 |
+
*
|
305 |
+
* @access public
|
306 |
+
* @global WP_Post $post
|
307 |
+
* @version 6.0.0
|
308 |
+
*/
|
309 |
+
public function renderPolicyPrincipalMetabox()
|
310 |
+
{
|
311 |
+
global $post;
|
312 |
+
|
313 |
+
if (is_a($post, 'WP_Post')) {
|
314 |
+
$content = $this->loadTemplate(
|
315 |
+
dirname(__FILE__) . '/tmpl/metabox/policy-principal-metabox.php',
|
316 |
+
(object) array('post' => $post)
|
317 |
+
);
|
318 |
+
} else {
|
319 |
+
$content = null;
|
320 |
+
}
|
321 |
+
|
322 |
+
return $content;
|
323 |
+
}
|
324 |
+
|
325 |
/**
|
326 |
* Render the AAM HTML content
|
327 |
*
|
337 |
*/
|
338 |
public function renderContent($type = 'main')
|
339 |
{
|
340 |
+
$basedir = __DIR__ . '/tmpl/page/';
|
341 |
|
342 |
switch ($type) {
|
343 |
case 'main':
|
344 |
// No need to do the authorization as this is already done in the
|
345 |
// AAM_Backend_Manager class
|
346 |
$content = $this->loadTemplate(
|
347 |
+
$basedir . 'main-panel.php',
|
348 |
(object) array('type' => 'main')
|
349 |
);
|
350 |
break;
|
352 |
case 'settings':
|
353 |
if (current_user_can('aam_manage_settings')) {
|
354 |
$content = $this->loadTemplate(
|
355 |
+
$basedir . 'main-panel.php',
|
356 |
(object) array('type' => 'settings')
|
357 |
);
|
358 |
}
|
360 |
|
361 |
case 'extensions':
|
362 |
if (current_user_can('aam_manage_extensions')) {
|
363 |
+
$content = $this->loadTemplate($basedir . 'addon-panel.php');
|
364 |
}
|
365 |
break;
|
366 |
|
application/Backend/View/Localization.php
CHANGED
@@ -60,6 +60,7 @@ class AAM_Backend_View_Localization
|
|
60 |
'Delete Role' => __('Delete Role', AAM_KEY),
|
61 |
'Failed to lock user' => __('Failed to lock user', AAM_KEY),
|
62 |
'Search user' => __('Search user', AAM_KEY),
|
|
|
63 |
'_TOTAL_ user(s)' => __('_TOTAL_ user(s)', AAM_KEY),
|
64 |
'Create New User' => __('Create New User', AAM_KEY),
|
65 |
'Role' => __('Role', AAM_KEY),
|
@@ -72,6 +73,7 @@ class AAM_Backend_View_Localization
|
|
72 |
'Processing...' => __('Processing...', AAM_KEY),
|
73 |
'Loading roles...' => __('Loading roles...', AAM_KEY),
|
74 |
'Failed to generate JWT token' => __('Failed to generate JWT token', AAM_KEY),
|
|
|
75 |
'Current user' => __('Current user', AAM_KEY),
|
76 |
'Current role' => __('Current role', AAM_KEY),
|
77 |
'Manage Access' => __('Manage Access', AAM_KEY),
|
60 |
'Delete Role' => __('Delete Role', AAM_KEY),
|
61 |
'Failed to lock user' => __('Failed to lock user', AAM_KEY),
|
62 |
'Search user' => __('Search user', AAM_KEY),
|
63 |
+
'Counter was reset successfully' => __('Counter was reset successfully', AAM_KEY),
|
64 |
'_TOTAL_ user(s)' => __('_TOTAL_ user(s)', AAM_KEY),
|
65 |
'Create New User' => __('Create New User', AAM_KEY),
|
66 |
'Role' => __('Role', AAM_KEY),
|
73 |
'Processing...' => __('Processing...', AAM_KEY),
|
74 |
'Loading roles...' => __('Loading roles...', AAM_KEY),
|
75 |
'Failed to generate JWT token' => __('Failed to generate JWT token', AAM_KEY),
|
76 |
+
'Failed to process request' => __('Failed to process request', AAM_KEY),
|
77 |
'Current user' => __('Current user', AAM_KEY),
|
78 |
'Current role' => __('Current role', AAM_KEY),
|
79 |
'Manage Access' => __('Manage Access', AAM_KEY),
|
application/Backend/Widget/Login.php
CHANGED
@@ -62,7 +62,7 @@ class AAM_Backend_Widget_Login extends WP_Widget
|
|
62 |
|
63 |
require AAM_Core_Config::get(
|
64 |
'service.secureLogin.settings.widget.template',
|
65 |
-
realpath(dirname(__DIR__) . '/
|
66 |
);
|
67 |
}
|
68 |
|
@@ -80,7 +80,7 @@ class AAM_Backend_Widget_Login extends WP_Widget
|
|
80 |
{
|
81 |
$instance = $this->normalize($instance);
|
82 |
|
83 |
-
require dirname(__DIR__) . '/
|
84 |
}
|
85 |
|
86 |
/**
|
62 |
|
63 |
require AAM_Core_Config::get(
|
64 |
'service.secureLogin.settings.widget.template',
|
65 |
+
realpath(dirname(__DIR__) . '/tmpl/widget/login-frontend.php')
|
66 |
);
|
67 |
}
|
68 |
|
80 |
{
|
81 |
$instance = $this->normalize($instance);
|
82 |
|
83 |
+
require dirname(__DIR__) . '/tmpl/widget/login-backend.php';
|
84 |
}
|
85 |
|
86 |
/**
|
application/Backend/phtml/metabox/policy-metabox.phtml
DELETED
@@ -1,427 +0,0 @@
|
|
1 |
-
<?php if (defined('AAM_KEY')) { ?>
|
2 |
-
<div>
|
3 |
-
<style type="text/css">
|
4 |
-
/* CODEMIRROR CSS RULES */
|
5 |
-
/* BASICS */
|
6 |
-
|
7 |
-
.CodeMirror {
|
8 |
-
/* Set height, width, borders, and global font properties here */
|
9 |
-
font-family: monospace;
|
10 |
-
height: 300px;
|
11 |
-
color: black;
|
12 |
-
direction: ltr;
|
13 |
-
border: 1px solid #EEEEEE;
|
14 |
-
padding: 5px;
|
15 |
-
}
|
16 |
-
|
17 |
-
/* PADDING */
|
18 |
-
|
19 |
-
.CodeMirror-lines {
|
20 |
-
padding: 4px 0; /* Vertical padding around content */
|
21 |
-
}
|
22 |
-
.CodeMirror pre {
|
23 |
-
padding: 0 4px; /* Horizontal padding of content */
|
24 |
-
}
|
25 |
-
|
26 |
-
.CodeMirror-scrollbar-filler, .CodeMirror-gutter-filler {
|
27 |
-
background-color: white; /* The little square between H and V scrollbars */
|
28 |
-
}
|
29 |
-
|
30 |
-
/* GUTTER */
|
31 |
-
|
32 |
-
.CodeMirror-gutters {
|
33 |
-
white-space: nowrap;
|
34 |
-
}
|
35 |
-
.CodeMirror-linenumbers {}
|
36 |
-
.CodeMirror-linenumber {
|
37 |
-
padding: 0 3px 0 0px;
|
38 |
-
min-width: 15px;
|
39 |
-
text-align: right;
|
40 |
-
color: #999;
|
41 |
-
white-space: nowrap;
|
42 |
-
}
|
43 |
-
|
44 |
-
.CodeMirror-guttermarker { color: black; }
|
45 |
-
.CodeMirror-guttermarker-subtle { color: #999; }
|
46 |
-
|
47 |
-
/* CURSOR */
|
48 |
-
|
49 |
-
.CodeMirror-cursor {
|
50 |
-
border-left: 1px solid black;
|
51 |
-
border-right: none;
|
52 |
-
width: 0;
|
53 |
-
}
|
54 |
-
/* Shown when moving in bi-directional text */
|
55 |
-
.CodeMirror div.CodeMirror-secondarycursor {
|
56 |
-
border-left: 1px solid silver;
|
57 |
-
}
|
58 |
-
.cm-fat-cursor .CodeMirror-cursor {
|
59 |
-
width: auto;
|
60 |
-
border: 0 !important;
|
61 |
-
background: #7e7;
|
62 |
-
}
|
63 |
-
.cm-fat-cursor div.CodeMirror-cursors {
|
64 |
-
z-index: 1;
|
65 |
-
}
|
66 |
-
.cm-fat-cursor-mark {
|
67 |
-
background-color: rgba(20, 255, 20, 0.5);
|
68 |
-
-webkit-animation: blink 1.06s steps(1) infinite;
|
69 |
-
-moz-animation: blink 1.06s steps(1) infinite;
|
70 |
-
animation: blink 1.06s steps(1) infinite;
|
71 |
-
}
|
72 |
-
.cm-animate-fat-cursor {
|
73 |
-
width: auto;
|
74 |
-
border: 0;
|
75 |
-
-webkit-animation: blink 1.06s steps(1) infinite;
|
76 |
-
-moz-animation: blink 1.06s steps(1) infinite;
|
77 |
-
animation: blink 1.06s steps(1) infinite;
|
78 |
-
background-color: #7e7;
|
79 |
-
}
|
80 |
-
@-moz-keyframes blink {
|
81 |
-
0% {}
|
82 |
-
50% { background-color: transparent; }
|
83 |
-
100% {}
|
84 |
-
}
|
85 |
-
@-webkit-keyframes blink {
|
86 |
-
0% {}
|
87 |
-
50% { background-color: transparent; }
|
88 |
-
100% {}
|
89 |
-
}
|
90 |
-
@keyframes blink {
|
91 |
-
0% {}
|
92 |
-
50% { background-color: transparent; }
|
93 |
-
100% {}
|
94 |
-
}
|
95 |
-
|
96 |
-
/* Can style cursor different in overwrite (non-insert) mode */
|
97 |
-
.CodeMirror-overwrite .CodeMirror-cursor {}
|
98 |
-
|
99 |
-
.cm-tab { display: inline-block; text-decoration: inherit; }
|
100 |
-
|
101 |
-
.CodeMirror-rulers {
|
102 |
-
position: absolute;
|
103 |
-
left: 0; right: 0; top: -50px; bottom: -20px;
|
104 |
-
overflow: hidden;
|
105 |
-
}
|
106 |
-
.CodeMirror-ruler {
|
107 |
-
border-left: 1px solid #ccc;
|
108 |
-
top: 0; bottom: 0;
|
109 |
-
position: absolute;
|
110 |
-
}
|
111 |
-
|
112 |
-
/* DEFAULT THEME */
|
113 |
-
|
114 |
-
.cm-s-default .cm-header {color: blue;}
|
115 |
-
.cm-s-default .cm-quote {color: #090;}
|
116 |
-
.cm-negative {color: #d44;}
|
117 |
-
.cm-positive {color: #292;}
|
118 |
-
.cm-header, .cm-strong {font-weight: bold;}
|
119 |
-
.cm-em {font-style: italic;}
|
120 |
-
.cm-link {text-decoration: underline;}
|
121 |
-
.cm-strikethrough {text-decoration: line-through;}
|
122 |
-
|
123 |
-
.cm-s-default .cm-keyword {color: #708;}
|
124 |
-
.cm-s-default .cm-atom {color: #219;}
|
125 |
-
.cm-s-default .cm-number {color: #164;}
|
126 |
-
.cm-s-default .cm-def {color: #00f;}
|
127 |
-
.cm-s-default .cm-variable,
|
128 |
-
.cm-s-default .cm-punctuation,
|
129 |
-
.cm-s-default .cm-property,
|
130 |
-
.cm-s-default .cm-operator {}
|
131 |
-
.cm-s-default .cm-variable-2 {color: #05a;}
|
132 |
-
.cm-s-default .cm-variable-3, .cm-s-default .cm-type {color: #085;}
|
133 |
-
.cm-s-default .cm-comment {color: #a50;}
|
134 |
-
.cm-s-default .cm-string {color: #a11;}
|
135 |
-
.cm-s-default .cm-string-2 {color: #f50;}
|
136 |
-
.cm-s-default .cm-meta {color: #555;}
|
137 |
-
.cm-s-default .cm-qualifier {color: #555;}
|
138 |
-
.cm-s-default .cm-builtin {color: #30a;}
|
139 |
-
.cm-s-default .cm-bracket {color: #997;}
|
140 |
-
.cm-s-default .cm-tag {color: #170;}
|
141 |
-
.cm-s-default .cm-attribute {color: #00c;}
|
142 |
-
.cm-s-default .cm-hr {color: #999;}
|
143 |
-
.cm-s-default .cm-link {color: #00c;}
|
144 |
-
|
145 |
-
.cm-s-default .cm-error {color: #f00;}
|
146 |
-
.cm-invalidchar {color: #f00;}
|
147 |
-
|
148 |
-
.CodeMirror-composing { border-bottom: 2px solid; }
|
149 |
-
|
150 |
-
/* Default styles for common addons */
|
151 |
-
|
152 |
-
div.CodeMirror span.CodeMirror-matchingbracket {color: #0b0;}
|
153 |
-
div.CodeMirror span.CodeMirror-nonmatchingbracket {color: #a22;}
|
154 |
-
.CodeMirror-matchingtag { background: rgba(255, 150, 0, .3); }
|
155 |
-
.CodeMirror-activeline-background {background: #e8f2ff;}
|
156 |
-
|
157 |
-
/* STOP */
|
158 |
-
|
159 |
-
/* The rest of this file contains styles related to the mechanics of
|
160 |
-
the editor. You probably shouldn't touch them. */
|
161 |
-
|
162 |
-
.CodeMirror {
|
163 |
-
position: relative;
|
164 |
-
overflow: hidden;
|
165 |
-
background: white;
|
166 |
-
}
|
167 |
-
|
168 |
-
.CodeMirror-scroll {
|
169 |
-
overflow: scroll !important; /* Things will break if this is overridden */
|
170 |
-
/* 30px is the magic margin used to hide the element's real scrollbars */
|
171 |
-
/* See overflow: hidden in .CodeMirror */
|
172 |
-
margin-bottom: -30px; margin-right: -30px;
|
173 |
-
padding-bottom: 30px;
|
174 |
-
height: 100%;
|
175 |
-
outline: none; /* Prevent dragging from highlighting the element */
|
176 |
-
position: relative;
|
177 |
-
}
|
178 |
-
.CodeMirror-sizer {
|
179 |
-
position: relative;
|
180 |
-
border-right: 30px solid transparent;
|
181 |
-
}
|
182 |
-
|
183 |
-
/* The fake, visible scrollbars. Used to force redraw during scrolling
|
184 |
-
before actual scrolling happens, thus preventing shaking and
|
185 |
-
flickering artifacts. */
|
186 |
-
.CodeMirror-vscrollbar, .CodeMirror-hscrollbar, .CodeMirror-scrollbar-filler, .CodeMirror-gutter-filler {
|
187 |
-
position: absolute;
|
188 |
-
z-index: 6;
|
189 |
-
display: none;
|
190 |
-
}
|
191 |
-
.CodeMirror-vscrollbar {
|
192 |
-
right: 0; top: 0;
|
193 |
-
overflow-x: hidden;
|
194 |
-
overflow-y: scroll;
|
195 |
-
}
|
196 |
-
.CodeMirror-hscrollbar {
|
197 |
-
bottom: 0; left: 0;
|
198 |
-
overflow-y: hidden;
|
199 |
-
overflow-x: scroll;
|
200 |
-
}
|
201 |
-
.CodeMirror-scrollbar-filler {
|
202 |
-
right: 0; bottom: 0;
|
203 |
-
}
|
204 |
-
.CodeMirror-gutter-filler {
|
205 |
-
left: 0; bottom: 0;
|
206 |
-
}
|
207 |
-
|
208 |
-
.CodeMirror-gutters {
|
209 |
-
position: absolute; left: 0; top: 0;
|
210 |
-
min-height: 100%;
|
211 |
-
z-index: 3;
|
212 |
-
}
|
213 |
-
.CodeMirror-gutter {
|
214 |
-
white-space: normal;
|
215 |
-
height: 100%;
|
216 |
-
display: inline-block;
|
217 |
-
vertical-align: top;
|
218 |
-
margin-bottom: -30px;
|
219 |
-
}
|
220 |
-
.CodeMirror-gutter-wrapper {
|
221 |
-
position: absolute;
|
222 |
-
z-index: 4;
|
223 |
-
background: none !important;
|
224 |
-
border: none !important;
|
225 |
-
}
|
226 |
-
.CodeMirror-gutter-background {
|
227 |
-
position: absolute;
|
228 |
-
top: 0; bottom: 0;
|
229 |
-
z-index: 4;
|
230 |
-
}
|
231 |
-
.CodeMirror-gutter-elt {
|
232 |
-
position: absolute;
|
233 |
-
cursor: default;
|
234 |
-
z-index: 4;
|
235 |
-
}
|
236 |
-
.CodeMirror-gutter-wrapper ::selection { background-color: transparent }
|
237 |
-
.CodeMirror-gutter-wrapper ::-moz-selection { background-color: transparent }
|
238 |
-
|
239 |
-
.CodeMirror-lines {
|
240 |
-
cursor: text;
|
241 |
-
min-height: 1px; /* prevents collapsing before first draw */
|
242 |
-
}
|
243 |
-
.CodeMirror pre {
|
244 |
-
/* Reset some styles that the rest of the page might have set */
|
245 |
-
-moz-border-radius: 0; -webkit-border-radius: 0; border-radius: 0;
|
246 |
-
border-width: 0;
|
247 |
-
background: transparent;
|
248 |
-
font-family: inherit;
|
249 |
-
font-size: inherit;
|
250 |
-
margin: 0;
|
251 |
-
white-space: pre;
|
252 |
-
word-wrap: normal;
|
253 |
-
line-height: inherit;
|
254 |
-
color: inherit;
|
255 |
-
z-index: 2;
|
256 |
-
position: relative;
|
257 |
-
overflow: visible;
|
258 |
-
-webkit-tap-highlight-color: transparent;
|
259 |
-
-webkit-font-variant-ligatures: contextual;
|
260 |
-
font-variant-ligatures: contextual;
|
261 |
-
}
|
262 |
-
#policy-model .CodeMirror pre {
|
263 |
-
padding-left: 20px;
|
264 |
-
}
|
265 |
-
.CodeMirror-wrap pre {
|
266 |
-
word-wrap: break-word;
|
267 |
-
white-space: pre-wrap;
|
268 |
-
word-break: normal;
|
269 |
-
}
|
270 |
-
|
271 |
-
.CodeMirror-linebackground {
|
272 |
-
position: absolute;
|
273 |
-
left: 0; right: 0; top: 0; bottom: 0;
|
274 |
-
z-index: 0;
|
275 |
-
}
|
276 |
-
|
277 |
-
.CodeMirror-linewidget {
|
278 |
-
position: relative;
|
279 |
-
z-index: 2;
|
280 |
-
padding: 0.1px; /* Force widget margins to stay inside of the container */
|
281 |
-
}
|
282 |
-
|
283 |
-
.CodeMirror-widget {}
|
284 |
-
|
285 |
-
.CodeMirror-rtl pre { direction: rtl; }
|
286 |
-
|
287 |
-
.CodeMirror-code {
|
288 |
-
outline: none;
|
289 |
-
}
|
290 |
-
|
291 |
-
/* Force content-box sizing for the elements where we expect it */
|
292 |
-
.CodeMirror-scroll,
|
293 |
-
.CodeMirror-sizer,
|
294 |
-
.CodeMirror-gutter,
|
295 |
-
.CodeMirror-gutters,
|
296 |
-
.CodeMirror-linenumber {
|
297 |
-
-moz-box-sizing: content-box;
|
298 |
-
box-sizing: content-box;
|
299 |
-
}
|
300 |
-
|
301 |
-
.CodeMirror-measure {
|
302 |
-
position: absolute;
|
303 |
-
width: 100%;
|
304 |
-
height: 0;
|
305 |
-
overflow: hidden;
|
306 |
-
visibility: hidden;
|
307 |
-
}
|
308 |
-
|
309 |
-
.CodeMirror-cursor {
|
310 |
-
position: absolute;
|
311 |
-
pointer-events: none;
|
312 |
-
}
|
313 |
-
.CodeMirror-measure pre { position: static; }
|
314 |
-
|
315 |
-
div.CodeMirror-cursors {
|
316 |
-
visibility: hidden;
|
317 |
-
position: relative;
|
318 |
-
z-index: 3;
|
319 |
-
}
|
320 |
-
div.CodeMirror-dragcursors {
|
321 |
-
visibility: visible;
|
322 |
-
}
|
323 |
-
|
324 |
-
.CodeMirror-focused div.CodeMirror-cursors {
|
325 |
-
visibility: visible;
|
326 |
-
}
|
327 |
-
|
328 |
-
.CodeMirror-selected { background: #d9d9d9; }
|
329 |
-
.CodeMirror-focused .CodeMirror-selected { background: #d7d4f0; }
|
330 |
-
.CodeMirror-crosshair { cursor: crosshair; }
|
331 |
-
.CodeMirror-line::selection, .CodeMirror-line > span::selection, .CodeMirror-line > span > span::selection { background: #d7d4f0; }
|
332 |
-
.CodeMirror-line::-moz-selection, .CodeMirror-line > span::-moz-selection, .CodeMirror-line > span > span::-moz-selection { background: #d7d4f0; }
|
333 |
-
|
334 |
-
.cm-searching {
|
335 |
-
background-color: #ffa;
|
336 |
-
background-color: rgba(255, 255, 0, .4);
|
337 |
-
}
|
338 |
-
|
339 |
-
/* Used to force a border model for a node */
|
340 |
-
.cm-force-border { padding-right: .1px; }
|
341 |
-
|
342 |
-
@media print {
|
343 |
-
/* Hide the cursor when printing */
|
344 |
-
.CodeMirror div.CodeMirror-cursors {
|
345 |
-
visibility: hidden;
|
346 |
-
}
|
347 |
-
}
|
348 |
-
|
349 |
-
/* See issue #2901 */
|
350 |
-
.cm-tab-wrap-hack:after { content: ''; }
|
351 |
-
|
352 |
-
/* Help users use markselection to safely style text background */
|
353 |
-
span.CodeMirror-selectedtext { background: none; }
|
354 |
-
|
355 |
-
.aam-alert-danger{
|
356 |
-
border-radius: 0;
|
357 |
-
margin: 10px 0;
|
358 |
-
color: #a94442;
|
359 |
-
background-color: #f2dede;
|
360 |
-
border-color: #ebccd1;
|
361 |
-
padding: 15px;
|
362 |
-
border: 1px solid transparent;
|
363 |
-
}
|
364 |
-
.aam-infobox {
|
365 |
-
border-left: 5px solid #257fad;
|
366 |
-
padding: 20px;
|
367 |
-
background-color: #d9edf7;
|
368 |
-
margin-bottom: 0;
|
369 |
-
}
|
370 |
-
</style>
|
371 |
-
|
372 |
-
<?php
|
373 |
-
if (!empty($args->post->post_content)) {
|
374 |
-
// Validate the policy
|
375 |
-
$validator = new AAM_Core_Policy_Validator(htmlspecialchars_decode($args->post->post_content));
|
376 |
-
$errors = $validator->validate();
|
377 |
-
} else {
|
378 |
-
$args->post->post_content = AAM_Backend_View_Helper::getDefaultPolicy();
|
379 |
-
$errors = array();
|
380 |
-
}
|
381 |
-
?>
|
382 |
-
|
383 |
-
<div class="aam-alert-danger<?php echo empty($errors) ? ' hidden' : ''; ?>" id="policy-parsing-error">
|
384 |
-
<?php echo implode('<br/>', $errors); ?>
|
385 |
-
</div>
|
386 |
-
|
387 |
-
<textarea id="aam-policy-editor" name="aam-policy" class="policy-editor" rows="10"><?php echo stripslashes($args->post->post_content); ?></textarea>
|
388 |
-
|
389 |
-
<p class="aam-infobox">
|
390 |
-
<?php echo sprintf(AAM_Backend_View_Helper::preparePhrase('To learn more about Access & Security policy document, please check [%sAccess & Security Policy%s] page.', 'b'), '<a href="https://aamplugin.com/reference/policy" target="_blank">', '</a>'); ?>
|
391 |
-
</p>
|
392 |
-
|
393 |
-
<script type='text/javascript' src="<?php echo AAM_MEDIA . '/js/vendor.js'; ?>"></script>
|
394 |
-
|
395 |
-
<script type='text/javascript'>
|
396 |
-
(function($){
|
397 |
-
var editor = CodeMirror.fromTextArea(
|
398 |
-
document.getElementById("aam-policy-editor"),
|
399 |
-
{
|
400 |
-
mode: "application/json",
|
401 |
-
lineNumbers: true
|
402 |
-
}
|
403 |
-
);
|
404 |
-
|
405 |
-
$(document).ready(function () {
|
406 |
-
$('form[name="post"]').bind('submit', function(event) {
|
407 |
-
var json = editor.getValue();
|
408 |
-
|
409 |
-
$('#policy-parsing-error').addClass('hidden');
|
410 |
-
|
411 |
-
try {
|
412 |
-
JSON.parse(json);
|
413 |
-
|
414 |
-
$('#aam-policy-editor').val(json);
|
415 |
-
} catch (e) {
|
416 |
-
event.preventDefault();
|
417 |
-
|
418 |
-
$('#policy-parsing-error').removeClass('hidden').html(
|
419 |
-
'<b><?php echo __('Syntax Error', AAM_KEY); ?></b>: ' + e.message.replace('JSON.parse:', '')
|
420 |
-
);
|
421 |
-
}
|
422 |
-
});
|
423 |
-
});
|
424 |
-
}(jQuery));
|
425 |
-
</script>
|
426 |
-
</div>
|
427 |
-
<?php }
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
application/Backend/phtml/metabox/policy-principal-metabox.phtml
DELETED
@@ -1,3 +0,0 @@
|
|
1 |
-
<?php if (defined('AAM_KEY')) { ?>
|
2 |
-
<iframe src="<?php echo admin_url('admin.php?page=aam&aamframe=principal&oid=' . $args->post->ID . '&otype=post'); ?>" width="100%" height="450" style="border: 0; margin-top:0;" id="policy-principal"></iframe>
|
3 |
-
<?php }
|
|
|
|
|
|
application/Backend/{phtml/index.phtml → tmpl/index.php}
RENAMED
@@ -1,6 +1,6 @@
|
|
1 |
<?php if (defined('AAM_KEY')) { ?>
|
2 |
<div class="wrap" id="aam-container">
|
3 |
-
<?php echo $this->loadTemplate(__DIR__ . '/page/current-subject.
|
4 |
|
5 |
<div class="row">
|
6 |
<div class="col-xs-12 col-md-8">
|
@@ -8,9 +8,7 @@
|
|
8 |
<div class="postbox">
|
9 |
<div class="inside" id="access-manager-inside">
|
10 |
<div class="aam-postbox-inside" id="aam-content">
|
11 |
-
|
12 |
-
<?php echo AAM_Backend_View_Helper::preparePhrase('[Loading AAM UI]. Please wait. If content will not load within next 30 seconds, clear your browser cache and reload the page. If still nothing, it is most likely some sort of JavaScript or CSS conflict with one your active plugins or theme. Try to deactivate all plugins and switch to any default WordPress theme to find out what causes the issue.', 'strong'); ?>
|
13 |
-
</p>
|
14 |
</div>
|
15 |
</div>
|
16 |
</div>
|
@@ -111,8 +109,8 @@
|
|
111 |
</div>
|
112 |
</div>
|
113 |
|
114 |
-
<?php echo $this->loadTemplate(__DIR__ . '/page/subject-panel.
|
115 |
-
<?php echo $this->loadTemplate(__DIR__ . '/page/subject-panel-advanced.
|
116 |
</div>
|
117 |
</div>
|
118 |
</div>
|
1 |
<?php if (defined('AAM_KEY')) { ?>
|
2 |
<div class="wrap" id="aam-container">
|
3 |
+
<?php echo $this->loadTemplate(__DIR__ . '/page/current-subject.php'); ?>
|
4 |
|
5 |
<div class="row">
|
6 |
<div class="col-xs-12 col-md-8">
|
8 |
<div class="postbox">
|
9 |
<div class="inside" id="access-manager-inside">
|
10 |
<div class="aam-postbox-inside" id="aam-content">
|
11 |
+
<?php echo $this->loadPartial('loading-content'); ?>
|
|
|
|
|
12 |
</div>
|
13 |
</div>
|
14 |
</div>
|
109 |
</div>
|
110 |
</div>
|
111 |
|
112 |
+
<?php echo $this->loadTemplate(__DIR__ . '/page/subject-panel.php'); ?>
|
113 |
+
<?php echo $this->loadTemplate(__DIR__ . '/page/subject-panel-advanced.php'); ?>
|
114 |
</div>
|
115 |
</div>
|
116 |
</div>
|
application/Backend/{phtml/metabox/iframe-footer.phtml → tmpl/metabox/iframe-footer.php}
RENAMED
File without changes
|
application/Backend/{phtml/metabox/iframe-header.phtml → tmpl/metabox/iframe-header.php}
RENAMED
@@ -18,5 +18,5 @@
|
|
18 |
<?php do_action('aam_iframe_header_action'); ?>
|
19 |
</head>
|
20 |
|
21 |
-
<body id="aam-container">
|
22 |
<?php }
|
18 |
<?php do_action('aam_iframe_header_action'); ?>
|
19 |
</head>
|
20 |
|
21 |
+
<body id="aam-container" class="aam-iframe">
|
22 |
<?php }
|
application/Backend/tmpl/metabox/policy-metabox.php
ADDED
@@ -0,0 +1,59 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php if (defined('AAM_KEY')) { ?>
|
2 |
+
<div>
|
3 |
+
<style type="text/css">.CodeMirror{font-family:monospace;height:300px;color:#000;direction:ltr;border:1px solid #eee;padding:5px}.CodeMirror-lines{padding:4px 0}.CodeMirror pre{padding:0 4px}.CodeMirror-gutter-filler,.CodeMirror-scrollbar-filler{background-color:#fff}.CodeMirror-gutters{white-space:nowrap}.CodeMirror-linenumber{padding:0 3px 0 0;min-width:15px;text-align:right;color:#999;white-space:nowrap}.CodeMirror-guttermarker{color:#000}.CodeMirror-guttermarker-subtle{color:#999}.CodeMirror-cursor{border-left:1px solid #000;border-right:none;width:0}.CodeMirror div.CodeMirror-secondarycursor{border-left:1px solid silver}.cm-fat-cursor .CodeMirror-cursor{width:auto;border:0!important;background:#7e7}.cm-fat-cursor div.CodeMirror-cursors{z-index:1}.cm-fat-cursor-mark{background-color:rgba(20,255,20,.5);-webkit-animation:blink 1.06s steps(1) infinite;-moz-animation:blink 1.06s steps(1) infinite;animation:blink 1.06s steps(1) infinite}.cm-animate-fat-cursor{width:auto;border:0;-webkit-animation:blink 1.06s steps(1) infinite;-moz-animation:blink 1.06s steps(1) infinite;animation:blink 1.06s steps(1) infinite;background-color:#7e7}@-moz-keyframes blink{50%{background-color:transparent}}@-webkit-keyframes blink{50%{background-color:transparent}}@keyframes blink{50%{background-color:transparent}}.cm-tab{display:inline-block;text-decoration:inherit}.CodeMirror-rulers{position:absolute;left:0;right:0;top:-50px;bottom:-20px;overflow:hidden}.CodeMirror-ruler{border-left:1px solid #ccc;top:0;bottom:0;position:absolute}.cm-s-default .cm-header{color:#00f}.cm-s-default .cm-quote{color:#090}.cm-negative{color:#d44}.cm-positive{color:#292}.cm-header,.cm-strong{font-weight:700}.cm-em{font-style:italic}.cm-link{text-decoration:underline}.cm-strikethrough{text-decoration:line-through}.cm-s-default .cm-keyword{color:#708}.cm-s-default .cm-atom{color:#219}.cm-s-default .cm-number{color:#164}.cm-s-default .cm-def{color:#00f}.cm-s-default .cm-variable-2{color:#05a}.cm-s-default .cm-type,.cm-s-default .cm-variable-3{color:#085}.cm-s-default .cm-comment{color:#a50}.cm-s-default .cm-string{color:#a11}.cm-s-default .cm-string-2{color:#f50}.cm-s-default .cm-meta{color:#555}.cm-s-default .cm-qualifier{color:#555}.cm-s-default .cm-builtin{color:#30a}.cm-s-default .cm-bracket{color:#997}.cm-s-default .cm-tag{color:#170}.cm-s-default .cm-attribute{color:#00c}.cm-s-default .cm-hr{color:#999}.cm-s-default .cm-link{color:#00c}.cm-s-default .cm-error{color:red}.cm-invalidchar{color:red}.CodeMirror-composing{border-bottom:2px solid}div.CodeMirror span.CodeMirror-matchingbracket{color:#0b0}div.CodeMirror span.CodeMirror-nonmatchingbracket{color:#a22}.CodeMirror-matchingtag{background:rgba(255,150,0,.3)}.CodeMirror-activeline-background{background:#e8f2ff}.CodeMirror{position:relative;overflow:hidden;background:#fff}.CodeMirror-scroll{overflow:scroll!important;margin-bottom:-30px;margin-right:-30px;padding-bottom:30px;height:100%;outline:0;position:relative}.CodeMirror-sizer{position:relative;border-right:30px solid transparent}.CodeMirror-gutter-filler,.CodeMirror-hscrollbar,.CodeMirror-scrollbar-filler,.CodeMirror-vscrollbar{position:absolute;z-index:6;display:none}.CodeMirror-vscrollbar{right:0;top:0;overflow-x:hidden;overflow-y:scroll}.CodeMirror-hscrollbar{bottom:0;left:0;overflow-y:hidden;overflow-x:scroll}.CodeMirror-scrollbar-filler{right:0;bottom:0}.CodeMirror-gutter-filler{left:0;bottom:0}.CodeMirror-gutters{position:absolute;left:0;top:0;min-height:100%;z-index:3}.CodeMirror-gutter{white-space:normal;height:100%;display:inline-block;vertical-align:top;margin-bottom:-30px}.CodeMirror-gutter-wrapper{position:absolute;z-index:4;background:0 0!important;border:none!important}.CodeMirror-gutter-background{position:absolute;top:0;bottom:0;z-index:4}.CodeMirror-gutter-elt{position:absolute;cursor:default;z-index:4}.CodeMirror-gutter-wrapper ::selection{background-color:transparent}.CodeMirror-gutter-wrapper ::-moz-selection{background-color:transparent}.CodeMirror-lines{cursor:text;min-height:1px}.CodeMirror pre{-moz-border-radius:0;-webkit-border-radius:0;border-radius:0;border-width:0;background:0 0;font-family:inherit;font-size:inherit;margin:0;white-space:pre;word-wrap:normal;line-height:inherit;color:inherit;z-index:2;position:relative;overflow:visible;-webkit-tap-highlight-color:transparent;-webkit-font-variant-ligatures:contextual;font-variant-ligatures:contextual}#policy-model .CodeMirror pre{padding-left:20px}.CodeMirror-wrap pre{word-wrap:break-word;white-space:pre-wrap;word-break:normal}.CodeMirror-linebackground{position:absolute;left:0;right:0;top:0;bottom:0;z-index:0}.CodeMirror-linewidget{position:relative;z-index:2;padding:.1px}.CodeMirror-rtl pre{direction:rtl}.CodeMirror-code{outline:0}.CodeMirror-gutter,.CodeMirror-gutters,.CodeMirror-linenumber,.CodeMirror-scroll,.CodeMirror-sizer{-moz-box-sizing:content-box;box-sizing:content-box}.CodeMirror-measure{position:absolute;width:100%;height:0;overflow:hidden;visibility:hidden}.CodeMirror-cursor{position:absolute;pointer-events:none}.CodeMirror-measure pre{position:static}div.CodeMirror-cursors{visibility:hidden;position:relative;z-index:3}div.CodeMirror-dragcursors{visibility:visible}.CodeMirror-focused div.CodeMirror-cursors{visibility:visible}.CodeMirror-selected{background:#d9d9d9}.CodeMirror-focused .CodeMirror-selected{background:#d7d4f0}.CodeMirror-crosshair{cursor:crosshair}.CodeMirror-line::selection,.CodeMirror-line>span::selection,.CodeMirror-line>span>span::selection{background:#d7d4f0}.CodeMirror-line::-moz-selection,.CodeMirror-line>span::-moz-selection,.CodeMirror-line>span>span::-moz-selection{background:#d7d4f0}.cm-searching{background-color:#ffa;background-color:rgba(255,255,0,.4)}.cm-force-border{padding-right:.1px}@media print{.CodeMirror div.CodeMirror-cursors{visibility:hidden}}.cm-tab-wrap-hack:after{content:''}span.CodeMirror-selectedtext{background:0 0}.aam-alert-danger{border-radius:0;margin:10px 0;color:#a94442;background-color:#f2dede;border-color:#ebccd1;padding:15px;border:1px solid transparent}.aam-infobox{border-left:5px solid #257fad;padding:20px;background-color:#d9edf7;margin-bottom:0}</style>
|
4 |
+
|
5 |
+
<?php
|
6 |
+
if (!empty($params->post->post_content)) {
|
7 |
+
// Validate the policy
|
8 |
+
$validator = new AAM_Core_Policy_Validator(htmlspecialchars_decode($params->post->post_content));
|
9 |
+
$errors = $validator->validate();
|
10 |
+
} else {
|
11 |
+
$params->post->post_content = AAM_Backend_Feature_Main_Policy::getDefaultPolicy();
|
12 |
+
$errors = array();
|
13 |
+
}
|
14 |
+
?>
|
15 |
+
|
16 |
+
<div class="aam-alert-danger<?php echo (empty($errors) ? ' hidden' : ''); ?>" id="policy-parsing-error">
|
17 |
+
<?php echo implode('<br/>', $errors); ?>
|
18 |
+
</div>
|
19 |
+
|
20 |
+
<textarea id="aam-policy-editor" name="aam-policy" class="policy-editor" rows="10"><?php echo $params->post->post_content; ?></textarea>
|
21 |
+
|
22 |
+
<p class="aam-infobox">
|
23 |
+
<?php echo sprintf(AAM_Backend_View_Helper::preparePhrase('To learn more about Access & Security policy document, please check [%sAccess & Security Policy%s] page.', 'b'), '<a href="https://aamplugin.com/reference/policy" target="_blank">', '</a>'); ?>
|
24 |
+
</p>
|
25 |
+
|
26 |
+
<script type='text/javascript' src="<?php echo AAM_MEDIA . '/js/vendor.js'; ?>"></script>
|
27 |
+
|
28 |
+
<script type='text/javascript'>
|
29 |
+
(function($) {
|
30 |
+
var editor = CodeMirror.fromTextArea(
|
31 |
+
document.getElementById("aam-policy-editor"), {
|
32 |
+
mode: "application/json",
|
33 |
+
lineNumbers: true
|
34 |
+
}
|
35 |
+
);
|
36 |
+
|
37 |
+
$(document).ready(function() {
|
38 |
+
$('form[name="post"]').bind('submit', function(event) {
|
39 |
+
var json = editor.getValue();
|
40 |
+
|
41 |
+
$('#policy-parsing-error').addClass('hidden');
|
42 |
+
|
43 |
+
try {
|
44 |
+
JSON.parse(json);
|
45 |
+
|
46 |
+
$('#aam-policy-editor').val(json);
|
47 |
+
} catch (e) {
|
48 |
+
event.preventDefault();
|
49 |
+
|
50 |
+
$('#policy-parsing-error').removeClass('hidden').html(
|
51 |
+
'<b><?php echo __('Syntax Error', AAM_KEY); ?></b>: ' + e.message.replace('JSON.parse:', '')
|
52 |
+
);
|
53 |
+
}
|
54 |
+
});
|
55 |
+
});
|
56 |
+
}(jQuery));
|
57 |
+
</script>
|
58 |
+
</div>
|
59 |
+
<?php }
|
application/Backend/tmpl/metabox/policy-principal-metabox.php
ADDED
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
1 |
+
<?php if (defined('AAM_KEY')) { ?>
|
2 |
+
<iframe src="<?php echo admin_url('admin.php?page=aam&aamframe=principal&id=' . $params->post->ID); ?>" width="100%" height="450" style="border: 0; margin-top:0;" id="policy-principal"></iframe>
|
3 |
+
<?php }
|
application/Backend/{phtml/metabox/post-iframe.phtml → tmpl/metabox/post-iframe.php}
RENAMED
@@ -1,11 +1,11 @@
|
|
1 |
<?php /** @version 6.0.0 */ ?>
|
2 |
|
3 |
<?php if (defined('AAM_KEY')) { ?>
|
4 |
-
<?php echo $this->loadTemplate(__DIR__ . '/iframe-header.
|
5 |
|
6 |
<div class="row" style="margin: 10px 0 0 0;">
|
7 |
<div class="col-sm-4" style="padding: 0;">
|
8 |
-
<?php echo $this->loadTemplate(dirname(__DIR__) . '/page/subject-panel.
|
9 |
</div>
|
10 |
|
11 |
<div class="col-sm-8">
|
@@ -15,5 +15,5 @@
|
|
15 |
</div>
|
16 |
</div>
|
17 |
|
18 |
-
<?php echo $this->loadTemplate(__DIR__ . '/iframe-footer.
|
19 |
<?php }
|
1 |
<?php /** @version 6.0.0 */ ?>
|
2 |
|
3 |
<?php if (defined('AAM_KEY')) { ?>
|
4 |
+
<?php echo $this->loadTemplate(__DIR__ . '/iframe-header.php'); ?>
|
5 |
|
6 |
<div class="row" style="margin: 10px 0 0 0;">
|
7 |
<div class="col-sm-4" style="padding: 0;">
|
8 |
+
<?php echo $this->loadTemplate(dirname(__DIR__) . '/page/subject-panel.php'); ?>
|
9 |
</div>
|
10 |
|
11 |
<div class="col-sm-8">
|
15 |
</div>
|
16 |
</div>
|
17 |
|
18 |
+
<?php echo $this->loadTemplate(__DIR__ . '/iframe-footer.php'); ?>
|
19 |
<?php }
|
application/Backend/{phtml/metabox/post-metabox.phtml → tmpl/metabox/post-metabox.php}
RENAMED
File without changes
|
application/Backend/tmpl/metabox/principal-iframe.php
ADDED
@@ -0,0 +1,12 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php /** @version 6.0.0 */ ?>
|
2 |
+
|
3 |
+
<?php if (defined('AAM_KEY')) { ?>
|
4 |
+
<?php echo $this->loadTemplate(__DIR__ . '/iframe-header.php', $params); ?>
|
5 |
+
|
6 |
+
<?php echo $this->loadTemplate(dirname(__DIR__) . '/page/subject-panel.php', $params); ?>
|
7 |
+
|
8 |
+
<!-- Additional attributes -->
|
9 |
+
<input type="hidden" id="aam-policy-id" value="<?php echo $params->policyId; ?>" />
|
10 |
+
|
11 |
+
<?php echo $this->loadTemplate(__DIR__ . '/iframe-footer.php', $params); ?>
|
12 |
+
<?php }
|
application/Backend/{phtml/metabox/term-metabox.phtml → tmpl/metabox/term-metabox.php}
RENAMED
File without changes
|
application/Backend/tmpl/metabox/user-iframe.php
ADDED
@@ -0,0 +1,21 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php /** @version 6.0.0 */ ?>
|
2 |
+
|
3 |
+
<?php if (defined('AAM_KEY')) { ?>
|
4 |
+
<?php echo $this->loadTemplate(__DIR__ . '/iframe-header.php'); ?>
|
5 |
+
|
6 |
+
<div class="row" style="margin: 10px 0 0 0;">
|
7 |
+
<div class="col-sm-12">
|
8 |
+
<div id="aam-content">
|
9 |
+
<?php echo $this->loadPartial('loading-content'); ?>
|
10 |
+
</div>
|
11 |
+
</div>
|
12 |
+
</div>
|
13 |
+
|
14 |
+
<!-- User specific attributes -->
|
15 |
+
<input type="hidden" id="aam-subject-type" value="user" />
|
16 |
+
<input type="hidden" id="aam-subject-id" value="<?php echo $params->user->ID; ?>" />
|
17 |
+
<input type="hidden" id="aam-subject-name" value="<?php echo esc_js($params->user->display_name); ?>" />
|
18 |
+
<input type="hidden" id="aam-subject-level" value="<?php echo AAM_Core_API::maxLevel($params->user->allcaps); ?>" />
|
19 |
+
|
20 |
+
<?php echo $this->loadTemplate(__DIR__ . '/iframe-footer.php'); ?>
|
21 |
+
<?php }
|
application/Backend/tmpl/metabox/user-metabox.php
ADDED
@@ -0,0 +1,5 @@
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php /** @version 6.0.0 */ ?>
|
2 |
+
|
3 |
+
<?php if (defined('AAM_KEY')) { ?>
|
4 |
+
<iframe src="<?php echo admin_url('admin.php?page=aam&aamframe=user&id=' . $params->user->ID); ?>" width="100%" height="550" style="border-bottom: 1px solid #e5e5e5; margin-top:10px;"></iframe>
|
5 |
+
<?php }
|
application/Backend/{phtml/page/addon-panel.phtml → tmpl/page/addon-panel.php}
RENAMED
File without changes
|
application/Backend/{phtml/page/current-subject.phtml → tmpl/page/current-subject.php}
RENAMED
File without changes
|
application/Backend/{phtml/page/main-panel.phtml → tmpl/page/main-panel.php}
RENAMED
File without changes
|
application/Backend/{phtml/page/subject-panel-advanced.phtml → tmpl/page/subject-panel-advanced.php}
RENAMED
File without changes
|
application/Backend/{phtml/page/subject-panel.phtml → tmpl/page/subject-panel.php}
RENAMED
@@ -11,19 +11,19 @@
|
|
11 |
<ul class="nav nav-tabs" role="tablist">
|
12 |
<?php $active = 0; ?>
|
13 |
<?php if (current_user_can('aam_manage_roles')) { ?>
|
14 |
-
<li role="presentation" class="<?php echo (!$active++ ? 'active ' : ''); ?>text-center"><a href="#roles" aria-controls="roles" role="tab" data-toggle="tab"><i class="icon-users"></i><
|
15 |
<?php } ?>
|
16 |
<?php if (current_user_can('aam_manage_users')) { ?>
|
17 |
-
<li role="presentation" class="<?php echo (!$active++ ? 'active ' : ''); ?>text-center"><a href="#users" aria-controls="users" role="tab" data-toggle="tab"><i class="icon-user"></i><
|
18 |
<?php } ?>
|
19 |
<?php if (current_user_can('aam_manage_visitors')) { ?>
|
20 |
-
<li role="presentation" class="<?php echo (!$active++ ? 'active ' : ''); ?>text-center"><a href="#visitor" aria-controls="visitor" role="tab" data-toggle="tab"><i class="icon-user-secret"></i><
|
21 |
<?php } ?>
|
22 |
<?php if (current_user_can('aam_manage_default')) { ?>
|
23 |
-
<li role="presentation" class="<?php echo (!$active++ ? 'active ' : ''); ?>text-center"><a href="#default" aria-controls="default" role="tab" data-toggle="tab" class="text-danger"><i class="icon-asterisk"></i><
|
24 |
<?php } ?>
|
25 |
<?php if ($active === 0) { ?>
|
26 |
-
<li role="presentation" class="active text-center"><a href="#none" aria-controls="none" role="tab" data-toggle="tab" class="text-muted"><i class="icon-asterisk"></i><
|
27 |
<?php } ?>
|
28 |
</ul>
|
29 |
<div class="tab-content">
|
@@ -63,18 +63,12 @@
|
|
63 |
<?php } ?>
|
64 |
<?php if (current_user_can('aam_manage_visitors')) { ?>
|
65 |
<div role="tabpanel" class="tab-pane<?php echo (!$active++ ? ' active' : ''); ?>" id="visitor">
|
66 |
-
|
67 |
-
<span class="aam-bordered"><?php echo __('Manage access to your website for visitors (any user that is not authenticated)', AAM_KEY); ?>.</span>
|
68 |
-
<button class="btn btn-primary btn-block" id="manage-visitor"><i class="icon-cog"></i> <?php echo __('Manage Visitors', AAM_KEY); ?></button>
|
69 |
-
</div>
|
70 |
</div>
|
71 |
<?php } ?>
|
72 |
<?php if (current_user_can('aam_manage_default')) { ?>
|
73 |
<div role="tabpanel" class="tab-pane<?php echo (!$active++ ? ' active' : ''); ?>" id="default">
|
74 |
-
|
75 |
-
<span class="aam-bordered"><?php echo __('Manage default access to your website resources for all users, roles and visitor. This includes Administrator role and your user', AAM_KEY); ?>.</span>
|
76 |
-
<button class="btn btn-danger btn-block" id="manage-default"><i class="icon-cog"></i> <?php echo __('Manage Default Access', AAM_KEY); ?></button>
|
77 |
-
</div>
|
78 |
</div>
|
79 |
<?php } ?>
|
80 |
<?php if ($active === 0) { ?>
|
11 |
<ul class="nav nav-tabs" role="tablist">
|
12 |
<?php $active = 0; ?>
|
13 |
<?php if (current_user_can('aam_manage_roles')) { ?>
|
14 |
+
<li role="presentation" class="<?php echo (!$active++ ? 'active ' : ''); ?>text-center"><a href="#roles" aria-controls="roles" role="tab" data-toggle="tab"><i class="icon-users"></i><span class="aam-subject-title"><?php echo __('Roles', AAM_KEY); ?></span></a></li>
|
15 |
<?php } ?>
|
16 |
<?php if (current_user_can('aam_manage_users')) { ?>
|
17 |
+
<li role="presentation" class="<?php echo (!$active++ ? 'active ' : ''); ?>text-center"><a href="#users" aria-controls="users" role="tab" data-toggle="tab"><i class="icon-user"></i><span class="aam-subject-title"><?php echo __('Users', AAM_KEY); ?></span></a></li>
|
18 |
<?php } ?>
|
19 |
<?php if (current_user_can('aam_manage_visitors')) { ?>
|
20 |
+
<li role="presentation" class="<?php echo (!$active++ ? 'active ' : ''); ?>text-center"><a href="#visitor" aria-controls="visitor" role="tab" data-toggle="tab"><i class="icon-user-secret"></i><span class="aam-subject-title"><?php echo __('Visitor', AAM_KEY); ?></span></a></li>
|
21 |
<?php } ?>
|
22 |
<?php if (current_user_can('aam_manage_default')) { ?>
|
23 |
+
<li role="presentation" class="<?php echo (!$active++ ? 'active ' : ''); ?>text-center"><a href="#default" aria-controls="default" role="tab" data-toggle="tab" class="text-danger"><i class="icon-asterisk"></i><span class="aam-subject-title"><?php echo __('Default', AAM_KEY); ?></span></a></li>
|
24 |
<?php } ?>
|
25 |
<?php if ($active === 0) { ?>
|
26 |
+
<li role="presentation" class="active text-center"><a href="#none" aria-controls="none" role="tab" data-toggle="tab" class="text-muted"><i class="icon-asterisk"></i><span class="aam-subject-title"><?php echo __('None', AAM_KEY); ?></span></a></li>
|
27 |
<?php } ?>
|
28 |
</ul>
|
29 |
<div class="tab-content">
|
63 |
<?php } ?>
|
64 |
<?php if (current_user_can('aam_manage_visitors')) { ?>
|
65 |
<div role="tabpanel" class="tab-pane<?php echo (!$active++ ? ' active' : ''); ?>" id="visitor">
|
66 |
+
<?php echo apply_filters('aam_visitor_subject_tab_filter', $this->loadPartial('visitor-subject-tab', $params), $params); ?>
|
|
|
|
|
|
|
67 |
</div>
|
68 |
<?php } ?>
|
69 |
<?php if (current_user_can('aam_manage_default')) { ?>
|
70 |
<div role="tabpanel" class="tab-pane<?php echo (!$active++ ? ' active' : ''); ?>" id="default">
|
71 |
+
<?php echo apply_filters('aam_default_subject_tab_filter', $this->loadPartial('default-subject-tab', $params), $params); ?>
|
|
|
|
|
|
|
72 |
</div>
|
73 |
<?php } ?>
|
74 |
<?php if ($active === 0) { ?>
|
application/Backend/tmpl/partial/default-principal-subject-tab.php
ADDED
@@ -0,0 +1,9 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php /** @version 6.0.0 */ ?>
|
2 |
+
|
3 |
+
<?php if (defined('AAM_KEY')) { ?>
|
4 |
+
<div class="visitor-message">
|
5 |
+
<p class="aam-notification">
|
6 |
+
<?php echo AAM_Backend_View_Helper::preparePhrase('This feature is allowed only with [Plus Package] addon.', 'b'); ?>
|
7 |
+
</p>
|
8 |
+
</div>
|
9 |
+
<?php }
|
application/Backend/tmpl/partial/default-subject-tab.php
ADDED
@@ -0,0 +1,8 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php /** @version 6.0.0 */ ?>
|
2 |
+
|
3 |
+
<?php if (defined('AAM_KEY')) { ?>
|
4 |
+
<div class="visitor-message">
|
5 |
+
<span class="aam-bordered"><?php echo __('Manage default access to your website resources for all users, roles and visitor. This includes Administrator role and your user', AAM_KEY); ?>.</span>
|
6 |
+
<button class="btn btn-danger btn-block" id="manage-default"><i class="icon-cog"></i> <?php echo __('Manage Default Access', AAM_KEY); ?></button>
|
7 |
+
</div>
|
8 |
+
<?php }
|
application/Backend/{phtml/partial/jwt-login-url.phtml → tmpl/partial/jwt-login-url.php}
RENAMED
File without changes
|
application/Backend/tmpl/partial/loading-content.php
ADDED
@@ -0,0 +1,7 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php /** @version 6.0.0 */ ?>
|
2 |
+
|
3 |
+
<?php if (defined('AAM_KEY')) { ?>
|
4 |
+
<p class="alert alert-info text-larger text-center" id="aam-initial-load">
|
5 |
+
<?php echo AAM_Backend_View_Helper::preparePhrase('[Loading AAM UI]. Please wait. If content will not load within next 30 seconds, clear your browser cache and reload the page. If still nothing, it is most likely some sort of JavaScript or CSS conflict with one your active plugins or theme. Try to deactivate all plugins and switch to any default WordPress theme to find out what causes the issue.', 'strong'); ?>
|
6 |
+
</p>
|
7 |
+
<?php }
|
application/Backend/{phtml/partial/post-access-form.phtml → tmpl/partial/post-access-form.php}
RENAMED
@@ -76,8 +76,17 @@
|
|
76 |
<label><?php echo __('Access Limit Threshold', AAM_KEY); ?></label>
|
77 |
<input type="number" class="form-control" placeholder="<?php echo __('Enter digital number', AAM_KEY); ?>" id="aam-access-threshold" value="<?php echo $params->object->get('limited.threshold'); ?>" />
|
78 |
</div>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
79 |
</div>
|
80 |
<div class="modal-footer">
|
|
|
81 |
<button type="button" class="btn btn-success btn-save" id="save-limited-btn"><?php echo __('Save', AAM_KEY); ?></button>
|
82 |
<button type="button" class="btn btn-default" data-dismiss="modal"><?php echo __('Close', AAM_KEY); ?></button>
|
83 |
</div>
|
@@ -168,7 +177,7 @@
|
|
168 |
<div class="modal-body">
|
169 |
<div class="form-group">
|
170 |
<label><?php echo __('Password', AAM_KEY); ?></label>
|
171 |
-
<input type="text" class="form-control" placeholder="<?php echo __('Enter Password', AAM_KEY); ?>" id="aam-access-password" value="<?php echo
|
172 |
</div>
|
173 |
</div>
|
174 |
<div class="modal-footer">
|
76 |
<label><?php echo __('Access Limit Threshold', AAM_KEY); ?></label>
|
77 |
<input type="number" class="form-control" placeholder="<?php echo __('Enter digital number', AAM_KEY); ?>" id="aam-access-threshold" value="<?php echo $params->object->get('limited.threshold'); ?>" />
|
78 |
</div>
|
79 |
+
<?php if ($params->subject->isUser()) { ?>
|
80 |
+
<?php $counter = intval(get_user_meta($params->subject->getId(), sprintf(AAM_Service_Content::POST_COUNTER_DB_OPTION, $params->object->ID), true)); ?>
|
81 |
+
<?php $remaining = $params->object->get('limited.threshold') - $counter; ?>
|
82 |
+
|
83 |
+
<div class="form-group">
|
84 |
+
<p class="alert alert-info"><?php echo sprintf(AAM_Backend_View_Helper::preparePhrase('The user can access content [%d] times.', 'b'), $remaining >= 0 ? $remaining : 0); ?></p>
|
85 |
+
</div>
|
86 |
+
<?php } ?>
|
87 |
</div>
|
88 |
<div class="modal-footer">
|
89 |
+
<?php if (!empty($counter)) { ?><button type="button" class="btn btn-warning btn-save" id="reset-limited-btn"><?php echo __('Reset', AAM_KEY); ?></button><?php } ?>
|
90 |
<button type="button" class="btn btn-success btn-save" id="save-limited-btn"><?php echo __('Save', AAM_KEY); ?></button>
|
91 |
<button type="button" class="btn btn-default" data-dismiss="modal"><?php echo __('Close', AAM_KEY); ?></button>
|
92 |
</div>
|
177 |
<div class="modal-body">
|
178 |
<div class="form-group">
|
179 |
<label><?php echo __('Password', AAM_KEY); ?></label>
|
180 |
+
<input type="text" class="form-control" placeholder="<?php echo __('Enter Password', AAM_KEY); ?>" id="aam-access-password" value="<?php echo $params->object->get('protected.password'); ?>" />
|
181 |
</div>
|
182 |
</div>
|
183 |
<div class="modal-footer">
|
application/Backend/{phtml/partial/posts-terms-help-tips.phtml → tmpl/partial/posts-terms-help-tips.php}
RENAMED
File without changes
|
application/Backend/{phtml/partial/role-inheritance.phtml → tmpl/partial/role-inheritance.php}
RENAMED
File without changes
|
application/Backend/{phtml/partial/taxonomy-access-form.phtml → tmpl/partial/taxonomy-access-form.php}
RENAMED
File without changes
|
application/Backend/{phtml/partial/term-access-form.phtml → tmpl/partial/term-access-form.php}
RENAMED
File without changes
|
application/Backend/{phtml/partial/type-access-form.phtml → tmpl/partial/type-access-form.php}
RENAMED
File without changes
|
application/Backend/tmpl/partial/visitor-principal-subject-tab.php
ADDED
@@ -0,0 +1,17 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php /** @version 6.0.0 */ ?>
|
2 |
+
|
3 |
+
<?php if (defined('AAM_KEY')) { ?>
|
4 |
+
<div class="visitor-message">
|
5 |
+
<span class="aam-bordered"><?php echo __('Attach current access & security policy to visitors (any user that is not authenticated)', AAM_KEY); ?>.</span>
|
6 |
+
<?php
|
7 |
+
$visitor = new AAM_Core_Subject_Visitor();
|
8 |
+
$hasPolicy = $visitor->getObject(AAM_Core_Object_Policy::OBJECT_TYPE)->has($params->policyId);
|
9 |
+
$btnStatus = $hasPolicy ? 'detach' : 'attach';
|
10 |
+
?>
|
11 |
+
<?php if ($hasPolicy) { ?>
|
12 |
+
<button class="btn btn-primary btn-block" id="attach-policy-visitor" data-has="1" <?php echo ($btnStatus ? '' : ' disabled'); ?>><?php echo __('Detach Policy From Visitors', AAM_KEY); ?></button>
|
13 |
+
<?php } else { ?>
|
14 |
+
<button class="btn btn-primary btn-block" id="attach-policy-visitor" data-has="0" <?php echo ($btnStatus ? '' : ' disabled'); ?>><?php echo __('Attach Policy To Visitors', AAM_KEY); ?></button>
|
15 |
+
<?php } ?>
|
16 |
+
</div>
|
17 |
+
<?php }
|
application/Backend/tmpl/partial/visitor-subject-tab.php
ADDED
@@ -0,0 +1,8 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php /** @version 6.0.0 */ ?>
|
2 |
+
|
3 |
+
<?php if (defined('AAM_KEY')) { ?>
|
4 |
+
<div class="visitor-message">
|
5 |
+
<span class="aam-bordered"><?php echo __('Manage access to your website for visitors (any user that is not authenticated)', AAM_KEY); ?>.</span>
|
6 |
+
<button class="btn btn-primary btn-block" id="manage-visitor"><i class="icon-cog"></i> <?php echo __('Manage Visitors', AAM_KEY); ?></button>
|
7 |
+
</div>
|
8 |
+
<?php }
|
application/Backend/tmpl/policy/default-policy.php
ADDED
@@ -0,0 +1,27 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
/**
|
4 |
+
* ======================================================================
|
5 |
+
* LICENSE: This file is subject to the terms and conditions defined in *
|
6 |
+
* file 'license.txt', which is part of this source code package. *
|
7 |
+
* ======================================================================
|
8 |
+
*
|
9 |
+
* @version 6.0.0
|
10 |
+
*/
|
11 |
+
|
12 |
+
global $wp_version;
|
13 |
+
|
14 |
+
return sprintf('{
|
15 |
+
"Version": "1.0.0",
|
16 |
+
"Dependency": {
|
17 |
+
"wordpress": ">=%s",
|
18 |
+
"advanced-access-manager": ">=%s"
|
19 |
+
},
|
20 |
+
"Statement": [
|
21 |
+
{
|
22 |
+
"Effect": "deny",
|
23 |
+
"Resource": [],
|
24 |
+
"Action": []
|
25 |
+
}
|
26 |
+
]
|
27 |
+
}', $wp_version, AAM_VERSION);
|
application/Backend/{phtml/service/404redirect.phtml → tmpl/service/404redirect.php}
RENAMED
File without changes
|
application/Backend/{phtml/service/capability.phtml → tmpl/service/capability.php}
RENAMED
File without changes
|
application/Backend/{phtml/service/jwt.phtml → tmpl/service/jwt.php}
RENAMED
File without changes
|
application/Backend/{phtml/service/login-redirect.phtml → tmpl/service/login-redirect.php}
RENAMED
File without changes
|
application/Backend/{phtml/service/logout-redirect.phtml → tmpl/service/logout-redirect.php}
RENAMED
File without changes
|
application/Backend/{phtml/service/menu.phtml → tmpl/service/menu.php}
RENAMED
@@ -73,7 +73,7 @@
|
|
73 |
<div class="col-xs-12 col-md-6 aam-submenu-item">
|
74 |
<div class="aam-menu-details">
|
75 |
<?php echo $submenu['name']; ?>
|
76 |
-
<small><a href="#menu-details-modal" data-toggle="modal" data-uri="<?php echo urldecode($submenu['uri']); ?>" data-cap="<?php echo $submenu['capability']; ?>" data-name="<?php echo $submenu['name']; ?>" class="aam-menu-item"><?php echo __('more details', AAM_KEY); ?></a></small>
|
77 |
</div>
|
78 |
<input type="checkbox" class="aam-checkbox-danger" id="menu-item-<?php echo $i . $j; ?>" data-menu-id="<?php echo $submenu['id']; ?>" <?php echo ($submenu['checked'] ? ' checked="checked"' : ''); ?> />
|
79 |
<label for="menu-item-<?php echo $i . $j; ?>" data-toggle="tooltip" title="<?php echo ($object->isRestricted($submenu['id']) ? __('Uncheck to allow', AAM_KEY) : __('Check to restrict', AAM_KEY)); ?>"></label>
|
@@ -159,6 +159,10 @@
|
|
159 |
<th width="20%"><?php echo __('URI', AAM_KEY); ?></th>
|
160 |
<td id="menu-item-uri"></td>
|
161 |
</tr>
|
|
|
|
|
|
|
|
|
162 |
</tbody>
|
163 |
</table>
|
164 |
</div>
|
73 |
<div class="col-xs-12 col-md-6 aam-submenu-item">
|
74 |
<div class="aam-menu-details">
|
75 |
<?php echo $submenu['name']; ?>
|
76 |
+
<small><a href="#menu-details-modal" data-toggle="modal" data-uri="<?php echo urldecode($submenu['uri']); ?>" data-cap="<?php echo $submenu['capability']; ?>" data-name="<?php echo $submenu['name']; ?>" data-id="<?php echo $submenu['id']; ?>" class="aam-menu-item"><?php echo __('more details', AAM_KEY); ?></a></small>
|
77 |
</div>
|
78 |
<input type="checkbox" class="aam-checkbox-danger" id="menu-item-<?php echo $i . $j; ?>" data-menu-id="<?php echo $submenu['id']; ?>" <?php echo ($submenu['checked'] ? ' checked="checked"' : ''); ?> />
|
79 |
<label for="menu-item-<?php echo $i . $j; ?>" data-toggle="tooltip" title="<?php echo ($object->isRestricted($submenu['id']) ? __('Uncheck to allow', AAM_KEY) : __('Check to restrict', AAM_KEY)); ?>"></label>
|
159 |
<th width="20%"><?php echo __('URI', AAM_KEY); ?></th>
|
160 |
<td id="menu-item-uri"></td>
|
161 |
</tr>
|
162 |
+
<tr>
|
163 |
+
<th width="20%"><?php echo __('ID', AAM_KEY); ?></th>
|
164 |
+
<td id="menu-item-id"></td>
|
165 |
+
</tr>
|
166 |
</tbody>
|
167 |
</table>
|
168 |
</div>
|
application/Backend/{phtml/service/metabox.phtml → tmpl/service/metabox.php}
RENAMED
@@ -30,7 +30,7 @@
|
|
30 |
global $wp_post_types;
|
31 |
|
32 |
$first = false;
|
33 |
-
$object = AAM_Backend_Subject::getInstance()->getObject(
|
34 |
$metaboxList = $this->getMetaboxList();
|
35 |
?>
|
36 |
|
@@ -71,10 +71,10 @@
|
|
71 |
<div class="col-xs-12 col-md-6 aam-submenu-item">
|
72 |
<div class="aam-menu-details">
|
73 |
<?php echo $metabox['title']; ?>
|
74 |
-
<small><a href="#metabox-details-modal" data-toggle="modal" data-title="<?php echo $metabox['title']; ?>" data-screen="<?php echo $screen; ?>" class="aam-metabox-item"><?php echo __('more details', AAM_KEY); ?></a></small>
|
75 |
</div>
|
76 |
|
77 |
-
<input type="checkbox" class="aam-checkbox-danger" id="metabox-<?php echo $screen; ?>-<?php echo $metabox['id']; ?>" data-metabox="<?php echo $screen
|
78 |
<label for="metabox-<?php echo $screen; ?>-<?php echo $metabox['id']; ?>" data-toggle="tooltip" title="<?php echo ($object->isHidden($screen, $metabox['id']) ? __('Uncheck to show', AAM_KEY) : __('Check to hide', AAM_KEY)); ?>"></label>
|
79 |
</div>
|
80 |
<?php } ?>
|
@@ -136,6 +136,10 @@
|
|
136 |
<th width="20%"><?php echo __('Screen ID', AAM_KEY); ?></th>
|
137 |
<td id="metabox-screen-id"></td>
|
138 |
</tr>
|
|
|
|
|
|
|
|
|
139 |
</tbody>
|
140 |
</table>
|
141 |
</div>
|
30 |
global $wp_post_types;
|
31 |
|
32 |
$first = false;
|
33 |
+
$object = AAM_Backend_Subject::getInstance()->getObject(AAM_Core_Object_Metabox::OBJECT_TYPE);
|
34 |
$metaboxList = $this->getMetaboxList();
|
35 |
?>
|
36 |
|
71 |
<div class="col-xs-12 col-md-6 aam-submenu-item">
|
72 |
<div class="aam-menu-details">
|
73 |
<?php echo $metabox['title']; ?>
|
74 |
+
<small><a href="#metabox-details-modal" data-toggle="modal" data-title="<?php echo $metabox['title']; ?>" data-screen="<?php echo $screen; ?>" data-id="<?php echo strtolower($screen . '|' . $metabox['id']); ?>" class="aam-metabox-item"><?php echo __('more details', AAM_KEY); ?></a></small>
|
75 |
</div>
|
76 |
|
77 |
+
<input type="checkbox" class="aam-checkbox-danger" id="metabox-<?php echo $screen; ?>-<?php echo $metabox['id']; ?>" data-metabox="<?php echo strtolower($screen . '|' . $metabox['id']); ?>" <?php echo ($object->isHidden($screen, $metabox['id']) ? ' checked="checked"' : ''); ?> />
|
78 |
<label for="metabox-<?php echo $screen; ?>-<?php echo $metabox['id']; ?>" data-toggle="tooltip" title="<?php echo ($object->isHidden($screen, $metabox['id']) ? __('Uncheck to show', AAM_KEY) : __('Check to hide', AAM_KEY)); ?>"></label>
|
79 |
</div>
|
80 |
<?php } ?>
|
136 |
<th width="20%"><?php echo __('Screen ID', AAM_KEY); ?></th>
|
137 |
<td id="metabox-screen-id"></td>
|
138 |
</tr>
|
139 |
+
<tr>
|
140 |
+
<th width="20%"><?php echo __('Internal ID', AAM_KEY); ?></th>
|
141 |
+
<td id="metabox-id"></td>
|
142 |
+
</tr>
|
143 |
</tbody>
|
144 |
</table>
|
145 |
</div>
|
application/Backend/{phtml/service/policy.phtml → tmpl/service/policy.php}
RENAMED
@@ -43,4 +43,4 @@
|
|
43 |
</div>
|
44 |
<?php } ?>
|
45 |
</div>
|
46 |
-
<?php }
|
43 |
</div>
|
44 |
<?php } ?>
|
45 |
</div>
|
46 |
+
<?php }
|
application/Backend/{phtml/service/post.phtml → tmpl/service/post.php}
RENAMED
File without changes
|
application/Backend/{phtml/service/redirect.phtml → tmpl/service/redirect.php}
RENAMED
File without changes
|
application/Backend/{phtml/service/route.phtml → tmpl/service/route.php}
RENAMED
File without changes
|
application/Backend/{phtml/service/toolbar.phtml → tmpl/service/toolbar.php}
RENAMED
@@ -33,7 +33,7 @@
|
|
33 |
<a role="button" data-toggle="collapse" data-parent="#toolbar-list" href="#toolbar-<?php echo $branch->id; ?>" aria-controls="toolbar-<?php echo $branch->id; ?>" <?php if (!$first) { echo 'aria-expanded="true"'; } ?>>
|
34 |
<?php echo $this->normalizeTitle($branch); ?> <small class="aam-menu-capability"><?php echo str_replace(site_url(), '', $branch->href); ?></small>
|
35 |
</a>
|
36 |
-
<?php if ($object->
|
37 |
<i class="aam-panel-title-icon icon-eye-off text-danger"></i>
|
38 |
<?php } ?>
|
39 |
</h4>
|
@@ -49,15 +49,15 @@
|
|
49 |
<hr class="aam-divider" />
|
50 |
<?php if (!empty($branch->children)) { ?>
|
51 |
<div class="row aam-inner-tab">
|
52 |
-
<?php echo ($object->
|
53 |
<?php foreach ($this->getAllChildren($branch) as $child) { ?>
|
54 |
<div class="col-xs-12 col-md-6 aam-submenu-item">
|
55 |
<div class="aam-menu-details">
|
56 |
<?php echo $this->normalizeTitle($child); ?>
|
57 |
<small><a href="#toolbar-details-modal" data-toggle="modal" data-uri="<?php echo urldecode(str_replace(site_url(), '', $child->href)); ?>" data-id="<?php echo esc_js($child->id); ?>" data-name="<?php echo esc_js($this->normalizeTitle($child)); ?>" class="aam-toolbar-item"><?php echo __('more details', AAM_KEY); ?></a></small>
|
58 |
</div>
|
59 |
-
<input type="checkbox" class="aam-checkbox-danger" id="toolbar-<?php echo $child->id; ?>" data-toolbar="<?php echo $child->id; ?>" <?php echo ($object->
|
60 |
-
<label for="toolbar-<?php echo $child->id; ?>" data-toggle="tooltip" title="<?php echo ($object->
|
61 |
</div>
|
62 |
<?php } ?>
|
63 |
</div>
|
@@ -65,7 +65,7 @@
|
|
65 |
<?php } ?>
|
66 |
<div class="row<?php echo (!empty($branch->children) ? ' aam-margin-top-xs' : ''); ?>">
|
67 |
<div class="col-xs-10 col-md-6 col-xs-offset-1 col-md-offset-3">
|
68 |
-
<?php if ($object->
|
69 |
<a href="#" class="btn btn-primary btn-sm btn-block aam-restrict-toolbar" data-toolbar="toolbar-<?php echo $branch->id; ?>" data-target="#toolbar-<?php echo $branch->id; ?>">
|
70 |
<i class="icon-eye"></i> <?php echo __('Show Menu', AAM_KEY); ?>
|
71 |
</a>
|
33 |
<a role="button" data-toggle="collapse" data-parent="#toolbar-list" href="#toolbar-<?php echo $branch->id; ?>" aria-controls="toolbar-<?php echo $branch->id; ?>" <?php if (!$first) { echo 'aria-expanded="true"'; } ?>>
|
34 |
<?php echo $this->normalizeTitle($branch); ?> <small class="aam-menu-capability"><?php echo str_replace(site_url(), '', $branch->href); ?></small>
|
35 |
</a>
|
36 |
+
<?php if ($object->isHidden('toolbar-' . $branch->id)) { ?>
|
37 |
<i class="aam-panel-title-icon icon-eye-off text-danger"></i>
|
38 |
<?php } ?>
|
39 |
</h4>
|
49 |
<hr class="aam-divider" />
|
50 |
<?php if (!empty($branch->children)) { ?>
|
51 |
<div class="row aam-inner-tab">
|
52 |
+
<?php echo ($object->isHidden('toolbar-' . $branch->id) ? '<div class="aam-lock"></div>' : ''); ?>
|
53 |
<?php foreach ($this->getAllChildren($branch) as $child) { ?>
|
54 |
<div class="col-xs-12 col-md-6 aam-submenu-item">
|
55 |
<div class="aam-menu-details">
|
56 |
<?php echo $this->normalizeTitle($child); ?>
|
57 |
<small><a href="#toolbar-details-modal" data-toggle="modal" data-uri="<?php echo urldecode(str_replace(site_url(), '', $child->href)); ?>" data-id="<?php echo esc_js($child->id); ?>" data-name="<?php echo esc_js($this->normalizeTitle($child)); ?>" class="aam-toolbar-item"><?php echo __('more details', AAM_KEY); ?></a></small>
|
58 |
</div>
|
59 |
+
<input type="checkbox" class="aam-checkbox-danger" id="toolbar-<?php echo $child->id; ?>" data-toolbar="<?php echo $child->id; ?>" <?php echo ($object->isHidden($child->id) ? ' checked="checked"' : ''); ?> />
|
60 |
+
<label for="toolbar-<?php echo $child->id; ?>" data-toggle="tooltip" title="<?php echo ($object->isHidden($child->id) ? __('Uncheck to allow', AAM_KEY) : __('Check to restrict', AAM_KEY)); ?>"></label>
|
61 |
</div>
|
62 |
<?php } ?>
|
63 |
</div>
|
65 |
<?php } ?>
|
66 |
<div class="row<?php echo (!empty($branch->children) ? ' aam-margin-top-xs' : ''); ?>">
|
67 |
<div class="col-xs-10 col-md-6 col-xs-offset-1 col-md-offset-3">
|
68 |
+
<?php if ($object->isHidden('toolbar-' . $branch->id)) { ?>
|
69 |
<a href="#" class="btn btn-primary btn-sm btn-block aam-restrict-toolbar" data-toolbar="toolbar-<?php echo $branch->id; ?>" data-target="#toolbar-<?php echo $branch->id; ?>">
|
70 |
<i class="icon-eye"></i> <?php echo __('Show Menu', AAM_KEY); ?>
|
71 |
</a>
|
application/Backend/{phtml/service/uri.phtml → tmpl/service/uri.php}
RENAMED
@@ -139,7 +139,6 @@
|
|
139 |
<table id="uri-list" class="table table-striped table-bordered">
|
140 |
<thead>
|
141 |
<tr>
|
142 |
-
<th>ID</th>
|
143 |
<th width="60%"><?php echo __('URI', AAM_KEY); ?></th>
|
144 |
<th width="20%"><?php echo __('Type', AAM_KEY); ?></th>
|
145 |
<th>Type Details</th>
|
139 |
<table id="uri-list" class="table table-striped table-bordered">
|
140 |
<thead>
|
141 |
<tr>
|
|
|
142 |
<th width="60%"><?php echo __('URI', AAM_KEY); ?></th>
|
143 |
<th width="20%"><?php echo __('Type', AAM_KEY); ?></th>
|
144 |
<th>Type Details</th>
|
application/Backend/{phtml/service/welcome.phtml → tmpl/service/welcome.php}
RENAMED
File without changes
|
application/Backend/{phtml/settings/configpress.phtml → tmpl/settings/configpress.php}
RENAMED
File without changes
|
application/Backend/{phtml/settings/content.phtml → tmpl/settings/content.php}
RENAMED
File without changes
|
application/Backend/{phtml/settings/core.phtml → tmpl/settings/core.php}
RENAMED
File without changes
|
application/Backend/{phtml/settings/security.phtml → tmpl/settings/security.php}
RENAMED
File without changes
|
application/Backend/{phtml/settings/service.phtml → tmpl/settings/service.php}
RENAMED
@@ -13,6 +13,6 @@
|
|
13 |
</thead>
|
14 |
<tbody></tbody>
|
15 |
</table>
|
16 |
-
<div class="hidden" id="service-list-json"><?php echo wp_json_encode($this->getList()); ?></div>
|
17 |
</div>
|
18 |
<?php }
|
13 |
</thead>
|
14 |
<tbody></tbody>
|
15 |
</table>
|
16 |
+
<div class="hidden" id="service-list-json"><?php echo wp_json_encode($this->getList(), JSON_HEX_QUOT); ?></div>
|
17 |
</div>
|
18 |
<?php }
|
application/Backend/{phtml/user/multiple-roles.phtml → tmpl/user/multiple-roles.php}
RENAMED
File without changes
|
application/Backend/{phtml/widget/login-backend.phtml → tmpl/widget/login-backend.php}
RENAMED
File without changes
|
application/Backend/{phtml/widget/login-frontend.phtml → tmpl/widget/login-frontend.php}
RENAMED
File without changes
|
application/Core/API.php
CHANGED
@@ -89,8 +89,9 @@ final class AAM_Core_API
|
|
89 |
* @access public
|
90 |
* @version 6.0.0
|
91 |
*/
|
92 |
-
public static function updateOption(
|
93 |
-
|
|
|
94 |
if (is_multisite()) {
|
95 |
if (is_null($blog_id)) {
|
96 |
$blog = get_current_blog_id();
|
@@ -136,34 +137,6 @@ final class AAM_Core_API
|
|
136 |
return $response;
|
137 |
}
|
138 |
|
139 |
-
/**
|
140 |
-
* Check is currently logged in user is allowed to manage specified user level
|
141 |
-
*
|
142 |
-
* @param int $level
|
143 |
-
*
|
144 |
-
* @return boolean
|
145 |
-
*
|
146 |
-
* @access public
|
147 |
-
*/
|
148 |
-
public static function isUserLevelAllowed($level)
|
149 |
-
{
|
150 |
-
$allow_equal_level = true;
|
151 |
-
|
152 |
-
if (self::capExists('manage_same_user_level')) {
|
153 |
-
$allow_equal_level = current_user_can('manage_same_user_level');
|
154 |
-
}
|
155 |
-
|
156 |
-
$user_level = AAM::getUser()->getMaxLevel();
|
157 |
-
|
158 |
-
if ($allow_equal_level) {
|
159 |
-
$allowed = $user_level >= $level;
|
160 |
-
} else {
|
161 |
-
$allowed = $user_level > $level;
|
162 |
-
}
|
163 |
-
|
164 |
-
return $allowed;
|
165 |
-
}
|
166 |
-
|
167 |
/**
|
168 |
* Get role list
|
169 |
*
|
@@ -252,8 +225,16 @@ final class AAM_Core_API
|
|
252 |
*/
|
253 |
public static function capExists($cap)
|
254 |
{
|
|
|
255 |
$caps = self::getAllCapabilities();
|
256 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
257 |
return (is_string($cap) && array_key_exists($cap, $caps));
|
258 |
}
|
259 |
|
@@ -330,48 +311,6 @@ final class AAM_Core_API
|
|
330 |
return $result;
|
331 |
}
|
332 |
|
333 |
-
/**
|
334 |
-
* Encrypt secret information
|
335 |
-
*
|
336 |
-
* This method is used by Content & Access Policy services to encrypt passwords
|
337 |
-
*
|
338 |
-
* @param string $string
|
339 |
-
* @param string $action
|
340 |
-
*
|
341 |
-
* @return string
|
342 |
-
*
|
343 |
-
* @access public
|
344 |
-
* @version 6.0.0
|
345 |
-
*/
|
346 |
-
public static function crypt($string, $action = 'encrypt')
|
347 |
-
{
|
348 |
-
if (function_exists('openssl_encrypt')) {
|
349 |
-
$key = hash('sha256', SECURE_AUTH_KEY);
|
350 |
-
$iv = substr(hash('sha256', SECURE_AUTH_SALT), 0, 16);
|
351 |
-
|
352 |
-
if ($action === 'encrypt') {
|
353 |
-
$string = openssl_encrypt($string, 'AES-256-CBC', $key, 0, $iv);
|
354 |
-
$string = base64_encode($string);
|
355 |
-
} else {
|
356 |
-
$string = openssl_decrypt(
|
357 |
-
base64_decode($string),
|
358 |
-
'AES-256-CBC',
|
359 |
-
$key,
|
360 |
-
0,
|
361 |
-
$iv
|
362 |
-
);
|
363 |
-
}
|
364 |
-
} else {
|
365 |
-
_doing_it_wrong(
|
366 |
-
__CLASS__ . '::' . __METHOD__,
|
367 |
-
'OpenSSL PHP library is not installed',
|
368 |
-
'6.0.0'
|
369 |
-
);
|
370 |
-
}
|
371 |
-
|
372 |
-
return $string;
|
373 |
-
}
|
374 |
-
|
375 |
/**
|
376 |
* Get WP core password hasher
|
377 |
*
|
89 |
* @access public
|
90 |
* @version 6.0.0
|
91 |
*/
|
92 |
+
public static function updateOption(
|
93 |
+
$option, $data, $blog_id = null, $autoload = null
|
94 |
+
) {
|
95 |
if (is_multisite()) {
|
96 |
if (is_null($blog_id)) {
|
97 |
$blog = get_current_blog_id();
|
137 |
return $response;
|
138 |
}
|
139 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
140 |
/**
|
141 |
* Get role list
|
142 |
*
|
225 |
*/
|
226 |
public static function capExists($cap)
|
227 |
{
|
228 |
+
// Get list of all capabilities registered on the role levels
|
229 |
$caps = self::getAllCapabilities();
|
230 |
|
231 |
+
// Get list of all capabilities that are assigned on the user level if user
|
232 |
+
// is authenticated
|
233 |
+
if (is_user_logged_in()) {
|
234 |
+
$user = wp_get_current_user();
|
235 |
+
$caps = array_merge($user->caps, $user->allcaps, $caps);
|
236 |
+
}
|
237 |
+
|
238 |
return (is_string($cap) && array_key_exists($cap, $caps));
|
239 |
}
|
240 |
|
311 |
return $result;
|
312 |
}
|
313 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
314 |
/**
|
315 |
* Get WP core password hasher
|
316 |
*
|
application/Core/ConfigPress/Reader.php
CHANGED
@@ -95,7 +95,7 @@ class AAM_Core_ConfigPress_Reader
|
|
95 |
{
|
96 |
$config = array();
|
97 |
|
98 |
-
foreach ($data as $section => $
|
99 |
//check if section has parent section or property
|
100 |
if (preg_match('/[\s\w]{1}' . self::INHERIT_KEY . '[\s\w]{1}/', $section)) {
|
101 |
$section = $this->inherit($section, $config);
|
@@ -110,10 +110,10 @@ class AAM_Core_ConfigPress_Reader
|
|
110 |
}
|
111 |
}
|
112 |
|
113 |
-
if (is_array($
|
114 |
-
$this->buildNestedSection($
|
115 |
} else { //single property, no need to do anything
|
116 |
-
$config[$section] = $this->parseValue($
|
117 |
}
|
118 |
}
|
119 |
|
95 |
{
|
96 |
$config = array();
|
97 |
|
98 |
+
foreach ($data as $section => $block) {
|
99 |
//check if section has parent section or property
|
100 |
if (preg_match('/[\s\w]{1}' . self::INHERIT_KEY . '[\s\w]{1}/', $section)) {
|
101 |
$section = $this->inherit($section, $config);
|
110 |
}
|
111 |
}
|
112 |
|
113 |
+
if (is_array($block)) { //this is a INI section, build the nested tree
|
114 |
+
$this->buildNestedSection($block, $config[$section]);
|
115 |
} else { //single property, no need to do anything
|
116 |
+
$config[$section] = $this->parseValue($block);
|
117 |
}
|
118 |
}
|
119 |
|
application/Core/Contract/RequestTrait.php
CHANGED
@@ -32,7 +32,13 @@ trait AAM_Core_Contract_RequestTrait
|
|
32 |
*/
|
33 |
public function getFromPost($param, $filter = FILTER_DEFAULT, $options = null)
|
34 |
{
|
35 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
36 |
}
|
37 |
|
38 |
/**
|
@@ -49,7 +55,13 @@ trait AAM_Core_Contract_RequestTrait
|
|
49 |
*/
|
50 |
public function getFromQuery($param, $filter = FILTER_DEFAULT, $options = null)
|
51 |
{
|
52 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
53 |
}
|
54 |
|
55 |
/**
|
@@ -66,7 +78,7 @@ trait AAM_Core_Contract_RequestTrait
|
|
66 |
*/
|
67 |
public function getFromRequest($param, $filter = FILTER_DEFAULT, $options = null)
|
68 |
{
|
69 |
-
return filter_var(
|
70 |
}
|
71 |
|
72 |
/**
|
@@ -83,7 +95,15 @@ trait AAM_Core_Contract_RequestTrait
|
|
83 |
*/
|
84 |
public function getFromCookie($param, $filter = FILTER_DEFAULT, $options = null)
|
85 |
{
|
86 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
87 |
}
|
88 |
|
89 |
/**
|
@@ -104,10 +124,47 @@ trait AAM_Core_Contract_RequestTrait
|
|
104 |
|
105 |
// Cover the unexpected server issues (e.g. FastCGI may cause unexpected null)
|
106 |
if (empty($var)) {
|
107 |
-
$var = filter_var(
|
|
|
|
|
108 |
}
|
109 |
|
110 |
return $var;
|
111 |
}
|
112 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
113 |
}
|
32 |
*/
|
33 |
public function getFromPost($param, $filter = FILTER_DEFAULT, $options = null)
|
34 |
{
|
35 |
+
$post = filter_input(INPUT_POST, $param, $filter, $options);
|
36 |
+
|
37 |
+
if (is_null($post)) {
|
38 |
+
$post = filter_var($this->readFromArray($_POST, $param), $filter, $options);
|
39 |
+
}
|
40 |
+
|
41 |
+
return $post;
|
42 |
}
|
43 |
|
44 |
/**
|
55 |
*/
|
56 |
public function getFromQuery($param, $filter = FILTER_DEFAULT, $options = null)
|
57 |
{
|
58 |
+
$get = filter_input(INPUT_GET, $param, $filter, $options);
|
59 |
+
|
60 |
+
if (is_null($get)) {
|
61 |
+
$get = filter_var($this->readFromArray($_GET, $param), $filter, $options);
|
62 |
+
}
|
63 |
+
|
64 |
+
return $get;
|
65 |
}
|
66 |
|
67 |
/**
|
78 |
*/
|
79 |
public function getFromRequest($param, $filter = FILTER_DEFAULT, $options = null)
|
80 |
{
|
81 |
+
return filter_var($this->readFromArray($_REQUEST, $param), $filter, $options);
|
82 |
}
|
83 |
|
84 |
/**
|
95 |
*/
|
96 |
public function getFromCookie($param, $filter = FILTER_DEFAULT, $options = null)
|
97 |
{
|
98 |
+
$cookie = filter_input(INPUT_COOKIE, $param, $filter, $options);
|
99 |
+
|
100 |
+
if (is_null($cookie)) {
|
101 |
+
$cookie = filter_var($this->readFromArray(
|
102 |
+
$_COOKIE, $param), $filter, $options
|
103 |
+
);
|
104 |
+
}
|
105 |
+
|
106 |
+
return $cookie;
|
107 |
}
|
108 |
|
109 |
/**
|
124 |
|
125 |
// Cover the unexpected server issues (e.g. FastCGI may cause unexpected null)
|
126 |
if (empty($var)) {
|
127 |
+
$var = filter_var(
|
128 |
+
$this->readFromArray($_SERVER, $param), $filter, $options
|
129 |
+
);
|
130 |
}
|
131 |
|
132 |
return $var;
|
133 |
}
|
134 |
|
135 |
+
/**
|
136 |
+
* Check array for specified parameter and return the it's value or
|
137 |
+
* default one
|
138 |
+
*
|
139 |
+
* @param array $array Global array _GET, _POST etc
|
140 |
+
* @param string $param Array Parameter
|
141 |
+
* @param mixed $default Default value
|
142 |
+
*
|
143 |
+
* @return mixed
|
144 |
+
*
|
145 |
+
* @access protected
|
146 |
+
* @version 6.0.0
|
147 |
+
*/
|
148 |
+
protected function readFromArray($array, $param, $default = null)
|
149 |
+
{
|
150 |
+
$value = $default;
|
151 |
+
|
152 |
+
if (is_null($param)) {
|
153 |
+
$value = $array;
|
154 |
+
} else {
|
155 |
+
$chunks = explode('.', $param);
|
156 |
+
$value = $array;
|
157 |
+
foreach ($chunks as $chunk) {
|
158 |
+
if (isset($value[$chunk])) {
|
159 |
+
$value = $value[$chunk];
|
160 |
+
} else {
|
161 |
+
$value = $default;
|
162 |
+
break;
|
163 |
+
}
|
164 |
+
}
|
165 |
+
}
|
166 |
+
|
167 |
+
return $value;
|
168 |
+
}
|
169 |
+
|
170 |
}
|
application/Core/Gateway.php
CHANGED
@@ -36,7 +36,7 @@ final class AAM_Core_Gateway
|
|
36 |
_doing_it_wrong(
|
37 |
__CLASS__ . '::' . __METHOD__,
|
38 |
"The method {$name} is not defined in the AAM API",
|
39 |
-
|
40 |
);
|
41 |
}
|
42 |
|
@@ -92,18 +92,18 @@ final class AAM_Core_Gateway
|
|
92 |
*
|
93 |
* If no $id specified, current user will be returned
|
94 |
*
|
95 |
-
* @param int
|
96 |
-
* @param boolean $init
|
97 |
*
|
98 |
* @return AAM_Core_Subject
|
99 |
*
|
100 |
* @access public
|
101 |
* @version 6.0.0
|
102 |
*/
|
103 |
-
public function getUser($id = null
|
104 |
{
|
105 |
if (!empty($id)) {
|
106 |
-
$user = new AAM_Core_Subject_User($id
|
|
|
107 |
} else {
|
108 |
$user = AAM::getUser();
|
109 |
}
|
36 |
_doing_it_wrong(
|
37 |
__CLASS__ . '::' . __METHOD__,
|
38 |
"The method {$name} is not defined in the AAM API",
|
39 |
+
AAM_VERSION
|
40 |
);
|
41 |
}
|
42 |
|
92 |
*
|
93 |
* If no $id specified, current user will be returned
|
94 |
*
|
95 |
+
* @param int $id
|
|
|
96 |
*
|
97 |
* @return AAM_Core_Subject
|
98 |
*
|
99 |
* @access public
|
100 |
* @version 6.0.0
|
101 |
*/
|
102 |
+
public function getUser($id = null)
|
103 |
{
|
104 |
if (!empty($id)) {
|
105 |
+
$user = new AAM_Core_Subject_User($id);
|
106 |
+
$user->initialize();
|
107 |
} else {
|
108 |
$user = AAM::getUser();
|
109 |
}
|
application/Core/Jwt/Issuer.php
CHANGED
@@ -137,7 +137,7 @@ class AAM_Core_Jwt_Issuer
|
|
137 |
_doing_it_wrong(
|
138 |
__CLASS__ . '::' . __METHOD__,
|
139 |
'Invalid JWT token: ' . $ex->getMessage(),
|
140 |
-
|
141 |
);
|
142 |
}
|
143 |
|
@@ -167,7 +167,7 @@ class AAM_Core_Jwt_Issuer
|
|
167 |
_doing_it_wrong(
|
168 |
__CLASS__ . '::' . __METHOD__,
|
169 |
'Invalid JWT token: ' . $ex->getMessage(),
|
170 |
-
|
171 |
);
|
172 |
}
|
173 |
|
137 |
_doing_it_wrong(
|
138 |
__CLASS__ . '::' . __METHOD__,
|
139 |
'Invalid JWT token: ' . $ex->getMessage(),
|
140 |
+
AAM_VERSION
|
141 |
);
|
142 |
}
|
143 |
|
167 |
_doing_it_wrong(
|
168 |
__CLASS__ . '::' . __METHOD__,
|
169 |
'Invalid JWT token: ' . $ex->getMessage(),
|
170 |
+
AAM_VERSION
|
171 |
);
|
172 |
}
|
173 |
|
application/Core/Migration/2019_06_30-migrate-settings-to-6.0.0.php
CHANGED
@@ -50,6 +50,9 @@ class Migration600 implements AAM_Core_Contract_MigrationInterface
|
|
50 |
// TODO: aam-utilities => aam_config
|
51 |
|
52 |
// TODO: aam-extensions => aam_addons
|
|
|
|
|
|
|
53 |
}
|
54 |
|
55 |
/**
|
@@ -188,7 +191,7 @@ class Migration600 implements AAM_Core_Contract_MigrationInterface
|
|
188 |
} elseif ($k === 'protected') {
|
189 |
$options['protected'] = array(
|
190 |
'enabled' => self::_isTrue($value),
|
191 |
-
'password' =>
|
192 |
);
|
193 |
} elseif ($k === 'expire') {
|
194 |
$options['ceased'] = array(
|
50 |
// TODO: aam-utilities => aam_config
|
51 |
|
52 |
// TODO: aam-extensions => aam_addons
|
53 |
+
|
54 |
+
//clear schedules
|
55 |
+
wp_clear_scheduled_hook('aam-cron');
|
56 |
}
|
57 |
|
58 |
/**
|
191 |
} elseif ($k === 'protected') {
|
192 |
$options['protected'] = array(
|
193 |
'enabled' => self::_isTrue($value),
|
194 |
+
'password' => $legacy['password']
|
195 |
);
|
196 |
} elseif ($k === 'expire') {
|
197 |
$options['ceased'] = array(
|
application/Core/Object.php
CHANGED
@@ -55,6 +55,16 @@ abstract class AAM_Core_Object
|
|
55 |
*/
|
56 |
private $_option = array();
|
57 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
58 |
/**
|
59 |
* Overwritten indicator
|
60 |
*
|
@@ -129,7 +139,7 @@ abstract class AAM_Core_Object
|
|
129 |
_doing_it_wrong(
|
130 |
$function,
|
131 |
sprintf(__('AAM object function %s is not defined', AAM_KEY), $function),
|
132 |
-
|
133 |
);
|
134 |
}
|
135 |
|
@@ -219,6 +229,36 @@ abstract class AAM_Core_Object
|
|
219 |
return $this->_option;
|
220 |
}
|
221 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
222 |
/**
|
223 |
* Merge options based on merging preferences
|
224 |
*
|
@@ -267,16 +307,37 @@ abstract class AAM_Core_Object
|
|
267 |
/**
|
268 |
* Set overwritten flat
|
269 |
*
|
270 |
-
* @param
|
271 |
*
|
272 |
* @return void
|
273 |
*
|
274 |
* @access public
|
275 |
* @version 6.0.0
|
276 |
*/
|
277 |
-
public function
|
278 |
{
|
279 |
-
$this->_overwritten
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
280 |
}
|
281 |
|
282 |
/**
|
55 |
*/
|
56 |
private $_option = array();
|
57 |
|
58 |
+
/**
|
59 |
+
* Explicit options (not inherited from parent subjects)
|
60 |
+
*
|
61 |
+
* @var array
|
62 |
+
*
|
63 |
+
* @access private
|
64 |
+
* @version 6.0.0
|
65 |
+
*/
|
66 |
+
private $_explicitOption = array();
|
67 |
+
|
68 |
/**
|
69 |
* Overwritten indicator
|
70 |
*
|
139 |
_doing_it_wrong(
|
140 |
$function,
|
141 |
sprintf(__('AAM object function %s is not defined', AAM_KEY), $function),
|
142 |
+
AAM_VERSION
|
143 |
);
|
144 |
}
|
145 |
|
229 |
return $this->_option;
|
230 |
}
|
231 |
|
232 |
+
/**
|
233 |
+
* Get specific access property
|
234 |
+
*
|
235 |
+
* @param string $property
|
236 |
+
* @param mixed $default
|
237 |
+
*
|
238 |
+
* @return mixed
|
239 |
+
*
|
240 |
+
* @access public
|
241 |
+
* @version 5.0.0
|
242 |
+
*/
|
243 |
+
public function get($property, $default = null)
|
244 |
+
{
|
245 |
+
$option = $this->getOption();
|
246 |
+
|
247 |
+
$chunks = explode('.', $property);
|
248 |
+
$value = (isset($option[$chunks[0]]) ? $option[$chunks[0]] : null);
|
249 |
+
|
250 |
+
foreach (array_slice($chunks, 1) as $chunk) {
|
251 |
+
if (isset($value[$chunk])) {
|
252 |
+
$value = $value[$chunk];
|
253 |
+
} else {
|
254 |
+
$value = $default;
|
255 |
+
break;
|
256 |
+
}
|
257 |
+
}
|
258 |
+
|
259 |
+
return (is_null($value) ? $default : $value);
|
260 |
+
}
|
261 |
+
|
262 |
/**
|
263 |
* Merge options based on merging preferences
|
264 |
*
|
307 |
/**
|
308 |
* Set overwritten flat
|
309 |
*
|
310 |
+
* @param array $option
|
311 |
*
|
312 |
* @return void
|
313 |
*
|
314 |
* @access public
|
315 |
* @version 6.0.0
|
316 |
*/
|
317 |
+
public function determineOverwritten($option)
|
318 |
{
|
319 |
+
$this->_overwritten = !empty($option);
|
320 |
+
$this->_explicitOption = $option;
|
321 |
+
}
|
322 |
+
|
323 |
+
public function isExplicit($property)
|
324 |
+
{
|
325 |
+
$option = $this->_explicitOption;
|
326 |
+
$explicit = true;
|
327 |
+
|
328 |
+
$chunks = explode('.', $property);
|
329 |
+
$value = (isset($option[$chunks[0]]) ? $option[$chunks[0]] : null);
|
330 |
+
|
331 |
+
foreach (array_slice($chunks, 1) as $chunk) {
|
332 |
+
if (isset($value[$chunk])) {
|
333 |
+
$value = $value[$chunk];
|
334 |
+
} else {
|
335 |
+
$explicit = false;
|
336 |
+
break;
|
337 |
+
}
|
338 |
+
}
|
339 |
+
|
340 |
+
return $explicit;
|
341 |
}
|
342 |
|
343 |
/**
|
application/Core/Object/LoginRedirect.php
CHANGED
@@ -35,9 +35,7 @@ class AAM_Core_Object_LoginRedirect extends AAM_Core_Object
|
|
35 |
$option = $this->getSubject()->readOption(self::OBJECT_TYPE);
|
36 |
|
37 |
// If options are defined, set the overwritten flag
|
38 |
-
|
39 |
-
$this->setOverwritten(true);
|
40 |
-
}
|
41 |
|
42 |
$this->setOption(is_array($option) ? $option : array());
|
43 |
}
|
35 |
$option = $this->getSubject()->readOption(self::OBJECT_TYPE);
|
36 |
|
37 |
// If options are defined, set the overwritten flag
|
38 |
+
$this->determineOverwritten($option);
|
|
|
|
|
39 |
|
40 |
$this->setOption(is_array($option) ? $option : array());
|
41 |
}
|
application/Core/Object/LogoutRedirect.php
CHANGED
@@ -35,9 +35,7 @@ class AAM_Core_Object_LogoutRedirect extends AAM_Core_Object
|
|
35 |
$option = $this->getSubject()->readOption(self::OBJECT_TYPE);
|
36 |
|
37 |
// If options are defined, set the overwritten flag
|
38 |
-
|
39 |
-
$this->setOverwritten(true);
|
40 |
-
}
|
41 |
|
42 |
$this->setOption(is_array($option) ? $option : array());
|
43 |
}
|
35 |
$option = $this->getSubject()->readOption(self::OBJECT_TYPE);
|
36 |
|
37 |
// If options are defined, set the overwritten flag
|
38 |
+
$this->determineOverwritten($option);
|
|
|
|
|
39 |
|
40 |
$this->setOption(is_array($option) ? $option : array());
|
41 |
}
|
application/Core/Object/Menu.php
CHANGED
@@ -33,15 +33,11 @@ class AAM_Core_Object_Menu extends AAM_Core_Object
|
|
33 |
{
|
34 |
$option = $this->getSubject()->readOption(self::OBJECT_TYPE);
|
35 |
|
36 |
-
|
37 |
-
$this->setOverwritten(true);
|
38 |
-
}
|
39 |
|
40 |
// Trigger custom functionality that may populate the menu options. For
|
41 |
// example, this hooks is used by Access Policy service
|
42 |
-
$option = apply_filters(
|
43 |
-
'aam_admin_menu_object_option_filter', $option, $this->getSubject()
|
44 |
-
);
|
45 |
|
46 |
$this->setOption(is_array($option) ? $option : array());
|
47 |
}
|
33 |
{
|
34 |
$option = $this->getSubject()->readOption(self::OBJECT_TYPE);
|
35 |
|
36 |
+
$this->determineOverwritten($option);
|
|
|
|
|
37 |
|
38 |
// Trigger custom functionality that may populate the menu options. For
|
39 |
// example, this hooks is used by Access Policy service
|
40 |
+
$option = apply_filters('aam_menu_object_option_filter', $option, $this);
|
|
|
|
|
41 |
|
42 |
$this->setOption(is_array($option) ? $option : array());
|
43 |
}
|
application/Core/Object/Metabox.php
CHANGED
@@ -33,15 +33,11 @@ class AAM_Core_Object_Metabox extends AAM_Core_Object
|
|
33 |
{
|
34 |
$option = $this->getSubject()->readOption(self::OBJECT_TYPE);
|
35 |
|
36 |
-
|
37 |
-
$this->setOverwritten(true);
|
38 |
-
}
|
39 |
|
40 |
// Trigger custom functionality that may populate the menu options. For
|
41 |
// example, this hooks is used by Access Policy service
|
42 |
-
$option = apply_filters(
|
43 |
-
'aam_metabox_object_option_filter', $option, $this->getSubject()
|
44 |
-
);
|
45 |
|
46 |
$this->setOption(is_array($option) ? $option : array());
|
47 |
}
|
@@ -51,26 +47,17 @@ class AAM_Core_Object_Metabox extends AAM_Core_Object
|
|
51 |
*
|
52 |
* @param string $screen
|
53 |
* @param string $metaboxId
|
54 |
-
* @param array $metabox
|
55 |
*
|
56 |
* @return boolean
|
57 |
*
|
58 |
* @access public
|
59 |
* @version 6.0.0
|
60 |
*/
|
61 |
-
public function isHidden($screen, $metaboxId
|
62 |
{
|
63 |
$option = $this->getOption();
|
64 |
|
65 |
-
|
66 |
-
// that $metabox['title'] has to be handled too
|
67 |
-
return apply_filters(
|
68 |
-
'aam_metabox_is_hidden_filter',
|
69 |
-
!empty($option["{$screen}|{$metaboxId}"]),
|
70 |
-
$screen,
|
71 |
-
$metaboxId,
|
72 |
-
$metabox
|
73 |
-
);
|
74 |
}
|
75 |
|
76 |
}
|
33 |
{
|
34 |
$option = $this->getSubject()->readOption(self::OBJECT_TYPE);
|
35 |
|
36 |
+
$this->determineOverwritten($option);
|
|
|
|
|
37 |
|
38 |
// Trigger custom functionality that may populate the menu options. For
|
39 |
// example, this hooks is used by Access Policy service
|
40 |
+
$option = apply_filters('aam_metabox_object_option_filter', $option, $this);
|
|
|
|
|
41 |
|
42 |
$this->setOption(is_array($option) ? $option : array());
|
43 |
}
|
47 |
*
|
48 |
* @param string $screen
|
49 |
* @param string $metaboxId
|
|
|
50 |
*
|
51 |
* @return boolean
|
52 |
*
|
53 |
* @access public
|
54 |
* @version 6.0.0
|
55 |
*/
|
56 |
+
public function isHidden($screen, $metaboxId)
|
57 |
{
|
58 |
$option = $this->getOption();
|
59 |
|
60 |
+
return !empty($option[strtolower("{$screen}|{$metaboxId}")]);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
61 |
}
|
62 |
|
63 |
}
|
application/Core/Object/Policy.php
CHANGED
@@ -5,51 +5,52 @@
|
|
5 |
* LICENSE: This file is subject to the terms and conditions defined in *
|
6 |
* file 'license.txt', which is part of this source code package. *
|
7 |
* ======================================================================
|
|
|
|
|
8 |
*/
|
9 |
|
10 |
/**
|
11 |
* Policy object
|
12 |
-
*
|
13 |
* @package AAM
|
14 |
-
* @
|
15 |
*/
|
16 |
class AAM_Core_Object_Policy extends AAM_Core_Object
|
17 |
{
|
18 |
|
19 |
/**
|
20 |
* Type of object
|
|
|
|
|
21 |
*/
|
22 |
const OBJECT_TYPE = 'policy';
|
23 |
|
24 |
/**
|
25 |
* Initialize the policy rules for current subject
|
26 |
-
*
|
27 |
* @return void
|
28 |
-
*
|
29 |
* @access protected
|
|
|
30 |
*/
|
31 |
protected function initialize()
|
32 |
{
|
33 |
-
$
|
34 |
-
$option = $subject->readOption('policy');
|
35 |
|
36 |
-
|
37 |
-
$option = array();
|
38 |
-
} else {
|
39 |
-
$this->setOverwritten(true);
|
40 |
-
}
|
41 |
|
42 |
$this->setOption(is_array($option) ? $option : array());
|
43 |
}
|
44 |
|
45 |
/**
|
46 |
* Check if policy attached
|
47 |
-
*
|
48 |
* @param int $id
|
49 |
-
*
|
50 |
* @return boolean
|
51 |
-
*
|
52 |
* @access public
|
|
|
53 |
*/
|
54 |
public function has($id)
|
55 |
{
|
@@ -58,21 +59,4 @@ class AAM_Core_Object_Policy extends AAM_Core_Object
|
|
58 |
return !empty($option[$id]);
|
59 |
}
|
60 |
|
61 |
-
|
62 |
-
*
|
63 |
-
* @param type $id
|
64 |
-
*
|
65 |
-
* @return type
|
66 |
-
*/
|
67 |
-
public function delete($id)
|
68 |
-
{
|
69 |
-
$option = $this->getOption();
|
70 |
-
if (isset($option[$id])) {
|
71 |
-
unset($option[$id]);
|
72 |
-
}
|
73 |
-
$this->setOption($option);
|
74 |
-
|
75 |
-
return $this->getSubject()->updateOption($this->getOption(), 'policy');
|
76 |
-
}
|
77 |
-
|
78 |
-
}
|
5 |
* LICENSE: This file is subject to the terms and conditions defined in *
|
6 |
* file 'license.txt', which is part of this source code package. *
|
7 |
* ======================================================================
|
8 |
+
*
|
9 |
+
* @version 6.0.0
|
10 |
*/
|
11 |
|
12 |
/**
|
13 |
* Policy object
|
14 |
+
*
|
15 |
* @package AAM
|
16 |
+
* @version 6.0.0
|
17 |
*/
|
18 |
class AAM_Core_Object_Policy extends AAM_Core_Object
|
19 |
{
|
20 |
|
21 |
/**
|
22 |
* Type of object
|
23 |
+
*
|
24 |
+
* @version 6.0.0
|
25 |
*/
|
26 |
const OBJECT_TYPE = 'policy';
|
27 |
|
28 |
/**
|
29 |
* Initialize the policy rules for current subject
|
30 |
+
*
|
31 |
* @return void
|
32 |
+
*
|
33 |
* @access protected
|
34 |
+
* @version 6.0.0
|
35 |
*/
|
36 |
protected function initialize()
|
37 |
{
|
38 |
+
$option = $this->getSubject()->readOption(self::OBJECT_TYPE);
|
|
|
39 |
|
40 |
+
$this->determineOverwritten($option);
|
|
|
|
|
|
|
|
|
41 |
|
42 |
$this->setOption(is_array($option) ? $option : array());
|
43 |
}
|
44 |
|
45 |
/**
|
46 |
* Check if policy attached
|
47 |
+
*
|
48 |
* @param int $id
|
49 |
+
*
|
50 |
* @return boolean
|
51 |
+
*
|
52 |
* @access public
|
53 |
+
* @version 6.0.0
|
54 |
*/
|
55 |
public function has($id)
|
56 |
{
|
59 |
return !empty($option[$id]);
|
60 |
}
|
61 |
|
62 |
+
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
application/Core/Object/Post.php
CHANGED
@@ -56,10 +56,16 @@ class AAM_Core_Object_Post extends AAM_Core_Object
|
|
56 |
// This is done to remove redundant calls to the database on the backend view
|
57 |
if (is_a($post, 'WP_Post')) {
|
58 |
$this->setPost($post);
|
59 |
-
$this->setId($post->ID);
|
60 |
} elseif (is_numeric($post)) {
|
61 |
$this->setPost(get_post($post));
|
62 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
63 |
}
|
64 |
|
65 |
$this->initialize();
|
@@ -88,30 +94,19 @@ class AAM_Core_Object_Post extends AAM_Core_Object
|
|
88 |
*/
|
89 |
protected function initialize()
|
90 |
{
|
91 |
-
$option = array();
|
92 |
-
|
93 |
-
if ($this->suppressFilters() === false) {
|
94 |
-
// Trigger custom functionality that may populate the post access options.
|
95 |
-
// For example, this hooks is used by Access Policy service.
|
96 |
-
$option = apply_filters('aam_pre_init_post_object_filter', $option, $this);
|
97 |
-
}
|
98 |
-
|
99 |
// Read direct access settings - those that are explicitly defined for the
|
100 |
// post
|
101 |
-
$
|
102 |
self::OBJECT_TYPE, $this->ID . '|' . $this->post_type
|
103 |
);
|
104 |
|
105 |
-
|
106 |
-
$this->setOverwritten(true);
|
107 |
-
$option = array_replace($option, $direct); // merge access settings
|
108 |
-
}
|
109 |
|
110 |
if ($this->suppressFilters() === false) {
|
111 |
// Trigger custom functionality that may populate the post access options
|
112 |
// after initial setup. Typically is used by third party functionality and
|
113 |
// premium AAM plugins.
|
114 |
-
$option = apply_filters('
|
115 |
}
|
116 |
|
117 |
// Finally set the option for this object
|
@@ -199,36 +194,6 @@ class AAM_Core_Object_Post extends AAM_Core_Object
|
|
199 |
return $this->is($property);
|
200 |
}
|
201 |
|
202 |
-
/**
|
203 |
-
* Get specific access property
|
204 |
-
*
|
205 |
-
* @param string $property
|
206 |
-
* @param mixed $default
|
207 |
-
*
|
208 |
-
* @return mixed
|
209 |
-
*
|
210 |
-
* @access public
|
211 |
-
* @version 6.0.0
|
212 |
-
*/
|
213 |
-
public function get($property, $default = null)
|
214 |
-
{
|
215 |
-
$option = $this->getOption();
|
216 |
-
|
217 |
-
$chunks = explode('.', $property);
|
218 |
-
$value = (isset($option[$chunks[0]]) ? $option[$chunks[0]] : null);
|
219 |
-
|
220 |
-
foreach (array_slice($chunks, 1) as $chunk) {
|
221 |
-
if (isset($value[$chunk])) {
|
222 |
-
$value = $value[$chunk];
|
223 |
-
} else {
|
224 |
-
$value = $default;
|
225 |
-
break;
|
226 |
-
}
|
227 |
-
}
|
228 |
-
|
229 |
-
return (is_null($value) ? $default : $value);
|
230 |
-
}
|
231 |
-
|
232 |
/**
|
233 |
* Get WP Post
|
234 |
*
|
56 |
// This is done to remove redundant calls to the database on the backend view
|
57 |
if (is_a($post, 'WP_Post')) {
|
58 |
$this->setPost($post);
|
|
|
59 |
} elseif (is_numeric($post)) {
|
60 |
$this->setPost(get_post($post));
|
61 |
+
}
|
62 |
+
|
63 |
+
// Making sure that we actually have post, otherwise just initiate with dummy
|
64 |
+
if (is_a($this->getPost(), 'WP_Post')) {
|
65 |
+
$this->setId($this->getPost()->ID);
|
66 |
+
} else {
|
67 |
+
$this->setPost(new WP_Post((object) array('ID' => 0)));
|
68 |
+
$this->setId(0);
|
69 |
}
|
70 |
|
71 |
$this->initialize();
|
94 |
*/
|
95 |
protected function initialize()
|
96 |
{
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
97 |
// Read direct access settings - those that are explicitly defined for the
|
98 |
// post
|
99 |
+
$option = $this->getSubject()->readOption(
|
100 |
self::OBJECT_TYPE, $this->ID . '|' . $this->post_type
|
101 |
);
|
102 |
|
103 |
+
$this->determineOverwritten($option);
|
|
|
|
|
|
|
104 |
|
105 |
if ($this->suppressFilters() === false) {
|
106 |
// Trigger custom functionality that may populate the post access options
|
107 |
// after initial setup. Typically is used by third party functionality and
|
108 |
// premium AAM plugins.
|
109 |
+
$option = apply_filters('aam_post_object_option_filter', $option, $this);
|
110 |
}
|
111 |
|
112 |
// Finally set the option for this object
|
194 |
return $this->is($property);
|
195 |
}
|
196 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
197 |
/**
|
198 |
* Get WP Post
|
199 |
*
|
application/Core/Object/Redirect.php
CHANGED
@@ -33,10 +33,7 @@ class AAM_Core_Object_Redirect extends AAM_Core_Object
|
|
33 |
{
|
34 |
$option = $this->getSubject()->readOption(self::OBJECT_TYPE);
|
35 |
|
36 |
-
|
37 |
-
if (!empty($option)) {
|
38 |
-
$this->setOverwritten(true);
|
39 |
-
}
|
40 |
|
41 |
$this->setOption(is_array($option) ? $option : array());
|
42 |
}
|
33 |
{
|
34 |
$option = $this->getSubject()->readOption(self::OBJECT_TYPE);
|
35 |
|
36 |
+
$this->determineOverwritten($option);
|
|
|
|
|
|
|
37 |
|
38 |
$this->setOption(is_array($option) ? $option : array());
|
39 |
}
|
application/Core/Object/Route.php
CHANGED
@@ -33,9 +33,7 @@ class AAM_Core_Object_Route extends AAM_Core_Object
|
|
33 |
{
|
34 |
$option = $this->getSubject()->readOption('route');
|
35 |
|
36 |
-
|
37 |
-
$this->setOverwritten(true);
|
38 |
-
}
|
39 |
|
40 |
// Trigger custom functionality that may populate the menu options. For
|
41 |
// example, this hooks is used by Access Policy service
|
33 |
{
|
34 |
$option = $this->getSubject()->readOption('route');
|
35 |
|
36 |
+
$this->determineOverwritten($option);
|
|
|
|
|
37 |
|
38 |
// Trigger custom functionality that may populate the menu options. For
|
39 |
// example, this hooks is used by Access Policy service
|
application/Core/Object/Toolbar.php
CHANGED
@@ -33,15 +33,13 @@ class AAM_Core_Object_Toolbar extends AAM_Core_Object
|
|
33 |
{
|
34 |
$option = $this->getSubject()->readOption('toolbar');
|
35 |
|
36 |
-
|
37 |
-
$this->setOverwritten(true);
|
38 |
-
}
|
39 |
|
40 |
// Trigger custom functionality that may populate the menu options. For
|
41 |
// example, this hooks is used by Access Policy service
|
42 |
if (empty($option)) {
|
43 |
$option = apply_filters(
|
44 |
-
'aam_toolbar_object_option_filter', $option, $this
|
45 |
);
|
46 |
}
|
47 |
|
@@ -60,7 +58,7 @@ class AAM_Core_Object_Toolbar extends AAM_Core_Object
|
|
60 |
* @access public
|
61 |
* @version 6.0.0
|
62 |
*/
|
63 |
-
public function
|
64 |
{
|
65 |
$options = $this->getOption();
|
66 |
|
33 |
{
|
34 |
$option = $this->getSubject()->readOption('toolbar');
|
35 |
|
36 |
+
$this->determineOverwritten($option);
|
|
|
|
|
37 |
|
38 |
// Trigger custom functionality that may populate the menu options. For
|
39 |
// example, this hooks is used by Access Policy service
|
40 |
if (empty($option)) {
|
41 |
$option = apply_filters(
|
42 |
+
'aam_toolbar_object_option_filter', $option, $this
|
43 |
);
|
44 |
}
|
45 |
|
58 |
* @access public
|
59 |
* @version 6.0.0
|
60 |
*/
|
61 |
+
public function isHidden($item, $both = false)
|
62 |
{
|
63 |
$options = $this->getOption();
|
64 |
|
application/Core/Object/Uri.php
CHANGED
@@ -33,16 +33,12 @@ class AAM_Core_Object_Uri extends AAM_Core_Object
|
|
33 |
{
|
34 |
$option = $this->getSubject()->readOption(self::OBJECT_TYPE);
|
35 |
|
36 |
-
|
37 |
-
$this->setOverwritten(true);
|
38 |
-
}
|
39 |
|
40 |
// Trigger custom functionality that may populate the menu options. For
|
41 |
// example, this hooks is used by Access Policy service
|
42 |
if (empty($option)) {
|
43 |
-
$option = apply_filters(
|
44 |
-
'aam_uri_object_option_filter', $option, $this->getSubject()
|
45 |
-
);
|
46 |
}
|
47 |
|
48 |
$this->setOption(is_array($option) ? $option : array());
|
@@ -63,18 +59,18 @@ class AAM_Core_Object_Uri extends AAM_Core_Object
|
|
63 |
{
|
64 |
$match = null;
|
65 |
|
66 |
-
foreach ($this->getOption() as $rule) {
|
67 |
-
$
|
68 |
-
$out
|
69 |
|
70 |
-
if (!empty($
|
71 |
-
parse_str($
|
72 |
}
|
73 |
|
74 |
// Normalize the search and target URIs
|
75 |
-
$s
|
76 |
-
$
|
77 |
-
$regex
|
78 |
|
79 |
// Perform the initial match for the base URI
|
80 |
$uri_matched = apply_filters(
|
@@ -95,19 +91,19 @@ class AAM_Core_Object_Uri extends AAM_Core_Object
|
|
95 |
/**
|
96 |
* Delete specified URI rule
|
97 |
*
|
98 |
-
* @param string $
|
99 |
*
|
100 |
* @return boolean
|
101 |
*
|
102 |
* @access public
|
103 |
* @version 6.0.0
|
104 |
*/
|
105 |
-
public function delete($
|
106 |
{
|
107 |
$option = $this->getOption();
|
108 |
|
109 |
-
if (isset($option[$
|
110 |
-
unset($option[$
|
111 |
|
112 |
$this->setOption($option);
|
113 |
|
@@ -134,18 +130,18 @@ class AAM_Core_Object_Uri extends AAM_Core_Object
|
|
134 |
$merged = array();
|
135 |
$pref = AAM::api()->getConfig('core.settings.uri.merge.preference', 'deny');
|
136 |
|
137 |
-
foreach (array_merge($options, $this->getOption()) as $
|
138 |
// If merging preference is "deny" and at least one of the access
|
139 |
// settings is checked, then final merged array will have it set
|
140 |
// to checked
|
141 |
-
if (!isset($merged[$
|
142 |
-
$merged[$
|
143 |
} else {
|
144 |
if (($pref === 'deny') && ($options['type'] !== 'allow')) {
|
145 |
-
$merged[$
|
146 |
break;
|
147 |
} elseif ($pref === 'allow' && ($options['type'] === 'allow')) {
|
148 |
-
$merged[$
|
149 |
break;
|
150 |
}
|
151 |
}
|
33 |
{
|
34 |
$option = $this->getSubject()->readOption(self::OBJECT_TYPE);
|
35 |
|
36 |
+
$this->determineOverwritten($option);
|
|
|
|
|
37 |
|
38 |
// Trigger custom functionality that may populate the menu options. For
|
39 |
// example, this hooks is used by Access Policy service
|
40 |
if (empty($option)) {
|
41 |
+
$option = apply_filters('aam_uri_object_option_filter', $option, $this);
|
|
|
|
|
42 |
}
|
43 |
|
44 |
$this->setOption(is_array($option) ? $option : array());
|
59 |
{
|
60 |
$match = null;
|
61 |
|
62 |
+
foreach ($this->getOption() as $uri => $rule) {
|
63 |
+
$meta = wp_parse_url($uri);
|
64 |
+
$out = array();
|
65 |
|
66 |
+
if (!empty($meta['query'])) {
|
67 |
+
parse_str($meta['query'], $out);
|
68 |
}
|
69 |
|
70 |
// Normalize the search and target URIs
|
71 |
+
$s = rtrim($s, '/');
|
72 |
+
$meta['path'] = rtrim(isset($meta['path']) ? $meta['path'] : '', '/');
|
73 |
+
$regex = '@^' . preg_quote($meta['path']) . '$@';
|
74 |
|
75 |
// Perform the initial match for the base URI
|
76 |
$uri_matched = apply_filters(
|
91 |
/**
|
92 |
* Delete specified URI rule
|
93 |
*
|
94 |
+
* @param string $uri
|
95 |
*
|
96 |
* @return boolean
|
97 |
*
|
98 |
* @access public
|
99 |
* @version 6.0.0
|
100 |
*/
|
101 |
+
public function delete($uri)
|
102 |
{
|
103 |
$option = $this->getOption();
|
104 |
|
105 |
+
if (isset($option[$uri])) {
|
106 |
+
unset($option[$uri]);
|
107 |
|
108 |
$this->setOption($option);
|
109 |
|
130 |
$merged = array();
|
131 |
$pref = AAM::api()->getConfig('core.settings.uri.merge.preference', 'deny');
|
132 |
|
133 |
+
foreach (array_merge($options, $this->getOption()) as $uri => $options) {
|
134 |
// If merging preference is "deny" and at least one of the access
|
135 |
// settings is checked, then final merged array will have it set
|
136 |
// to checked
|
137 |
+
if (!isset($merged[$uri])) {
|
138 |
+
$merged[$uri] = $options;
|
139 |
} else {
|
140 |
if (($pref === 'deny') && ($options['type'] !== 'allow')) {
|
141 |
+
$merged[$uri] = $options;
|
142 |
break;
|
143 |
} elseif ($pref === 'allow' && ($options['type'] === 'allow')) {
|
144 |
+
$merged[$uri] = $options;
|
145 |
break;
|
146 |
}
|
147 |
}
|
application/Core/Object/Visibility.php
CHANGED
@@ -25,6 +25,45 @@ class AAM_Core_Object_Visibility extends AAM_Core_Object
|
|
25 |
*/
|
26 |
const OBJECT_TYPE = 'visibility';
|
27 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
28 |
/**
|
29 |
* @inheritDoc
|
30 |
* @version 6.0.0
|
@@ -37,9 +76,11 @@ class AAM_Core_Object_Visibility extends AAM_Core_Object
|
|
37 |
$this->pushOptions('post', $id, $settings);
|
38 |
}
|
39 |
|
40 |
-
|
41 |
-
|
42 |
-
|
|
|
|
|
43 |
}
|
44 |
|
45 |
/**
|
@@ -58,17 +99,17 @@ class AAM_Core_Object_Visibility extends AAM_Core_Object
|
|
58 |
{
|
59 |
$option = $this->getOption();
|
60 |
$filtered = array();
|
61 |
-
$listOptions = apply_filters('aam_visibility_options_filter', array('hidden'));
|
62 |
|
63 |
foreach ($options as $key => $value) {
|
64 |
-
if (in_array($key, $
|
65 |
$filtered[$key] = $value;
|
66 |
}
|
67 |
}
|
68 |
|
69 |
if (empty($filtered)) {
|
70 |
$filtered = array_combine(
|
71 |
-
$
|
|
|
72 |
);
|
73 |
}
|
74 |
|
25 |
*/
|
26 |
const OBJECT_TYPE = 'visibility';
|
27 |
|
28 |
+
/**
|
29 |
+
* List of properties that are responsible for visibility
|
30 |
+
*
|
31 |
+
* @var array
|
32 |
+
*
|
33 |
+
* @access protected
|
34 |
+
* @version 6.0.0
|
35 |
+
*/
|
36 |
+
protected $accessProperties = array();
|
37 |
+
|
38 |
+
/**
|
39 |
+
* Constructor
|
40 |
+
*
|
41 |
+
* @param AAM_Core_Subject $subject
|
42 |
+
* @param mixed $id
|
43 |
+
* @param boolean $setSuppressFilters
|
44 |
+
*
|
45 |
+
* @return void
|
46 |
+
*
|
47 |
+
* @access public
|
48 |
+
* @version 6.0.0
|
49 |
+
*/
|
50 |
+
public function __construct(
|
51 |
+
AAM_Core_Subject $subject, $id = null, $suppressFilters = false
|
52 |
+
) {
|
53 |
+
$this->setSubject($subject);
|
54 |
+
$this->setId($id);
|
55 |
+
$this->setSuppressFilters($suppressFilters);
|
56 |
+
|
57 |
+
// Determine post access properties that are responsible for the post
|
58 |
+
// visibility
|
59 |
+
$this->accessProperties = apply_filters(
|
60 |
+
'aam_visibility_options_filter', array('hidden')
|
61 |
+
);
|
62 |
+
|
63 |
+
// Initialize the object
|
64 |
+
$this->initialize();
|
65 |
+
}
|
66 |
+
|
67 |
/**
|
68 |
* @inheritDoc
|
69 |
* @version 6.0.0
|
76 |
$this->pushOptions('post', $id, $settings);
|
77 |
}
|
78 |
|
79 |
+
if ($this->suppressFilters() === false) {
|
80 |
+
// Initialize post visibility option. This hooks is used by Access Policy
|
81 |
+
// service as well as Plus Package to populate visibility list
|
82 |
+
do_action('aam_visibility_object_init_action', $this);
|
83 |
+
}
|
84 |
}
|
85 |
|
86 |
/**
|
99 |
{
|
100 |
$option = $this->getOption();
|
101 |
$filtered = array();
|
|
|
102 |
|
103 |
foreach ($options as $key => $value) {
|
104 |
+
if (in_array($key, $this->accessProperties, true)) {
|
105 |
$filtered[$key] = $value;
|
106 |
}
|
107 |
}
|
108 |
|
109 |
if (empty($filtered)) {
|
110 |
$filtered = array_combine(
|
111 |
+
$this->accessProperties,
|
112 |
+
array_fill(0, count($this->accessProperties), false)
|
113 |
);
|
114 |
}
|
115 |
|
application/Core/Policy/Condition.php
CHANGED
@@ -5,26 +5,20 @@
|
|
5 |
* LICENSE: This file is subject to the terms and conditions defined in *
|
6 |
* file 'license.txt', which is part of this source code package. *
|
7 |
* ======================================================================
|
|
|
|
|
8 |
*/
|
9 |
|
10 |
/**
|
11 |
* AAM core policy condition evaluator
|
12 |
*
|
13 |
* @package AAM
|
14 |
-
* @
|
15 |
-
* @since AAM v5.8.2
|
16 |
*/
|
17 |
-
|
|
|
18 |
|
19 |
-
|
20 |
-
* Single instance of itself
|
21 |
-
*
|
22 |
-
* @var AAM_Core_Policy_Condition
|
23 |
-
*
|
24 |
-
* @access protected
|
25 |
-
* @static
|
26 |
-
*/
|
27 |
-
protected static $instance = null;
|
28 |
|
29 |
/**
|
30 |
* Map between condition type and method that evaluates the
|
@@ -33,6 +27,7 @@ final class AAM_Core_Policy_Condition {
|
|
33 |
* @var array
|
34 |
*
|
35 |
* @access protected
|
|
|
36 |
*/
|
37 |
protected $map = array(
|
38 |
'between' => 'evaluateBetweenConditions',
|
@@ -49,15 +44,6 @@ final class AAM_Core_Policy_Condition {
|
|
49 |
'regex' => 'evaluateRegexConditions'
|
50 |
);
|
51 |
|
52 |
-
/**
|
53 |
-
* Constructor
|
54 |
-
*
|
55 |
-
* @return void
|
56 |
-
*
|
57 |
-
* @access protected
|
58 |
-
*/
|
59 |
-
protected function __construct() {}
|
60 |
-
|
61 |
/**
|
62 |
* Evaluate the group of conditions based on type
|
63 |
*
|
@@ -67,11 +53,13 @@ final class AAM_Core_Policy_Condition {
|
|
67 |
* @return boolean
|
68 |
*
|
69 |
* @access public
|
|
|
70 |
*/
|
71 |
-
public function evaluate($conditions, $args = array())
|
72 |
-
|
|
|
73 |
|
74 |
-
foreach($conditions as $type => $
|
75 |
$type = strtolower($type);
|
76 |
|
77 |
if (isset($this->map[$type])) {
|
@@ -79,19 +67,19 @@ final class AAM_Core_Policy_Condition {
|
|
79 |
|
80 |
// Since v5.9.2 - if specific condition type is array, then combine
|
81 |
// them with AND operation
|
82 |
-
if (isset($
|
83 |
-
foreach($
|
84 |
-
$
|
85 |
}
|
86 |
} else {
|
87 |
-
$
|
88 |
}
|
89 |
} else {
|
90 |
-
$
|
91 |
}
|
92 |
}
|
93 |
|
94 |
-
return $
|
95 |
}
|
96 |
|
97 |
/**
|
@@ -103,23 +91,25 @@ final class AAM_Core_Policy_Condition {
|
|
103 |
* @return boolean
|
104 |
*
|
105 |
* @access protected
|
|
|
106 |
*/
|
107 |
-
protected function evaluateBetweenConditions($conditions, $args)
|
|
|
108 |
$result = false;
|
109 |
|
110 |
-
foreach($this->prepareConditions($conditions, $args) as $
|
111 |
// Convert the right condition into the array of array to cover more
|
112 |
// complex between conditions like [[0,8],[13,15]]
|
113 |
-
if (is_array($
|
114 |
-
$right = $
|
115 |
} else {
|
116 |
-
$right = array($
|
117 |
}
|
118 |
-
foreach($right as $subset) {
|
119 |
$min = (is_array($subset) ? array_shift($subset) : $subset);
|
120 |
$max = (is_array($subset) ? end($subset) : $subset);
|
121 |
|
122 |
-
$result = $result || ($
|
123 |
}
|
124 |
}
|
125 |
|
@@ -137,11 +127,13 @@ final class AAM_Core_Policy_Condition {
|
|
137 |
* @return boolean
|
138 |
*
|
139 |
* @access protected
|
|
|
140 |
*/
|
141 |
-
protected function evaluateEqualsConditions($conditions, $args)
|
|
|
142 |
$result = false;
|
143 |
|
144 |
-
foreach($this->prepareConditions($conditions, $args) as $condition) {
|
145 |
$result = $result || ($condition['left'] === $condition['right']);
|
146 |
}
|
147 |
|
@@ -157,8 +149,10 @@ final class AAM_Core_Policy_Condition {
|
|
157 |
* @return boolean
|
158 |
*
|
159 |
* @access protected
|
|
|
160 |
*/
|
161 |
-
protected function evaluateNotEqualsConditions($conditions, $args)
|
|
|
162 |
return !$this->evaluateEqualsConditions($conditions, $args);
|
163 |
}
|
164 |
|
@@ -171,11 +165,13 @@ final class AAM_Core_Policy_Condition {
|
|
171 |
* @return boolean
|
172 |
*
|
173 |
* @access protected
|
|
|
174 |
*/
|
175 |
-
protected function evaluateGreaterConditions($conditions, $args)
|
|
|
176 |
$result = false;
|
177 |
|
178 |
-
foreach($this->prepareConditions($conditions, $args) as $condition) {
|
179 |
$result = $result || ($condition['left'] > $condition['right']);
|
180 |
}
|
181 |
|
@@ -191,11 +187,13 @@ final class AAM_Core_Policy_Condition {
|
|
191 |
* @return boolean
|
192 |
*
|
193 |
* @access protected
|
|
|
194 |
*/
|
195 |
-
protected function evaluateLessConditions($conditions, $args)
|
|
|
196 |
$result = false;
|
197 |
|
198 |
-
foreach($this->prepareConditions($conditions, $args) as $condition) {
|
199 |
$result = $result || ($condition['left'] < $condition['right']);
|
200 |
}
|
201 |
|
@@ -211,11 +209,13 @@ final class AAM_Core_Policy_Condition {
|
|
211 |
* @return boolean
|
212 |
*
|
213 |
* @access protected
|
|
|
214 |
*/
|
215 |
-
protected function evaluateGreaterOrEqualsConditions($conditions, $args)
|
|
|
216 |
$result = false;
|
217 |
|
218 |
-
foreach($this->prepareConditions($conditions, $args) as $condition) {
|
219 |
$result = $result || ($condition['left'] >= $condition['right']);
|
220 |
}
|
221 |
|
@@ -231,11 +231,13 @@ final class AAM_Core_Policy_Condition {
|
|
231 |
* @return boolean
|
232 |
*
|
233 |
* @access protected
|
|
|
234 |
*/
|
235 |
-
protected function evaluateLessOrEqualsConditions($conditions, $args)
|
|
|
236 |
$result = false;
|
237 |
|
238 |
-
foreach($this->prepareConditions($conditions, $args) as $condition) {
|
239 |
$result = $result || ($condition['left'] <= $condition['right']);
|
240 |
}
|
241 |
|
@@ -251,12 +253,14 @@ final class AAM_Core_Policy_Condition {
|
|
251 |
* @return boolean
|
252 |
*
|
253 |
* @access protected
|
|
|
254 |
*/
|
255 |
-
protected function evaluateInConditions($conditions, $args)
|
|
|
256 |
$result = false;
|
257 |
|
258 |
-
foreach($this->prepareConditions($conditions, $args) as $
|
259 |
-
$result = $result || in_array($
|
260 |
}
|
261 |
|
262 |
return $result;
|
@@ -271,8 +275,10 @@ final class AAM_Core_Policy_Condition {
|
|
271 |
* @return boolean
|
272 |
*
|
273 |
* @access protected
|
|
|
274 |
*/
|
275 |
-
protected function evaluateNotInConditions($conditions, $args)
|
|
|
276 |
return !$this->evaluateInConditions($conditions, $args);
|
277 |
}
|
278 |
|
@@ -285,14 +291,16 @@ final class AAM_Core_Policy_Condition {
|
|
285 |
* @return boolean
|
286 |
*
|
287 |
* @access protected
|
|
|
288 |
*/
|
289 |
-
protected function evaluateLikeConditions($conditions, $args)
|
|
|
290 |
$result = false;
|
291 |
|
292 |
-
foreach($this->prepareConditions($conditions, $args) as $
|
293 |
-
foreach((array)$
|
294 |
$sub = str_replace('\*', '.*', preg_quote($el));
|
295 |
-
$result = $result || preg_match('@^' . $sub . '$@', $
|
296 |
}
|
297 |
}
|
298 |
|
@@ -308,8 +316,10 @@ final class AAM_Core_Policy_Condition {
|
|
308 |
* @return boolean
|
309 |
*
|
310 |
* @access protected
|
|
|
311 |
*/
|
312 |
-
protected function evaluateNotLikeConditions($conditions, $args)
|
|
|
313 |
return !$this->evaluateLikeConditions($conditions, $args);
|
314 |
}
|
315 |
|
@@ -322,11 +332,13 @@ final class AAM_Core_Policy_Condition {
|
|
322 |
* @return boolean
|
323 |
*
|
324 |
* @access protected
|
|
|
325 |
*/
|
326 |
-
protected function evaluateRegexConditions($conditions, $args)
|
|
|
327 |
$result = false;
|
328 |
|
329 |
-
foreach($this->prepareConditions($conditions, $args) as $condition) {
|
330 |
$result = $result || preg_match($condition['right'], $condition['left']);
|
331 |
}
|
332 |
|
@@ -342,12 +354,14 @@ final class AAM_Core_Policy_Condition {
|
|
342 |
* @return array
|
343 |
*
|
344 |
* @access protected
|
|
|
345 |
*/
|
346 |
-
protected function prepareConditions($conditions, $args)
|
|
|
347 |
$result = array();
|
348 |
|
349 |
if (is_array($conditions)) {
|
350 |
-
foreach($conditions as $left => $right) {
|
351 |
$result[] = array(
|
352 |
'left' => $this->parseExpression($left, $args),
|
353 |
'right' => $this->parseExpression($right, $args)
|
@@ -367,19 +381,23 @@ final class AAM_Core_Policy_Condition {
|
|
367 |
* @return mixed Prepared part of the condition or false on failure
|
368 |
*
|
369 |
* @access protected
|
|
|
370 |
*/
|
371 |
-
protected function parseExpression($exp, $args)
|
|
|
372 |
if (is_scalar($exp)) {
|
373 |
if (preg_match_all('/(\$\{[^}]+\})/', $exp, $match)) {
|
374 |
$exp = AAM_Core_Policy_Token::evaluate($exp, $match[1], $args);
|
375 |
}
|
376 |
|
|
|
|
|
377 |
// If there is type scaling, perform it too
|
378 |
-
if (preg_match('/^\(\*(
|
379 |
-
$exp = $this->
|
380 |
}
|
381 |
} elseif (is_array($exp) || is_object($exp)) {
|
382 |
-
foreach($exp as &$value) {
|
383 |
$value = $this->parseExpression($value, $args);
|
384 |
}
|
385 |
} elseif (is_null($exp) === false) {
|
@@ -390,7 +408,7 @@ final class AAM_Core_Policy_Condition {
|
|
390 |
}
|
391 |
|
392 |
/**
|
393 |
-
*
|
394 |
*
|
395 |
* @param mixed $value
|
396 |
* @param string $type
|
@@ -398,11 +416,13 @@ final class AAM_Core_Policy_Condition {
|
|
398 |
* @return mixed
|
399 |
*
|
400 |
* @access protected
|
|
|
401 |
*/
|
402 |
-
protected function
|
403 |
-
|
|
|
404 |
case 'string':
|
405 |
-
$value = (string)$value;
|
406 |
break;
|
407 |
|
408 |
case 'ip':
|
@@ -410,12 +430,12 @@ final class AAM_Core_Policy_Condition {
|
|
410 |
break;
|
411 |
|
412 |
case 'int':
|
413 |
-
$value = (int)$value;
|
414 |
break;
|
415 |
|
416 |
case 'boolean':
|
417 |
case 'bool':
|
418 |
-
$value = (
|
419 |
break;
|
420 |
|
421 |
case 'array':
|
@@ -433,20 +453,4 @@ final class AAM_Core_Policy_Condition {
|
|
433 |
return $value;
|
434 |
}
|
435 |
|
436 |
-
/**
|
437 |
-
* Get single instance of itself
|
438 |
-
*
|
439 |
-
* @return AAM_Core_Policy_Condition
|
440 |
-
*
|
441 |
-
* @access public
|
442 |
-
* @static
|
443 |
-
*/
|
444 |
-
public static function getInstance() {
|
445 |
-
if (is_null(self::$instance)) {
|
446 |
-
self::$instance = new self;
|
447 |
-
}
|
448 |
-
|
449 |
-
return self::$instance;
|
450 |
-
}
|
451 |
-
|
452 |
}
|
5 |
* LICENSE: This file is subject to the terms and conditions defined in *
|
6 |
* file 'license.txt', which is part of this source code package. *
|
7 |
* ======================================================================
|
8 |
+
*
|
9 |
+
* @version 6.0.0
|
10 |
*/
|
11 |
|
12 |
/**
|
13 |
* AAM core policy condition evaluator
|
14 |
*
|
15 |
* @package AAM
|
16 |
+
* @version 6.0.0
|
|
|
17 |
*/
|
18 |
+
class AAM_Core_Policy_Condition
|
19 |
+
{
|
20 |
|
21 |
+
use AAM_Core_Contract_SingletonTrait;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
22 |
|
23 |
/**
|
24 |
* Map between condition type and method that evaluates the
|
27 |
* @var array
|
28 |
*
|
29 |
* @access protected
|
30 |
+
* @version 6.0.0
|
31 |
*/
|
32 |
protected $map = array(
|
33 |
'between' => 'evaluateBetweenConditions',
|
44 |
'regex' => 'evaluateRegexConditions'
|
45 |
);
|
46 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
47 |
/**
|
48 |
* Evaluate the group of conditions based on type
|
49 |
*
|
53 |
* @return boolean
|
54 |
*
|
55 |
* @access public
|
56 |
+
* @version 6.0.0
|
57 |
*/
|
58 |
+
public function evaluate($conditions, $args = array())
|
59 |
+
{
|
60 |
+
$res = true;
|
61 |
|
62 |
+
foreach ($conditions as $type => $condition) {
|
63 |
$type = strtolower($type);
|
64 |
|
65 |
if (isset($this->map[$type])) {
|
67 |
|
68 |
// Since v5.9.2 - if specific condition type is array, then combine
|
69 |
// them with AND operation
|
70 |
+
if (isset($condition[0]) && is_array($condition[0])) {
|
71 |
+
foreach ($condition as $set) {
|
72 |
+
$res = $res && call_user_func($callback, $set, $args);
|
73 |
}
|
74 |
} else {
|
75 |
+
$res = $res && call_user_func($callback, $condition, $args);
|
76 |
}
|
77 |
} else {
|
78 |
+
$res = false;
|
79 |
}
|
80 |
}
|
81 |
|
82 |
+
return $res;
|
83 |
}
|
84 |
|
85 |
/**
|
91 |
* @return boolean
|
92 |
*
|
93 |
* @access protected
|
94 |
+
* @version 6.0.0
|
95 |
*/
|
96 |
+
protected function evaluateBetweenConditions($conditions, $args)
|
97 |
+
{
|
98 |
$result = false;
|
99 |
|
100 |
+
foreach ($this->prepareConditions($conditions, $args) as $cnd) {
|
101 |
// Convert the right condition into the array of array to cover more
|
102 |
// complex between conditions like [[0,8],[13,15]]
|
103 |
+
if (is_array($cnd['right'][0])) {
|
104 |
+
$right = $cnd['right'];
|
105 |
} else {
|
106 |
+
$right = array($cnd['right']);
|
107 |
}
|
108 |
+
foreach ($right as $subset) {
|
109 |
$min = (is_array($subset) ? array_shift($subset) : $subset);
|
110 |
$max = (is_array($subset) ? end($subset) : $subset);
|
111 |
|
112 |
+
$result = $result || ($cnd['left'] >= $min && $cnd['left'] <= $max);
|
113 |
}
|
114 |
}
|
115 |
|
127 |
* @return boolean
|
128 |
*
|
129 |
* @access protected
|
130 |
+
* @version 6.0.0
|
131 |
*/
|
132 |
+
protected function evaluateEqualsConditions($conditions, $args)
|
133 |
+
{
|
134 |
$result = false;
|
135 |
|
136 |
+
foreach ($this->prepareConditions($conditions, $args) as $condition) {
|
137 |
$result = $result || ($condition['left'] === $condition['right']);
|
138 |
}
|
139 |
|
149 |
* @return boolean
|
150 |
*
|
151 |
* @access protected
|
152 |
+
* @version 6.0.0
|
153 |
*/
|
154 |
+
protected function evaluateNotEqualsConditions($conditions, $args)
|
155 |
+
{
|
156 |
return !$this->evaluateEqualsConditions($conditions, $args);
|
157 |
}
|
158 |
|
165 |
* @return boolean
|
166 |
*
|
167 |
* @access protected
|
168 |
+
* @version 6.0.0
|
169 |
*/
|
170 |
+
protected function evaluateGreaterConditions($conditions, $args)
|
171 |
+
{
|
172 |
$result = false;
|
173 |
|
174 |
+
foreach ($this->prepareConditions($conditions, $args) as $condition) {
|
175 |
$result = $result || ($condition['left'] > $condition['right']);
|
176 |
}
|
177 |
|
187 |
* @return boolean
|
188 |
*
|
189 |
* @access protected
|
190 |
+
* @version 6.0.0
|
191 |
*/
|
192 |
+
protected function evaluateLessConditions($conditions, $args)
|
193 |
+
{
|
194 |
$result = false;
|
195 |
|
196 |
+
foreach ($this->prepareConditions($conditions, $args) as $condition) {
|
197 |
$result = $result || ($condition['left'] < $condition['right']);
|
198 |
}
|
199 |
|
209 |
* @return boolean
|
210 |
*
|
211 |
* @access protected
|
212 |
+
* @version 6.0.0
|
213 |
*/
|
214 |
+
protected function evaluateGreaterOrEqualsConditions($conditions, $args)
|
215 |
+
{
|
216 |
$result = false;
|
217 |
|
218 |
+
foreach ($this->prepareConditions($conditions, $args) as $condition) {
|
219 |
$result = $result || ($condition['left'] >= $condition['right']);
|
220 |
}
|
221 |
|
231 |
* @return boolean
|
232 |
*
|
233 |
* @access protected
|
234 |
+
* @version 6.0.0
|
235 |
*/
|
236 |
+
protected function evaluateLessOrEqualsConditions($conditions, $args)
|
237 |
+
{
|
238 |
$result = false;
|
239 |
|
240 |
+
foreach ($this->prepareConditions($conditions, $args) as $condition) {
|
241 |
$result = $result || ($condition['left'] <= $condition['right']);
|
242 |
}
|
243 |
|
253 |
* @return boolean
|
254 |
*
|
255 |
* @access protected
|
256 |
+
* @version 6.0.0
|
257 |
*/
|
258 |
+
protected function evaluateInConditions($conditions, $args)
|
259 |
+
{
|
260 |
$result = false;
|
261 |
|
262 |
+
foreach ($this->prepareConditions($conditions, $args) as $cnd) {
|
263 |
+
$result = $result || in_array($cnd['left'], (array) $cnd['right'], true);
|
264 |
}
|
265 |
|
266 |
return $result;
|
275 |
* @return boolean
|
276 |
*
|
277 |
* @access protected
|
278 |
+
* @version 6.0.0
|
279 |
*/
|
280 |
+
protected function evaluateNotInConditions($conditions, $args)
|
281 |
+
{
|
282 |
return !$this->evaluateInConditions($conditions, $args);
|
283 |
}
|
284 |
|
291 |
* @return boolean
|
292 |
*
|
293 |
* @access protected
|
294 |
+
* @version 6.0.0
|
295 |
*/
|
296 |
+
protected function evaluateLikeConditions($conditions, $args)
|
297 |
+
{
|
298 |
$result = false;
|
299 |
|
300 |
+
foreach ($this->prepareConditions($conditions, $args) as $cnd) {
|
301 |
+
foreach ((array) $cnd['right'] as $el) {
|
302 |
$sub = str_replace('\*', '.*', preg_quote($el));
|
303 |
+
$result = $result || preg_match('@^' . $sub . '$@', $cnd['left']);
|
304 |
}
|
305 |
}
|
306 |
|
316 |
* @return boolean
|
317 |
*
|
318 |
* @access protected
|
319 |
+
* @version 6.0.0
|
320 |
*/
|
321 |
+
protected function evaluateNotLikeConditions($conditions, $args)
|
322 |
+
{
|
323 |
return !$this->evaluateLikeConditions($conditions, $args);
|
324 |
}
|
325 |
|
332 |
* @return boolean
|
333 |
*
|
334 |
* @access protected
|
335 |
+
* @version 6.0.0
|
336 |
*/
|
337 |
+
protected function evaluateRegexConditions($conditions, $args)
|
338 |
+
{
|
339 |
$result = false;
|
340 |
|
341 |
+
foreach ($this->prepareConditions($conditions, $args) as $condition) {
|
342 |
$result = $result || preg_match($condition['right'], $condition['left']);
|
343 |
}
|
344 |
|
354 |
* @return array
|
355 |
*
|
356 |
* @access protected
|
357 |
+
* @version 6.0.0
|
358 |
*/
|
359 |
+
protected function prepareConditions($conditions, $args)
|
360 |
+
{
|
361 |
$result = array();
|
362 |
|
363 |
if (is_array($conditions)) {
|
364 |
+
foreach ($conditions as $left => $right) {
|
365 |
$result[] = array(
|
366 |
'left' => $this->parseExpression($left, $args),
|
367 |
'right' => $this->parseExpression($right, $args)
|
381 |
* @return mixed Prepared part of the condition or false on failure
|
382 |
*
|
383 |
* @access protected
|
384 |
+
* @version 6.0.0
|
385 |
*/
|
386 |
+
protected function parseExpression($exp, $args)
|
387 |
+
{
|
388 |
if (is_scalar($exp)) {
|
389 |
if (preg_match_all('/(\$\{[^}]+\})/', $exp, $match)) {
|
390 |
$exp = AAM_Core_Policy_Token::evaluate($exp, $match[1], $args);
|
391 |
}
|
392 |
|
393 |
+
$types = 'string|ip|int|boolean|bool|array|null';
|
394 |
+
|
395 |
// If there is type scaling, perform it too
|
396 |
+
if (preg_match('/^\(\*(' . $types . ')\)(.*)/i', $exp, $scale)) {
|
397 |
+
$exp = $this->castValue($scale[2], $scale[1]);
|
398 |
}
|
399 |
} elseif (is_array($exp) || is_object($exp)) {
|
400 |
+
foreach ($exp as &$value) {
|
401 |
$value = $this->parseExpression($value, $args);
|
402 |
}
|
403 |
} elseif (is_null($exp) === false) {
|
408 |
}
|
409 |
|
410 |
/**
|
411 |
+
* Cast value to specific type
|
412 |
*
|
413 |
* @param mixed $value
|
414 |
* @param string $type
|
416 |
* @return mixed
|
417 |
*
|
418 |
* @access protected
|
419 |
+
* @version 6.0.0
|
420 |
*/
|
421 |
+
protected function castValue($value, $type)
|
422 |
+
{
|
423 |
+
switch (strtolower($type)) {
|
424 |
case 'string':
|
425 |
+
$value = (string) $value;
|
426 |
break;
|
427 |
|
428 |
case 'ip':
|
430 |
break;
|
431 |
|
432 |
case 'int':
|
433 |
+
$value = (int) $value;
|
434 |
break;
|
435 |
|
436 |
case 'boolean':
|
437 |
case 'bool':
|
438 |
+
$value = filter_var($value, FILTER_VALIDATE_BOOLEAN);
|
439 |
break;
|
440 |
|
441 |
case 'array':
|
453 |
return $value;
|
454 |
}
|
455 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
456 |
}
|
application/Core/Policy/Factory.php
CHANGED
@@ -5,50 +5,68 @@
|
|
5 |
* LICENSE: This file is subject to the terms and conditions defined in *
|
6 |
* file 'license.txt', which is part of this source code package. *
|
7 |
* ======================================================================
|
|
|
|
|
8 |
*/
|
9 |
|
10 |
/**
|
11 |
* AAM core policy manager factory
|
12 |
-
*
|
13 |
* @package AAM
|
14 |
-
* @
|
15 |
-
* @since AAM v5.7.2
|
16 |
*/
|
17 |
-
final class AAM_Core_Policy_Factory
|
18 |
-
|
|
|
19 |
/**
|
20 |
-
* Collection of instances
|
21 |
-
*
|
22 |
-
* @var array
|
23 |
-
*
|
24 |
* @access private
|
25 |
-
* @
|
26 |
*/
|
27 |
private static $_instances = array();
|
28 |
-
|
29 |
/**
|
30 |
-
* Get single instance of
|
31 |
-
*
|
32 |
* @param AAM_Core_Subject $subject
|
33 |
-
*
|
34 |
* @return AAM_Core_Policy_Manager
|
35 |
-
*
|
36 |
* @access public
|
37 |
-
* @
|
38 |
*/
|
39 |
-
public static function get(AAM_Core_Subject $subject = null)
|
|
|
40 |
if (is_null($subject)) {
|
41 |
$subject = AAM::getUser();
|
42 |
}
|
43 |
-
|
44 |
-
$id = $subject->getId();
|
45 |
$sid = $subject::UID . (empty($id) ? '' : '_' . $id);
|
46 |
|
47 |
if (!isset(self::$_instances[$sid])) {
|
48 |
self::$_instances[$sid] = new AAM_Core_Policy_Manager($subject);
|
|
|
|
|
49 |
}
|
50 |
-
|
51 |
return self::$_instances[$sid];
|
52 |
}
|
53 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
54 |
}
|
5 |
* LICENSE: This file is subject to the terms and conditions defined in *
|
6 |
* file 'license.txt', which is part of this source code package. *
|
7 |
* ======================================================================
|
8 |
+
*
|
9 |
+
* @version 6.0.0
|
10 |
*/
|
11 |
|
12 |
/**
|
13 |
* AAM core policy manager factory
|
14 |
+
*
|
15 |
* @package AAM
|
16 |
+
* @version 6.0.0
|
|
|
17 |
*/
|
18 |
+
final class AAM_Core_Policy_Factory
|
19 |
+
{
|
20 |
+
|
21 |
/**
|
22 |
+
* Collection of policy manage instances
|
23 |
+
*
|
24 |
+
* @var array
|
25 |
+
*
|
26 |
* @access private
|
27 |
+
* @version 6.0.0
|
28 |
*/
|
29 |
private static $_instances = array();
|
30 |
+
|
31 |
/**
|
32 |
+
* Get single instance of access manager
|
33 |
+
*
|
34 |
* @param AAM_Core_Subject $subject
|
35 |
+
*
|
36 |
* @return AAM_Core_Policy_Manager
|
37 |
+
*
|
38 |
* @access public
|
39 |
+
* @version 6.0.0
|
40 |
*/
|
41 |
+
public static function get(AAM_Core_Subject $subject = null)
|
42 |
+
{
|
43 |
if (is_null($subject)) {
|
44 |
$subject = AAM::getUser();
|
45 |
}
|
46 |
+
|
47 |
+
$id = $subject->getId();
|
48 |
$sid = $subject::UID . (empty($id) ? '' : '_' . $id);
|
49 |
|
50 |
if (!isset(self::$_instances[$sid])) {
|
51 |
self::$_instances[$sid] = new AAM_Core_Policy_Manager($subject);
|
52 |
+
// Parse all attached to the user policies
|
53 |
+
self::$_instances[$sid]->initialize();
|
54 |
}
|
55 |
+
|
56 |
return self::$_instances[$sid];
|
57 |
}
|
58 |
+
|
59 |
+
/**
|
60 |
+
* Reset internal cache
|
61 |
+
*
|
62 |
+
* @return void
|
63 |
+
*
|
64 |
+
* @access public
|
65 |
+
* @version 6.0.0
|
66 |
+
*/
|
67 |
+
public static function reset()
|
68 |
+
{
|
69 |
+
self::$_instances = array();
|
70 |
+
}
|
71 |
+
|
72 |
}
|
application/Core/Policy/Manager.php
CHANGED
@@ -5,414 +5,449 @@
|
|
5 |
* LICENSE: This file is subject to the terms and conditions defined in *
|
6 |
* file 'license.txt', which is part of this source code package. *
|
7 |
* ======================================================================
|
|
|
|
|
8 |
*/
|
9 |
|
10 |
/**
|
11 |
-
* AAM
|
12 |
-
*
|
13 |
* @package AAM
|
14 |
-
* @
|
15 |
-
* @since AAM v5.7.2
|
16 |
*/
|
17 |
-
|
18 |
-
|
|
|
19 |
/**
|
20 |
* Policy core object
|
21 |
-
*
|
22 |
* @var AAM_Core_Object_Policy
|
23 |
-
*
|
24 |
-
* @access protected
|
|
|
25 |
*/
|
26 |
-
protected $
|
27 |
-
|
28 |
/**
|
29 |
* Current subject
|
30 |
-
*
|
31 |
* @var AAM_Core_Subject
|
32 |
-
*
|
33 |
-
* @access protected
|
|
|
34 |
*/
|
35 |
protected $subject;
|
36 |
-
|
37 |
/**
|
38 |
* Parsed policy tree
|
39 |
-
*
|
40 |
* @var array
|
41 |
-
*
|
42 |
-
* @access protected
|
|
|
43 |
*/
|
44 |
-
protected $tree =
|
45 |
-
|
|
|
|
|
|
|
46 |
/**
|
47 |
* Constructor
|
48 |
-
*
|
49 |
* @access protected
|
50 |
-
*
|
51 |
* @return void
|
|
|
52 |
*/
|
53 |
-
public function __construct(AAM_Core_Subject $subject)
|
54 |
-
|
55 |
-
$this->
|
|
|
56 |
}
|
57 |
|
58 |
/**
|
59 |
-
*
|
60 |
*
|
61 |
-
* @return void
|
62 |
-
*/
|
63 |
-
public function initializePolicyTree() {
|
64 |
-
$this->preparePolicyTree();
|
65 |
-
}
|
66 |
-
|
67 |
-
/**
|
68 |
-
* Call policy object public methods
|
69 |
-
*
|
70 |
* @param string $name
|
71 |
* @param array $args
|
72 |
-
*
|
73 |
* @return mixed
|
74 |
-
*
|
75 |
* @access public
|
|
|
76 |
*/
|
77 |
-
public function
|
78 |
-
|
79 |
-
|
80 |
-
|
81 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
82 |
}
|
83 |
-
|
84 |
-
return $
|
85 |
}
|
86 |
-
|
87 |
/**
|
88 |
-
* Find all
|
89 |
-
*
|
90 |
-
* @param string
|
91 |
-
* @param array
|
92 |
-
*
|
93 |
-
*
|
94 |
* @return array
|
95 |
-
*
|
96 |
* @access public
|
|
|
97 |
*/
|
98 |
-
public function
|
99 |
-
|
100 |
-
|
101 |
-
|
102 |
-
|
103 |
-
|
104 |
-
$statements[$this->strToLower($key)] = $stm;
|
105 |
-
}
|
106 |
}
|
107 |
-
|
108 |
-
|
109 |
-
|
110 |
-
|
111 |
-
|
112 |
-
|
113 |
-
|
114 |
-
* This method is working with "Statement" array.
|
115 |
-
*
|
116 |
-
* @param string $resource Resource name
|
117 |
-
* @param array $args Args that will be injected during condition evaluation
|
118 |
-
*
|
119 |
-
* @return boolean|null
|
120 |
-
*
|
121 |
-
* @access public
|
122 |
-
*/
|
123 |
-
public function isAllowed($resource, $args = array()) {
|
124 |
-
$allowed = null;
|
125 |
-
$tree = $this->preparePolicyTree();
|
126 |
-
$id = $this->strToLower($resource);
|
127 |
-
|
128 |
-
if (isset($tree['Statement'][$id])) {
|
129 |
-
$stm = $tree['Statement'][$id];
|
130 |
-
|
131 |
-
if ($this->isApplicable($stm, $args)) {
|
132 |
-
$effect = strtolower($stm['Effect']);
|
133 |
-
$allowed = ($effect === 'allow');
|
134 |
}
|
135 |
}
|
136 |
-
|
137 |
-
return $
|
138 |
}
|
139 |
|
140 |
/**
|
141 |
-
*
|
|
|
|
|
|
|
|
|
142 |
*
|
143 |
-
* @param string $str
|
144 |
-
*
|
145 |
-
* @return string
|
146 |
-
*
|
147 |
* @access protected
|
|
|
148 |
*/
|
149 |
-
protected function
|
150 |
-
|
151 |
-
|
152 |
-
|
153 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
154 |
}
|
155 |
|
156 |
-
return $
|
157 |
}
|
158 |
|
159 |
/**
|
160 |
-
*
|
161 |
-
*
|
162 |
-
*
|
163 |
-
*
|
164 |
-
*
|
|
|
165 |
*
|
166 |
-
* @param string $resource
|
167 |
-
* @param array $args
|
168 |
-
*
|
169 |
-
* @return boolean
|
170 |
-
*
|
171 |
* @access public
|
|
|
|
|
172 |
*/
|
173 |
-
public function
|
174 |
-
|
175 |
-
$
|
176 |
-
|
177 |
-
|
178 |
-
|
179 |
-
|
180 |
-
|
181 |
-
|
182 |
-
$effect = strtolower($stm['Effect']);
|
183 |
-
$denied = ($effect === 'deny' && !empty($stm['Enforce']));
|
184 |
}
|
185 |
}
|
186 |
-
|
187 |
-
return $
|
188 |
}
|
189 |
-
|
190 |
/**
|
191 |
-
*
|
192 |
-
*
|
193 |
-
*
|
194 |
-
*
|
195 |
-
*
|
196 |
-
* @
|
197 |
-
*
|
|
|
|
|
198 |
* @access public
|
|
|
199 |
*/
|
200 |
-
public function
|
201 |
-
|
|
|
|
|
202 |
|
203 |
-
if (isset($this->tree['
|
204 |
-
$
|
205 |
-
|
206 |
-
if ($this->isApplicable($
|
207 |
-
|
208 |
-
$value = AAM_Core_Policy_Token::evaluate($param['Value'], $match[1]);
|
209 |
-
} else {
|
210 |
-
$value = $param['Value'];
|
211 |
-
}
|
212 |
}
|
213 |
}
|
214 |
-
|
215 |
-
return $
|
216 |
}
|
217 |
-
|
218 |
/**
|
219 |
-
*
|
220 |
-
*
|
221 |
-
*
|
222 |
-
*
|
223 |
-
* @param int $id Policy ID
|
224 |
-
* @param string $action Either "attach" or "detach"
|
225 |
-
*
|
226 |
-
* @return bool
|
227 |
-
*
|
228 |
* @access public
|
229 |
-
* @
|
230 |
*/
|
231 |
-
public function
|
232 |
-
|
233 |
-
|
234 |
-
// Verify that current user can perform following action
|
235 |
-
$stm = $this->find(
|
236 |
-
"/^post:{$post->post_type}:({$post->post_name}|{$post->ID}):{$action}/i",
|
237 |
-
array('post' => $post),
|
238 |
-
true
|
239 |
-
);
|
240 |
-
|
241 |
-
return (empty($stm['Effect']) || $stm['Effect'] === 'allow');
|
242 |
}
|
243 |
-
|
244 |
/**
|
245 |
-
*
|
246 |
-
*
|
247 |
-
* @
|
248 |
-
*
|
249 |
-
*
|
250 |
-
* @
|
251 |
-
*
|
252 |
-
* @access protected
|
253 |
*/
|
254 |
-
|
255 |
-
|
256 |
-
|
257 |
-
|
258 |
-
|
259 |
-
|
260 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
261 |
}
|
262 |
-
|
263 |
-
return $result;
|
264 |
}
|
265 |
-
|
266 |
/**
|
267 |
-
*
|
268 |
-
*
|
269 |
-
*
|
270 |
-
*
|
271 |
-
*
|
272 |
* @return array
|
273 |
-
*
|
274 |
* @access protected
|
|
|
275 |
*/
|
276 |
-
protected function
|
277 |
-
|
278 |
-
|
279 |
-
|
280 |
-
|
281 |
-
|
282 |
-
|
283 |
-
|
284 |
-
$this->policyObject->getOption(),
|
285 |
-
function($state) {
|
286 |
-
return !empty($state);
|
287 |
-
}
|
288 |
-
);
|
289 |
-
|
290 |
-
if (count($ids)) {
|
291 |
-
$policies = get_posts(array(
|
292 |
-
'include' => array_keys($ids),
|
293 |
-
'post_status' => 'publish',
|
294 |
-
'post_type' => 'aam_policy'
|
295 |
-
));
|
296 |
-
|
297 |
-
foreach($policies as $policy) {
|
298 |
-
$this->extendTree(
|
299 |
-
$this->tree, $this->parsePolicy($policy->post_content)
|
300 |
-
);
|
301 |
-
}
|
302 |
-
}
|
303 |
-
}
|
304 |
-
|
305 |
-
return $this->tree;
|
306 |
}
|
307 |
-
|
308 |
/**
|
309 |
-
* Parse policy
|
310 |
-
*
|
311 |
-
* @param
|
312 |
-
*
|
313 |
* @return array
|
314 |
-
*
|
315 |
* @access protected
|
|
|
316 |
*/
|
317 |
-
protected function parsePolicy($policy)
|
318 |
-
|
319 |
-
|
|
|
320 |
// Do not load the policy if any errors
|
321 |
if (json_last_error() === JSON_ERROR_NONE) {
|
322 |
$tree = array(
|
323 |
-
'Statement' =>
|
324 |
-
'Param' =>
|
325 |
);
|
326 |
} else {
|
327 |
$tree = array('Statement' => array(), 'Param' => array());
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
328 |
}
|
329 |
-
|
330 |
return $tree;
|
331 |
}
|
332 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
333 |
/**
|
334 |
* Extend tree with additional statements and params
|
335 |
-
*
|
336 |
* @param array &$tree
|
337 |
* @param array $addition
|
338 |
-
*
|
339 |
* @return array
|
340 |
-
*
|
341 |
* @access protected
|
|
|
342 |
*/
|
343 |
-
protected function
|
|
|
|
|
|
|
|
|
344 |
// Step #1. If there are any statements, let's index them by resource:action
|
345 |
// and insert into the list of statements
|
346 |
-
foreach($addition['Statement'] as $stm) {
|
347 |
-
$
|
348 |
-
$
|
349 |
-
|
350 |
-
foreach($
|
351 |
-
// Allow to build resource name dynamically.
|
352 |
// e.g. "Term:category:${USERMETA.region}:posts"
|
353 |
if (preg_match_all('/(\$\{[^}]+\})/', $res, $match)) {
|
354 |
$res = AAM_Core_Policy_Token::evaluate($res, $match[1]);
|
355 |
}
|
356 |
-
|
357 |
-
|
358 |
-
|
359 |
-
|
360 |
-
|
|
|
361 |
}
|
362 |
}
|
363 |
}
|
364 |
}
|
365 |
|
366 |
-
|
367 |
-
$closure = function($res, $option) {
|
368 |
-
$param = $this->tree['Param']["option:{$option}"];
|
369 |
-
|
370 |
-
if ($this->isApplicable($param)) {
|
371 |
-
if (is_array($res) && is_array($param['Value'])) {
|
372 |
-
$res = array_merge($res, $param['Value']);
|
373 |
-
} else {
|
374 |
-
$res = $param['Value'];
|
375 |
-
}
|
376 |
-
}
|
377 |
-
|
378 |
-
return $res;
|
379 |
-
};
|
380 |
|
381 |
// Step #2. If there are any params, let's index them and insert into the list
|
382 |
-
foreach($addition['Param'] as $param) {
|
383 |
if (!empty($param['Key'])) {
|
384 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
385 |
|
386 |
-
if (!isset($
|
387 |
-
$
|
388 |
|
389 |
if (strpos($id, 'option:') === 0) {
|
390 |
-
|
391 |
-
|
|
|
|
|
|
|
392 |
}
|
393 |
}
|
394 |
}
|
395 |
}
|
396 |
}
|
397 |
-
|
398 |
/**
|
399 |
-
*
|
400 |
-
*
|
401 |
-
* @
|
402 |
-
*
|
403 |
-
*
|
404 |
-
* @return array
|
405 |
-
*
|
406 |
* @access private
|
|
|
407 |
*/
|
408 |
-
private function
|
409 |
-
|
410 |
-
|
411 |
-
|
|
|
|
|
|
|
|
|
412 |
}
|
413 |
}
|
414 |
-
|
415 |
-
return $arr;
|
416 |
}
|
417 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
418 |
}
|
5 |
* LICENSE: This file is subject to the terms and conditions defined in *
|
6 |
* file 'license.txt', which is part of this source code package. *
|
7 |
* ======================================================================
|
8 |
+
*
|
9 |
+
* @version 6.0.0
|
10 |
*/
|
11 |
|
12 |
/**
|
13 |
+
* AAM policy manager for a specific subject
|
14 |
+
*
|
15 |
* @package AAM
|
16 |
+
* @version 6.0.0
|
|
|
17 |
*/
|
18 |
+
class AAM_Core_Policy_Manager
|
19 |
+
{
|
20 |
+
|
21 |
/**
|
22 |
* Policy core object
|
23 |
+
*
|
24 |
* @var AAM_Core_Object_Policy
|
25 |
+
*
|
26 |
+
* @access protected
|
27 |
+
* @version 6.0.0
|
28 |
*/
|
29 |
+
protected $object;
|
30 |
+
|
31 |
/**
|
32 |
* Current subject
|
33 |
+
*
|
34 |
* @var AAM_Core_Subject
|
35 |
+
*
|
36 |
+
* @access protected
|
37 |
+
* @version 6.0.0
|
38 |
*/
|
39 |
protected $subject;
|
40 |
+
|
41 |
/**
|
42 |
* Parsed policy tree
|
43 |
+
*
|
44 |
* @var array
|
45 |
+
*
|
46 |
+
* @access protected
|
47 |
+
* @version 6.0.0
|
48 |
*/
|
49 |
+
protected $tree = array(
|
50 |
+
'Statement' => array(),
|
51 |
+
'Param' => array()
|
52 |
+
);
|
53 |
+
|
54 |
/**
|
55 |
* Constructor
|
56 |
+
*
|
57 |
* @access protected
|
58 |
+
*
|
59 |
* @return void
|
60 |
+
* @version 6.0.0
|
61 |
*/
|
62 |
+
public function __construct(AAM_Core_Subject $subject)
|
63 |
+
{
|
64 |
+
$this->object = $subject->getObject(AAM_Core_Object_Policy::OBJECT_TYPE);
|
65 |
+
$this->subject = $subject;
|
66 |
}
|
67 |
|
68 |
/**
|
69 |
+
* Get policy parameter
|
70 |
*
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
71 |
* @param string $name
|
72 |
* @param array $args
|
73 |
+
*
|
74 |
* @return mixed
|
75 |
+
*
|
76 |
* @access public
|
77 |
+
* @version 6.0.0
|
78 |
*/
|
79 |
+
public function getParam($id, $args = array())
|
80 |
+
{
|
81 |
+
$value = null;
|
82 |
+
|
83 |
+
if (isset($this->tree['Param'][$id])) {
|
84 |
+
$param = $this->tree['Param'][$id];
|
85 |
+
|
86 |
+
if ($this->isApplicable($param, $args)) {
|
87 |
+
if (preg_match_all('/(\$\{[^}]+\})/', $param['Value'], $match)) {
|
88 |
+
$value = AAM_Core_Policy_Token::evaluate(
|
89 |
+
$param['Value'], $match[1]
|
90 |
+
);
|
91 |
+
} else {
|
92 |
+
$value = $param['Value'];
|
93 |
+
}
|
94 |
+
}
|
95 |
}
|
96 |
+
|
97 |
+
return $value;
|
98 |
}
|
99 |
+
|
100 |
/**
|
101 |
+
* Find all statements that match provided resource of list of resources
|
102 |
+
*
|
103 |
+
* @param string|array $s
|
104 |
+
* @param array $args
|
105 |
+
*
|
|
|
106 |
* @return array
|
107 |
+
*
|
108 |
* @access public
|
109 |
+
* @version 6.0.0
|
110 |
*/
|
111 |
+
public function getResources($s, $args = array())
|
112 |
+
{
|
113 |
+
if (is_array($s)) {
|
114 |
+
$regex = '/^(' . implode('|', $s) . '):/i';
|
115 |
+
} else {
|
116 |
+
$regex = "/^{$s}:/i";
|
|
|
|
|
117 |
}
|
118 |
+
|
119 |
+
$statements = array();
|
120 |
+
|
121 |
+
foreach ($this->tree['Statement'] as $key => $stm) {
|
122 |
+
if (preg_match($regex, $key) && $this->isApplicable($stm, $args)) {
|
123 |
+
// Remove the resource type to keep it clean
|
124 |
+
$statements[preg_replace($regex, '', $key)] = $stm;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
125 |
}
|
126 |
}
|
127 |
+
|
128 |
+
return $this->replaceTokens($statements);
|
129 |
}
|
130 |
|
131 |
/**
|
132 |
+
* Replace all the dynamic tokens recursively
|
133 |
+
*
|
134 |
+
* @param array $data
|
135 |
+
*
|
136 |
+
* @return array
|
137 |
*
|
|
|
|
|
|
|
|
|
138 |
* @access protected
|
139 |
+
* @version 6.0.0
|
140 |
*/
|
141 |
+
protected function replaceTokens($data)
|
142 |
+
{
|
143 |
+
$replaced = array();
|
144 |
+
|
145 |
+
foreach($data as $key => $value) {
|
146 |
+
if (preg_match_all('/(\$\{[^}]+\})/', $key, $match)) {
|
147 |
+
$key = AAM_Core_Policy_Token::evaluate($key, $match[1]);
|
148 |
+
}
|
149 |
+
|
150 |
+
if (is_array($value)) {
|
151 |
+
$replaced[$key] = $this->replaceTokens($value);
|
152 |
+
} elseif (preg_match_all('/(\$\{[^}]+\})/', $value, $match)) {
|
153 |
+
$replaced[$key] = AAM_Core_Policy_Token::evaluate($value, $match[1]);
|
154 |
+
} else {
|
155 |
+
$replaced[$key] = $value;
|
156 |
+
}
|
157 |
}
|
158 |
|
159 |
+
return $replaced;
|
160 |
}
|
161 |
|
162 |
/**
|
163 |
+
* Hook into WP core function to override WP options
|
164 |
+
*
|
165 |
+
* @param mixed $res
|
166 |
+
* @param string $option
|
167 |
+
*
|
168 |
+
* @return mixed
|
169 |
*
|
|
|
|
|
|
|
|
|
|
|
170 |
* @access public
|
171 |
+
* @see AAM_Core_Policy_Manager::updatePolicyTree
|
172 |
+
* @version 6.0.0
|
173 |
*/
|
174 |
+
public function getOption($res, $option)
|
175 |
+
{
|
176 |
+
$param = $this->tree['Param']["option:{$option}"];
|
177 |
+
|
178 |
+
if ($this->isApplicable($param)) {
|
179 |
+
if (is_array($res) && is_array($param['Value'])) {
|
180 |
+
$res = array_merge($res, $param['Value']);
|
181 |
+
} else {
|
182 |
+
$res = $param['Value'];
|
|
|
|
|
183 |
}
|
184 |
}
|
185 |
+
|
186 |
+
return $res;
|
187 |
}
|
188 |
+
|
189 |
/**
|
190 |
+
* Check if specified action is allowed for resource
|
191 |
+
*
|
192 |
+
* This method is working with "Statement" array.
|
193 |
+
*
|
194 |
+
* @param string $resource Resource name
|
195 |
+
* @param array $args Args that will be injected during condition evaluation
|
196 |
+
*
|
197 |
+
* @return boolean|null
|
198 |
+
*
|
199 |
* @access public
|
200 |
+
* @version 6.0.0
|
201 |
*/
|
202 |
+
public function isAllowed($resource, $args = array())
|
203 |
+
{
|
204 |
+
$allowed = null;
|
205 |
+
$id = strtolower($resource);
|
206 |
|
207 |
+
if (isset($this->tree['Statement'][$id])) {
|
208 |
+
$stm = $this->tree['Statement'][$id];
|
209 |
+
|
210 |
+
if ($this->isApplicable($stm, $args)) {
|
211 |
+
$allowed = (strtolower($stm['Effect']) === 'allow');
|
|
|
|
|
|
|
|
|
212 |
}
|
213 |
}
|
214 |
+
|
215 |
+
return $allowed;
|
216 |
}
|
217 |
+
|
218 |
/**
|
219 |
+
* Get parsed policy tree
|
220 |
+
*
|
221 |
+
* @return array
|
222 |
+
*
|
|
|
|
|
|
|
|
|
|
|
223 |
* @access public
|
224 |
+
* @version 6.0.0
|
225 |
*/
|
226 |
+
public function getTree()
|
227 |
+
{
|
228 |
+
return $this->tree;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
229 |
}
|
230 |
+
|
231 |
/**
|
232 |
+
* Parse all attached policies into the tree
|
233 |
+
*
|
234 |
+
* @return void
|
235 |
+
*
|
236 |
+
* @access public
|
237 |
+
* @version 6.0.0
|
|
|
|
|
238 |
*/
|
239 |
+
public function initialize()
|
240 |
+
{
|
241 |
+
// Get the list of all policies that are attached to the subject
|
242 |
+
$ids = array_filter($this->object->getOption(), function ($attached) {
|
243 |
+
return !empty($attached);
|
244 |
+
});
|
245 |
+
|
246 |
+
// If there is at least one policy attached and it is published, then
|
247 |
+
// parse into the tree
|
248 |
+
if (count($ids)) {
|
249 |
+
$policies = $this->fetchPolicies(array_keys($ids));
|
250 |
+
|
251 |
+
foreach ($policies as $policy) {
|
252 |
+
$this->updatePolicyTree($this->tree, $this->parsePolicy($policy));
|
253 |
+
}
|
254 |
+
|
255 |
+
$this->_cleanupTree();
|
256 |
}
|
|
|
|
|
257 |
}
|
258 |
+
|
259 |
/**
|
260 |
+
* Fetch public policies by IDs
|
261 |
+
*
|
262 |
+
* @param array $ids
|
263 |
+
*
|
|
|
264 |
* @return array
|
265 |
+
*
|
266 |
* @access protected
|
267 |
+
* @version 6.0.0
|
268 |
*/
|
269 |
+
protected function fetchPolicies($ids)
|
270 |
+
{
|
271 |
+
return get_posts(array(
|
272 |
+
'include' => $ids,
|
273 |
+
'post_status' => 'publish',
|
274 |
+
'suppress_filters' => true,
|
275 |
+
'post_type' => AAM_Service_AccessPolicy::POLICY_CPT
|
276 |
+
));
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
277 |
}
|
278 |
+
|
279 |
/**
|
280 |
+
* Parse JSON policy and extract statements and params
|
281 |
+
*
|
282 |
+
* @param WP_Post $policy
|
283 |
+
*
|
284 |
* @return array
|
285 |
+
*
|
286 |
* @access protected
|
287 |
+
* @version 6.0.0
|
288 |
*/
|
289 |
+
protected function parsePolicy($policy)
|
290 |
+
{
|
291 |
+
$val = json_decode($policy->post_content, true);
|
292 |
+
|
293 |
// Do not load the policy if any errors
|
294 |
if (json_last_error() === JSON_ERROR_NONE) {
|
295 |
$tree = array(
|
296 |
+
'Statement' => $this->_getArrayOfArrays($val, 'Statement'),
|
297 |
+
'Param' => $this->_getArrayOfArrays($val, 'Param'),
|
298 |
);
|
299 |
} else {
|
300 |
$tree = array('Statement' => array(), 'Param' => array());
|
301 |
+
|
302 |
+
// Make sure that this is noticed
|
303 |
+
_doing_it_wrong(
|
304 |
+
__CLASS__ . '::' . __METHOD__,
|
305 |
+
sprintf(
|
306 |
+
'Access policy %d error %s', $policy->ID, json_last_error_msg()
|
307 |
+
),
|
308 |
+
AAM_VERSION
|
309 |
+
);
|
310 |
}
|
311 |
+
|
312 |
return $tree;
|
313 |
}
|
314 |
+
|
315 |
+
/**
|
316 |
+
* Get array of array for Statement and Param policy props
|
317 |
+
*
|
318 |
+
* @param array $input
|
319 |
+
* @param string $prop
|
320 |
+
*
|
321 |
+
* @return array
|
322 |
+
*
|
323 |
+
* @access private
|
324 |
+
* @version 6.0.0
|
325 |
+
*/
|
326 |
+
private function _getArrayOfArrays($input, $prop)
|
327 |
+
{
|
328 |
+
$response = array();
|
329 |
+
|
330 |
+
// Parse Statements and determine if it is multidimensional
|
331 |
+
if (array_key_exists($prop, $input)) {
|
332 |
+
if (!isset($input[$prop][0]) || !is_array($input[$prop][0])) {
|
333 |
+
$response = array($input[$prop]);
|
334 |
+
} else {
|
335 |
+
$response = $input[$prop];
|
336 |
+
}
|
337 |
+
}
|
338 |
+
|
339 |
+
return $response;
|
340 |
+
}
|
341 |
+
|
342 |
/**
|
343 |
* Extend tree with additional statements and params
|
344 |
+
*
|
345 |
* @param array &$tree
|
346 |
* @param array $addition
|
347 |
+
*
|
348 |
* @return array
|
349 |
+
*
|
350 |
* @access protected
|
351 |
+
* @version 6.0.0
|
352 |
*/
|
353 |
+
protected function updatePolicyTree(&$tree, $addition)
|
354 |
+
{
|
355 |
+
$stmts = &$tree['Statement'];
|
356 |
+
$params = &$tree['Param'];
|
357 |
+
|
358 |
// Step #1. If there are any statements, let's index them by resource:action
|
359 |
// and insert into the list of statements
|
360 |
+
foreach ($addition['Statement'] as $stm) {
|
361 |
+
$resources = (isset($stm['Resource']) ? (array) $stm['Resource'] : array());
|
362 |
+
$actions = (isset($stm['Action']) ? (array) $stm['Action'] : array(''));
|
363 |
+
|
364 |
+
foreach ($resources as $res) {
|
365 |
+
// Allow to build resource name dynamically.
|
366 |
// e.g. "Term:category:${USERMETA.region}:posts"
|
367 |
if (preg_match_all('/(\$\{[^}]+\})/', $res, $match)) {
|
368 |
$res = AAM_Core_Policy_Token::evaluate($res, $match[1]);
|
369 |
}
|
370 |
+
|
371 |
+
foreach ($actions as $act) {
|
372 |
+
$id = strtolower($res . (!empty($act) ? ":{$act}" : ''));
|
373 |
+
|
374 |
+
if (!isset($stmts[$id]) || empty($stmts[$id]['Enforce'])) {
|
375 |
+
$stmts[$id] = $stm;
|
376 |
}
|
377 |
}
|
378 |
}
|
379 |
}
|
380 |
|
381 |
+
$callback = array($this, 'getOption'); // Callback that hooks into get_option
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
382 |
|
383 |
// Step #2. If there are any params, let's index them and insert into the list
|
384 |
+
foreach ($addition['Param'] as $param) {
|
385 |
if (!empty($param['Key'])) {
|
386 |
+
// Allow to build param name dynamically.
|
387 |
+
// e.g. "${USERMETA.region}_posts"
|
388 |
+
if (preg_match_all('/(\$\{[^}]+\})/', $param['Key'], $match)) {
|
389 |
+
$id = AAM_Core_Policy_Token::evaluate($param['Key'], $match[1]);
|
390 |
+
} else {
|
391 |
+
$id = $param['Key'];
|
392 |
+
}
|
393 |
|
394 |
+
if (!isset($params[$id]) || empty($params[$id]['Enforce'])) {
|
395 |
+
$params[$id] = $param;
|
396 |
|
397 |
if (strpos($id, 'option:') === 0) {
|
398 |
+
$name = substr($id, 7);
|
399 |
+
|
400 |
+
// Hook into the core
|
401 |
+
add_filter('pre_option_' . $name, $callback, 1, 2);
|
402 |
+
add_filter('pre_site_option_' . $name, $callback, 1, 2);
|
403 |
}
|
404 |
}
|
405 |
}
|
406 |
}
|
407 |
}
|
408 |
+
|
409 |
/**
|
410 |
+
* Perform some internal clean-up
|
411 |
+
*
|
412 |
+
* @return void
|
413 |
+
*
|
|
|
|
|
|
|
414 |
* @access private
|
415 |
+
* @version 6.0.0
|
416 |
*/
|
417 |
+
private function _cleanupTree()
|
418 |
+
{
|
419 |
+
foreach($this->tree['Statement'] as $id => $stm) {
|
420 |
+
if (isset($stm['Resource'])) {
|
421 |
+
unset($this->tree['Statement'][$id]['Resource']);
|
422 |
+
}
|
423 |
+
if (isset($stm['Action'])) {
|
424 |
+
unset($this->tree['Statement'][$id]['Action']);
|
425 |
}
|
426 |
}
|
|
|
|
|
427 |
}
|
428 |
+
|
429 |
+
/**
|
430 |
+
* Check if policy block is applicable
|
431 |
+
*
|
432 |
+
* @param array $block
|
433 |
+
* @param array $args
|
434 |
+
*
|
435 |
+
* @return boolean
|
436 |
+
*
|
437 |
+
* @access protected
|
438 |
+
* @version 6.0.0
|
439 |
+
*/
|
440 |
+
protected function isApplicable($block, $args = array())
|
441 |
+
{
|
442 |
+
$result = true;
|
443 |
+
|
444 |
+
if (!empty($block['Condition']) && is_array($block['Condition'])) {
|
445 |
+
$result = AAM_Core_Policy_Condition::getInstance()->evaluate(
|
446 |
+
$block['Condition'], $args
|
447 |
+
);
|
448 |
+
}
|
449 |
+
|
450 |
+
return $result;
|
451 |
+
}
|
452 |
+
|
453 |
}
|
application/Core/Policy/Resource.php
ADDED
@@ -0,0 +1,82 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
/**
|
4 |
+
* ======================================================================
|
5 |
+
* LICENSE: This file is subject to the terms and conditions defined in *
|
6 |
+
* file 'license.txt', which is part of this source code package. *
|
7 |
+
* ======================================================================
|
8 |
+
*/
|
9 |
+
|
10 |
+
/**
|
11 |
+
* AAM core policy resources
|
12 |
+
*
|
13 |
+
* @package AAM
|
14 |
+
* @version 6.0.0
|
15 |
+
*/
|
16 |
+
class AAM_Core_Policy_Resource
|
17 |
+
{
|
18 |
+
|
19 |
+
/**
|
20 |
+
* Backend Menu resource
|
21 |
+
*
|
22 |
+
* @version 6.0.0
|
23 |
+
*/
|
24 |
+
const MENU = 'BackendMenu';
|
25 |
+
|
26 |
+
/**
|
27 |
+
* Top admin bar resource
|
28 |
+
*
|
29 |
+
* @version 6.0.0
|
30 |
+
*/
|
31 |
+
const TOOLBAR = 'Toolbar';
|
32 |
+
|
33 |
+
/**
|
34 |
+
* Backend & Frontend widget resource
|
35 |
+
*
|
36 |
+
* @version 6.0.0
|
37 |
+
*/
|
38 |
+
const WIDGET = 'Widget';
|
39 |
+
|
40 |
+
/**
|
41 |
+
* Backend metabox resource
|
42 |
+
*
|
43 |
+
* @version 6.0.0
|
44 |
+
*/
|
45 |
+
const METABOX = 'Metabox';
|
46 |
+
|
47 |
+
/**
|
48 |
+
* Capability resource
|
49 |
+
*
|
50 |
+
* @version 6.0.0
|
51 |
+
*/
|
52 |
+
const CAPABILITY = 'Capability';
|
53 |
+
|
54 |
+
/**
|
55 |
+
* Role resource
|
56 |
+
*
|
57 |
+
* @version 6.0.0
|
58 |
+
*/
|
59 |
+
const ROLE = 'Role';
|
60 |
+
|
61 |
+
/**
|
62 |
+
* Post resource
|
63 |
+
*
|
64 |
+
* @version 6.0.0
|
65 |
+
*/
|
66 |
+
const POST = 'Post';
|
67 |
+
|
68 |
+
/**
|
69 |
+
* Uri resource
|
70 |
+
*
|
71 |
+
* @version 6.0.0
|
72 |
+
*/
|
73 |
+
const URI = "URI";
|
74 |
+
|
75 |
+
/**
|
76 |
+
* Plugin resource
|
77 |
+
*
|
78 |
+
* @version 6.0.0
|
79 |
+
*/
|
80 |
+
const PLUGIN = 'Plugin';
|
81 |
+
|
82 |
+
}
|
application/Core/Policy/Token.php
CHANGED
@@ -5,16 +5,18 @@
|
|
5 |
* LICENSE: This file is subject to the terms and conditions defined in *
|
6 |
* file 'license.txt', which is part of this source code package. *
|
7 |
* ======================================================================
|
|
|
|
|
8 |
*/
|
9 |
|
10 |
/**
|
11 |
* AAM core policy token evaluator
|
12 |
*
|
13 |
* @package AAM
|
14 |
-
* @
|
15 |
-
* @since AAM v5.8.2
|
16 |
*/
|
17 |
-
|
|
|
18 |
|
19 |
/**
|
20 |
* Literal map token's type to the executable method that returns actual value
|
@@ -22,21 +24,21 @@ final class AAM_Core_Policy_Token {
|
|
22 |
* @var array
|
23 |
*
|
24 |
* @access protected
|
25 |
-
* @
|
26 |
*/
|
27 |
protected static $map = array(
|
28 |
-
'USER'
|
29 |
-
'
|
30 |
-
'DATETIME'
|
31 |
-
'
|
32 |
-
'
|
33 |
-
'
|
34 |
-
'
|
35 |
-
'
|
36 |
-
'ARGS'
|
37 |
-
'CONST'
|
38 |
-
'
|
39 |
-
'
|
40 |
);
|
41 |
|
42 |
/**
|
@@ -44,14 +46,16 @@ final class AAM_Core_Policy_Token {
|
|
44 |
*
|
45 |
* @param string $part String with tokens
|
46 |
* @param array $tokens Extracted token
|
|
|
47 |
*
|
48 |
* @return string
|
49 |
*
|
50 |
* @access public
|
51 |
-
* @
|
52 |
*/
|
53 |
-
public static function evaluate($part, array $tokens, array $args = array())
|
54 |
-
|
|
|
55 |
$val = self::getValue(
|
56 |
preg_replace('/^\$\{([^}]+)\}$/', '${1}', $token),
|
57 |
$args
|
@@ -76,14 +80,15 @@ final class AAM_Core_Policy_Token {
|
|
76 |
* @return mixed
|
77 |
*
|
78 |
* @access protected
|
79 |
-
* @
|
80 |
*/
|
81 |
-
protected static function getValue($token, $args)
|
|
|
82 |
$value = null;
|
83 |
$parts = explode('.', $token);
|
84 |
|
85 |
if (isset(self::$map[$parts[0]])) {
|
86 |
-
if ($parts[0] === '
|
87 |
$value = call_user_func(self::$map[$parts[0]], $parts[1], $args);
|
88 |
} else {
|
89 |
$value = call_user_func(self::$map[$parts[0]], $parts[1]);
|
@@ -103,12 +108,13 @@ final class AAM_Core_Policy_Token {
|
|
103 |
* @return mixed
|
104 |
*
|
105 |
* @access protected
|
106 |
-
* @
|
107 |
*/
|
108 |
-
protected static function getUserValue($prop)
|
|
|
109 |
$user = AAM::getUser();
|
110 |
|
111 |
-
switch(strtolower($prop)) {
|
112 |
case 'ip':
|
113 |
case 'ipaddress':
|
114 |
$value = AAM_Core_Request::server('REMOTE_ADDR');
|
@@ -116,13 +122,12 @@ final class AAM_Core_Policy_Token {
|
|
116 |
|
117 |
case 'authenticated':
|
118 |
case 'isauthenticated':
|
119 |
-
$value =
|
120 |
break;
|
121 |
|
122 |
case 'capabilities':
|
123 |
case 'caps':
|
124 |
-
$
|
125 |
-
foreach((array) $user->allcaps as $cap => $effect) {
|
126 |
if (!empty($effect)) {
|
127 |
$value[] = $cap;
|
128 |
}
|
@@ -140,19 +145,20 @@ final class AAM_Core_Policy_Token {
|
|
140 |
/**
|
141 |
* Get user meta value(s)
|
142 |
*
|
143 |
-
* @param string $
|
144 |
*
|
145 |
* @return void
|
146 |
*
|
147 |
* @access protected
|
148 |
-
* @
|
149 |
*/
|
150 |
-
protected static function getUserMetaValue($
|
|
|
151 |
$value = null;
|
152 |
$id = get_current_user_id();
|
153 |
|
154 |
if (!empty($id)) { // Only authenticated users have some sort of meta
|
155 |
-
$meta = get_user_meta($id, $
|
156 |
|
157 |
// If $meta has only one value in the array, then extract it, otherwise
|
158 |
// return the array of values
|
@@ -175,24 +181,26 @@ final class AAM_Core_Policy_Token {
|
|
175 |
* @return mixed
|
176 |
*
|
177 |
* @access protected
|
178 |
-
* @
|
179 |
*/
|
180 |
-
protected static function getArgValue($prop, $args)
|
|
|
181 |
return (isset($args[$prop]) ? $args[$prop] : null);
|
182 |
}
|
183 |
|
184 |
/**
|
185 |
-
* Get
|
186 |
*
|
187 |
* @param string $prop
|
188 |
*
|
189 |
-
* @return
|
190 |
*
|
191 |
* @access protected
|
192 |
-
* @
|
193 |
*/
|
194 |
-
protected static function
|
195 |
-
|
|
|
196 |
}
|
197 |
|
198 |
/**
|
@@ -203,9 +211,10 @@ final class AAM_Core_Policy_Token {
|
|
203 |
* @return mixed
|
204 |
*
|
205 |
* @access protected
|
206 |
-
* @
|
207 |
*/
|
208 |
-
protected static function
|
|
|
209 |
return (defined($const) ? constant($const) : null);
|
210 |
}
|
211 |
|
5 |
* LICENSE: This file is subject to the terms and conditions defined in *
|
6 |
* file 'license.txt', which is part of this source code package. *
|
7 |
* ======================================================================
|
8 |
+
*
|
9 |
+
* @version 6.0.0
|
10 |
*/
|
11 |
|
12 |
/**
|
13 |
* AAM core policy token evaluator
|
14 |
*
|
15 |
* @package AAM
|
16 |
+
* @version 6.0.0
|
|
|
17 |
*/
|
18 |
+
class AAM_Core_Policy_Token
|
19 |
+
{
|
20 |
|
21 |
/**
|
22 |
* Literal map token's type to the executable method that returns actual value
|
24 |
* @var array
|
25 |
*
|
26 |
* @access protected
|
27 |
+
* @version 6.0.0
|
28 |
*/
|
29 |
protected static $map = array(
|
30 |
+
'USER' => 'AAM_Core_Policy_Token::getUserValue',
|
31 |
+
'USER_META' => 'AAM_Core_Policy_Token::getUserMetaValue',
|
32 |
+
'DATETIME' => 'date',
|
33 |
+
'HTTP_GET' => 'AAM_Core_Request::get',
|
34 |
+
'HTTP_QUERY' => 'AAM_Core_Request::get',
|
35 |
+
'HTTP_POST' => 'AAM_Core_Request::post',
|
36 |
+
'HTTP_COOKIE' => 'AAM_Core_Request::cookie',
|
37 |
+
'PHP_SERVER' => 'AAM_Core_Request::server',
|
38 |
+
'ARGS' => 'AAM_Core_Policy_Token::getArgValue',
|
39 |
+
'CONST' => 'AAM_Core_Policy_Token::getConstant',
|
40 |
+
'WP_OPTION' => 'AAM_Core_API::getOption',
|
41 |
+
'JWT' => 'AAM_Core_Policy_Token::getJwtClaim'
|
42 |
);
|
43 |
|
44 |
/**
|
46 |
*
|
47 |
* @param string $part String with tokens
|
48 |
* @param array $tokens Extracted token
|
49 |
+
* @param array $args Inline arguments
|
50 |
*
|
51 |
* @return string
|
52 |
*
|
53 |
* @access public
|
54 |
+
* @version 6.0.0
|
55 |
*/
|
56 |
+
public static function evaluate($part, array $tokens, array $args = array())
|
57 |
+
{
|
58 |
+
foreach ($tokens as $token) {
|
59 |
$val = self::getValue(
|
60 |
preg_replace('/^\$\{([^}]+)\}$/', '${1}', $token),
|
61 |
$args
|
80 |
* @return mixed
|
81 |
*
|
82 |
* @access protected
|
83 |
+
* @version 6.0.0
|
84 |
*/
|
85 |
+
protected static function getValue($token, $args)
|
86 |
+
{
|
87 |
$value = null;
|
88 |
$parts = explode('.', $token);
|
89 |
|
90 |
if (isset(self::$map[$parts[0]])) {
|
91 |
+
if ($parts[0] === 'ARGS') {
|
92 |
$value = call_user_func(self::$map[$parts[0]], $parts[1], $args);
|
93 |
} else {
|
94 |
$value = call_user_func(self::$map[$parts[0]], $parts[1]);
|
108 |
* @return mixed
|
109 |
*
|
110 |
* @access protected
|
111 |
+
* @version 6.0.0
|
112 |
*/
|
113 |
+
protected static function getUserValue($prop)
|
114 |
+
{
|
115 |
$user = AAM::getUser();
|
116 |
|
117 |
+
switch (strtolower($prop)) {
|
118 |
case 'ip':
|
119 |
case 'ipaddress':
|
120 |
$value = AAM_Core_Request::server('REMOTE_ADDR');
|
122 |
|
123 |
case 'authenticated':
|
124 |
case 'isauthenticated':
|
125 |
+
$value = is_user_logged_in();
|
126 |
break;
|
127 |
|
128 |
case 'capabilities':
|
129 |
case 'caps':
|
130 |
+
foreach ((array) $user->allcaps as $cap => $effect) {
|
|
|
131 |
if (!empty($effect)) {
|
132 |
$value[] = $cap;
|
133 |
}
|
145 |
/**
|
146 |
* Get user meta value(s)
|
147 |
*
|
148 |
+
* @param string $meta_key
|
149 |
*
|
150 |
* @return void
|
151 |
*
|
152 |
* @access protected
|
153 |
+
* @version 6.0.0
|
154 |
*/
|
155 |
+
protected static function getUserMetaValue($meta_key)
|
156 |
+
{
|
157 |
$value = null;
|
158 |
$id = get_current_user_id();
|
159 |
|
160 |
if (!empty($id)) { // Only authenticated users have some sort of meta
|
161 |
+
$meta = get_user_meta($id, $meta_key);
|
162 |
|
163 |
// If $meta has only one value in the array, then extract it, otherwise
|
164 |
// return the array of values
|
181 |
* @return mixed
|
182 |
*
|
183 |
* @access protected
|
184 |
+
* @version 6.0.0
|
185 |
*/
|
186 |
+
protected static function getArgValue($prop, $args)
|
187 |
+
{
|
188 |
return (isset($args[$prop]) ? $args[$prop] : null);
|
189 |
}
|
190 |
|
191 |
/**
|
192 |
+
* Get JWT claim property
|
193 |
*
|
194 |
* @param string $prop
|
195 |
*
|
196 |
+
* @return mixed
|
197 |
*
|
198 |
* @access protected
|
199 |
+
* @version 6.0.0
|
200 |
*/
|
201 |
+
protected static function getJwtClaim($prop)
|
202 |
+
{
|
203 |
+
return apply_filters('aam_get_jwt_claim', null, $prop);
|
204 |
}
|
205 |
|
206 |
/**
|
211 |
* @return mixed
|
212 |
*
|
213 |
* @access protected
|
214 |
+
* @version 6.0.0
|
215 |
*/
|
216 |
+
protected static function getConstant($const)
|
217 |
+
{
|
218 |
return (defined($const) ? constant($const) : null);
|
219 |
}
|
220 |
|
application/Core/Policy/Validator.php
CHANGED
@@ -5,122 +5,150 @@
|
|
5 |
* LICENSE: This file is subject to the terms and conditions defined in *
|
6 |
* file 'license.txt', which is part of this source code package. *
|
7 |
* ======================================================================
|
|
|
|
|
8 |
*/
|
9 |
|
10 |
use Composer\Semver\Semver;
|
11 |
|
12 |
/**
|
13 |
-
* AAM
|
14 |
-
*
|
15 |
* @package AAM
|
16 |
-
* @
|
17 |
-
* @since AAM v5.7.3
|
18 |
*/
|
19 |
-
class AAM_Core_Policy_Validator
|
20 |
-
|
|
|
21 |
/**
|
22 |
* Raw policy text
|
23 |
-
*
|
24 |
* @var string
|
25 |
-
*
|
26 |
-
* @access protected
|
|
|
27 |
*/
|
28 |
protected $policy;
|
29 |
-
|
30 |
/**
|
31 |
* Parsed JSON document
|
32 |
-
*
|
33 |
* @var array
|
34 |
-
*
|
35 |
-
* @access protected
|
|
|
36 |
*/
|
37 |
protected $json;
|
38 |
-
|
39 |
/**
|
40 |
* Collection of errors
|
41 |
-
*
|
42 |
* @var array
|
43 |
-
*
|
44 |
-
* @access protected
|
|
|
45 |
*/
|
46 |
protected $errors = array();
|
47 |
-
|
48 |
/**
|
49 |
* Constructor
|
50 |
-
*
|
51 |
* @param string $policy
|
52 |
-
*
|
|
|
|
|
53 |
* @access public
|
|
|
54 |
*/
|
55 |
-
public function __construct($policy)
|
|
|
56 |
$this->policy = trim($policy);
|
57 |
$this->json = json_decode($policy, true);
|
58 |
}
|
59 |
-
|
60 |
/**
|
61 |
-
* Validate the policy
|
62 |
-
*
|
63 |
* @return array
|
64 |
-
*
|
65 |
* @access public
|
|
|
66 |
*/
|
67 |
-
public function validate()
|
|
|
68 |
$steps = array(
|
69 |
'isJSON', // #1. Check if policy is valid JSON
|
70 |
'isNotEmpty', // #2. Check if policy is not empty
|
71 |
'isValidDependency', // #3. Check if all dependencies are defined properly
|
72 |
);
|
73 |
-
|
74 |
-
foreach($steps as $step) {
|
75 |
if (call_user_func(array($this, $step)) === false) {
|
76 |
break;
|
77 |
}
|
78 |
}
|
79 |
-
|
80 |
return $this->errors;
|
81 |
}
|
82 |
-
|
83 |
/**
|
84 |
* Check if policy is valid JSON
|
85 |
-
*
|
86 |
* @return boolean
|
87 |
-
*
|
88 |
-
* @access
|
|
|
89 |
*/
|
90 |
-
|
|
|
91 |
$result = is_array($this->json);
|
92 |
-
|
93 |
if ($result === false) {
|
94 |
$this->errors[] = __('The policy is not valid JSON object', AAM_KEY);
|
95 |
}
|
96 |
-
|
97 |
return $result;
|
98 |
}
|
99 |
-
|
100 |
/**
|
101 |
* Check if policy is empty
|
102 |
-
*
|
103 |
* @return boolean
|
104 |
-
*
|
105 |
-
* @access
|
|
|
106 |
*/
|
107 |
-
|
|
|
108 |
$result = !empty($this->policy) && !empty($this->json);
|
109 |
-
|
110 |
if ($result === false) {
|
111 |
$this->errors[] = __('The policy document is empty', AAM_KEY);
|
112 |
}
|
113 |
-
|
114 |
return $result;
|
115 |
}
|
116 |
-
|
117 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
118 |
if (!empty($this->json['Dependency'])) {
|
119 |
-
foreach($this->json['Dependency'] as $app => $constraints) {
|
120 |
try {
|
121 |
$satisfies = Semver::satisfies(
|
122 |
-
|
|
|
123 |
);
|
|
|
124 |
if ($satisfies === false) {
|
125 |
throw new Exception(
|
126 |
AAM_Backend_View_Helper::preparePhrase(
|
@@ -135,38 +163,63 @@ class AAM_Core_Policy_Validator {
|
|
135 |
}
|
136 |
}
|
137 |
}
|
138 |
-
|
139 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
140 |
global $wp_version;
|
141 |
-
|
142 |
-
|
|
|
|
|
143 |
$version = $wp_version;
|
144 |
} else {
|
145 |
-
$version = $this->getPluginVersion($
|
146 |
}
|
147 |
-
|
148 |
return $version;
|
149 |
}
|
150 |
-
|
151 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
152 |
static $plugins = null;
|
153 |
-
|
154 |
if (is_null($plugins)) {
|
155 |
if (file_exists(ABSPATH . 'wp-admin/includes/plugin.php')) {
|
156 |
require_once ABSPATH . 'wp-admin/includes/plugin.php';
|
157 |
}
|
158 |
-
|
159 |
$plugins = get_plugins();
|
160 |
}
|
161 |
-
|
162 |
$version = null;
|
163 |
-
|
164 |
-
foreach($plugins as $plugin => $data) {
|
165 |
if (stripos($plugin, $slug . '/') === 0) {
|
166 |
$version = $data['Version'];
|
167 |
}
|
168 |
}
|
169 |
-
|
170 |
if (is_null($version)) {
|
171 |
throw new Exception(
|
172 |
AAM_Backend_View_Helper::preparePhrase(
|
@@ -175,7 +228,8 @@ class AAM_Core_Policy_Validator {
|
|
175 |
)
|
176 |
);
|
177 |
}
|
178 |
-
|
179 |
return $version;
|
180 |
}
|
|
|
181 |
}
|
5 |
* LICENSE: This file is subject to the terms and conditions defined in *
|
6 |
* file 'license.txt', which is part of this source code package. *
|
7 |
* ======================================================================
|
8 |
+
*
|
9 |
+
* @version 6.0.0
|
10 |
*/
|
11 |
|
12 |
use Composer\Semver\Semver;
|
13 |
|
14 |
/**
|
15 |
+
* AAM access policy validator
|
16 |
+
*
|
17 |
* @package AAM
|
18 |
+
* @version 6.0.0
|
|
|
19 |
*/
|
20 |
+
class AAM_Core_Policy_Validator
|
21 |
+
{
|
22 |
+
|
23 |
/**
|
24 |
* Raw policy text
|
25 |
+
*
|
26 |
* @var string
|
27 |
+
*
|
28 |
+
* @access protected
|
29 |
+
* @version 6.0.0
|
30 |
*/
|
31 |
protected $policy;
|
32 |
+
|
33 |
/**
|
34 |
* Parsed JSON document
|
35 |
+
*
|
36 |
* @var array
|
37 |
+
*
|
38 |
+
* @access protected
|
39 |
+
* @version 6.0.0
|
40 |
*/
|
41 |
protected $json;
|
42 |
+
|
43 |
/**
|
44 |
* Collection of errors
|
45 |
+
*
|
46 |
* @var array
|
47 |
+
*
|
48 |
+
* @access protected
|
49 |
+
* @version 6.0.0
|
50 |
*/
|
51 |
protected $errors = array();
|
52 |
+
|
53 |
/**
|
54 |
* Constructor
|
55 |
+
*
|
56 |
* @param string $policy
|
57 |
+
*
|
58 |
+
* @return void
|
59 |
+
*
|
60 |
* @access public
|
61 |
+
* @version 6.0.0
|
62 |
*/
|
63 |
+
public function __construct($policy)
|
64 |
+
{
|
65 |
$this->policy = trim($policy);
|
66 |
$this->json = json_decode($policy, true);
|
67 |
}
|
68 |
+
|
69 |
/**
|
70 |
+
* Validate the policy by invoking several validation steps
|
71 |
+
*
|
72 |
* @return array
|
73 |
+
*
|
74 |
* @access public
|
75 |
+
* @version 6.0.0
|
76 |
*/
|
77 |
+
public function validate()
|
78 |
+
{
|
79 |
$steps = array(
|
80 |
'isJSON', // #1. Check if policy is valid JSON
|
81 |
'isNotEmpty', // #2. Check if policy is not empty
|
82 |
'isValidDependency', // #3. Check if all dependencies are defined properly
|
83 |
);
|
84 |
+
|
85 |
+
foreach ($steps as $step) {
|
86 |
if (call_user_func(array($this, $step)) === false) {
|
87 |
break;
|
88 |
}
|
89 |
}
|
90 |
+
|
91 |
return $this->errors;
|
92 |
}
|
93 |
+
|
94 |
/**
|
95 |
* Check if policy is valid JSON
|
96 |
+
*
|
97 |
* @return boolean
|
98 |
+
*
|
99 |
+
* @access protected
|
100 |
+
* @version 6.0.0
|
101 |
*/
|
102 |
+
protected function isJSON()
|
103 |
+
{
|
104 |
$result = is_array($this->json);
|
105 |
+
|
106 |
if ($result === false) {
|
107 |
$this->errors[] = __('The policy is not valid JSON object', AAM_KEY);
|
108 |
}
|
109 |
+
|
110 |
return $result;
|
111 |
}
|
112 |
+
|
113 |
/**
|
114 |
* Check if policy is empty
|
115 |
+
*
|
116 |
* @return boolean
|
117 |
+
*
|
118 |
+
* @access protected
|
119 |
+
* @version 6.0.0
|
120 |
*/
|
121 |
+
protected function isNotEmpty()
|
122 |
+
{
|
123 |
$result = !empty($this->policy) && !empty($this->json);
|
124 |
+
|
125 |
if ($result === false) {
|
126 |
$this->errors[] = __('The policy document is empty', AAM_KEY);
|
127 |
}
|
128 |
+
|
129 |
return $result;
|
130 |
}
|
131 |
+
|
132 |
+
/**
|
133 |
+
* Check for the policy dependencies
|
134 |
+
*
|
135 |
+
* Make sure that depending plugins are installed and have proper versions
|
136 |
+
*
|
137 |
+
* @return void
|
138 |
+
*
|
139 |
+
* @access protected
|
140 |
+
* @version 6.0.0
|
141 |
+
*/
|
142 |
+
protected function isValidDependency()
|
143 |
+
{
|
144 |
if (!empty($this->json['Dependency'])) {
|
145 |
+
foreach ($this->json['Dependency'] as $app => $constraints) {
|
146 |
try {
|
147 |
$satisfies = Semver::satisfies(
|
148 |
+
$this->getAppVersion($app),
|
149 |
+
$constraints
|
150 |
);
|
151 |
+
|
152 |
if ($satisfies === false) {
|
153 |
throw new Exception(
|
154 |
AAM_Backend_View_Helper::preparePhrase(
|
163 |
}
|
164 |
}
|
165 |
}
|
166 |
+
|
167 |
+
/**
|
168 |
+
* Get dependency's version
|
169 |
+
*
|
170 |
+
* @param string $app
|
171 |
+
*
|
172 |
+
* @return void
|
173 |
+
*
|
174 |
+
* @access protected
|
175 |
+
* @version 6.0.0
|
176 |
+
*/
|
177 |
+
protected function getAppVersion($app)
|
178 |
+
{
|
179 |
global $wp_version;
|
180 |
+
|
181 |
+
$slug = strtolower($app);
|
182 |
+
|
183 |
+
if ($slug === 'wordpress') {
|
184 |
$version = $wp_version;
|
185 |
} else {
|
186 |
+
$version = $this->getPluginVersion($slug);
|
187 |
}
|
188 |
+
|
189 |
return $version;
|
190 |
}
|
191 |
+
|
192 |
+
/**
|
193 |
+
* Get plugin's version
|
194 |
+
*
|
195 |
+
* @param string $slug
|
196 |
+
*
|
197 |
+
* @return string
|
198 |
+
*
|
199 |
+
* @access protected
|
200 |
+
* @throws Exception
|
201 |
+
* @version 6.0.0
|
202 |
+
*/
|
203 |
+
protected function getPluginVersion($slug)
|
204 |
+
{
|
205 |
static $plugins = null;
|
206 |
+
|
207 |
if (is_null($plugins)) {
|
208 |
if (file_exists(ABSPATH . 'wp-admin/includes/plugin.php')) {
|
209 |
require_once ABSPATH . 'wp-admin/includes/plugin.php';
|
210 |
}
|
211 |
+
|
212 |
$plugins = get_plugins();
|
213 |
}
|
214 |
+
|
215 |
$version = null;
|
216 |
+
|
217 |
+
foreach ($plugins as $plugin => $data) {
|
218 |
if (stripos($plugin, $slug . '/') === 0) {
|
219 |
$version = $data['Version'];
|
220 |
}
|
221 |
}
|
222 |
+
|
223 |
if (is_null($version)) {
|
224 |
throw new Exception(
|
225 |
AAM_Backend_View_Helper::preparePhrase(
|
228 |
)
|
229 |
);
|
230 |
}
|
231 |
+
|
232 |
return $version;
|
233 |
}
|
234 |
+
|
235 |
}
|
application/Core/Subject.php
CHANGED
@@ -105,7 +105,7 @@ abstract class AAM_Core_Subject
|
|
105 |
_doing_it_wrong(
|
106 |
static::class . '::' . $name,
|
107 |
'Subject does not have method defined',
|
108 |
-
|
109 |
);
|
110 |
}
|
111 |
|
@@ -334,7 +334,7 @@ abstract class AAM_Core_Subject
|
|
334 |
)->getOption();
|
335 |
|
336 |
// Merge access settings while reading hierarchical chain
|
337 |
-
$option =
|
338 |
|
339 |
// Merge access settings if multi-roles option is enabled
|
340 |
$multi = AAM::api()->getConfig('core.settings.multiSubject', false);
|
105 |
_doing_it_wrong(
|
106 |
static::class . '::' . $name,
|
107 |
'Subject does not have method defined',
|
108 |
+
AAM_VERSION
|
109 |
);
|
110 |
}
|
111 |
|
334 |
)->getOption();
|
335 |
|
336 |
// Merge access settings while reading hierarchical chain
|
337 |
+
$option = array_replace_recursive($option, $object->getOption());
|
338 |
|
339 |
// Merge access settings if multi-roles option is enabled
|
340 |
$multi = AAM::api()->getConfig('core.settings.multiSubject', false);
|
application/Core/Subject/Role.php
CHANGED
@@ -35,6 +35,16 @@ class AAM_Core_Subject_Role extends AAM_Core_Subject
|
|
35 |
*/
|
36 |
protected $name;
|
37 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
38 |
/**
|
39 |
* Constructor
|
40 |
*
|
@@ -193,11 +203,6 @@ class AAM_Core_Subject_Role extends AAM_Core_Subject
|
|
193 |
$has = $this->has_cap($cap);
|
194 |
}
|
195 |
|
196 |
-
// Override result if necessary
|
197 |
-
if (apply_filters('aam_allowed_cap_filter', true, $cap) === false) {
|
198 |
-
$has = false;
|
199 |
-
}
|
200 |
-
|
201 |
return $has;
|
202 |
}
|
203 |
|
@@ -207,11 +212,15 @@ class AAM_Core_Subject_Role extends AAM_Core_Subject
|
|
207 |
*/
|
208 |
public function getParent()
|
209 |
{
|
210 |
-
|
211 |
-
|
212 |
-
|
213 |
-
|
214 |
-
|
|
|
|
|
|
|
|
|
215 |
}
|
216 |
|
217 |
/**
|
35 |
*/
|
36 |
protected $name;
|
37 |
|
38 |
+
/**
|
39 |
+
* Parent role's subject
|
40 |
+
*
|
41 |
+
* @var AAM_Core_Subject
|
42 |
+
*
|
43 |
+
* @access private
|
44 |
+
* @version 6.0.0
|
45 |
+
*/
|
46 |
+
private $_parent = null;
|
47 |
+
|
48 |
/**
|
49 |
* Constructor
|
50 |
*
|
203 |
$has = $this->has_cap($cap);
|
204 |
}
|
205 |
|
|
|
|
|
|
|
|
|
|
|
206 |
return $has;
|
207 |
}
|
208 |
|
212 |
*/
|
213 |
public function getParent()
|
214 |
{
|
215 |
+
if (is_null($this->_parent)) {
|
216 |
+
$this->_parent = apply_filters(
|
217 |
+
'aam_parent_role_filter',
|
218 |
+
AAM_Core_Subject_Default::getInstance(),
|
219 |
+
$this
|
220 |
+
);
|
221 |
+
}
|
222 |
+
|
223 |
+
return $this->_parent;
|
224 |
}
|
225 |
|
226 |
/**
|
application/Core/Subject/User.php
CHANGED
@@ -55,27 +55,35 @@ class AAM_Core_Subject_User extends AAM_Core_Subject
|
|
55 |
/**
|
56 |
* Constructor
|
57 |
*
|
58 |
-
* @param int
|
59 |
-
* @param boolean $initialize
|
60 |
*
|
61 |
* @return void
|
62 |
*
|
63 |
* @access public
|
64 |
* @version 6.0.0
|
65 |
*/
|
66 |
-
public function __construct($id
|
67 |
{
|
68 |
// Set subject Id
|
69 |
$this->setId(intval($id));
|
70 |
|
71 |
// Retrieve underlining WP core principal
|
72 |
$this->setPrincipal($this->retrievePrincipal());
|
|
|
73 |
|
74 |
-
|
75 |
-
|
76 |
-
|
77 |
-
|
78 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
79 |
}
|
80 |
|
81 |
/**
|
55 |
/**
|
56 |
* Constructor
|
57 |
*
|
58 |
+
* @param int $id
|
|
|
59 |
*
|
60 |
* @return void
|
61 |
*
|
62 |
* @access public
|
63 |
* @version 6.0.0
|
64 |
*/
|
65 |
+
public function __construct($id)
|
66 |
{
|
67 |
// Set subject Id
|
68 |
$this->setId(intval($id));
|
69 |
|
70 |
// Retrieve underlining WP core principal
|
71 |
$this->setPrincipal($this->retrievePrincipal());
|
72 |
+
}
|
73 |
|
74 |
+
/**
|
75 |
+
* Initialize user subject
|
76 |
+
*
|
77 |
+
* @return void
|
78 |
+
*
|
79 |
+
* @access public
|
80 |
+
* @version 6.0.0
|
81 |
+
*/
|
82 |
+
public function initialize()
|
83 |
+
{
|
84 |
+
// Initialize current user. This hook is used by Access Policy service to
|
85 |
+
// mutate the capability and role lists for current user
|
86 |
+
do_action('aam_initialize_user_action', $this);
|
87 |
}
|
88 |
|
89 |
/**
|
application/Service/AccessPolicy.php
CHANGED
@@ -5,24 +5,42 @@
|
|
5 |
* LICENSE: This file is subject to the terms and conditions defined in *
|
6 |
* file 'license.txt', which is part of this source code package. *
|
7 |
* ======================================================================
|
|
|
|
|
8 |
*/
|
9 |
|
10 |
/**
|
11 |
* Access Policy service
|
12 |
*
|
13 |
-
* @
|
|
|
14 |
*/
|
15 |
class AAM_Service_AccessPolicy
|
16 |
{
|
17 |
-
use AAM_Core_Contract_ServiceTrait
|
|
|
18 |
|
19 |
/**
|
20 |
* AAM configuration setting that is associated with the feature
|
|
|
|
|
21 |
*/
|
22 |
const FEATURE_FLAG = 'core.service.access-policy.enabled';
|
23 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
24 |
/**
|
25 |
* Constructor
|
|
|
|
|
|
|
|
|
|
|
26 |
*/
|
27 |
protected function __construct()
|
28 |
{
|
@@ -33,15 +51,6 @@ class AAM_Service_AccessPolicy
|
|
33 |
AAM_Backend_Feature_Main_Policy::register();
|
34 |
}, 40);
|
35 |
|
36 |
-
//manager Admin Menu
|
37 |
-
if (is_multisite() && is_network_admin()) {
|
38 |
-
//register AAM in the network admin panel
|
39 |
-
add_action('_network_admin_menu', array($this, 'registerAdminMenu'));
|
40 |
-
} else {
|
41 |
-
add_action('_user_admin_menu', array($this, 'registerAdminMenu'));
|
42 |
-
add_action('_admin_menu', array($this, 'registerAdminMenu'));
|
43 |
-
}
|
44 |
-
|
45 |
//register custom access control metabox
|
46 |
add_action('add_meta_boxes', array($this, 'registerMetaboxes'));
|
47 |
|
@@ -55,7 +64,7 @@ class AAM_Service_AccessPolicy
|
|
55 |
add_filter('aam_service_list_filter', function ($services) {
|
56 |
$services[] = array(
|
57 |
'title' => __('Access Policies', AAM_KEY),
|
58 |
-
'description' => __('Manage
|
59 |
'setting' => self::FEATURE_FLAG
|
60 |
);
|
61 |
|
@@ -68,6 +77,44 @@ class AAM_Service_AccessPolicy
|
|
68 |
}
|
69 |
}
|
70 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
71 |
/**
|
72 |
* Hook into policy submission and filter its content
|
73 |
*
|
@@ -76,14 +123,15 @@ class AAM_Service_AccessPolicy
|
|
76 |
* @return array
|
77 |
*
|
78 |
* @access public
|
|
|
79 |
*/
|
80 |
public function managePolicyContent($data)
|
81 |
{
|
82 |
-
if (isset($data['post_type']) && ($data['post_type'] ===
|
83 |
-
$content =
|
84 |
|
85 |
if (empty($data['post_content'])) {
|
86 |
-
$content =
|
87 |
}
|
88 |
|
89 |
// Reformat the policy content
|
@@ -109,6 +157,7 @@ class AAM_Service_AccessPolicy
|
|
109 |
* @return void
|
110 |
*
|
111 |
* @access protected
|
|
|
112 |
*/
|
113 |
protected function initializeHooks()
|
114 |
{
|
@@ -117,13 +166,14 @@ class AAM_Service_AccessPolicy
|
|
117 |
register_post_type('aam_policy', array(
|
118 |
'label' => __('Access Policy', AAM_KEY),
|
119 |
'labels' => array(
|
120 |
-
'name'
|
121 |
-
'edit_item'
|
122 |
-
'
|
123 |
-
'
|
|
|
124 |
),
|
125 |
'description' => __('Access and security policy', AAM_KEY),
|
126 |
-
'public' =>
|
127 |
'show_ui' => true,
|
128 |
'show_in_menu' => false,
|
129 |
'exclude_from_search' => true,
|
@@ -143,203 +193,191 @@ class AAM_Service_AccessPolicy
|
|
143 |
));
|
144 |
});
|
145 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
146 |
// Manage access to the Capabilities
|
147 |
-
add_filter('
|
|
|
148 |
|
149 |
// Manage access to the Plugin list and individual plugins
|
150 |
add_filter('aam_allowed_plugin_action_filter', array($this, 'isPluginActionAllowed'), 10, 3);
|
151 |
-
|
152 |
-
// Manage access settings for the Objects
|
153 |
-
add_filter('aam_admin_menu_object_option_filter', array($this, 'initMenuObjectOptions'), 10, 2);
|
154 |
-
add_filter('aam_metabox_object_option_filter', array($this, 'initMetaboxObjectOptions'), 10, 2);
|
155 |
-
add_filter('aam-post-access-filter', array($this, 'initPostAccessOptions'), 10, 2);
|
156 |
-
add_filter('aam_route_object_option_filter', array($this, 'initRouteObjectOptions'), 10, 2);
|
157 |
-
add_filter('aam_toolbar_object_option_filter', array($this, 'initToolbarObjectOptions'), 10, 2);
|
158 |
-
add_filter('aam_uri_object_option_filter', array($this, 'initUriObjectOptions'), 10, 2);
|
159 |
-
|
160 |
-
// Visibility initialization process
|
161 |
-
add_action('aam_visibility_object_init_action', array($this, 'initVisibilityObject'), 1);
|
162 |
-
|
163 |
-
// User initialization process
|
164 |
-
add_action('aam_initialize_user_action', array($this, 'initializeUser'));
|
165 |
-
|
166 |
-
// Convert Access Policy settings into AAM core settings
|
167 |
-
add_filter('aam-policy-posts-terms-settings-filter', array($this, 'convertContentSettings'), 10, 5);
|
168 |
}
|
169 |
|
170 |
/**
|
|
|
171 |
*
|
172 |
-
* @
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
173 |
*/
|
174 |
-
public function
|
175 |
{
|
176 |
-
|
177 |
-
|
178 |
-
|
179 |
-
add_meta_box(
|
180 |
-
'aam-policy',
|
181 |
-
__('Access Policy Document', AAM_KEY),
|
182 |
-
function () {
|
183 |
-
global $post;
|
184 |
-
|
185 |
-
if (is_a($post, 'WP_Post')) {
|
186 |
-
echo $this->renderPolicyMetabox($post);
|
187 |
-
}
|
188 |
-
},
|
189 |
-
null,
|
190 |
-
'normal',
|
191 |
-
'high'
|
192 |
-
);
|
193 |
-
add_meta_box(
|
194 |
-
'aam-policy-attached',
|
195 |
-
__('Access Policy Assignee', AAM_KEY),
|
196 |
-
function () {
|
197 |
-
global $post;
|
198 |
|
199 |
-
|
200 |
-
|
201 |
-
}
|
202 |
-
},
|
203 |
-
null,
|
204 |
-
'side'
|
205 |
-
);
|
206 |
}
|
207 |
-
}
|
208 |
|
209 |
-
|
210 |
-
*
|
211 |
-
* @param type $post
|
212 |
-
* @return type
|
213 |
-
*/
|
214 |
-
public function renderPolicyMetabox($post)
|
215 |
-
{
|
216 |
-
return $this->loadTemplate(
|
217 |
-
dirname(__FILE__) . '/phtml/metabox/policy-metabox.phtml',
|
218 |
-
(object) array('post' => $post)
|
219 |
-
);
|
220 |
}
|
221 |
|
222 |
/**
|
|
|
223 |
*
|
224 |
-
* @param
|
225 |
-
* @
|
226 |
-
*/
|
227 |
-
public function renderPolicyPrincipalMetabox($post)
|
228 |
-
{
|
229 |
-
return $this->loadTemplate(
|
230 |
-
dirname(__FILE__) . '/phtml/metabox/policy-principal-metabox.phtml',
|
231 |
-
(object) array('post' => $post)
|
232 |
-
);
|
233 |
-
}
|
234 |
-
|
235 |
-
/**
|
236 |
-
* Check if specified action is allowed upon capability
|
237 |
-
*
|
238 |
-
* @param boolean $allowed
|
239 |
-
* @param string $cap
|
240 |
-
* @param string $action
|
241 |
*
|
242 |
-
* @return
|
243 |
*
|
244 |
* @access public
|
245 |
-
* @
|
|
|
246 |
*/
|
247 |
-
public function
|
248 |
{
|
249 |
-
$manager =
|
|
|
|
|
250 |
|
251 |
-
|
252 |
-
$
|
253 |
-
} else {
|
254 |
-
$result = $manager->isAllowed("Capability:{$cap}");
|
255 |
}
|
256 |
|
257 |
-
return $
|
258 |
}
|
259 |
|
260 |
/**
|
261 |
-
*
|
262 |
*
|
263 |
-
* @
|
|
|
|
|
|
|
264 |
*
|
265 |
* @access public
|
|
|
|
|
266 |
*/
|
267 |
-
public function
|
268 |
{
|
269 |
-
|
270 |
-
|
271 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
272 |
}
|
273 |
|
274 |
/**
|
275 |
-
* Check if
|
276 |
*
|
277 |
-
* @param boolean
|
278 |
-
* @param string
|
279 |
-
* @param string
|
280 |
*
|
281 |
* @return boolean
|
282 |
*
|
283 |
* @access public
|
284 |
-
* @link https://aamplugin.com/reference/policy#
|
|
|
285 |
*/
|
286 |
-
public function
|
287 |
{
|
288 |
-
$manager =
|
|
|
289 |
|
290 |
-
|
291 |
-
$result = $manager->isAllowed("Plugin:WP:{$action}");
|
292 |
-
} else {
|
293 |
-
$result = $manager->isAllowed("Plugin:{$slug}:WP:{$action}");
|
294 |
-
}
|
295 |
-
|
296 |
-
return $result;
|
297 |
}
|
298 |
|
299 |
/**
|
300 |
-
* Initialize
|
301 |
*
|
302 |
-
* @param
|
303 |
-
* @param AAM_Core_Subject $subject
|
304 |
*
|
305 |
-
* @return
|
306 |
*
|
307 |
* @access public
|
308 |
-
* @
|
|
|
|
|
309 |
*/
|
310 |
-
public function
|
311 |
{
|
312 |
-
$
|
|
|
313 |
|
314 |
-
|
315 |
-
|
316 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
317 |
}
|
318 |
|
319 |
-
|
320 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
321 |
|
322 |
-
|
323 |
-
|
324 |
-
|
325 |
-
* @param array $option
|
326 |
-
* @param AAM_Core_Subject $subject
|
327 |
-
*
|
328 |
-
* @return array
|
329 |
-
*
|
330 |
-
* @access public
|
331 |
-
* @see https://aamplugin.com/reference/policy#metabox
|
332 |
-
*/
|
333 |
-
public function initMetaboxObjectOptions($option, AAM_Core_Subject $subject)
|
334 |
-
{
|
335 |
-
$stms = $this->getPolicyManager($subject)->find("/^(Metabox|Widget):/i");
|
336 |
|
337 |
-
|
338 |
-
|
339 |
-
|
|
|
340 |
}
|
341 |
|
342 |
-
|
|
|
|
|
|
|
343 |
}
|
344 |
|
345 |
/**
|
@@ -353,153 +391,144 @@ class AAM_Service_AccessPolicy
|
|
353 |
* @access public
|
354 |
* @see https://aamplugin.com/reference/policy#post
|
355 |
*/
|
356 |
-
public function
|
357 |
{
|
358 |
-
$
|
359 |
-
|
360 |
-
|
361 |
-
|
362 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
363 |
|
364 |
-
|
|
|
|
|
365 |
|
366 |
-
|
367 |
-
|
368 |
-
|
369 |
-
|
370 |
-
|
371 |
-
|
372 |
-
|
373 |
-
|
374 |
-
|
375 |
-
|
376 |
-
$stm['Effect'] === 'deny',
|
377 |
-
'',
|
378 |
-
($action === 'read' ? $meta : array()),
|
379 |
-
array($post)
|
380 |
-
)
|
381 |
-
);
|
382 |
}
|
383 |
|
384 |
-
return $option;
|
385 |
}
|
386 |
|
387 |
/**
|
388 |
-
*
|
389 |
*
|
390 |
-
* @param array
|
391 |
-
* @param
|
|
|
392 |
*
|
393 |
-
* @return
|
394 |
*
|
395 |
-
* @access
|
396 |
-
* @
|
397 |
*/
|
398 |
-
|
399 |
{
|
400 |
-
$
|
401 |
-
|
402 |
-
foreach ($stms as $key => $stm) {
|
403 |
-
$chunks = explode(':', $key);
|
404 |
-
$method = (isset($chunks[3]) ? $chunks[3] : 'post');
|
405 |
-
$id = "{$chunks[1]}|{$chunks[2]}|{$method}";
|
406 |
-
|
407 |
-
$option[$id] = ($stm['Effect'] === 'deny' ? 1 : 0);
|
408 |
-
}
|
409 |
-
|
410 |
-
return $option;
|
411 |
}
|
412 |
|
413 |
/**
|
414 |
-
*
|
415 |
*
|
416 |
-
* @param array
|
417 |
-
* @param
|
418 |
*
|
419 |
-
* @return
|
420 |
*
|
421 |
-
* @access
|
422 |
-
* @see https://aamplugin.com/reference/policy#toolbar
|
423 |
*/
|
424 |
-
|
425 |
{
|
426 |
-
$
|
427 |
|
428 |
-
|
429 |
-
$
|
430 |
-
$option[$chunks[1]] = ($stm['Effect'] === 'deny' ? 1 : 0);
|
431 |
-
}
|
432 |
|
433 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
434 |
}
|
435 |
|
436 |
/**
|
437 |
-
*
|
438 |
*
|
439 |
-
* @param array
|
440 |
-
* @param AAM_Core_Subject $subject
|
441 |
*
|
442 |
* @return array
|
443 |
*
|
444 |
-
* @access
|
445 |
-
* @
|
446 |
*/
|
447 |
-
|
448 |
{
|
449 |
-
$
|
|
|
|
|
|
|
450 |
|
451 |
-
|
452 |
-
$chunks = explode(':', $key);
|
453 |
-
$effect = ($stm['Effect'] === 'deny' ? 1 : 0);
|
454 |
-
$type = $stm['Effect'];
|
455 |
-
$destination = null;
|
456 |
-
$code = null;
|
457 |
-
|
458 |
-
if ($effect === 1 && !empty($stm['Metadata']['Redirect'])) {
|
459 |
-
$redirect = $stm['Metadata']['Redirect'];
|
460 |
-
$type = strtolower($redirect['Type']);
|
461 |
-
$code = isset($redirect['Code']) ? $redirect['Code'] : 307;
|
462 |
-
|
463 |
-
switch ($type) {
|
464 |
-
case 'message':
|
465 |
-
$destination = $redirect['Message'];
|
466 |
-
break;
|
467 |
-
|
468 |
-
case 'page':
|
469 |
-
if (isset($redirect['Id'])) {
|
470 |
-
$destination = intval($redirect['Id']);
|
471 |
-
} elseif (isset($redirect['Slug'])) {
|
472 |
-
$page = get_page_by_path($redirect['Slug'], OBJECT);
|
473 |
-
$destination = (is_a($page, 'WP_Post') ? $page->ID : 0);
|
474 |
-
}
|
475 |
-
break;
|
476 |
-
|
477 |
-
case 'url':
|
478 |
-
$destination = filter_var(
|
479 |
-
$redirect['URL'],
|
480 |
-
FILTER_VALIDATE_URL
|
481 |
-
);
|
482 |
-
if (empty($destination)) {
|
483 |
-
$type = 'message';
|
484 |
-
$destination = "Invalid URL: [{$redirect['URL']}]";
|
485 |
-
}
|
486 |
-
break;
|
487 |
-
|
488 |
-
case 'callback':
|
489 |
-
$destination = $redirect['Callback'];
|
490 |
-
break;
|
491 |
-
}
|
492 |
-
}
|
493 |
|
494 |
-
|
495 |
-
|
496 |
-
'
|
497 |
-
|
498 |
-
'
|
499 |
-
|
|
|
|
|
|
|
|
|
|
|
500 |
}
|
501 |
|
502 |
-
|
|
|
|
|
503 |
}
|
504 |
|
505 |
/**
|
@@ -511,289 +540,205 @@ class AAM_Service_AccessPolicy
|
|
511 |
*
|
512 |
* @access public
|
513 |
*/
|
514 |
-
public function
|
515 |
{
|
516 |
-
$
|
517 |
-
|
518 |
-
// Read all the settings from the Access & Security Policies
|
519 |
-
$stms = AAM_Core_Policy_Factory::get($subject)->find("/^post:(.*):list$/");
|
520 |
|
521 |
-
foreach
|
522 |
-
$chunks = explode(':', $
|
|
|
523 |
|
524 |
-
|
525 |
-
|
526 |
-
|
527 |
-
|
528 |
-
|
529 |
-
OBJECT,
|
530 |
-
$
|
531 |
-
|
532 |
-
$postId = (is_a($post, 'WP_Post') ? $post->ID : 0);
|
533 |
-
}
|
534 |
|
535 |
-
|
536 |
-
|
537 |
-
|
538 |
-
|
539 |
-
|
540 |
-
|
541 |
-
"hidden" => ($stm['Effect'] === 'deny' ? 1 : 0)
|
542 |
-
)
|
543 |
-
);
|
544 |
}
|
545 |
}
|
546 |
}
|
547 |
|
548 |
/**
|
549 |
-
* Initialize
|
550 |
*
|
551 |
-
* @param
|
|
|
552 |
*
|
553 |
-
* @return
|
554 |
*
|
555 |
* @access public
|
556 |
-
* @
|
557 |
-
* @link https://aamplugin.com/reference/policy#role
|
558 |
*/
|
559 |
-
public function
|
560 |
{
|
561 |
-
$
|
562 |
-
$
|
563 |
-
|
564 |
-
// Retrieve all capabilities set in Access Policy
|
565 |
-
// Load Capabilities from the policy
|
566 |
-
$policyCaps = array();
|
567 |
|
568 |
-
foreach
|
569 |
-
$
|
570 |
-
$
|
571 |
-
}
|
572 |
-
|
573 |
-
// Load Roles from the policy
|
574 |
-
$roles = (array)$subject->roles;
|
575 |
-
$allRoles = AAM_Core_API::getRoles();
|
576 |
-
$roleCaps = array();
|
577 |
-
|
578 |
-
foreach ($manager->find("/^Role:/i") as $key => $stm) {
|
579 |
-
$chunks = explode(':', $key);
|
580 |
|
581 |
-
if ($
|
582 |
-
|
583 |
-
|
584 |
-
|
585 |
-
|
586 |
-
|
587 |
-
|
588 |
-
|
589 |
-
|
590 |
-
|
591 |
-
foreach ($roles as $i => $role) {
|
592 |
-
if ($role === $chunks[1]) {
|
593 |
-
unset($roles[$i]);
|
594 |
-
}
|
595 |
-
}
|
596 |
-
}
|
597 |
-
}
|
598 |
-
|
599 |
-
//reset the user capabilities
|
600 |
-
$subject->allcaps = array_merge($subject->allcaps, $roleCaps, $policyCaps);
|
601 |
-
|
602 |
-
//make sure that no capabilities are going outside of define boundary
|
603 |
-
$subject->allcaps = $this->applyCapabilityBoundaries($manager, $subject->allcaps);
|
604 |
-
$subject->caps = $this->applyCapabilityBoundaries($manager, $subject->caps);
|
605 |
-
|
606 |
-
// also delete all capabilities that are assigned to denied role ONLY
|
607 |
-
// $diff contains the list of roles that were denied for user
|
608 |
-
$diff = array_diff_key($subject->roles, $roles);
|
609 |
-
|
610 |
-
// prepare the list of capabilities that potentially should be removed from
|
611 |
-
// user
|
612 |
-
$removeCaps = array();
|
613 |
-
foreach ($diff as $role) {
|
614 |
-
$removeCaps = array_merge($removeCaps, $allRoles->get_role($role)->capabilities);
|
615 |
-
}
|
616 |
-
|
617 |
-
// prepare the list of capabilities that should still be assigned to user
|
618 |
-
$keepCaps = array();
|
619 |
-
foreach ($roles as $role) {
|
620 |
-
if ($allRoles->is_role($role)) {
|
621 |
-
$keepCaps = array_merge($keepCaps, $allRoles->get_role($role)->capabilities);
|
622 |
-
}
|
623 |
-
}
|
624 |
-
|
625 |
-
foreach (array_keys($removeCaps) as $key) {
|
626 |
-
if (!array_key_exists($key, $keepCaps)) {
|
627 |
-
unset($subject->allcaps[$key]);
|
628 |
-
if (isset($subject->caps[$key])) {
|
629 |
-
unset($subject->caps[$key]);
|
630 |
-
}
|
631 |
}
|
632 |
}
|
633 |
|
634 |
-
$
|
635 |
}
|
636 |
|
637 |
/**
|
638 |
-
*
|
639 |
*
|
640 |
-
* @param
|
641 |
-
* @param array $caps
|
642 |
*
|
643 |
* @return array
|
644 |
*
|
645 |
* @access protected
|
|
|
646 |
*/
|
647 |
-
protected function
|
648 |
{
|
649 |
-
$
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
650 |
|
651 |
-
|
652 |
-
|
653 |
-
|
654 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
655 |
}
|
656 |
|
657 |
-
return
|
|
|
|
|
|
|
|
|
658 |
}
|
659 |
|
660 |
/**
|
661 |
-
*
|
662 |
*
|
663 |
-
* @
|
|
|
|
|
|
|
|
|
664 |
*
|
665 |
* @access public
|
|
|
|
|
666 |
*/
|
667 |
-
public function
|
668 |
{
|
669 |
-
|
670 |
-
add_submenu_page(
|
671 |
-
'aam',
|
672 |
-
'Access Policies',
|
673 |
-
'Access Policies',
|
674 |
-
AAM_Core_Config::get(
|
675 |
-
'policy.capability',
|
676 |
-
(AAM_Core_API::capExists('aam_manage_policy') ? 'aam_manage_policy' : 'administrator')
|
677 |
-
),
|
678 |
-
'edit.php?post_type=aam_policy'
|
679 |
-
);
|
680 |
|
681 |
-
$
|
682 |
-
|
683 |
-
|
684 |
-
|
685 |
-
'Add New Policies',
|
686 |
-
'Add New Policies',
|
687 |
-
$type->cap->create_posts,
|
688 |
-
'post-new.php?post_type=aam_policy'
|
689 |
-
);
|
690 |
}
|
|
|
|
|
691 |
}
|
692 |
|
693 |
/**
|
694 |
-
*
|
695 |
*
|
696 |
-
* @param
|
697 |
-
* @param bool|int $effect
|
698 |
-
* @param string $prefix
|
699 |
-
* @param array $meta
|
700 |
-
* @param array $args
|
701 |
*
|
702 |
* @return array
|
|
|
|
|
|
|
703 |
*/
|
704 |
-
public function
|
705 |
{
|
706 |
-
$
|
|
|
707 |
|
708 |
-
|
709 |
-
$
|
710 |
-
|
711 |
-
"{$prefix}protected" => true
|
712 |
-
);
|
713 |
-
}
|
714 |
|
715 |
-
|
716 |
-
|
717 |
-
$res = AAM_Core_Policy_Token::evaluate($meta['Teaser']['Value'], $match[1], $args);
|
718 |
-
} else {
|
719 |
-
$res = $meta['Teaser']['Value'];
|
720 |
}
|
721 |
-
|
722 |
-
$result = array_merge($result, array(
|
723 |
-
"{$prefix}teaser" => $res,
|
724 |
-
"{$prefix}limit" => true,
|
725 |
-
));
|
726 |
}
|
727 |
|
728 |
-
|
729 |
-
|
730 |
-
$type = (isset($meta['Redirect']['Type']) ? $meta['Redirect']['Type'] : 'message');
|
731 |
-
switch ($type) {
|
732 |
-
case 'page':
|
733 |
-
if (isset($meta['Redirect']['Id'])) {
|
734 |
-
$destination = intval($meta['Redirect']['Id']);
|
735 |
-
} elseif (isset($meta['Redirect']['Slug'])) {
|
736 |
-
$page = get_page_by_path(
|
737 |
-
$meta['Redirect']['Slug'],
|
738 |
-
OBJECT
|
739 |
-
);
|
740 |
-
$destination = (is_a($page, 'WP_Post') ? $page->ID : 0);
|
741 |
-
}
|
742 |
-
if (isset($meta['Redirect']['Code'])) {
|
743 |
-
$destination .= "|{$meta['Redirect']['Code']}";
|
744 |
-
} else {
|
745 |
-
$destination .= "|307";
|
746 |
-
}
|
747 |
-
break;
|
748 |
-
|
749 |
-
case 'url':
|
750 |
-
$destination = filter_var(
|
751 |
-
$meta['Redirect']['URL'],
|
752 |
-
FILTER_VALIDATE_URL
|
753 |
-
);
|
754 |
-
if (empty($destination)) {
|
755 |
-
$type = 'message';
|
756 |
-
$destination = "Invalid URL: [{$meta['Redirect']['URL']}]";
|
757 |
-
}
|
758 |
-
if (isset($meta['Redirect']['Code'])) {
|
759 |
-
$destination .= "|{$meta['Redirect']['Code']}";
|
760 |
-
} else {
|
761 |
-
$destination .= "|307";
|
762 |
-
}
|
763 |
-
break;
|
764 |
-
|
765 |
-
case 'callback':
|
766 |
-
$destination = $meta['Redirect']['Callback'];
|
767 |
-
break;
|
768 |
-
|
769 |
-
case 'login':
|
770 |
-
$destination = null;
|
771 |
-
break;
|
772 |
-
|
773 |
-
default:
|
774 |
-
$destination = $meta['Redirect']['Message'];
|
775 |
-
break;
|
776 |
-
}
|
777 |
|
778 |
-
|
779 |
-
|
780 |
-
|
781 |
-
|
782 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
783 |
|
784 |
-
|
785 |
-
$
|
|
|
|
|
786 |
|
787 |
-
$
|
788 |
-
"{$prefix}{$action}" => $effect
|
789 |
-
));
|
790 |
}
|
791 |
|
792 |
-
return $
|
793 |
}
|
|
|
794 |
}
|
795 |
|
796 |
if (defined('AAM_KEY')) {
|
797 |
-
|
798 |
-
|
799 |
-
}
|
5 |
* LICENSE: This file is subject to the terms and conditions defined in *
|
6 |
* file 'license.txt', which is part of this source code package. *
|
7 |
* ======================================================================
|
8 |
+
*
|
9 |
+
* @version 6.0.0
|
10 |
*/
|
11 |
|
12 |
/**
|
13 |
* Access Policy service
|
14 |
*
|
15 |
+
* @package AAM
|
16 |
+
* @version 6.0.0
|
17 |
*/
|
18 |
class AAM_Service_AccessPolicy
|
19 |
{
|
20 |
+
use AAM_Core_Contract_ServiceTrait,
|
21 |
+
AAM_Core_Contract_RequestTrait;
|
22 |
|
23 |
/**
|
24 |
* AAM configuration setting that is associated with the feature
|
25 |
+
*
|
26 |
+
* @version 6.0.0
|
27 |
*/
|
28 |
const FEATURE_FLAG = 'core.service.access-policy.enabled';
|
29 |
|
30 |
+
/**
|
31 |
+
* Access policy CPT
|
32 |
+
*
|
33 |
+
* @version 6.0.0
|
34 |
+
*/
|
35 |
+
const POLICY_CPT = 'aam_policy';
|
36 |
+
|
37 |
/**
|
38 |
* Constructor
|
39 |
+
*
|
40 |
+
* @return void
|
41 |
+
*
|
42 |
+
* @access protected
|
43 |
+
* @version 6.0.0
|
44 |
*/
|
45 |
protected function __construct()
|
46 |
{
|
51 |
AAM_Backend_Feature_Main_Policy::register();
|
52 |
}, 40);
|
53 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
54 |
//register custom access control metabox
|
55 |
add_action('add_meta_boxes', array($this, 'registerMetaboxes'));
|
56 |
|
64 |
add_filter('aam_service_list_filter', function ($services) {
|
65 |
$services[] = array(
|
66 |
'title' => __('Access Policies', AAM_KEY),
|
67 |
+
'description' => __('Manage access to the website with well documented JSON access policies for any user, role or visitors. Keep the paper-trail of all the access changes with policy revisions.', AAM_KEY),
|
68 |
'setting' => self::FEATURE_FLAG
|
69 |
);
|
70 |
|
77 |
}
|
78 |
}
|
79 |
|
80 |
+
/**
|
81 |
+
* Register UI metaboxes for the Access Policy edit screen
|
82 |
+
*
|
83 |
+
* @global WP_Post $post
|
84 |
+
*
|
85 |
+
* @return void
|
86 |
+
*
|
87 |
+
* @access public
|
88 |
+
* @version 6.0.0
|
89 |
+
*/
|
90 |
+
public function registerMetaboxes()
|
91 |
+
{
|
92 |
+
global $post;
|
93 |
+
|
94 |
+
if (is_a($post, 'WP_Post') && ($post->post_type === self::POLICY_CPT)) {
|
95 |
+
add_meta_box(
|
96 |
+
self::POLICY_CPT,
|
97 |
+
__('Access Policy Document', AAM_KEY),
|
98 |
+
function() {
|
99 |
+
echo AAM_Backend_View::getInstance()->renderPolicyMetabox();
|
100 |
+
},
|
101 |
+
null,
|
102 |
+
'normal',
|
103 |
+
'high'
|
104 |
+
);
|
105 |
+
|
106 |
+
add_meta_box(
|
107 |
+
'aam-policy-assignee',
|
108 |
+
__('Access Policy Assignee', AAM_KEY),
|
109 |
+
function() {
|
110 |
+
echo AAM_Backend_View::getInstance()->renderPolicyPrincipalMetabox();
|
111 |
+
},
|
112 |
+
null,
|
113 |
+
'side'
|
114 |
+
);
|
115 |
+
}
|
116 |
+
}
|
117 |
+
|
118 |
/**
|
119 |
* Hook into policy submission and filter its content
|
120 |
*
|
123 |
* @return array
|
124 |
*
|
125 |
* @access public
|
126 |
+
* @version 6.0.0
|
127 |
*/
|
128 |
public function managePolicyContent($data)
|
129 |
{
|
130 |
+
if (isset($data['post_type']) && ($data['post_type'] === self::POLICY_CPT)) {
|
131 |
+
$content = $this->getFromPost('aam-policy');
|
132 |
|
133 |
if (empty($data['post_content'])) {
|
134 |
+
$content = AAM_Backend_Feature_Main_Policy::getDefaultPolicy();
|
135 |
}
|
136 |
|
137 |
// Reformat the policy content
|
157 |
* @return void
|
158 |
*
|
159 |
* @access protected
|
160 |
+
* @version 6.0.0
|
161 |
*/
|
162 |
protected function initializeHooks()
|
163 |
{
|
166 |
register_post_type('aam_policy', array(
|
167 |
'label' => __('Access Policy', AAM_KEY),
|
168 |
'labels' => array(
|
169 |
+
'name' => __('Access Policies', AAM_KEY),
|
170 |
+
'edit_item' => __('Edit Policy', AAM_KEY),
|
171 |
+
'singular_name' => __('Policy', AAM_KEY),
|
172 |
+
'add_new_item' => __('Add New Policy', AAM_KEY),
|
173 |
+
'new_item' => __('New Policy', AAM_KEY)
|
174 |
),
|
175 |
'description' => __('Access and security policy', AAM_KEY),
|
176 |
+
'public' => false,
|
177 |
'show_ui' => true,
|
178 |
'show_in_menu' => false,
|
179 |
'exclude_from_search' => true,
|
193 |
));
|
194 |
});
|
195 |
|
196 |
+
// Hook into AAM core objects initialization
|
197 |
+
add_filter('aam_menu_object_option_filter', array($this, 'initializeMenu'), 10, 2);
|
198 |
+
add_filter('aam_metabox_object_option_filter', array($this, 'initializeMetabox'), 10, 2);
|
199 |
+
add_filter('aam_toolbar_object_option_filter', array($this, 'initializeToolbar'), 10, 2);
|
200 |
+
add_filter('aam_post_object_option_filter', array($this, 'initializePost'), 10, 2);
|
201 |
+
add_action('aam_visibility_object_init_action', array($this, 'initializeVisibility'));
|
202 |
+
add_filter('aam_uri_object_option_filter', array($this, 'initializeUri'), 10, 2);
|
203 |
+
//add_filter('aam_route_object_option_filter', array($this, 'initializeRoute'), 10, 2);
|
204 |
+
|
205 |
// Manage access to the Capabilities
|
206 |
+
add_filter('aam_cap_can_filter', array($this, 'isCapabilityAllowed'), 10, 3);
|
207 |
+
add_action('aam_initialize_user_action', array($this, 'initializeUser'));
|
208 |
|
209 |
// Manage access to the Plugin list and individual plugins
|
210 |
add_filter('aam_allowed_plugin_action_filter', array($this, 'isPluginActionAllowed'), 10, 3);
|
211 |
+
add_filter('all_plugins', array($this, 'filterPlugins'));
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
212 |
}
|
213 |
|
214 |
/**
|
215 |
+
* Initialize Admin Menu Object options
|
216 |
*
|
217 |
+
* @param array $option
|
218 |
+
* @param AAM_Core_Object_Menu $object
|
219 |
+
*
|
220 |
+
* @return array
|
221 |
+
*
|
222 |
+
* @access public
|
223 |
+
* @see https://aamplugin.com/reference/policy#backendmenu
|
224 |
+
* @version 6.0.0
|
225 |
*/
|
226 |
+
public function initializeMenu($option, AAM_Core_Object_Menu $object)
|
227 |
{
|
228 |
+
$manager = AAM_Core_Policy_Factory::get($object->getSubject());
|
229 |
+
$found = $manager->getResources(AAM_Core_Policy_Resource::MENU);
|
230 |
+
$parsed = array();
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
231 |
|
232 |
+
foreach ($found as $key => $stm) {
|
233 |
+
$parsed[$key] = ($stm['Effect'] === 'deny' ? true : false);
|
|
|
|
|
|
|
|
|
|
|
234 |
}
|
|
|
235 |
|
236 |
+
return array_replace($option, $parsed); // First-class citizen
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
237 |
}
|
238 |
|
239 |
/**
|
240 |
+
* Initialize Toolbar Object options
|
241 |
*
|
242 |
+
* @param array $option
|
243 |
+
* @param AAM_Core_Object_Toolbar $object
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
244 |
*
|
245 |
+
* @return array
|
246 |
*
|
247 |
* @access public
|
248 |
+
* @see https://aamplugin.com/reference/policy#toolbar
|
249 |
+
* @version 6.0.0
|
250 |
*/
|
251 |
+
public function initializeToolbar($option, AAM_Core_Object_Toolbar $object)
|
252 |
{
|
253 |
+
$manager = AAM_Core_Policy_Factory::get($object->getSubject());
|
254 |
+
$found = $manager->getResources(AAM_Core_Policy_Resource::TOOLBAR);
|
255 |
+
$parsed = array();
|
256 |
|
257 |
+
foreach ($found as $key => $stm) {
|
258 |
+
$parsed[$key] = ($stm['Effect'] === 'deny' ? true : false);
|
|
|
|
|
259 |
}
|
260 |
|
261 |
+
return array_replace($option, $parsed); // First-class citizen
|
262 |
}
|
263 |
|
264 |
/**
|
265 |
+
* Initialize Metabox Object options
|
266 |
*
|
267 |
+
* @param array $option
|
268 |
+
* @param AAM_Core_Object_Metabox $object
|
269 |
+
*
|
270 |
+
* @return array
|
271 |
*
|
272 |
* @access public
|
273 |
+
* @see https://aamplugin.com/reference/policy#metabox
|
274 |
+
* @version 6.0.0
|
275 |
*/
|
276 |
+
public function initializeMetabox($option, AAM_Core_Object_Metabox $object)
|
277 |
{
|
278 |
+
$manager = AAM_Core_Policy_Factory::get($object->getSubject());
|
279 |
+
$found = $manager->getResources(array(
|
280 |
+
AAM_Core_Policy_Resource::METABOX, AAM_Core_Policy_Resource::WIDGET
|
281 |
+
));
|
282 |
+
|
283 |
+
$parsed = array();
|
284 |
+
|
285 |
+
foreach ($found as $key => $stm) {
|
286 |
+
$parsed[$key] = ($stm['Effect'] === 'deny' ? true : false);
|
287 |
+
}
|
288 |
+
|
289 |
+
return array_replace($option, $parsed); // First-class citizen
|
290 |
}
|
291 |
|
292 |
/**
|
293 |
+
* Check if specified action is allowed upon capability
|
294 |
*
|
295 |
+
* @param boolean $allowed
|
296 |
+
* @param string $cap
|
297 |
+
* @param string $action
|
298 |
*
|
299 |
* @return boolean
|
300 |
*
|
301 |
* @access public
|
302 |
+
* @link https://aamplugin.com/reference/policy#capability
|
303 |
+
* @version 6.0.0
|
304 |
*/
|
305 |
+
public function isCapabilityAllowed($allowed, $cap, $action)
|
306 |
{
|
307 |
+
$manager = AAM_Core_Policy_Factory::get(AAM::getUser());
|
308 |
+
$result = $manager->isAllowed("Capability:{$cap}:AAM:{$action}");
|
309 |
|
310 |
+
return ($result === null ? $allowed : $result);
|
|
|
|
|
|
|
|
|
|
|
|
|
311 |
}
|
312 |
|
313 |
/**
|
314 |
+
* Initialize user with policy capabilities and roles
|
315 |
*
|
316 |
+
* @param AAM_Core_Subject_User $subject
|
|
|
317 |
*
|
318 |
+
* @return void
|
319 |
*
|
320 |
* @access public
|
321 |
+
* @link https://aamplugin.com/reference/policy#capability
|
322 |
+
* @link https://aamplugin.com/reference/policy#role
|
323 |
+
* @version 6.0.0
|
324 |
*/
|
325 |
+
public function initializeUser(AAM_Core_Subject_User $subject)
|
326 |
{
|
327 |
+
$manager = AAM_Core_Policy_Factory::get($subject);
|
328 |
+
$wp_user = $subject->getPrincipal();
|
329 |
|
330 |
+
// Update user's list of roles if policy states so
|
331 |
+
$roles = $manager->getResources(AAM_Core_Policy_Resource::ROLE);
|
332 |
+
|
333 |
+
if (count($roles)) {
|
334 |
+
foreach($roles as $id => $statement) {
|
335 |
+
$effect = strtolower($statement['Effect']);
|
336 |
+
$exists = array_key_exists($id, $wp_user->caps);
|
337 |
+
|
338 |
+
if ($effect === 'allow') { // Add new
|
339 |
+
$wp_user->caps[$id] = true;
|
340 |
+
} elseif (($effect === 'deny') && $exists) { // Remove
|
341 |
+
unset($wp_user->caps[$id]);
|
342 |
+
}
|
343 |
+
}
|
344 |
+
|
345 |
+
// Re-index all user capabilities based on new set of roles
|
346 |
+
$wp_user->get_role_caps();
|
347 |
+
|
348 |
+
// Add siblings to the User subject
|
349 |
+
$user_roles = array_values($wp_user->roles);
|
350 |
+
|
351 |
+
if (count($user_roles) > 1) {
|
352 |
+
$subject->getParent()->setSiblings(array_map(function($id) {
|
353 |
+
return AAM::api()->getRole($id);
|
354 |
+
}, array_slice($user_roles, 1)));
|
355 |
+
}
|
356 |
}
|
357 |
|
358 |
+
// Get all the capabilities that mentioned in the policies explicitly
|
359 |
+
$caps = array_filter(
|
360 |
+
$manager->getResources(AAM_Core_Policy_Resource::CAPABILITY),
|
361 |
+
function($stm, $res) {
|
362 |
+
return (strpos($res, ':') === false); // Exclude any :AAM: resources
|
363 |
+
},
|
364 |
+
ARRAY_FILTER_USE_BOTH
|
365 |
+
);
|
366 |
|
367 |
+
foreach($caps as $cap => $statement) {
|
368 |
+
$effect = (strtolower($statement['Effect']) === 'allow' ? true : false);
|
369 |
+
$wp_user->allcaps[$cap] = $effect;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
370 |
|
371 |
+
// Also update user's specific cap if exists
|
372 |
+
if (array_key_exists($cap, $wp_user->caps)) {
|
373 |
+
$wp_user->caps[$cap] = $effect;
|
374 |
+
}
|
375 |
}
|
376 |
|
377 |
+
// Finally update user level
|
378 |
+
$wp_user->user_level = array_reduce(
|
379 |
+
array_keys($wp_user->allcaps), array($wp_user, 'level_reduction'), 0
|
380 |
+
);
|
381 |
}
|
382 |
|
383 |
/**
|
391 |
* @access public
|
392 |
* @see https://aamplugin.com/reference/policy#post
|
393 |
*/
|
394 |
+
public function initializePost($option, AAM_Core_Object_Post $object)
|
395 |
{
|
396 |
+
$manager = AAM_Core_Policy_Factory::get($object->getSubject());
|
397 |
+
|
398 |
+
$found = $manager->getResources(sprintf(
|
399 |
+
'%s:%s:(%d|%s)',
|
400 |
+
AAM_Core_Policy_Resource::POST,
|
401 |
+
$object->post_type,
|
402 |
+
$object->ID,
|
403 |
+
$object->post_name
|
404 |
+
));
|
405 |
+
|
406 |
+
$parsed = array();
|
407 |
+
|
408 |
+
foreach($found as $action => $stmt) {
|
409 |
+
switch($action) {
|
410 |
+
case 'edit':
|
411 |
+
case 'delete':
|
412 |
+
case 'publish':
|
413 |
+
case 'comment':
|
414 |
+
$this->convertedPostSimpleAction($parsed, $action, $stmt);
|
415 |
+
break;
|
416 |
|
417 |
+
case 'list':
|
418 |
+
$this->convertedPostSimpleAction($parsed, 'hidden', $stmt);
|
419 |
+
break;
|
420 |
|
421 |
+
case 'read':
|
422 |
+
$this->convertedPostReadAction($parsed, $stmt);
|
423 |
+
break;
|
424 |
+
|
425 |
+
default:
|
426 |
+
$parsed = apply_filters(
|
427 |
+
'aam_policy_post_conversion_filter', array(), $action, $stmt
|
428 |
+
);
|
429 |
+
break;
|
430 |
+
}
|
|
|
|
|
|
|
|
|
|
|
|
|
431 |
}
|
432 |
|
433 |
+
return array_replace_recursive($option, $parsed); // First-class citizen
|
434 |
}
|
435 |
|
436 |
/**
|
437 |
+
* Covert simple post action to post object property
|
438 |
*
|
439 |
+
* @param array &$options
|
440 |
+
* @param string $action
|
441 |
+
* @param array $statement
|
442 |
*
|
443 |
+
* @return void
|
444 |
*
|
445 |
+
* @access protected
|
446 |
+
* @version 6.0.0
|
447 |
*/
|
448 |
+
protected function convertedPostSimpleAction(&$options, $action, $statement)
|
449 |
{
|
450 |
+
$options[$action] = strtolower($statement['Effect']) !== "allow";
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
451 |
}
|
452 |
|
453 |
/**
|
454 |
+
* Convert Post Read action based on metadata
|
455 |
*
|
456 |
+
* @param array &$options
|
457 |
+
* @param array $statement
|
458 |
*
|
459 |
+
* @return void
|
460 |
*
|
461 |
+
* @access protected
|
|
|
462 |
*/
|
463 |
+
protected function convertedPostReadAction(&$options, $statement)
|
464 |
{
|
465 |
+
$effect = strtolower($statement['Effect']) !== "allow";
|
466 |
|
467 |
+
if (array_key_exists('Metadata', $statement)) {
|
468 |
+
$metadata = $statement['Metadata'];
|
|
|
|
|
469 |
|
470 |
+
// Password Protected options
|
471 |
+
if(array_key_exists('Password', $metadata)) {
|
472 |
+
$options['protected'] = array(
|
473 |
+
'enabled' => $effect,
|
474 |
+
'password' => $metadata['Password']['Value']
|
475 |
+
);
|
476 |
+
}
|
477 |
+
|
478 |
+
// Teaser message is defined
|
479 |
+
if(array_key_exists('Teaser', $metadata)) {
|
480 |
+
$options['teaser'] = array(
|
481 |
+
'enabled' => $effect,
|
482 |
+
'message' => $metadata['Teaser']['Value']
|
483 |
+
);
|
484 |
+
}
|
485 |
+
|
486 |
+
// Redirect options
|
487 |
+
if(array_key_exists('Redirect', $metadata)) {
|
488 |
+
$redirect = $this->convertRedirectAction($metadata['Redirect']);
|
489 |
+
$redirect['enabled'] = $effect;
|
490 |
+
$options['redirected'] = $redirect;
|
491 |
+
}
|
492 |
+
} else { // Simply restrict access to read a post
|
493 |
+
$options['restricted'] = $effect;
|
494 |
+
}
|
495 |
}
|
496 |
|
497 |
/**
|
498 |
+
* Convert Redirect type of action
|
499 |
*
|
500 |
+
* @param array $metadata
|
|
|
501 |
*
|
502 |
* @return array
|
503 |
*
|
504 |
+
* @access protected
|
505 |
+
* @version 6.0.0
|
506 |
*/
|
507 |
+
protected function convertRedirectAction($metadata)
|
508 |
{
|
509 |
+
$response = array(
|
510 |
+
'type' => $metadata['Type'],
|
511 |
+
'httpCode' => (int)(isset($metadata['Code']) ? $metadata['Code'] : 307)
|
512 |
+
);
|
513 |
|
514 |
+
$destination = null;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
515 |
|
516 |
+
if ($metadata['Type'] === 'page') {
|
517 |
+
if (isset($metadata['Id'])) {
|
518 |
+
$destination = intval($metadata['Id']);
|
519 |
+
} elseif (isset($metadata['Slug'])) {
|
520 |
+
$page = get_page_by_path($metadata['Slug'], OBJECT);
|
521 |
+
$destination = (is_a($page, 'WP_Post') ? $page->ID : 0);
|
522 |
+
}
|
523 |
+
} elseif ($metadata['Type'] === 'url') {
|
524 |
+
$destination = $metadata['URL'];
|
525 |
+
} elseif ($metadata['Type'] === 'callback') {
|
526 |
+
$destination = $metadata['Callback'];
|
527 |
}
|
528 |
|
529 |
+
$response['destination'] = $destination;
|
530 |
+
|
531 |
+
return $response;
|
532 |
}
|
533 |
|
534 |
/**
|
540 |
*
|
541 |
* @access public
|
542 |
*/
|
543 |
+
public function initializeVisibility(AAM_Core_Object_Visibility $visibility)
|
544 |
{
|
545 |
+
$manager = AAM_Core_Policy_Factory::get($visibility->getSubject());
|
546 |
+
$found = $manager->getResources(AAM_Core_Policy_Resource::POST);
|
|
|
|
|
547 |
|
548 |
+
foreach($found as $resource => $stm) {
|
549 |
+
$chunks = explode(':', $resource);
|
550 |
+
$effect = (strtolower($stm['Effect']) === 'allow' ? false : true);
|
551 |
|
552 |
+
// Take in consideration only visibility properties
|
553 |
+
if ($chunks[2] === 'list') {
|
554 |
+
if (is_numeric($chunks[1])) {
|
555 |
+
$id = intval($chunks[1]);
|
556 |
+
} else {
|
557 |
+
$post = get_page_by_path($chunks[1], OBJECT, $chunks[0]);
|
558 |
+
$id = (is_a($post, 'WP_Post') ? $post->ID : null);
|
559 |
+
}
|
|
|
|
|
560 |
|
561 |
+
// Making sure that we have at least numeric post ID
|
562 |
+
if (!empty($id)) {
|
563 |
+
$visibility->pushOptions('post', "{$id}|{$chunks[0]}", array(
|
564 |
+
'hidden' => $effect
|
565 |
+
));
|
566 |
+
}
|
|
|
|
|
|
|
567 |
}
|
568 |
}
|
569 |
}
|
570 |
|
571 |
/**
|
572 |
+
* Initialize URI Object options
|
573 |
*
|
574 |
+
* @param array $option
|
575 |
+
* @param AAM_Core_Object_Uri $object
|
576 |
*
|
577 |
+
* @return array
|
578 |
*
|
579 |
* @access public
|
580 |
+
* @see https://aamplugin.com/reference/policy#uri
|
|
|
581 |
*/
|
582 |
+
public function initializeUri($option, AAM_Core_Object_Uri $object)
|
583 |
{
|
584 |
+
$manager = AAM_Core_Policy_Factory::get($object->getSubject());
|
585 |
+
$found = $manager->getResources(AAM_Core_Policy_Resource::URI);
|
586 |
+
$parsed = array();
|
|
|
|
|
|
|
587 |
|
588 |
+
foreach($found as $uri => $stm) {
|
589 |
+
$uri = rtrim($uri, '/'); // No need to honor the trailing forward slash
|
590 |
+
$effect = (strtolower($stm['Effect']) === 'allow' ? false : true);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
591 |
|
592 |
+
if ($effect === false) {
|
593 |
+
$parsed[$uri] = array(
|
594 |
+
'type' => 'allow'
|
595 |
+
);
|
596 |
+
} elseif (array_key_exists('Metadata', $stm)) {
|
597 |
+
$option[$uri] = $this->convertUriAction($stm['Metadata']);
|
598 |
+
} else {
|
599 |
+
$option[$uri] = array(
|
600 |
+
'type' => 'default'
|
601 |
+
);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
602 |
}
|
603 |
}
|
604 |
|
605 |
+
return array_merge($option, $parsed); //First-class citizen
|
606 |
}
|
607 |
|
608 |
/**
|
609 |
+
* Convert URI metadata to the URI access option
|
610 |
*
|
611 |
+
* @param array $metadata
|
|
|
612 |
*
|
613 |
* @return array
|
614 |
*
|
615 |
* @access protected
|
616 |
+
* @version 6.0.0
|
617 |
*/
|
618 |
+
protected function convertUriAction($metadata)
|
619 |
{
|
620 |
+
$type = strtolower($metadata['Type']);
|
621 |
+
$code = isset($metadata['Code']) ? $metadata['Code'] : 307;
|
622 |
+
$action = null;
|
623 |
+
|
624 |
+
switch($type) {
|
625 |
+
case 'page':
|
626 |
+
if (isset($metadata['Id'])) {
|
627 |
+
$action = intval($metadata['Id']);
|
628 |
+
} elseif (isset($metadata['Slug'])) {
|
629 |
+
$page = get_page_by_path($metadata['Slug'], OBJECT, 'page');
|
630 |
+
$action = (is_a($page, 'WP_Post') ? $page->ID : 0);
|
631 |
+
}
|
632 |
+
break;
|
633 |
|
634 |
+
case 'message':
|
635 |
+
$action = $metadata['Message'];
|
636 |
+
break;
|
637 |
+
|
638 |
+
case 'url':
|
639 |
+
$action = $metadata['URL'];
|
640 |
+
break;
|
641 |
+
|
642 |
+
case 'callback':
|
643 |
+
$action = $metadata['Callback'];
|
644 |
+
break;
|
645 |
+
|
646 |
+
case 'login':
|
647 |
+
$code = 401; //Unauthorized
|
648 |
+
break;
|
649 |
+
|
650 |
+
default:
|
651 |
+
break;
|
652 |
}
|
653 |
|
654 |
+
return array(
|
655 |
+
'type' => $type,
|
656 |
+
'action' => $action,
|
657 |
+
'code' => $code
|
658 |
+
);
|
659 |
}
|
660 |
|
661 |
/**
|
662 |
+
* Check if specific action is allowed upon all plugins or specified plugin
|
663 |
*
|
664 |
+
* @param boolean|null $allowed
|
665 |
+
* @param string $action
|
666 |
+
* @param string $slug
|
667 |
+
*
|
668 |
+
* @return boolean
|
669 |
*
|
670 |
* @access public
|
671 |
+
* @link https://aamplugin.com/reference/policy#plugin
|
672 |
+
* @version 6.0.0
|
673 |
*/
|
674 |
+
public function isPluginActionAllowed($allowed, $action, $slug = null)
|
675 |
{
|
676 |
+
$manager = AAM_Core_Policy_Factory::get(AAM::getUser());
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
677 |
|
678 |
+
if ($slug === null) {
|
679 |
+
$id = AAM_Core_Policy_Resource::PLUGIN . ":WP:{$action}";
|
680 |
+
} else {
|
681 |
+
$id = AAM_Core_Policy_Resource::PLUGIN . ":{$slug}:WP:{$action}";
|
|
|
|
|
|
|
|
|
|
|
682 |
}
|
683 |
+
|
684 |
+
return $manager->isAllowed($id);
|
685 |
}
|
686 |
|
687 |
/**
|
688 |
+
* Filter out all the plugins that are not allowed to be listed
|
689 |
*
|
690 |
+
* @param array $plugins
|
|
|
|
|
|
|
|
|
691 |
*
|
692 |
* @return array
|
693 |
+
*
|
694 |
+
* @access public
|
695 |
+
* @version 6.0.0
|
696 |
*/
|
697 |
+
public function filterPlugins($plugins)
|
698 |
{
|
699 |
+
$manager = AAM_Core_Policy_Factory::get(AAM::getUser());
|
700 |
+
$filtered = array();
|
701 |
|
702 |
+
foreach($plugins as $id => $plugin) {
|
703 |
+
list($slug) = explode('/', $id);
|
704 |
+
$resource = AAM_Core_Policy_Resource::PLUGIN . ":{$slug}:WP:list";
|
|
|
|
|
|
|
705 |
|
706 |
+
if ($manager->isAllowed($resource) !== false) {
|
707 |
+
$filtered[$id] = $plugin;
|
|
|
|
|
|
|
708 |
}
|
|
|
|
|
|
|
|
|
|
|
709 |
}
|
710 |
|
711 |
+
return $filtered;
|
712 |
+
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
713 |
|
714 |
+
/**
|
715 |
+
* Initialize Route Object options
|
716 |
+
*
|
717 |
+
* @param array $option
|
718 |
+
* @param AAM_Core_Subject $subject
|
719 |
+
*
|
720 |
+
* @return array
|
721 |
+
*
|
722 |
+
* @access public
|
723 |
+
* @see https://aamplugin.com/reference/policy#route
|
724 |
+
*/
|
725 |
+
public function initRouteObjectOptions($option, AAM_Core_Subject $subject)
|
726 |
+
{
|
727 |
+
$stms = $this->getPolicyManager($subject)->find("/^Route:/i");
|
728 |
|
729 |
+
foreach ($stms as $key => $stm) {
|
730 |
+
$chunks = explode(':', $key);
|
731 |
+
$method = (isset($chunks[3]) ? $chunks[3] : 'post');
|
732 |
+
$id = "{$chunks[1]}|{$chunks[2]}|{$method}";
|
733 |
|
734 |
+
$option[$id] = ($stm['Effect'] === 'deny' ? 1 : 0);
|
|
|
|
|
735 |
}
|
736 |
|
737 |
+
return $option;
|
738 |
}
|
739 |
+
|
740 |
}
|
741 |
|
742 |
if (defined('AAM_KEY')) {
|
743 |
+
AAM_Service_AccessPolicy::bootstrap();
|
744 |
+
}
|
|
application/Service/Content.php
CHANGED
@@ -27,6 +27,13 @@ class AAM_Service_Content
|
|
27 |
*/
|
28 |
const FEATURE_FLAG = 'core.service.content.enabled';
|
29 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
30 |
/**
|
31 |
* Constructor
|
32 |
*
|
@@ -302,6 +309,8 @@ class AAM_Service_Content
|
|
302 |
if ($auth->get_error_code() === 'post_access_redirected') {
|
303 |
$response->set_headers(array('Location' => $data['location']));
|
304 |
}
|
|
|
|
|
305 |
}
|
306 |
|
307 |
return $response;
|
@@ -404,9 +413,11 @@ class AAM_Service_Content
|
|
404 |
if (is_wp_error($error)) {
|
405 |
if ($error->get_error_code() === 'post_access_redirected') {
|
406 |
AAM_Core_Redirect::execute('url', $error->get_error_data());
|
407 |
-
}
|
408 |
-
|
409 |
}
|
|
|
|
|
410 |
}
|
411 |
}
|
412 |
}
|
@@ -569,7 +580,7 @@ class AAM_Service_Content
|
|
569 |
}
|
570 |
|
571 |
// Replace the [excerpt] placeholder with posts excerpt and do
|
572 |
-
//
|
573 |
$content = do_shortcode(
|
574 |
str_replace('[excerpt]', $post->post_excerpt, $message)
|
575 |
);
|
@@ -829,6 +840,25 @@ class AAM_Service_Content
|
|
829 |
return $caps;
|
830 |
}
|
831 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
832 |
/**
|
833 |
* Check if current user is authorized to read the post
|
834 |
*
|
@@ -854,7 +884,7 @@ class AAM_Service_Content
|
|
854 |
|
855 |
// Prepare the pipeline of steps that AAM core will perform to check post's
|
856 |
// accessibility
|
857 |
-
$pipeline = apply_filters('
|
858 |
// Step #1. Check if access expired to the post
|
859 |
array($this, 'checkPostExpiration'),
|
860 |
// Step #2. Check if user has access to read the post
|
@@ -960,7 +990,7 @@ class AAM_Service_Content
|
|
960 |
// Check current access counter only for authenticated users
|
961 |
if ($user && $post->is('limited')) {
|
962 |
$limited = $post->get('limited');
|
963 |
-
$option =
|
964 |
$counter = intval(get_user_meta($user, $option, true));
|
965 |
|
966 |
if ($counter >= $limited['threshold']) {
|
@@ -1020,7 +1050,7 @@ class AAM_Service_Content
|
|
1020 |
_doing_it_wrong(
|
1021 |
__CLASS__ . '::' . __METHOD__,
|
1022 |
'Callback is not invocable',
|
1023 |
-
|
1024 |
);
|
1025 |
}
|
1026 |
break;
|
@@ -1069,19 +1099,16 @@ class AAM_Service_Content
|
|
1069 |
// protected posts/pages
|
1070 |
if (empty($password)) {
|
1071 |
$password = wp_unslash(
|
1072 |
-
$this->
|
1073 |
);
|
1074 |
|
1075 |
$isMatched = AAM_Core_API::prepareHasher()->CheckPassword(
|
1076 |
$protected['password'], $password
|
1077 |
);
|
1078 |
} else {
|
1079 |
-
$
|
1080 |
-
$isMatched = $decrypted === $password;
|
1081 |
}
|
1082 |
|
1083 |
-
|
1084 |
-
|
1085 |
if ($isMatched === false) {
|
1086 |
$result = new WP_Error(
|
1087 |
'post_access_protected',
|
27 |
*/
|
28 |
const FEATURE_FLAG = 'core.service.content.enabled';
|
29 |
|
30 |
+
/**
|
31 |
+
* Post view counter
|
32 |
+
*
|
33 |
+
* @version 6.0.0
|
34 |
+
*/
|
35 |
+
const POST_COUNTER_DB_OPTION = 'aam_post_%s_access_counter';
|
36 |
+
|
37 |
/**
|
38 |
* Constructor
|
39 |
*
|
309 |
if ($auth->get_error_code() === 'post_access_redirected') {
|
310 |
$response->set_headers(array('Location' => $data['location']));
|
311 |
}
|
312 |
+
} else {
|
313 |
+
$this->incrementPostReadCounter($object);
|
314 |
}
|
315 |
|
316 |
return $response;
|
413 |
if (is_wp_error($error)) {
|
414 |
if ($error->get_error_code() === 'post_access_redirected') {
|
415 |
AAM_Core_Redirect::execute('url', $error->get_error_data());
|
416 |
+
} elseif ($error->get_error_code() !== 'post_access_protected') {
|
417 |
+
wp_die($error->get_error_message(), 'aam_access_denied');
|
418 |
}
|
419 |
+
} else {
|
420 |
+
$this->incrementPostReadCounter($post);
|
421 |
}
|
422 |
}
|
423 |
}
|
580 |
}
|
581 |
|
582 |
// Replace the [excerpt] placeholder with posts excerpt and do
|
583 |
+
// short-code evaluation
|
584 |
$content = do_shortcode(
|
585 |
str_replace('[excerpt]', $post->post_excerpt, $message)
|
586 |
);
|
840 |
return $caps;
|
841 |
}
|
842 |
|
843 |
+
/**
|
844 |
+
* Increment user view counter is tracking is defined
|
845 |
+
*
|
846 |
+
* @param AAM_Core_Object_Post $post
|
847 |
+
*
|
848 |
+
* @return void
|
849 |
+
*
|
850 |
+
* @access protected
|
851 |
+
* @version 6.0.0
|
852 |
+
*/
|
853 |
+
protected function incrementPostReadCounter($post)
|
854 |
+
{
|
855 |
+
if(is_user_logged_in() && $post->is('limited')) {
|
856 |
+
$option = sprintf(self::POST_COUNTER_DB_OPTION, $post->ID);
|
857 |
+
$counter = intval(get_user_meta(get_current_user_id(), $option, true));
|
858 |
+
update_user_meta(get_current_user_id(), $option, ++$counter);
|
859 |
+
}
|
860 |
+
}
|
861 |
+
|
862 |
/**
|
863 |
* Check if current user is authorized to read the post
|
864 |
*
|
884 |
|
885 |
// Prepare the pipeline of steps that AAM core will perform to check post's
|
886 |
// accessibility
|
887 |
+
$pipeline = apply_filters('aam_post_read_access_pipeline_filter', array(
|
888 |
// Step #1. Check if access expired to the post
|
889 |
array($this, 'checkPostExpiration'),
|
890 |
// Step #2. Check if user has access to read the post
|
990 |
// Check current access counter only for authenticated users
|
991 |
if ($user && $post->is('limited')) {
|
992 |
$limited = $post->get('limited');
|
993 |
+
$option = sprintf(self::POST_COUNTER_DB_OPTION, $post->ID);
|
994 |
$counter = intval(get_user_meta($user, $option, true));
|
995 |
|
996 |
if ($counter >= $limited['threshold']) {
|
1050 |
_doing_it_wrong(
|
1051 |
__CLASS__ . '::' . __METHOD__,
|
1052 |
'Callback is not invocable',
|
1053 |
+
AAM_VERSION
|
1054 |
);
|
1055 |
}
|
1056 |
break;
|
1099 |
// protected posts/pages
|
1100 |
if (empty($password)) {
|
1101 |
$password = wp_unslash(
|
1102 |
+
$this->getFromCookie('wp-postpass_' . COOKIEHASH)
|
1103 |
);
|
1104 |
|
1105 |
$isMatched = AAM_Core_API::prepareHasher()->CheckPassword(
|
1106 |
$protected['password'], $password
|
1107 |
);
|
1108 |
} else {
|
1109 |
+
$isMatched = $protected['password'] === $password;
|
|
|
1110 |
}
|
1111 |
|
|
|
|
|
1112 |
if ($isMatched === false) {
|
1113 |
$result = new WP_Error(
|
1114 |
'post_access_protected',
|
application/Service/Core.php
CHANGED
@@ -45,6 +45,19 @@ class AAM_Service_Core
|
|
45 |
add_filter('self_admin_url', array($this, 'pluginUpdateDetails'), 10);
|
46 |
}
|
47 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
48 |
// Check if user has ability to perform certain task based on provided
|
49 |
// capability and meta data
|
50 |
add_filter('map_meta_cap', array($this, 'mapMetaCaps'), 999, 4);
|
@@ -149,6 +162,21 @@ class AAM_Service_Core
|
|
149 |
return $url;
|
150 |
}
|
151 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
152 |
/**
|
153 |
* Eliminate XSS through translation file
|
154 |
*
|
45 |
add_filter('self_admin_url', array($this, 'pluginUpdateDetails'), 10);
|
46 |
}
|
47 |
|
48 |
+
if (is_admin()) {
|
49 |
+
if (AAM_Core_Config::get('ui.settings.renderAccessMetabox', true)) {
|
50 |
+
add_action('show_user_profile', array($this, 'renderAccessWidget'));
|
51 |
+
add_action('edit_user_profile', array($this, 'renderAccessWidget'));
|
52 |
+
}
|
53 |
+
|
54 |
+
// Register UI elements
|
55 |
+
add_action('aam_init_ui_action', function () {
|
56 |
+
AAM_Backend_Feature_Subject_Role::register();
|
57 |
+
AAM_Backend_Feature_Subject_User::register();
|
58 |
+
});
|
59 |
+
}
|
60 |
+
|
61 |
// Check if user has ability to perform certain task based on provided
|
62 |
// capability and meta data
|
63 |
add_filter('map_meta_cap', array($this, 'mapMetaCaps'), 999, 4);
|
162 |
return $url;
|
163 |
}
|
164 |
|
165 |
+
/**
|
166 |
+
* Render "Access Manager" widget on the user/profile edit screen
|
167 |
+
*
|
168 |
+
* @param WP_User $user
|
169 |
+
*
|
170 |
+
* @return void
|
171 |
+
*
|
172 |
+
* @access public
|
173 |
+
* @version 6.0.0
|
174 |
+
*/
|
175 |
+
public function renderAccessWidget($user)
|
176 |
+
{
|
177 |
+
echo AAM_Backend_View::getInstance()->renderUserMetabox($user);
|
178 |
+
}
|
179 |
+
|
180 |
/**
|
181 |
* Eliminate XSS through translation file
|
182 |
*
|
application/Service/ExtendedCapabilities.php
CHANGED
@@ -19,7 +19,8 @@
|
|
19 |
*/
|
20 |
class AAM_Service_ExtendedCapabilities
|
21 |
{
|
22 |
-
use AAM_Core_Contract_ServiceTrait
|
|
|
23 |
|
24 |
/**
|
25 |
* AAM configuration setting that is associated with the service
|
@@ -239,7 +240,7 @@ class AAM_Service_ExtendedCapabilities
|
|
239 |
*/
|
240 |
public function canUpdatePassword($login, &$password, &$password2)
|
241 |
{
|
242 |
-
$userId =
|
243 |
$isProfile = $userId === get_current_user_id();
|
244 |
|
245 |
if ($isProfile) {
|
19 |
*/
|
20 |
class AAM_Service_ExtendedCapabilities
|
21 |
{
|
22 |
+
use AAM_Core_Contract_ServiceTrait,
|
23 |
+
AAM_Core_Contract_RequestTrait;
|
24 |
|
25 |
/**
|
26 |
* AAM configuration setting that is associated with the service
|
240 |
*/
|
241 |
public function canUpdatePassword($login, &$password, &$password2)
|
242 |
{
|
243 |
+
$userId = $this->getFromPost('user_id', FILTER_VALIDATE_INT);
|
244 |
$isProfile = $userId === get_current_user_id();
|
245 |
|
246 |
if ($isProfile) {
|
application/Service/Jwt.php
CHANGED
@@ -110,10 +110,21 @@ class AAM_Service_Jwt
|
|
110 |
|
111 |
// Delete JWT cookie if it is set
|
112 |
add_action('wp_logout', function() {
|
113 |
-
if (
|
114 |
-
setcookie(
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
115 |
}
|
116 |
});
|
|
|
|
|
|
|
117 |
}
|
118 |
|
119 |
/**
|
@@ -396,6 +407,32 @@ class AAM_Service_Jwt
|
|
396 |
return $userId;
|
397 |
}
|
398 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
399 |
/**
|
400 |
* Authenticate user with JWT
|
401 |
*
|
@@ -475,10 +512,10 @@ class AAM_Service_Jwt
|
|
475 |
*
|
476 |
* @return object|null
|
477 |
*
|
478 |
-
* @access
|
479 |
* @version 6.0.0
|
480 |
*/
|
481 |
-
|
482 |
{
|
483 |
$container = explode(',', AAM_Core_Config::get(
|
484 |
'authentication.jwt.container',
|
@@ -488,24 +525,24 @@ class AAM_Service_Jwt
|
|
488 |
foreach ($container as $method) {
|
489 |
switch (strtolower(trim($method))) {
|
490 |
case 'header':
|
491 |
-
$jwt =
|
492 |
break;
|
493 |
|
494 |
case 'cookie':
|
495 |
-
$jwt =
|
496 |
break;
|
497 |
|
498 |
case 'post':
|
499 |
-
$jwt =
|
500 |
break;
|
501 |
|
502 |
case 'get':
|
503 |
case 'query':
|
504 |
-
$jwt =
|
505 |
break;
|
506 |
|
507 |
default:
|
508 |
-
$jwt = apply_filters('
|
509 |
break;
|
510 |
}
|
511 |
|
110 |
|
111 |
// Delete JWT cookie if it is set
|
112 |
add_action('wp_logout', function() {
|
113 |
+
if ($this->getFromCookie('aam_jwt_token')) {
|
114 |
+
setcookie(
|
115 |
+
'aam_jwt_token',
|
116 |
+
null,
|
117 |
+
time() - 1,
|
118 |
+
COOKIEPATH,
|
119 |
+
COOKIE_DOMAIN,
|
120 |
+
is_ssl(),
|
121 |
+
true
|
122 |
+
);
|
123 |
}
|
124 |
});
|
125 |
+
|
126 |
+
// Fetch specific claim from the JWT token if present
|
127 |
+
add_filter('aam_get_jwt_claim', array($this, 'getJwtClaim'), 20, 2);
|
128 |
}
|
129 |
|
130 |
/**
|
407 |
return $userId;
|
408 |
}
|
409 |
|
410 |
+
/**
|
411 |
+
* Get specific claim from the JWT token
|
412 |
+
*
|
413 |
+
* @param mixed $value
|
414 |
+
* @param string $prop
|
415 |
+
*
|
416 |
+
* @return mixed
|
417 |
+
*
|
418 |
+
* @access public
|
419 |
+
* @version 6.0.0
|
420 |
+
*/
|
421 |
+
public function getJwtClaim($value, $prop)
|
422 |
+
{
|
423 |
+
$token = $this->extractToken();
|
424 |
+
|
425 |
+
if ($token) {
|
426 |
+
$claims = AAM_Core_Jwt_Issuer::getInstance()->extractTokenClaims(
|
427 |
+
$token->jwt
|
428 |
+
);
|
429 |
+
|
430 |
+
$value = (property_exists($claims, $prop) ? $claims->$prop : null);
|
431 |
+
}
|
432 |
+
|
433 |
+
return $value;
|
434 |
+
}
|
435 |
+
|
436 |
/**
|
437 |
* Authenticate user with JWT
|
438 |
*
|
512 |
*
|
513 |
* @return object|null
|
514 |
*
|
515 |
+
* @access protected
|
516 |
* @version 6.0.0
|
517 |
*/
|
518 |
+
protected function extractToken()
|
519 |
{
|
520 |
$container = explode(',', AAM_Core_Config::get(
|
521 |
'authentication.jwt.container',
|
525 |
foreach ($container as $method) {
|
526 |
switch (strtolower(trim($method))) {
|
527 |
case 'header':
|
528 |
+
$jwt = $this->getFromServer('HTTP_AUTHENTICATION');
|
529 |
break;
|
530 |
|
531 |
case 'cookie':
|
532 |
+
$jwt = $this->getFromCookie('aam_jwt_token');
|
533 |
break;
|
534 |
|
535 |
case 'post':
|
536 |
+
$jwt = $this->getFromPost('aam-jwt');
|
537 |
break;
|
538 |
|
539 |
case 'get':
|
540 |
case 'query':
|
541 |
+
$jwt = $this->getFromQuery('aam-jwt');
|
542 |
break;
|
543 |
|
544 |
default:
|
545 |
+
$jwt = apply_filters('aam_extract_jwt_filter', null, $method);
|
546 |
break;
|
547 |
}
|
548 |
|
application/Service/Metabox.php
CHANGED
@@ -250,8 +250,8 @@ class AAM_Service_Metabox
|
|
250 |
{
|
251 |
$object = AAM::getUser()->getObject('metabox');
|
252 |
|
253 |
-
foreach ($metaboxes as $id
|
254 |
-
if ($object->isHidden($screen_id, $id
|
255 |
remove_meta_box($id, $screen_id, $zone);
|
256 |
}
|
257 |
}
|
250 |
{
|
251 |
$object = AAM::getUser()->getObject('metabox');
|
252 |
|
253 |
+
foreach (array_keys($metaboxes) as $id) {
|
254 |
+
if ($object->isHidden($screen_id, $id)) {
|
255 |
remove_meta_box($id, $screen_id, $zone);
|
256 |
}
|
257 |
}
|
application/Service/Route.php
CHANGED
@@ -213,7 +213,7 @@ class AAM_Service_Route
|
|
213 |
if ($object->isRestricted('restful', $route, $method)) {
|
214 |
$response = new WP_Error(
|
215 |
'rest_access_denied',
|
216 |
-
__('Access
|
217 |
array('status' => 401)
|
218 |
);
|
219 |
break;
|
213 |
if ($object->isRestricted('restful', $route, $method)) {
|
214 |
$response = new WP_Error(
|
215 |
'rest_access_denied',
|
216 |
+
__('Access Denied', AAM_KEY),
|
217 |
array('status' => 401)
|
218 |
);
|
219 |
break;
|
application/Service/SecureLogin.php
CHANGED
@@ -95,15 +95,14 @@ class AAM_Service_SecureLogin
|
|
95 |
add_action('wp_login_failed', array($this, 'trackFailedLoginAttempt'));
|
96 |
|
97 |
// AAM UI controls
|
98 |
-
add_filter('aam_user_row_actions_filter', function($actions, $user
|
99 |
// Move this to the Secure Login Service
|
100 |
if (current_user_can('aam_toggle_users')) {
|
101 |
-
$
|
102 |
-
$actions[] = $prefix . ($user->user_status ? 'unlock' : 'lock');
|
103 |
}
|
104 |
|
105 |
return $actions;
|
106 |
-
}, 10,
|
107 |
add_filter('aam_ajax_filter', array($this, 'handleAjax'), 10, 3);
|
108 |
add_filter('aam_user_expiration_actions_filter', function($actions) {
|
109 |
$actions['lock'] = __('Block User Account', AAM_KEY);
|
@@ -434,7 +433,7 @@ class AAM_Service_SecureLogin
|
|
434 |
$result = false;
|
435 |
|
436 |
if (current_user_can('aam_toggle_users') && current_user_can('edit_users')) {
|
437 |
-
if (
|
438 |
// User is not allowed to lock himself
|
439 |
if (intval($user->getId()) !== get_current_user_id()) {
|
440 |
$result = $this->changeUserStatus(
|
95 |
add_action('wp_login_failed', array($this, 'trackFailedLoginAttempt'));
|
96 |
|
97 |
// AAM UI controls
|
98 |
+
add_filter('aam_user_row_actions_filter', function($actions, $user) {
|
99 |
// Move this to the Secure Login Service
|
100 |
if (current_user_can('aam_toggle_users')) {
|
101 |
+
$actions[] = ($user->user_status ? 'unlock' : 'lock');
|
|
|
102 |
}
|
103 |
|
104 |
return $actions;
|
105 |
+
}, 10, 2);
|
106 |
add_filter('aam_ajax_filter', array($this, 'handleAjax'), 10, 3);
|
107 |
add_filter('aam_user_expiration_actions_filter', function($actions) {
|
108 |
$actions['lock'] = __('Block User Account', AAM_KEY);
|
433 |
$result = false;
|
434 |
|
435 |
if (current_user_can('aam_toggle_users') && current_user_can('edit_users')) {
|
436 |
+
if (apply_filters('aam_user_can_manage_level_filter', true, $user->getMaxLevel())) {
|
437 |
// User is not allowed to lock himself
|
438 |
if (intval($user->getId()) !== get_current_user_id()) {
|
439 |
$result = $this->changeUserStatus(
|
application/Service/Settings.php
CHANGED
@@ -36,6 +36,7 @@ class AAM_Service_Settings
|
|
36 |
AAM_Backend_Feature_Settings_Core::register();
|
37 |
AAM_Backend_Feature_Settings_Content::register();
|
38 |
AAM_Backend_Feature_Settings_ConfigPress::register();
|
|
|
39 |
}, 1);
|
40 |
}
|
41 |
}
|
36 |
AAM_Backend_Feature_Settings_Core::register();
|
37 |
AAM_Backend_Feature_Settings_Content::register();
|
38 |
AAM_Backend_Feature_Settings_ConfigPress::register();
|
39 |
+
AAM_Backend_Feature_Settings_Manager::register();
|
40 |
}, 1);
|
41 |
}
|
42 |
}
|
application/Service/Toolbar.php
CHANGED
@@ -119,7 +119,7 @@ class AAM_Service_Toolbar
|
|
119 |
_doing_it_wrong(
|
120 |
__CLASS__ . '::' . __METHOD__,
|
121 |
'Toolbar object does not have "nodes" property',
|
122 |
-
|
123 |
);
|
124 |
}
|
125 |
|
@@ -159,7 +159,7 @@ class AAM_Service_Toolbar
|
|
159 |
$nodes = $wp_admin_bar->get_nodes();
|
160 |
|
161 |
foreach ((is_array($nodes) ? $nodes : array()) as $id => $node) {
|
162 |
-
if ($toolbar->
|
163 |
if (!empty($node->parent)) { // update parent node with # link
|
164 |
$parent = $wp_admin_bar->get_node($node->parent);
|
165 |
if ($parent && ($parent->href === $node->href)) {
|
119 |
_doing_it_wrong(
|
120 |
__CLASS__ . '::' . __METHOD__,
|
121 |
'Toolbar object does not have "nodes" property',
|
122 |
+
AAM_VERSION
|
123 |
);
|
124 |
}
|
125 |
|
159 |
$nodes = $wp_admin_bar->get_nodes();
|
160 |
|
161 |
foreach ((is_array($nodes) ? $nodes : array()) as $id => $node) {
|
162 |
+
if ($toolbar->isHidden($id, true)) {
|
163 |
if (!empty($node->parent)) { // update parent node with # link
|
164 |
$parent = $wp_admin_bar->get_node($node->parent);
|
165 |
if ($parent && ($parent->href === $node->href)) {
|
application/Service/UserLevelFilter.php
CHANGED
@@ -75,6 +75,41 @@ class AAM_Service_UserLevelFilter
|
|
75 |
|
76 |
// Check if user has ability to perform certain task on other users
|
77 |
add_filter('map_meta_cap', array($this, 'mapMetaCaps'), 999, 4);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
78 |
}
|
79 |
|
80 |
/**
|
@@ -97,7 +132,7 @@ class AAM_Service_UserLevelFilter
|
|
97 |
$levels[$id] = AAM_Core_API::maxLevel($role['capabilities']);
|
98 |
}
|
99 |
|
100 |
-
if (
|
101 |
unset($roles[$id]);
|
102 |
}
|
103 |
}
|
@@ -127,7 +162,7 @@ class AAM_Service_UserLevelFilter
|
|
127 |
foreach ($roles->role_objects as $id => $role) {
|
128 |
$roleMax = AAM_Core_API::maxLevel($role->capabilities);
|
129 |
|
130 |
-
if (
|
131 |
$exclude[] = $id;
|
132 |
}
|
133 |
}
|
@@ -151,7 +186,7 @@ class AAM_Service_UserLevelFilter
|
|
151 |
|
152 |
foreach ($roles->role_objects as $id => $role) {
|
153 |
$roleMax = AAM_Core_API::maxLevel($role->capabilities);
|
154 |
-
if (isset($views[$id]) &&
|
155 |
unset($views[$id]);
|
156 |
}
|
157 |
}
|
@@ -179,21 +214,10 @@ class AAM_Service_UserLevelFilter
|
|
179 |
*/
|
180 |
public function mapMetaCaps($caps, $cap, $user_id, $args)
|
181 |
{
|
182 |
-
$
|
183 |
-
|
184 |
-
switch ($cap) {
|
185 |
-
case 'edit_user':
|
186 |
-
case 'delete_user':
|
187 |
-
// Some plugins or themes simply do not provide the the user ID for
|
188 |
-
// these capabilities. I did not find in WP core any place were they
|
189 |
-
// violate this rule
|
190 |
-
if (!empty($objectId)) {
|
191 |
-
$caps = $this->authorizeUserUpdate($caps, $objectId);
|
192 |
-
}
|
193 |
-
break;
|
194 |
|
195 |
-
|
196 |
-
|
197 |
}
|
198 |
|
199 |
return $caps;
|
@@ -215,7 +239,7 @@ class AAM_Service_UserLevelFilter
|
|
215 |
$user = AAM::api()->getUser($userId);
|
216 |
$userLevel = AAM_Core_API::maxLevel($user->allcaps);
|
217 |
|
218 |
-
if (
|
219 |
$caps[] = 'do_not_allow';
|
220 |
}
|
221 |
|
75 |
|
76 |
// Check if user has ability to perform certain task on other users
|
77 |
add_filter('map_meta_cap', array($this, 'mapMetaCaps'), 999, 4);
|
78 |
+
|
79 |
+
// Determine if current user is allowed to manage specific user level
|
80 |
+
add_filter(
|
81 |
+
'aam_user_can_manage_level_filter', array($this, 'isUserLevelAllowed'), 10, 2
|
82 |
+
);
|
83 |
+
}
|
84 |
+
|
85 |
+
/**
|
86 |
+
* Determine if current user is allowed to manage provided user level
|
87 |
+
*
|
88 |
+
* @param boolean $allowed
|
89 |
+
* @param int $level
|
90 |
+
*
|
91 |
+
* @return boolean
|
92 |
+
*
|
93 |
+
* @access public
|
94 |
+
* @version 6.0.0
|
95 |
+
*/
|
96 |
+
public function isUserLevelAllowed($allowed, $level)
|
97 |
+
{
|
98 |
+
$allow_equal_level = true;
|
99 |
+
|
100 |
+
if (AAM_Core_API::capExists('manage_same_user_level')) {
|
101 |
+
$allow_equal_level = current_user_can('manage_same_user_level');
|
102 |
+
}
|
103 |
+
|
104 |
+
$user_level = AAM::getUser()->getMaxLevel();
|
105 |
+
|
106 |
+
if ($allow_equal_level) {
|
107 |
+
$allowed = $user_level >= $level;
|
108 |
+
} else {
|
109 |
+
$allowed = $user_level > $level;
|
110 |
+
}
|
111 |
+
|
112 |
+
return $allowed;
|
113 |
}
|
114 |
|
115 |
/**
|
132 |
$levels[$id] = AAM_Core_API::maxLevel($role['capabilities']);
|
133 |
}
|
134 |
|
135 |
+
if (!$this->isUserLevelAllowed(true, $levels[$id])) {
|
136 |
unset($roles[$id]);
|
137 |
}
|
138 |
}
|
162 |
foreach ($roles->role_objects as $id => $role) {
|
163 |
$roleMax = AAM_Core_API::maxLevel($role->capabilities);
|
164 |
|
165 |
+
if (!$this->isUserLevelAllowed(true, $roleMax)) {
|
166 |
$exclude[] = $id;
|
167 |
}
|
168 |
}
|
186 |
|
187 |
foreach ($roles->role_objects as $id => $role) {
|
188 |
$roleMax = AAM_Core_API::maxLevel($role->capabilities);
|
189 |
+
if (isset($views[$id]) && !$this->isUserLevelAllowed(true, $roleMax)) {
|
190 |
unset($views[$id]);
|
191 |
}
|
192 |
}
|
214 |
*/
|
215 |
public function mapMetaCaps($caps, $cap, $user_id, $args)
|
216 |
{
|
217 |
+
$id = (isset($args[0]) ? $args[0] : null);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
218 |
|
219 |
+
if (in_array($cap, array('edit_user', 'delete_user')) && !empty($id)) {
|
220 |
+
$caps = $this->authorizeUserUpdate($caps, $id);
|
221 |
}
|
222 |
|
223 |
return $caps;
|
239 |
$user = AAM::api()->getUser($userId);
|
240 |
$userLevel = AAM_Core_API::maxLevel($user->allcaps);
|
241 |
|
242 |
+
if (!$this->isUserLevelAllowed(true, $userLevel)) {
|
243 |
$caps[] = 'do_not_allow';
|
244 |
}
|
245 |
|
application/Shortcode/Factory.php
CHANGED
@@ -55,7 +55,7 @@ class AAM_Shortcode_Factory
|
|
55 |
}
|
56 |
|
57 |
/**
|
58 |
-
* Process the
|
59 |
*
|
60 |
* @return string
|
61 |
*
|
@@ -72,7 +72,7 @@ class AAM_Shortcode_Factory
|
|
72 |
_doing_it_wrong(
|
73 |
__CLASS__ . '::' . __METHOD__,
|
74 |
'No valid strategy found for the given context',
|
75 |
-
|
76 |
);
|
77 |
}
|
78 |
|
55 |
}
|
56 |
|
57 |
/**
|
58 |
+
* Process the short-code
|
59 |
*
|
60 |
* @return string
|
61 |
*
|
72 |
_doing_it_wrong(
|
73 |
__CLASS__ . '::' . __METHOD__,
|
74 |
'No valid strategy found for the given context',
|
75 |
+
AAM_VERSION
|
76 |
);
|
77 |
}
|
78 |
|
lang/advanced-access-manager-en_US.po
CHANGED
@@ -1,7 +1,7 @@
|
|
1 |
msgid ""
|
2 |
msgstr ""
|
3 |
"Project-Id-Version: Advanced Access Manager\n"
|
4 |
-
"POT-Creation-Date: 2019-10-
|
5 |
"PO-Revision-Date: \n"
|
6 |
"Last-Translator: \n"
|
7 |
"Language-Team: AAMPlugin <support@aamplugin.com>\n"
|
@@ -24,6 +24,34 @@ msgstr ""
|
|
24 |
msgid "WP 4.7.0 or higher is required."
|
25 |
msgstr ""
|
26 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
27 |
#: application/Backend/Feature/Main/404Redirect.php:71
|
28 |
#: application/Service/NotFoundRedirect.php:52
|
29 |
msgid "404 Redirect"
|
@@ -37,32 +65,32 @@ msgstr ""
|
|
37 |
msgid "Permission denied to delete this capability"
|
38 |
msgstr ""
|
39 |
|
40 |
-
#: application/Backend/Feature/Main/Capability.php:
|
41 |
-
#: application/Backend/Feature/Main/Capability.php:
|
42 |
msgid "System"
|
43 |
msgstr ""
|
44 |
|
45 |
-
#: application/Backend/Feature/Main/Capability.php:
|
46 |
-
#: application/Backend/Feature/Main/Capability.php:
|
47 |
msgid "Posts & Pages"
|
48 |
msgstr ""
|
49 |
|
50 |
-
#: application/Backend/Feature/Main/Capability.php:
|
51 |
-
#: application/Backend/Feature/Main/Capability.php:
|
52 |
msgid "Backend"
|
53 |
msgstr ""
|
54 |
|
55 |
-
#: application/Backend/Feature/Main/Capability.php:
|
56 |
-
#: application/Backend/Feature/Main/Capability.php:
|
57 |
msgid "AAM Interface"
|
58 |
msgstr ""
|
59 |
|
60 |
-
#: application/Backend/Feature/Main/Capability.php:
|
61 |
-
#: application/Backend/Feature/Main/Capability.php:
|
62 |
msgid "Miscellaneous"
|
63 |
msgstr ""
|
64 |
|
65 |
-
#: application/Backend/Feature/Main/Capability.php:
|
66 |
#: application/Service/Capability.php:52
|
67 |
msgid "Capabilities"
|
68 |
msgstr ""
|
@@ -93,22 +121,18 @@ msgstr ""
|
|
93 |
msgid "Backend Menu"
|
94 |
msgstr ""
|
95 |
|
96 |
-
#: application/Backend/Feature/Main/Metabox.php:
|
97 |
#: application/Service/Metabox.php:42
|
98 |
msgid "Metaboxes & Widgets"
|
99 |
msgstr ""
|
100 |
|
101 |
-
#: application/Backend/Feature/Main/Policy.php:
|
102 |
-
msgid "Failed to fetch policy. Please try again."
|
103 |
-
msgstr ""
|
104 |
-
|
105 |
-
#: application/Backend/Feature/Main/Policy.php:179
|
106 |
msgid "(no title)"
|
107 |
msgstr ""
|
108 |
|
109 |
-
#: application/Backend/Feature/Main/Policy.php:
|
110 |
-
#: application/Service/AccessPolicy.php:
|
111 |
-
#: application/Service/AccessPolicy.php:
|
112 |
msgid "Access Policies"
|
113 |
msgstr ""
|
114 |
|
@@ -117,12 +141,12 @@ msgid "307 - Temporary Redirect (Default)"
|
|
117 |
msgstr ""
|
118 |
|
119 |
#: application/Backend/Feature/Main/Post.php:215
|
120 |
-
#: application/Backend/
|
121 |
msgid "301 - Moved Permanently"
|
122 |
msgstr ""
|
123 |
|
124 |
#: application/Backend/Feature/Main/Post.php:216
|
125 |
-
#: application/Backend/
|
126 |
msgid "303 - See Other"
|
127 |
msgstr ""
|
128 |
|
@@ -131,22 +155,22 @@ msgstr ""
|
|
131 |
msgid "%d times"
|
132 |
msgstr ""
|
133 |
|
134 |
-
#: application/Backend/Feature/Main/Post.php:
|
135 |
#, php-format
|
136 |
msgid "\"%s\" page"
|
137 |
msgstr ""
|
138 |
|
139 |
-
#: application/Backend/Feature/Main/Post.php:
|
140 |
#, php-format
|
141 |
msgid "%s URL"
|
142 |
msgstr ""
|
143 |
|
144 |
-
#: application/Backend/Feature/Main/Post.php:
|
145 |
msgid "Login page"
|
146 |
msgstr ""
|
147 |
|
148 |
-
#: application/Backend/Feature/Main/Post.php:
|
149 |
-
#: application/Service/Content.php:
|
150 |
msgid "Posts & Terms"
|
151 |
msgstr ""
|
152 |
|
@@ -165,7 +189,7 @@ msgstr ""
|
|
165 |
msgid "Admin Toolbar"
|
166 |
msgstr ""
|
167 |
|
168 |
-
#: application/Backend/Feature/Main/Uri.php:
|
169 |
msgid "URI Access"
|
170 |
msgstr ""
|
171 |
|
@@ -250,15 +274,15 @@ msgstr ""
|
|
250 |
msgid "Services"
|
251 |
msgstr ""
|
252 |
|
253 |
-
#: application/Backend/Feature/Subject/Role.php:
|
254 |
-
#: application/Backend/Feature/Subject/Role.php:
|
255 |
-
#: application/Backend/Feature/Subject/Role.php:
|
256 |
-
#: application/Backend/Feature/Subject/Role.php:
|
257 |
#: application/Backend/Feature/Subject/User.php:80
|
258 |
msgid "Unauthorized operation"
|
259 |
msgstr ""
|
260 |
|
261 |
-
#: application/Backend/Feature/Subject/Role.php:
|
262 |
msgid "Failed to delete the role"
|
263 |
msgstr ""
|
264 |
|
@@ -266,9 +290,9 @@ msgstr ""
|
|
266 |
msgid "Cannot manage yourself"
|
267 |
msgstr ""
|
268 |
|
269 |
-
#: application/Backend/Feature/Subject/User.php:
|
270 |
-
#: application/Backend/Feature/Subject/User.php:
|
271 |
-
#: application/Backend/View/Localization.php:141 media/js/aam.js:
|
272 |
msgid "Unexpected application error"
|
273 |
msgstr ""
|
274 |
|
@@ -280,28 +304,23 @@ msgstr ""
|
|
280 |
msgid "You are not allowed to manage AAM subjects"
|
281 |
msgstr ""
|
282 |
|
283 |
-
#: application/Backend/View.php:
|
284 |
-
#: application/Service/Route.php:215
|
285 |
-
msgid "Access denied"
|
286 |
-
msgstr ""
|
287 |
-
|
288 |
-
#: application/Backend/View/Localization.php:32 media/js/aam.js:2000
|
289 |
msgid "Search Capability"
|
290 |
msgstr ""
|
291 |
|
292 |
-
#: application/Backend/View/Localization.php:33 media/js/aam.js:
|
293 |
msgid "_TOTAL_ capability(s)"
|
294 |
msgstr ""
|
295 |
|
296 |
-
#: application/Backend/View/Localization.php:34 media/js/aam.js:
|
297 |
-
#: media/js/aam.js:
|
298 |
-
#: media/js/aam.js:
|
299 |
-
#: media/js/aam.js:
|
300 |
-
#: media/js/aam.js:
|
301 |
msgid "Saving..."
|
302 |
msgstr ""
|
303 |
|
304 |
-
#: application/Backend/View/Localization.php:35 media/js/aam.js:
|
305 |
msgid "Failed to add new capability"
|
306 |
msgstr ""
|
307 |
|
@@ -309,37 +328,39 @@ msgstr ""
|
|
309 |
msgid "Application error"
|
310 |
msgstr ""
|
311 |
|
312 |
-
#: application/Backend/View/Localization.php:37 media/js/aam.js:
|
313 |
msgid "Add Capability"
|
314 |
msgstr ""
|
315 |
|
316 |
-
#: application/Backend/View/Localization.php:38
|
317 |
-
#: application/Backend/
|
318 |
msgid "Update Capability"
|
319 |
msgstr ""
|
320 |
|
321 |
-
#: application/Backend/View/Localization.php:39
|
322 |
-
#:
|
323 |
-
#: application/Backend/
|
|
|
324 |
msgid "Show Menu"
|
325 |
msgstr ""
|
326 |
|
327 |
-
#: application/Backend/View/Localization.php:40
|
328 |
-
#:
|
329 |
-
#: application/Backend/
|
|
|
330 |
msgid "Restrict Menu"
|
331 |
msgstr ""
|
332 |
|
333 |
-
#: application/Backend/View/Localization.php:41 media/js/aam.js:
|
334 |
msgid "Failed to retrieve mataboxes"
|
335 |
msgstr ""
|
336 |
|
337 |
-
#: application/Backend/View/Localization.php:42 media/js/aam.js:
|
338 |
-
#: media/js/aam.js:
|
339 |
msgid "Search"
|
340 |
msgstr ""
|
341 |
|
342 |
-
#: application/Backend/View/Localization.php:43 media/js/aam.js:
|
343 |
msgid "_TOTAL_ object(s)"
|
344 |
msgstr ""
|
345 |
|
@@ -347,16 +368,16 @@ msgstr ""
|
|
347 |
msgid "Failed"
|
348 |
msgstr ""
|
349 |
|
350 |
-
#: application/Backend/View/Localization.php:45 media/js/aam.js:
|
351 |
-
#: media/js/aam.js:
|
352 |
msgid "Loading..."
|
353 |
msgstr ""
|
354 |
|
355 |
-
#: application/Backend/View/Localization.php:46 media/js/aam.js:
|
356 |
msgid "No role"
|
357 |
msgstr ""
|
358 |
|
359 |
-
#: application/Backend/View/Localization.php:47 media/js/aam.js:
|
360 |
msgid "Create New Role"
|
361 |
msgstr ""
|
362 |
|
@@ -364,21 +385,21 @@ msgstr ""
|
|
364 |
msgid "Search Role"
|
365 |
msgstr ""
|
366 |
|
367 |
-
#: application/Backend/View/Localization.php:49 media/js/aam.js:
|
368 |
msgid "_TOTAL_ role(s)"
|
369 |
msgstr ""
|
370 |
|
371 |
-
#: application/Backend/View/Localization.php:50
|
372 |
-
#:
|
373 |
-
#: application/Backend/
|
374 |
-
#: application/Backend/
|
375 |
-
#: application/Backend/
|
376 |
-
#:
|
377 |
msgid "Create"
|
378 |
msgstr ""
|
379 |
|
380 |
-
#: application/Backend/View/Localization.php:51
|
381 |
-
#: application/Backend/
|
382 |
msgid "Users"
|
383 |
msgstr ""
|
384 |
|
@@ -390,18 +411,20 @@ msgstr ""
|
|
390 |
msgid "Add Role"
|
391 |
msgstr ""
|
392 |
|
393 |
-
#: application/Backend/View/Localization.php:54 media/js/aam.js:
|
394 |
msgid "Failed to update role"
|
395 |
msgstr ""
|
396 |
|
397 |
-
#: application/Backend/View/Localization.php:55
|
398 |
-
#: application/Backend/
|
399 |
-
#: application/Backend/
|
400 |
msgid "Update"
|
401 |
msgstr ""
|
402 |
|
403 |
-
#: application/Backend/View/Localization.php:56
|
404 |
-
#: application/Backend/
|
|
|
|
|
405 |
msgid "Reset"
|
406 |
msgstr ""
|
407 |
|
@@ -409,373 +432,383 @@ msgstr ""
|
|
409 |
msgid "Update..."
|
410 |
msgstr ""
|
411 |
|
412 |
-
#: application/Backend/View/Localization.php:58 media/js/aam.js:
|
413 |
-
#: media/js/aam.js:
|
414 |
msgid "Deleting..."
|
415 |
msgstr ""
|
416 |
|
417 |
-
#: application/Backend/View/Localization.php:59 media/js/aam.js:
|
418 |
msgid "Failed to delete role"
|
419 |
msgstr ""
|
420 |
|
421 |
#: application/Backend/View/Localization.php:60
|
422 |
-
#: application/Backend/
|
423 |
msgid "Delete Role"
|
424 |
msgstr ""
|
425 |
|
426 |
-
#: application/Backend/View/Localization.php:61 media/js/aam.js:
|
427 |
msgid "Failed to lock user"
|
428 |
msgstr ""
|
429 |
|
430 |
-
#: application/Backend/View/Localization.php:62 media/js/aam.js:
|
431 |
msgid "Search user"
|
432 |
msgstr ""
|
433 |
|
434 |
-
#: application/Backend/View/Localization.php:63 media/js/aam.js:
|
|
|
|
|
|
|
|
|
435 |
msgid "_TOTAL_ user(s)"
|
436 |
msgstr ""
|
437 |
|
438 |
-
#: application/Backend/View/Localization.php:
|
439 |
msgid "Create New User"
|
440 |
msgstr ""
|
441 |
|
442 |
-
#: application/Backend/View/Localization.php:
|
443 |
-
#: application/Backend/
|
444 |
msgid "Role"
|
445 |
msgstr ""
|
446 |
|
447 |
-
#: application/Backend/View/Localization.php:
|
448 |
-
#: application/Core/Subject/Default.php:36 media/js/aam.js:
|
449 |
msgid "All Users, Roles and Visitor"
|
450 |
msgstr ""
|
451 |
|
452 |
-
#: application/Backend/View/Localization.php:
|
453 |
-
#: media/js/aam.js:
|
454 |
msgid "Failed to apply policy changes"
|
455 |
msgstr ""
|
456 |
|
457 |
-
#: application/Backend/View/Localization.php:
|
458 |
-
#:
|
|
|
459 |
msgid "Attach Policy To Visitors"
|
460 |
msgstr ""
|
461 |
|
462 |
-
#: application/Backend/View/Localization.php:
|
463 |
-
#:
|
|
|
464 |
msgid "Detach Policy From Visitors"
|
465 |
msgstr ""
|
466 |
|
467 |
-
#: application/Backend/View/Localization.php:
|
468 |
-
#:
|
469 |
-
#: media/js/aam.js:3659
|
470 |
msgid "Generating URL..."
|
471 |
msgstr ""
|
472 |
|
473 |
-
#: application/Backend/View/Localization.php:
|
474 |
-
#: application/Core/Subject/Visitor.php:43 media/js/aam.js:
|
475 |
msgid "Anonymous"
|
476 |
msgstr ""
|
477 |
|
478 |
-
#: application/Backend/View/Localization.php:
|
479 |
-
#: media/js/aam.js:
|
480 |
msgid "Processing..."
|
481 |
msgstr ""
|
482 |
|
483 |
-
#: application/Backend/View/Localization.php:
|
484 |
msgid "Loading roles..."
|
485 |
msgstr ""
|
486 |
|
487 |
-
#: application/Backend/View/Localization.php:
|
488 |
-
#:
|
489 |
-
#: media/js/aam.js:3669
|
490 |
msgid "Failed to generate JWT token"
|
491 |
msgstr ""
|
492 |
|
493 |
-
#: application/Backend/View/Localization.php:
|
|
|
|
|
|
|
|
|
494 |
msgid "Current user"
|
495 |
msgstr ""
|
496 |
|
497 |
-
#: application/Backend/View/Localization.php:
|
498 |
msgid "Current role"
|
499 |
msgstr ""
|
500 |
|
501 |
-
#: application/Backend/View/Localization.php:
|
502 |
msgid "Manage Access"
|
503 |
msgstr ""
|
504 |
|
505 |
-
#: application/Backend/View/Localization.php:
|
506 |
msgid "Filter by role"
|
507 |
msgstr ""
|
508 |
|
509 |
-
#: application/Backend/View/Localization.php:
|
510 |
-
#: application/Backend/View/PostOptionList.php:76 media/js/aam.js:
|
511 |
msgid "Edit"
|
512 |
msgstr ""
|
513 |
|
514 |
-
#: application/Backend/View/Localization.php:
|
515 |
-
#:
|
516 |
-
#: application/Backend/
|
517 |
-
#: application/Backend/
|
518 |
-
#: application/Backend/
|
519 |
-
#: application/Backend/
|
520 |
-
#: application/Backend/
|
521 |
-
#: application/Backend/
|
522 |
-
#:
|
523 |
msgid "Save"
|
524 |
msgstr ""
|
525 |
|
526 |
-
#: application/Backend/View/Localization.php:
|
527 |
msgid "Manage role"
|
528 |
msgstr ""
|
529 |
|
530 |
-
#: application/Backend/View/Localization.php:
|
531 |
msgid "Edit role"
|
532 |
msgstr ""
|
533 |
|
534 |
-
#: application/Backend/View/Localization.php:
|
535 |
-
#: media/js/aam.js:
|
536 |
msgid "Delete role"
|
537 |
msgstr ""
|
538 |
|
539 |
-
#: application/Backend/View/Localization.php:
|
540 |
msgid "Clone role"
|
541 |
msgstr ""
|
542 |
|
543 |
-
#: application/Backend/View/Localization.php:
|
544 |
msgid "Manage user"
|
545 |
msgstr ""
|
546 |
|
547 |
-
#: application/Backend/View/Localization.php:
|
548 |
msgid "Edit user"
|
549 |
msgstr ""
|
550 |
|
551 |
-
#: application/Backend/View/Localization.php:
|
552 |
-
#: media/js/aam.js:
|
553 |
msgid "Lock user"
|
554 |
msgstr ""
|
555 |
|
556 |
-
#: application/Backend/View/Localization.php:
|
557 |
-
#: media/js/aam.js:
|
558 |
msgid "Unlock user"
|
559 |
msgstr ""
|
560 |
|
561 |
-
#: application/Backend/View/Localization.php:
|
562 |
msgid "WordPress core does not allow to grant this capability"
|
563 |
msgstr ""
|
564 |
|
565 |
-
#: application/Backend/View/Localization.php:
|
566 |
-
#: media/js/aam.js:
|
567 |
msgid "Detach Policy From Everybody"
|
568 |
msgstr ""
|
569 |
|
570 |
-
#: application/Backend/View/Localization.php:
|
571 |
-
#: media/js/aam.js:
|
572 |
msgid "Attach Policy To Everybody"
|
573 |
msgstr ""
|
574 |
|
575 |
-
#: application/Backend/View/Localization.php:
|
576 |
msgid "Search Policy"
|
577 |
msgstr ""
|
578 |
|
579 |
-
#: application/Backend/View/Localization.php:
|
580 |
msgid "_TOTAL_ Policies"
|
581 |
msgstr ""
|
582 |
|
583 |
-
#: application/Backend/View/Localization.php:
|
584 |
msgid "Apply Policy"
|
585 |
msgstr ""
|
586 |
|
587 |
-
#: application/Backend/View/Localization.php:
|
588 |
msgid "Revoke Policy"
|
589 |
msgstr ""
|
590 |
|
591 |
-
#: application/Backend/View/Localization.php:
|
592 |
-
#: application/Service/AccessPolicy.php:
|
593 |
msgid "Edit Policy"
|
594 |
msgstr ""
|
595 |
|
596 |
-
#: application/Backend/View/Localization.php:
|
597 |
-
#: application/Backend/
|
598 |
-
#: application/Backend/
|
599 |
msgid "Uncheck to allow"
|
600 |
msgstr ""
|
601 |
|
602 |
-
#: application/Backend/View/Localization.php:
|
603 |
-
#: application/Backend/
|
604 |
-
#: application/Backend/
|
605 |
msgid "Check to restrict"
|
606 |
msgstr ""
|
607 |
|
608 |
-
#: application/Backend/View/Localization.php:
|
609 |
-
#:
|
|
|
610 |
msgid "Uncheck to show"
|
611 |
msgstr ""
|
612 |
|
613 |
-
#: application/Backend/View/Localization.php:
|
614 |
-
#:
|
|
|
615 |
msgid "Check to hide"
|
616 |
msgstr ""
|
617 |
|
618 |
-
#: application/Backend/View/Localization.php:
|
619 |
-
#: application/Backend/
|
620 |
msgid "Initialize"
|
621 |
msgstr ""
|
622 |
|
623 |
-
#: application/Backend/View/Localization.php:
|
624 |
msgid "No capabilities"
|
625 |
msgstr ""
|
626 |
|
627 |
-
#: application/Backend/View/Localization.php:
|
628 |
msgid "Post Type"
|
629 |
msgstr ""
|
630 |
|
631 |
-
#: application/Backend/View/Localization.php:
|
632 |
msgid "Hierarchical Taxonomy"
|
633 |
msgstr ""
|
634 |
|
635 |
-
#: application/Backend/View/Localization.php:
|
636 |
msgid "Hierarchical Term"
|
637 |
msgstr ""
|
638 |
|
639 |
-
#: application/Backend/View/Localization.php:
|
640 |
msgid "Tag Taxonomy"
|
641 |
msgstr ""
|
642 |
|
643 |
-
#: application/Backend/View/Localization.php:
|
644 |
msgid "Tag"
|
645 |
msgstr ""
|
646 |
|
647 |
-
#: application/Backend/View/Localization.php:
|
648 |
msgid "Customized Settings"
|
649 |
msgstr ""
|
650 |
|
651 |
-
#: application/Backend/View/Localization.php:
|
652 |
-
#: media/js/aam.js:
|
653 |
msgid "Parent"
|
654 |
msgstr ""
|
655 |
|
656 |
-
#: application/Backend/View/Localization.php:
|
657 |
msgid "Drill-Down"
|
658 |
msgstr ""
|
659 |
|
660 |
-
#: application/Backend/View/Localization.php:
|
661 |
msgid "_TOTAL_ route(s)"
|
662 |
msgstr ""
|
663 |
|
664 |
-
#: application/Backend/View/Localization.php:
|
665 |
msgid "No API endpoints found. You might have APIs disabled."
|
666 |
msgstr ""
|
667 |
|
668 |
-
#: application/Backend/View/Localization.php:
|
669 |
-
#: media/js/aam.js:
|
670 |
msgid "Nothing to show"
|
671 |
msgstr ""
|
672 |
|
673 |
-
#: application/Backend/View/Localization.php:
|
674 |
msgid "Failed to save URI rule"
|
675 |
msgstr ""
|
676 |
|
677 |
-
#: application/Backend/View/Localization.php:
|
678 |
msgid "Failed to delete URI rule"
|
679 |
msgstr ""
|
680 |
|
681 |
-
#: application/Backend/View/Localization.php:
|
682 |
msgid "_TOTAL_ URI(s)"
|
683 |
msgstr ""
|
684 |
|
685 |
-
#: application/Backend/View/Localization.php:
|
686 |
msgid "Edit Rule"
|
687 |
msgstr ""
|
688 |
|
689 |
-
#: application/Backend/View/Localization.php:
|
690 |
msgid "Delete Rule"
|
691 |
msgstr ""
|
692 |
|
693 |
-
#: application/Backend/View/Localization.php:
|
694 |
msgid "Denied"
|
695 |
msgstr ""
|
696 |
|
697 |
-
#: application/Backend/View/Localization.php:
|
698 |
msgid "Redirected"
|
699 |
msgstr ""
|
700 |
|
701 |
-
#: application/Backend/View/Localization.php:
|
702 |
msgid "Callback"
|
703 |
msgstr ""
|
704 |
|
705 |
-
#: application/Backend/View/Localization.php:
|
706 |
msgid "Allowed"
|
707 |
msgstr ""
|
708 |
|
709 |
-
#: application/Backend/View/Localization.php:
|
710 |
msgid "Generating token..."
|
711 |
msgstr ""
|
712 |
|
713 |
-
#: application/Backend/View/Localization.php:126 media/js/aam.js:
|
714 |
msgid "_TOTAL_ token(s)"
|
715 |
msgstr ""
|
716 |
|
717 |
-
#: application/Backend/View/Localization.php:127 media/js/aam.js:
|
718 |
msgid "No JWT tokens have been generated."
|
719 |
msgstr ""
|
720 |
|
721 |
-
#: application/Backend/View/Localization.php:128 media/js/aam.js:
|
722 |
msgid "Delete Token"
|
723 |
msgstr ""
|
724 |
|
725 |
-
#: application/Backend/View/Localization.php:129 media/js/aam.js:
|
726 |
msgid "View Token"
|
727 |
msgstr ""
|
728 |
|
729 |
-
#: application/Backend/View/Localization.php:130 media/js/aam.js:
|
730 |
msgid "Creating..."
|
731 |
msgstr ""
|
732 |
|
733 |
-
#: application/Backend/View/Localization.php:131 media/js/aam.js:
|
734 |
msgid "Search Service"
|
735 |
msgstr ""
|
736 |
|
737 |
-
#: application/Backend/View/Localization.php:132 media/js/aam.js:
|
738 |
msgid "_TOTAL_ service(s)"
|
739 |
msgstr ""
|
740 |
|
741 |
-
#: application/Backend/View/Localization.php:133
|
742 |
-
#: application/Backend/
|
743 |
-
#: application/Backend/
|
744 |
-
#: application/Backend/
|
745 |
msgid "Enabled"
|
746 |
msgstr ""
|
747 |
|
748 |
-
#: application/Backend/View/Localization.php:134
|
749 |
-
#: application/Backend/
|
750 |
-
#: application/Backend/
|
751 |
-
#: application/Backend/
|
752 |
msgid "Disabled"
|
753 |
msgstr ""
|
754 |
|
755 |
-
#: application/Backend/View/Localization.php:135 media/js/aam.js:
|
756 |
msgid "All settings has been cleared successfully"
|
757 |
msgstr ""
|
758 |
|
759 |
-
#: application/Backend/View/Localization.php:136
|
760 |
-
#: application/Backend/
|
761 |
msgid "Clear"
|
762 |
msgstr ""
|
763 |
|
764 |
-
#: application/Backend/View/Localization.php:137
|
765 |
-
#: application/Backend/
|
766 |
-
#: application/Backend/
|
767 |
msgid "Select Role"
|
768 |
msgstr ""
|
769 |
|
770 |
-
#: application/Backend/View/Localization.php:138 media/js/aam.js:
|
771 |
msgid "Data has been saved to clipboard"
|
772 |
msgstr ""
|
773 |
|
774 |
-
#: application/Backend/View/Localization.php:139 media/js/aam.js:
|
775 |
msgid "Failed to save data to clipboard"
|
776 |
msgstr ""
|
777 |
|
778 |
-
#: application/Backend/View/Localization.php:140 media/js/aam.js:
|
779 |
msgid "Operation completed successfully"
|
780 |
msgstr ""
|
781 |
|
@@ -800,7 +833,7 @@ msgid ""
|
|
800 |
msgstr ""
|
801 |
|
802 |
#: application/Backend/View/PostOptionList.php:41
|
803 |
-
#: application/Backend/
|
804 |
msgid "Teaser Message"
|
805 |
msgstr ""
|
806 |
|
@@ -853,13 +886,13 @@ msgid ""
|
|
853 |
msgstr ""
|
854 |
|
855 |
#: application/Backend/View/PostOptionList.php:64
|
856 |
-
#: application/Backend/
|
857 |
msgid "Password Protected"
|
858 |
msgstr ""
|
859 |
|
860 |
#: application/Backend/View/PostOptionList.php:65
|
861 |
-
#: application/Backend/
|
862 |
-
#: application/Backend/
|
863 |
msgid "Password"
|
864 |
msgstr ""
|
865 |
|
@@ -893,11 +926,11 @@ msgstr ""
|
|
893 |
msgid "Restrict access to edit the post."
|
894 |
msgstr ""
|
895 |
|
896 |
-
#: application/Backend/View/PostOptionList.php:81
|
897 |
-
#:
|
898 |
-
#: application/Backend/
|
899 |
-
#: application/Backend/
|
900 |
-
#:
|
901 |
msgid "Delete"
|
902 |
msgstr ""
|
903 |
|
@@ -931,810 +964,492 @@ msgstr ""
|
|
931 |
msgid "Howdy, %username%"
|
932 |
msgstr ""
|
933 |
|
934 |
-
#: application/
|
935 |
-
msgid "
|
936 |
msgstr ""
|
937 |
|
938 |
-
#: application/
|
939 |
-
|
940 |
-
msgid "AAM object function %s is not defined"
|
941 |
msgstr ""
|
942 |
|
943 |
-
#: application/
|
944 |
-
msgid "
|
945 |
msgstr ""
|
946 |
|
947 |
-
#: application/
|
948 |
-
msgid "
|
949 |
msgstr ""
|
950 |
|
951 |
-
#: application/
|
952 |
-
|
953 |
-
msgid "Access Denied"
|
954 |
msgstr ""
|
955 |
|
956 |
-
#: application/
|
957 |
-
msgid "
|
958 |
msgstr ""
|
959 |
|
960 |
-
#: application/
|
961 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
962 |
msgstr ""
|
963 |
|
964 |
-
#: application/
|
965 |
-
msgid "
|
966 |
msgstr ""
|
967 |
|
968 |
-
#: application/
|
969 |
-
msgid "
|
970 |
msgstr ""
|
971 |
|
972 |
-
#: application/
|
973 |
-
msgid "
|
974 |
msgstr ""
|
975 |
|
976 |
-
#: application/
|
977 |
-
msgid "
|
|
|
|
|
978 |
msgstr ""
|
979 |
|
980 |
-
#: application/
|
981 |
-
|
|
|
982 |
msgstr ""
|
983 |
|
984 |
-
#: application/
|
985 |
-
|
|
|
|
|
|
|
986 |
msgstr ""
|
987 |
|
988 |
-
#: application/
|
|
|
|
|
|
|
|
|
989 |
msgid ""
|
990 |
-
"
|
991 |
-
"
|
992 |
-
"
|
|
|
|
|
|
|
|
|
993 |
msgstr ""
|
994 |
|
995 |
-
#: application/
|
996 |
-
msgid "
|
997 |
msgstr ""
|
998 |
|
999 |
-
#: application/
|
1000 |
-
msgid ""
|
1001 |
-
"Manage list of all the registered with WordPress core capabilities for any "
|
1002 |
-
"role or individual user. The service allows to create new or update and "
|
1003 |
-
"delete existing capabilities. Very powerful set of tools for more advanced "
|
1004 |
-
"user/role access management."
|
1005 |
msgstr ""
|
1006 |
|
1007 |
-
#: application/
|
1008 |
-
msgid ""
|
1009 |
-
"Manage access to your website content for any user, role or visitor. This "
|
1010 |
-
"include access to posts, pages, media attachment, custom post types, "
|
1011 |
-
"categories, tags, custom taxonomies and terms."
|
1012 |
msgstr ""
|
1013 |
|
1014 |
-
#: application/
|
1015 |
-
msgid "
|
1016 |
msgstr ""
|
1017 |
|
1018 |
-
#: application/
|
1019 |
-
|
|
|
1020 |
msgstr ""
|
1021 |
|
1022 |
-
#: application/
|
1023 |
-
msgid ""
|
1024 |
-
"Manage the default access denied redirect when access gets denied for any "
|
1025 |
-
"protected website resource. The service hooks into the WordPress core wp_die "
|
1026 |
-
"function and redirect any frontend or backend denied requests accordingly."
|
1027 |
msgstr ""
|
1028 |
|
1029 |
-
#: application/
|
1030 |
-
msgid "
|
1031 |
msgstr ""
|
1032 |
|
1033 |
-
#: application/
|
1034 |
-
msgid ""
|
1035 |
-
"Extend the WordPress core collection of capabilities that allow more "
|
1036 |
-
"granular access control to the backend core features."
|
1037 |
msgstr ""
|
1038 |
|
1039 |
-
#: application/
|
1040 |
-
msgid ""
|
1041 |
-
"Manage the website authentication with JWT Bearer token. The service "
|
1042 |
-
"facilitates the ability to manage the list of issued JWT token for any user, "
|
1043 |
-
"revoke them or issue new on demand."
|
1044 |
msgstr ""
|
1045 |
|
1046 |
-
#: application/
|
1047 |
-
msgid "
|
|
|
|
|
1048 |
msgstr ""
|
1049 |
|
1050 |
-
#: application/
|
1051 |
-
msgid "
|
1052 |
msgstr ""
|
1053 |
|
1054 |
-
#: application/
|
1055 |
-
msgid "
|
1056 |
msgstr ""
|
1057 |
|
1058 |
-
#: application/
|
|
|
1059 |
msgid ""
|
1060 |
-
"
|
1061 |
-
"
|
|
|
1062 |
msgstr ""
|
1063 |
|
1064 |
-
#: application/
|
1065 |
-
msgid ""
|
1066 |
-
"Manage logout redirect for any group of users or individual user after user "
|
1067 |
-
"logged out successfully."
|
1068 |
msgstr ""
|
1069 |
|
1070 |
-
#: application/
|
1071 |
-
msgid ""
|
1072 |
-
"Manage visibility for the classic (not Gutenberg blocks) backend metaboxes, "
|
1073 |
-
"dashboard and frontend widgets for any role, user or visitors. The service "
|
1074 |
-
"ONLY removes unwanted metaboxes and widgets and does not prevent from direct "
|
1075 |
-
"data spoofing."
|
1076 |
msgstr ""
|
1077 |
|
1078 |
-
#: application/
|
1079 |
-
|
1080 |
-
"
|
1081 |
-
"individual user."
|
1082 |
msgstr ""
|
1083 |
|
1084 |
-
#: application/
|
1085 |
-
|
1086 |
-
"
|
1087 |
-
"unauthenticated application request. The service works great with JWT "
|
1088 |
-
"service that authenticate requests with JWT Bearer token."
|
1089 |
msgstr ""
|
1090 |
|
1091 |
-
#: application/
|
1092 |
-
msgid "
|
1093 |
msgstr ""
|
1094 |
|
1095 |
-
#: application/
|
1096 |
#, php-format
|
1097 |
-
msgid ""
|
1098 |
-
"Remote procedure call (RPC) interface is used to manage WordPress website "
|
1099 |
-
"content and features. For more information check %sXML-RPC Support%s article."
|
1100 |
msgstr ""
|
1101 |
|
1102 |
-
#: application/
|
1103 |
-
msgid "
|
1104 |
msgstr ""
|
1105 |
|
1106 |
-
#: application/
|
1107 |
-
#, php-format
|
1108 |
msgid ""
|
1109 |
-
"
|
1110 |
-
"
|
1111 |
msgstr ""
|
1112 |
|
1113 |
-
#: application/
|
1114 |
-
msgid "
|
1115 |
msgstr ""
|
1116 |
|
1117 |
-
#: application/
|
1118 |
-
msgid "
|
1119 |
msgstr ""
|
1120 |
|
1121 |
-
#: application/
|
1122 |
-
msgid ""
|
1123 |
-
"Enhance default WordPress authentication process with more secure login "
|
1124 |
-
"mechanism. The service registers frontend AJAX Login widget as well as "
|
1125 |
-
"additional endpoints for the RESTful API authentication."
|
1126 |
msgstr ""
|
1127 |
|
1128 |
-
#: application/
|
1129 |
-
msgid "
|
1130 |
msgstr ""
|
1131 |
|
1132 |
-
#: application/
|
1133 |
-
msgid "
|
1134 |
msgstr ""
|
1135 |
|
1136 |
-
#: application/
|
1137 |
-
msgid "
|
1138 |
msgstr ""
|
1139 |
|
1140 |
-
#: application/
|
1141 |
-
msgid "
|
1142 |
msgstr ""
|
1143 |
|
1144 |
-
#: application/
|
1145 |
-
msgid "
|
1146 |
msgstr ""
|
1147 |
|
1148 |
-
#: application/
|
1149 |
-
msgid "
|
1150 |
msgstr ""
|
1151 |
|
1152 |
-
#: application/
|
1153 |
-
msgid "
|
1154 |
msgstr ""
|
1155 |
|
1156 |
-
#: application/
|
1157 |
-
|
1158 |
-
msgid "%sAccess is restricted. Login to get access.%s"
|
1159 |
msgstr ""
|
1160 |
|
1161 |
-
#: application/
|
1162 |
-
|
|
|
1163 |
msgstr ""
|
1164 |
|
1165 |
-
#: application/
|
1166 |
-
msgid ""
|
1167 |
-
"Classic WordPress shortcodes that allow to manage access to parts of a "
|
1168 |
-
"frontent content as well as some UI helpers."
|
1169 |
msgstr ""
|
1170 |
|
1171 |
-
#: application/
|
1172 |
msgid ""
|
1173 |
-
"
|
1174 |
-
"
|
1175 |
-
"protect from direct access via link."
|
1176 |
msgstr ""
|
1177 |
|
1178 |
-
#: application/
|
|
|
|
|
|
|
|
|
1179 |
msgid ""
|
1180 |
-
"Manage
|
1181 |
-
"
|
1182 |
-
"how to manage user request (allow, deny, redirect, etc.)."
|
1183 |
msgstr ""
|
1184 |
|
1185 |
-
#: application/
|
1186 |
-
msgid "
|
1187 |
msgstr ""
|
1188 |
|
1189 |
-
#: application/
|
1190 |
-
msgid ""
|
1191 |
-
"Extend default WordPress core users and roles handling, and make sure that "
|
1192 |
-
"users with lower user level cannot see or manager users and roles with "
|
1193 |
-
"higher level."
|
1194 |
msgstr ""
|
1195 |
|
1196 |
-
#: application/
|
1197 |
-
|
1198 |
-
|
1199 |
-
|
|
|
|
|
1200 |
msgstr ""
|
1201 |
|
1202 |
-
#: application/
|
1203 |
-
msgid "Login
|
1204 |
msgstr ""
|
1205 |
|
1206 |
-
#:
|
1207 |
-
msgid "
|
1208 |
msgstr ""
|
1209 |
|
1210 |
-
#:
|
1211 |
-
msgid "
|
|
|
|
|
|
|
1212 |
msgstr ""
|
1213 |
|
1214 |
-
#:
|
1215 |
-
msgid "
|
|
|
|
|
|
|
|
|
|
|
1216 |
msgstr ""
|
1217 |
|
1218 |
-
#:
|
1219 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1220 |
msgstr ""
|
1221 |
|
1222 |
-
#:
|
1223 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1224 |
msgstr ""
|
1225 |
|
1226 |
-
#:
|
1227 |
-
msgid "
|
1228 |
msgstr ""
|
1229 |
|
1230 |
-
#:
|
1231 |
-
|
1232 |
-
msgid "ID:"
|
1233 |
msgstr ""
|
1234 |
|
1235 |
-
#:
|
1236 |
-
msgid "
|
1237 |
msgstr ""
|
1238 |
|
1239 |
-
#:
|
1240 |
-
msgid ": "
|
1241 |
-
msgstr ""
|
1242 |
-
|
1243 |
-
#: tests/Addon/PlusPackage/ContentAccessTest.php:185
|
1244 |
-
msgid "AAM Test"
|
1245 |
-
msgstr ""
|
1246 |
-
|
1247 |
-
#: tests/Addon/PlusPackage/ContentAccessTest.php:186
|
1248 |
-
msgid "Just for testing purposes"
|
1249 |
-
msgstr ""
|
1250 |
-
|
1251 |
-
#: application/Backend/phtml/index.phtml:12
|
1252 |
-
msgid ""
|
1253 |
-
"[Loading AAM UI]. Please wait. If content will not load within next 30 "
|
1254 |
-
"seconds, clear your browser cache and reload the page. If still nothing, it "
|
1255 |
-
"is most likely some sort of JavaScript or CSS conflict with one your active "
|
1256 |
-
"plugins or theme. Try to deactivate all plugins and switch to any default "
|
1257 |
-
"WordPress theme to find out what causes the issue."
|
1258 |
-
msgstr ""
|
1259 |
-
|
1260 |
-
#: application/Backend/phtml/index.phtml:25
|
1261 |
-
msgid "Notifications"
|
1262 |
-
msgstr ""
|
1263 |
-
|
1264 |
-
#: application/Backend/phtml/index.phtml:46
|
1265 |
-
msgid "Access"
|
1266 |
-
msgstr ""
|
1267 |
-
|
1268 |
-
#: application/Backend/phtml/index.phtml:51
|
1269 |
-
msgid "Settings"
|
1270 |
-
msgstr ""
|
1271 |
-
|
1272 |
-
#: application/Backend/phtml/index.phtml:57
|
1273 |
-
msgid "Add-Ons"
|
1274 |
-
msgstr ""
|
1275 |
-
|
1276 |
-
#: application/Backend/phtml/index.phtml:63
|
1277 |
-
msgid "Help"
|
1278 |
-
msgstr ""
|
1279 |
-
|
1280 |
-
#: application/Backend/phtml/index.phtml:77
|
1281 |
-
msgid "Reset AAM Settings"
|
1282 |
-
msgstr ""
|
1283 |
-
|
1284 |
-
#: application/Backend/phtml/index.phtml:87
|
1285 |
-
#: application/Backend/phtml/page/addon-panel.phtml:70
|
1286 |
-
#: application/Backend/phtml/page/addon-panel.phtml:81
|
1287 |
-
#: application/Backend/phtml/page/addon-panel.phtml:91
|
1288 |
-
#: application/Backend/phtml/page/addon-panel.phtml:104
|
1289 |
-
#: application/Backend/phtml/page/subject-panel-advanced.phtml:8
|
1290 |
-
#: application/Backend/phtml/page/subject-panel-advanced.phtml:20
|
1291 |
-
#: application/Backend/phtml/page/subject-panel-advanced.phtml:30
|
1292 |
-
#: application/Backend/phtml/page/subject-panel-advanced.phtml:42
|
1293 |
-
#: application/Backend/phtml/page/subject-panel-advanced.phtml:52
|
1294 |
-
#: application/Backend/phtml/page/subject-panel-advanced.phtml:60
|
1295 |
-
#: application/Backend/phtml/page/subject-panel-advanced.phtml:70
|
1296 |
-
#: application/Backend/phtml/page/subject-panel-advanced.phtml:112
|
1297 |
-
#: application/Backend/phtml/partial/post-access-form.phtml:49
|
1298 |
-
#: application/Backend/phtml/partial/post-access-form.phtml:61
|
1299 |
-
#: application/Backend/phtml/partial/post-access-form.phtml:71
|
1300 |
-
#: application/Backend/phtml/partial/post-access-form.phtml:82
|
1301 |
-
#: application/Backend/phtml/partial/post-access-form.phtml:92
|
1302 |
-
#: application/Backend/phtml/partial/post-access-form.phtml:155
|
1303 |
-
#: application/Backend/phtml/partial/post-access-form.phtml:165
|
1304 |
-
#: application/Backend/phtml/partial/post-access-form.phtml:176
|
1305 |
-
#: application/Backend/phtml/partial/post-access-form.phtml:186
|
1306 |
-
#: application/Backend/phtml/partial/post-access-form.phtml:197
|
1307 |
-
#: application/Backend/phtml/service/capability.phtml:49
|
1308 |
-
#: application/Backend/phtml/service/capability.phtml:65
|
1309 |
-
#: application/Backend/phtml/service/capability.phtml:75
|
1310 |
-
#: application/Backend/phtml/service/capability.phtml:91
|
1311 |
-
#: application/Backend/phtml/service/capability.phtml:101
|
1312 |
-
#: application/Backend/phtml/service/capability.phtml:110
|
1313 |
-
#: application/Backend/phtml/service/jwt.phtml:36
|
1314 |
-
#: application/Backend/phtml/service/jwt.phtml:85
|
1315 |
-
#: application/Backend/phtml/service/jwt.phtml:95
|
1316 |
-
#: application/Backend/phtml/service/jwt.phtml:119
|
1317 |
-
#: application/Backend/phtml/service/jwt.phtml:129
|
1318 |
-
#: application/Backend/phtml/service/jwt.phtml:137
|
1319 |
-
#: application/Backend/phtml/service/menu.phtml:124
|
1320 |
-
#: application/Backend/phtml/service/menu.phtml:144
|
1321 |
-
#: application/Backend/phtml/service/menu.phtml:166
|
1322 |
-
#: application/Backend/phtml/service/metabox.phtml:101
|
1323 |
-
#: application/Backend/phtml/service/metabox.phtml:115
|
1324 |
-
#: application/Backend/phtml/service/metabox.phtml:125
|
1325 |
-
#: application/Backend/phtml/service/metabox.phtml:143
|
1326 |
-
#: application/Backend/phtml/service/toolbar.phtml:86
|
1327 |
-
#: application/Backend/phtml/service/toolbar.phtml:108
|
1328 |
-
#: application/Backend/phtml/service/uri.phtml:26
|
1329 |
-
#: application/Backend/phtml/service/uri.phtml:109
|
1330 |
-
#: application/Backend/phtml/service/uri.phtml:119
|
1331 |
-
#: application/Backend/phtml/service/uri.phtml:131
|
1332 |
-
msgid "Close"
|
1333 |
-
msgstr ""
|
1334 |
-
|
1335 |
-
#: application/Backend/phtml/index.phtml:88
|
1336 |
-
msgid "Clear all settings"
|
1337 |
-
msgstr ""
|
1338 |
-
|
1339 |
-
#: application/Backend/phtml/index.phtml:91
|
1340 |
-
msgid "All AAM settings will be removed."
|
1341 |
-
msgstr ""
|
1342 |
-
|
1343 |
-
#: application/Backend/phtml/index.phtml:95
|
1344 |
-
msgid "Cancel"
|
1345 |
-
msgstr ""
|
1346 |
-
|
1347 |
-
#: application/Backend/phtml/index.phtml:107
|
1348 |
-
msgid ""
|
1349 |
-
"With the [Enterprise Package] get our dedicated support channel and all the "
|
1350 |
-
"premium add-ons for [100+ live websites]"
|
1351 |
-
msgstr ""
|
1352 |
-
|
1353 |
-
#: application/Backend/phtml/index.phtml:108
|
1354 |
-
#: application/Backend/phtml/page/addon-panel.phtml:55
|
1355 |
-
msgid "Read More"
|
1356 |
-
msgstr ""
|
1357 |
-
|
1358 |
-
#: application/Backend/phtml/metabox/policy-metabox.phtml:390
|
1359 |
-
#, php-format
|
1360 |
-
msgid ""
|
1361 |
-
"To learn more about Access & Security policy document, please check "
|
1362 |
-
"[%sAccess & Security Policy%s] page."
|
1363 |
-
msgstr ""
|
1364 |
-
|
1365 |
-
#: application/Backend/phtml/metabox/policy-metabox.phtml:419
|
1366 |
-
msgid "Syntax Error"
|
1367 |
-
msgstr ""
|
1368 |
-
|
1369 |
-
#: application/Backend/phtml/page/addon-panel.phtml:8
|
1370 |
-
msgid ""
|
1371 |
-
"By purchasing any of the premium addon(s) below, you obtain the license that "
|
1372 |
-
"allows you to install and use AAM software for one physical WordPress "
|
1373 |
-
"installation only. Exceptions are websites where URL is either [localhost] "
|
1374 |
-
"or starts with [dev.], [staging.], [test.] or [demo.] They are considered as "
|
1375 |
-
"development websites and you can use the purchased license unlimited number "
|
1376 |
-
"of times before it is activated on a production website. [Money back "
|
1377 |
-
"guaranteed] within 30 day from the time of purchase."
|
1378 |
-
msgstr ""
|
1379 |
-
|
1380 |
-
#: application/Backend/phtml/page/addon-panel.phtml:13
|
1381 |
-
msgid "Download Addon"
|
1382 |
-
msgstr ""
|
1383 |
-
|
1384 |
-
#: application/Backend/phtml/page/addon-panel.phtml:17
|
1385 |
-
msgid "Enter The License Key"
|
1386 |
-
msgstr ""
|
1387 |
-
|
1388 |
-
#: application/Backend/phtml/page/addon-panel.phtml:21
|
1389 |
-
msgid "Download"
|
1390 |
-
msgstr ""
|
1391 |
-
|
1392 |
-
#: application/Backend/phtml/page/addon-panel.phtml:29
|
1393 |
-
msgid "Premium"
|
1394 |
-
msgstr ""
|
1395 |
-
|
1396 |
-
#: application/Backend/phtml/page/addon-panel.phtml:41
|
1397 |
-
#: application/Backend/phtml/page/addon-panel.phtml:43
|
1398 |
-
msgid "License"
|
1399 |
-
msgstr ""
|
1400 |
-
|
1401 |
-
#: application/Backend/phtml/page/addon-panel.phtml:43
|
1402 |
-
msgid "unregistered version"
|
1403 |
-
msgstr ""
|
1404 |
-
|
1405 |
-
#: application/Backend/phtml/page/addon-panel.phtml:51
|
1406 |
-
msgid "Active"
|
1407 |
-
msgstr ""
|
1408 |
-
|
1409 |
-
#: application/Backend/phtml/page/addon-panel.phtml:53
|
1410 |
-
msgid "Inactive"
|
1411 |
-
msgstr ""
|
1412 |
-
|
1413 |
-
#: application/Backend/phtml/page/addon-panel.phtml:71
|
1414 |
-
msgid "License Key Info"
|
1415 |
-
msgstr ""
|
1416 |
-
|
1417 |
-
#: application/Backend/phtml/page/addon-panel.phtml:75
|
1418 |
-
msgid ""
|
1419 |
-
"Insert license key that you received after the payment (find the email "
|
1420 |
-
"example below). It might take up to 2 hours to process the payment."
|
1421 |
-
msgstr ""
|
1422 |
-
|
1423 |
-
#: application/Backend/phtml/page/addon-panel.phtml:92
|
1424 |
-
msgid "Plugin Installation"
|
1425 |
-
msgstr ""
|
1426 |
-
|
1427 |
-
#: application/Backend/phtml/page/addon-panel.phtml:96
|
1428 |
-
msgid "The plugin has been successfully downloaded from our server."
|
1429 |
-
msgstr ""
|
1430 |
-
|
1431 |
-
#: application/Backend/phtml/page/addon-panel.phtml:100
|
1432 |
-
#, php-format
|
1433 |
-
msgid ""
|
1434 |
-
"With AAM v6.0.0 or higher, all premium addons are [regular WordPress "
|
1435 |
-
"plugins] that you can upload by going to the %sPlugins%s page or extract "
|
1436 |
-
"downloaded ZIP archive to the [/wp-content/plugins] folder."
|
1437 |
-
msgstr ""
|
1438 |
-
|
1439 |
-
#: application/Backend/phtml/page/main-panel.phtml:33
|
1440 |
-
msgid "You are not allowed to manage any of the existing services."
|
1441 |
-
msgstr ""
|
1442 |
-
|
1443 |
-
#: application/Backend/phtml/page/subject-panel-advanced.phtml:9
|
1444 |
-
msgid "Create Role"
|
1445 |
-
msgstr ""
|
1446 |
-
|
1447 |
-
#: application/Backend/phtml/page/subject-panel-advanced.phtml:13
|
1448 |
-
#: application/Backend/phtml/page/subject-panel-advanced.phtml:35
|
1449 |
-
msgid "Role Name"
|
1450 |
-
msgstr ""
|
1451 |
-
|
1452 |
-
#: application/Backend/phtml/page/subject-panel-advanced.phtml:14
|
1453 |
-
#: application/Backend/phtml/page/subject-panel-advanced.phtml:36
|
1454 |
-
msgid "Enter Role Name"
|
1455 |
-
msgstr ""
|
1456 |
-
|
1457 |
-
#: application/Backend/phtml/page/subject-panel-advanced.phtml:31
|
1458 |
-
msgid "Update Role"
|
1459 |
-
msgstr ""
|
1460 |
-
|
1461 |
-
#: application/Backend/phtml/page/subject-panel-advanced.phtml:56
|
1462 |
-
#, php-format
|
1463 |
-
msgid "Are you sure that you want to delete the %s role?"
|
1464 |
-
msgstr ""
|
1465 |
-
|
1466 |
-
#: application/Backend/phtml/page/subject-panel-advanced.phtml:71
|
1467 |
-
msgid "Manage User"
|
1468 |
-
msgstr ""
|
1469 |
-
|
1470 |
-
#: application/Backend/phtml/page/subject-panel-advanced.phtml:74
|
1471 |
-
msgid ""
|
1472 |
-
"Define for how long user can access the website and what action needs to be "
|
1473 |
-
"taken after access expires."
|
1474 |
-
msgstr ""
|
1475 |
-
|
1476 |
-
#: application/Backend/phtml/page/subject-panel-advanced.phtml:83
|
1477 |
-
msgid "Action After Expiration"
|
1478 |
-
msgstr ""
|
1479 |
-
|
1480 |
-
#: application/Backend/phtml/page/subject-panel-advanced.phtml:86
|
1481 |
-
msgid "Select Action"
|
1482 |
-
msgstr ""
|
1483 |
-
|
1484 |
-
#: application/Backend/phtml/page/subject-panel-advanced.phtml:87
|
1485 |
-
msgid "Logout User"
|
1486 |
-
msgstr ""
|
1487 |
-
|
1488 |
-
#: application/Backend/phtml/page/subject-panel-advanced.phtml:88
|
1489 |
-
msgid "Delete Account"
|
1490 |
-
msgstr ""
|
1491 |
-
|
1492 |
-
#: application/Backend/phtml/page/subject-panel-advanced.phtml:89
|
1493 |
-
msgid "Change User Role"
|
1494 |
-
msgstr ""
|
1495 |
-
|
1496 |
-
#: application/Backend/phtml/page/subject-panel-advanced.phtml:100
|
1497 |
-
msgid "Change To Role"
|
1498 |
-
msgstr ""
|
1499 |
-
|
1500 |
-
#: application/Backend/phtml/page/subject-panel.phtml:7
|
1501 |
-
msgid "Users/Roles Manager"
|
1502 |
-
msgstr ""
|
1503 |
-
|
1504 |
-
#: application/Backend/phtml/page/subject-panel.phtml:14
|
1505 |
-
msgid "Roles"
|
1506 |
-
msgstr ""
|
1507 |
-
|
1508 |
-
#: application/Backend/phtml/page/subject-panel.phtml:20
|
1509 |
-
msgid "Visitor"
|
1510 |
-
msgstr ""
|
1511 |
-
|
1512 |
-
#: application/Backend/phtml/page/subject-panel.phtml:23
|
1513 |
-
msgid "Default"
|
1514 |
-
msgstr ""
|
1515 |
-
|
1516 |
-
#: application/Backend/phtml/page/subject-panel.phtml:26
|
1517 |
-
msgid "None"
|
1518 |
-
msgstr ""
|
1519 |
-
|
1520 |
-
#: application/Backend/phtml/page/subject-panel.phtml:39
|
1521 |
-
#: application/Backend/phtml/page/subject-panel.phtml:55
|
1522 |
-
msgid "Action"
|
1523 |
-
msgstr ""
|
1524 |
-
|
1525 |
-
#: application/Backend/phtml/page/subject-panel.phtml:54
|
1526 |
-
msgid "Username"
|
1527 |
-
msgstr ""
|
1528 |
-
|
1529 |
-
#: application/Backend/phtml/page/subject-panel.phtml:67
|
1530 |
-
msgid ""
|
1531 |
-
"Manage access to your website for visitors (any user that is not "
|
1532 |
-
"authenticated)"
|
1533 |
-
msgstr ""
|
1534 |
-
|
1535 |
-
#: application/Backend/phtml/page/subject-panel.phtml:68
|
1536 |
-
msgid "Manage Visitors"
|
1537 |
-
msgstr ""
|
1538 |
-
|
1539 |
-
#: application/Backend/phtml/page/subject-panel.phtml:75
|
1540 |
-
msgid ""
|
1541 |
-
"Manage default access to your website resources for all users, roles and "
|
1542 |
-
"visitor. This includes Administrator role and your user"
|
1543 |
-
msgstr ""
|
1544 |
-
|
1545 |
-
#: application/Backend/phtml/page/subject-panel.phtml:76
|
1546 |
-
msgid "Manage Default Access"
|
1547 |
-
msgstr ""
|
1548 |
-
|
1549 |
-
#: application/Backend/phtml/page/subject-panel.phtml:82
|
1550 |
-
msgid ""
|
1551 |
-
"You are not allowed to manage any of the existing users, roles, visitors or "
|
1552 |
-
"default access settings."
|
1553 |
-
msgstr ""
|
1554 |
-
|
1555 |
-
#: application/Backend/phtml/partial/jwt-login-url.phtml:6
|
1556 |
-
msgid "Login with URL"
|
1557 |
-
msgstr ""
|
1558 |
-
|
1559 |
-
#: application/Backend/phtml/partial/jwt-login-url.phtml:7
|
1560 |
-
#: application/Backend/phtml/service/jwt.phtml:67
|
1561 |
-
#: application/Backend/phtml/service/jwt.phtml:77
|
1562 |
-
#: application/Backend/phtml/service/jwt.phtml:102
|
1563 |
-
#: application/Backend/phtml/service/jwt.phtml:112
|
1564 |
-
msgid "Copy to clipboard"
|
1565 |
-
msgstr ""
|
1566 |
-
|
1567 |
-
#: application/Backend/phtml/partial/jwt-login-url.phtml:10
|
1568 |
-
msgid "Login URL has not been requested"
|
1569 |
-
msgstr ""
|
1570 |
-
|
1571 |
-
#: application/Backend/phtml/partial/jwt-login-url.phtml:12
|
1572 |
-
msgid "Request URL"
|
1573 |
-
msgstr ""
|
1574 |
-
|
1575 |
-
#: application/Backend/phtml/partial/jwt-login-url.phtml:16
|
1576 |
-
msgid ""
|
1577 |
-
"With this URL user will be automatically logged in until defined date and "
|
1578 |
-
"time. The JWT token associated with URL is [revokable] however not "
|
1579 |
-
"[refreshable]."
|
1580 |
-
msgstr ""
|
1581 |
-
|
1582 |
-
#: application/Backend/phtml/partial/post-access-form.phtml:5
|
1583 |
-
#: application/Backend/phtml/service/login-redirect.phtml:17
|
1584 |
-
#: application/Backend/phtml/service/logout-redirect.phtml:17
|
1585 |
-
#: application/Backend/phtml/service/menu.phtml:17
|
1586 |
-
#: application/Backend/phtml/service/metabox.phtml:23
|
1587 |
-
#: application/Backend/phtml/service/redirect.phtml:19
|
1588 |
-
#: application/Backend/phtml/service/toolbar.phtml:16
|
1589 |
-
#: application/Backend/phtml/service/uri.phtml:16
|
1590 |
-
msgid "Settings are customized"
|
1591 |
-
msgstr ""
|
1592 |
-
|
1593 |
-
#: application/Backend/phtml/partial/post-access-form.phtml:6
|
1594 |
-
#: application/Backend/phtml/service/login-redirect.phtml:18
|
1595 |
-
#: application/Backend/phtml/service/logout-redirect.phtml:18
|
1596 |
-
#: application/Backend/phtml/service/menu.phtml:18
|
1597 |
-
#: application/Backend/phtml/service/metabox.phtml:24
|
1598 |
-
#: application/Backend/phtml/service/redirect.phtml:20
|
1599 |
-
#: application/Backend/phtml/service/route.phtml:19
|
1600 |
-
#: application/Backend/phtml/service/toolbar.phtml:17
|
1601 |
-
#: application/Backend/phtml/service/uri.phtml:17
|
1602 |
-
msgid "Reset to default"
|
1603 |
-
msgstr ""
|
1604 |
-
|
1605 |
-
#: application/Backend/phtml/partial/post-access-form.phtml:23
|
1606 |
-
msgid "change"
|
1607 |
-
msgstr ""
|
1608 |
-
|
1609 |
-
#: application/Backend/phtml/partial/post-access-form.phtml:54
|
1610 |
-
msgid "Plain text or valid HTML"
|
1611 |
-
msgstr ""
|
1612 |
-
|
1613 |
-
#: application/Backend/phtml/partial/post-access-form.phtml:55
|
1614 |
-
msgid "Enter your teaser message..."
|
1615 |
-
msgstr ""
|
1616 |
-
|
1617 |
-
#: application/Backend/phtml/partial/post-access-form.phtml:56
|
1618 |
msgid ""
|
1619 |
"Use [[excerpt]] shortcode to insert post excerpt to the teaser "
|
1620 |
"message."
|
1621 |
msgstr ""
|
1622 |
|
1623 |
-
#: application/Backend/
|
1624 |
msgid "Define Access Limit"
|
1625 |
msgstr ""
|
1626 |
|
1627 |
-
#: application/Backend/
|
1628 |
msgid "Access Limit Threshold"
|
1629 |
msgstr ""
|
1630 |
|
1631 |
-
#: application/Backend/
|
1632 |
msgid "Enter digital number"
|
1633 |
msgstr ""
|
1634 |
|
1635 |
-
#: application/Backend/
|
|
|
|
|
|
|
|
|
|
|
1636 |
msgid "Access Redirect"
|
1637 |
msgstr ""
|
1638 |
|
1639 |
-
#: application/Backend/
|
1640 |
msgid ""
|
1641 |
"Use REDIRECT option only if you want to redirect user to a different "
|
1642 |
"location either temporary or permanently. Do not use it as a way to protect "
|
1643 |
"access to avoid inconsistent user experience."
|
1644 |
msgstr ""
|
1645 |
|
1646 |
-
#: application/Backend/
|
1647 |
-
#: application/Backend/
|
1648 |
-
#: application/Backend/
|
1649 |
-
#: application/Backend/
|
1650 |
-
#: application/Backend/
|
1651 |
-
#: application/Backend/
|
1652 |
msgid "Redirected to existing page [(select from the drop-down)]"
|
1653 |
msgstr ""
|
1654 |
|
1655 |
-
#: application/Backend/
|
1656 |
-
#: application/Backend/
|
1657 |
msgid "Redirected to the URL [(enter full URL starting from http or https)]"
|
1658 |
msgstr ""
|
1659 |
|
1660 |
-
#: application/Backend/
|
1661 |
-
#: application/Backend/
|
1662 |
-
#: application/Backend/
|
1663 |
msgid ""
|
1664 |
"Redirect to the login page [(after login, user will be redirected back to "
|
1665 |
"the restricted page)]"
|
1666 |
msgstr ""
|
1667 |
|
1668 |
-
#: application/Backend/
|
1669 |
-
#: application/Backend/
|
1670 |
-
#: application/Backend/
|
1671 |
-
#: application/Backend/
|
1672 |
-
#: application/Backend/
|
1673 |
-
#: application/Backend/
|
1674 |
-
#: application/Backend/
|
1675 |
#, php-format
|
1676 |
msgid "Trigger PHP callback function [(valid %sPHP callback%s is required)]"
|
1677 |
msgstr ""
|
1678 |
|
1679 |
-
#: application/Backend/
|
1680 |
-
#: application/Backend/
|
1681 |
-
#: application/Backend/
|
1682 |
-
#: application/Backend/
|
1683 |
-
#: application/Backend/
|
1684 |
-
#: application/Backend/
|
1685 |
-
#: application/Backend/
|
1686 |
msgid "Existing Page"
|
1687 |
msgstr ""
|
1688 |
|
1689 |
-
#: application/Backend/
|
1690 |
-
#: application/Backend/
|
1691 |
-
#: application/Backend/
|
1692 |
-
#: application/Backend/
|
1693 |
-
#: application/Backend/
|
1694 |
-
#: application/Backend/
|
1695 |
-
#: application/Backend/
|
1696 |
msgid "-- Select Page --"
|
1697 |
msgstr ""
|
1698 |
|
1699 |
-
#: application/Backend/
|
1700 |
-
#: application/Backend/
|
1701 |
-
#: application/Backend/
|
1702 |
-
#: application/Backend/
|
1703 |
-
#: application/Backend/
|
1704 |
-
#: application/Backend/
|
1705 |
msgid "The URL"
|
1706 |
msgstr ""
|
1707 |
|
1708 |
-
#: application/Backend/
|
1709 |
-
#: application/Backend/
|
1710 |
-
#: application/Backend/
|
1711 |
-
#: application/Backend/
|
1712 |
-
#: application/Backend/
|
1713 |
-
#: application/Backend/
|
1714 |
-
#: application/Backend/
|
1715 |
msgid "PHP Callback Function"
|
1716 |
msgstr ""
|
1717 |
|
1718 |
-
#: application/Backend/
|
1719 |
-
#: application/Backend/
|
1720 |
-
#: application/Backend/
|
1721 |
msgid "Enter valid callback"
|
1722 |
msgstr ""
|
1723 |
|
1724 |
-
#: application/Backend/
|
1725 |
-
#: application/Backend/
|
1726 |
msgid "HTTP Redirect Code"
|
1727 |
msgstr ""
|
1728 |
|
1729 |
-
#: application/Backend/
|
1730 |
msgid "Enter Password"
|
1731 |
msgstr ""
|
1732 |
|
1733 |
-
#: application/Backend/
|
1734 |
msgid "Expiration Date/Time"
|
1735 |
msgstr ""
|
1736 |
|
1737 |
-
#: application/Backend/
|
1738 |
#, php-format
|
1739 |
msgid ""
|
1740 |
"You are allowed to manage access to unlimited number of posts, pages or "
|
@@ -1745,16 +1460,16 @@ msgid ""
|
|
1745 |
"to manage access to the WordPress content%s."
|
1746 |
msgstr ""
|
1747 |
|
1748 |
-
#: application/Backend/
|
1749 |
-
msgid "Inherit
|
1750 |
msgstr ""
|
1751 |
|
1752 |
-
#: application/Backend/
|
1753 |
msgid ""
|
1754 |
"Also clone all AAM access settings (admin menu, metaboxes, redirects, etc.)"
|
1755 |
msgstr ""
|
1756 |
|
1757 |
-
#: application/Backend/
|
1758 |
#, php-format
|
1759 |
msgid ""
|
1760 |
"Managing access to the taxonomy \"%s\" is available with the premium %s[Plus "
|
@@ -1763,7 +1478,7 @@ msgid ""
|
|
1763 |
"Package add-on."
|
1764 |
msgstr ""
|
1765 |
|
1766 |
-
#: application/Backend/
|
1767 |
#, php-format
|
1768 |
msgid ""
|
1769 |
"Managing access to the %s \"%s\" is available with the premium %s[Plus "
|
@@ -1772,42 +1487,58 @@ msgid ""
|
|
1772 |
"add-on."
|
1773 |
msgstr ""
|
1774 |
|
1775 |
-
#: application/Backend/
|
1776 |
-
#: application/Backend/
|
1777 |
msgid "category"
|
1778 |
msgstr ""
|
1779 |
|
1780 |
-
#: application/Backend/
|
1781 |
-
#: application/Backend/
|
1782 |
msgid "tag"
|
1783 |
msgstr ""
|
1784 |
|
1785 |
-
#: application/Backend/
|
1786 |
#, php-format
|
1787 |
msgid ""
|
1788 |
"Manage default access to all posts that belong to the post type %s. This "
|
1789 |
"feature is available only with the premium %s[Plus Package]%s add-on."
|
1790 |
msgstr ""
|
1791 |
|
1792 |
-
#: application/Backend/
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1793 |
msgid "Setup [default] 404 redirect for all none-existing pages."
|
1794 |
msgstr ""
|
1795 |
|
1796 |
-
#: application/Backend/
|
1797 |
msgid "Default WordPress 404 handler"
|
1798 |
msgstr ""
|
1799 |
|
1800 |
-
#: application/Backend/
|
1801 |
msgid "Redirected to the URL [(enter valid URL starting from http or https)]"
|
1802 |
msgstr ""
|
1803 |
|
1804 |
-
#: application/Backend/
|
1805 |
msgid ""
|
1806 |
"You cannot setup 404 redirect for specific user, role or visitors. Switch to "
|
1807 |
"[Manage Default Access] and define default 404 redirect for everybody."
|
1808 |
msgstr ""
|
1809 |
|
1810 |
-
#: application/Backend/
|
1811 |
#, php-format
|
1812 |
msgid ""
|
1813 |
"[Be careful!] On this tab, you can manage capabilities for [%s]. Any changes "
|
@@ -1817,69 +1548,69 @@ msgid ""
|
|
1817 |
"article."
|
1818 |
msgstr ""
|
1819 |
|
1820 |
-
#: application/Backend/
|
1821 |
msgid "Filter"
|
1822 |
msgstr ""
|
1823 |
|
1824 |
-
#: application/Backend/
|
1825 |
msgid "All Capabilities"
|
1826 |
msgstr ""
|
1827 |
|
1828 |
-
#: application/Backend/
|
1829 |
msgid "Category"
|
1830 |
msgstr ""
|
1831 |
|
1832 |
-
#: application/Backend/
|
1833 |
-
#: application/Backend/
|
1834 |
-
#: application/Backend/
|
1835 |
-
#: application/Backend/
|
1836 |
msgid "Capability"
|
1837 |
msgstr ""
|
1838 |
|
1839 |
-
#: application/Backend/
|
1840 |
-
#: application/Backend/
|
1841 |
-
#: application/Backend/
|
1842 |
-
#: application/Backend/
|
1843 |
-
#: application/Backend/
|
1844 |
msgid "Actions"
|
1845 |
msgstr ""
|
1846 |
|
1847 |
-
#: application/Backend/
|
1848 |
msgid "Create Capability"
|
1849 |
msgstr ""
|
1850 |
|
1851 |
-
#: application/Backend/
|
1852 |
-
#: application/Backend/
|
1853 |
msgid "Enter Capability"
|
1854 |
msgstr ""
|
1855 |
|
1856 |
-
#: application/Backend/
|
1857 |
msgid "Also assign this capability to me"
|
1858 |
msgstr ""
|
1859 |
|
1860 |
-
#: application/Backend/
|
1861 |
msgid "Update this capability for me too"
|
1862 |
msgstr ""
|
1863 |
|
1864 |
-
#: application/Backend/
|
1865 |
msgid "Delete Capability"
|
1866 |
msgstr ""
|
1867 |
|
1868 |
-
#: application/Backend/
|
1869 |
msgid ""
|
1870 |
"You are about to delete the %s capability. Any functionality that depends on "
|
1871 |
"this capability will no longer be accessible by %n."
|
1872 |
msgstr ""
|
1873 |
|
1874 |
-
#: application/Backend/
|
1875 |
msgid "Delete For %n Only"
|
1876 |
msgstr ""
|
1877 |
|
1878 |
-
#: application/Backend/
|
1879 |
msgid "Delete For All Roles"
|
1880 |
msgstr ""
|
1881 |
|
1882 |
-
#: application/Backend/
|
1883 |
#, php-format
|
1884 |
msgid ""
|
1885 |
"Manage list of all valid JWT tokens to the website for [%s] account. For "
|
@@ -1887,74 +1618,74 @@ msgid ""
|
|
1887 |
"WordPress JWT authentication%s article."
|
1888 |
msgstr ""
|
1889 |
|
1890 |
-
#: application/Backend/
|
1891 |
msgid "Expires"
|
1892 |
msgstr ""
|
1893 |
|
1894 |
-
#: application/Backend/
|
1895 |
msgid "Create JWT Token"
|
1896 |
msgstr ""
|
1897 |
|
1898 |
-
#: application/Backend/
|
1899 |
msgid "JWT Expires"
|
1900 |
msgstr ""
|
1901 |
|
1902 |
-
#: application/Backend/
|
1903 |
msgid "Is token refreshable?"
|
1904 |
msgstr ""
|
1905 |
|
1906 |
-
#: application/Backend/
|
1907 |
msgid ""
|
1908 |
"Whether this token, before expires, can be used to obtain a new token for "
|
1909 |
"the same time duration or not."
|
1910 |
msgstr ""
|
1911 |
|
1912 |
-
#: application/Backend/
|
1913 |
-
#: application/Backend/
|
1914 |
-
msgid "JWT Token (for
|
1915 |
msgstr ""
|
1916 |
|
1917 |
-
#: application/Backend/
|
1918 |
msgid "Passwordless Login URL"
|
1919 |
msgstr ""
|
1920 |
|
1921 |
-
#: application/Backend/
|
1922 |
msgid ""
|
1923 |
"With this URL account will be automatically logged in as long as JWT token "
|
1924 |
"is valid."
|
1925 |
msgstr ""
|
1926 |
|
1927 |
-
#: application/Backend/
|
1928 |
msgid "View JWT Token"
|
1929 |
msgstr ""
|
1930 |
|
1931 |
-
#: application/Backend/
|
1932 |
msgid "Passwordless Login URL (with JWT token)"
|
1933 |
msgstr ""
|
1934 |
|
1935 |
-
#: application/Backend/
|
1936 |
msgid ""
|
1937 |
"Use this URL to authenticate account without the need to enter username/"
|
1938 |
"password."
|
1939 |
msgstr ""
|
1940 |
|
1941 |
-
#: application/Backend/
|
1942 |
msgid "Delete JWT Token"
|
1943 |
msgstr ""
|
1944 |
|
1945 |
-
#: application/Backend/
|
1946 |
msgid ""
|
1947 |
"You are about to delete already issued JWT token. Any application or user "
|
1948 |
"that has this token, will no longer be able to use it. Please confirm."
|
1949 |
msgstr ""
|
1950 |
|
1951 |
-
#: application/Backend/
|
1952 |
msgid ""
|
1953 |
"Define the [default] login redirect for all the users and roles when "
|
1954 |
"authentication is completed successfully."
|
1955 |
msgstr ""
|
1956 |
|
1957 |
-
#: application/Backend/
|
1958 |
#, php-format
|
1959 |
msgid ""
|
1960 |
"Customize login redirect for [%s] when the authentication is completed "
|
@@ -1963,63 +1694,63 @@ msgid ""
|
|
1963 |
"login solutions."
|
1964 |
msgstr ""
|
1965 |
|
1966 |
-
#: application/Backend/
|
1967 |
-
#: application/Backend/
|
1968 |
msgid "WordPress default behavior"
|
1969 |
msgstr ""
|
1970 |
|
1971 |
-
#: application/Backend/
|
1972 |
msgid ""
|
1973 |
"Redirected to the local URL [(enter full URL starting from http or https)]"
|
1974 |
msgstr ""
|
1975 |
|
1976 |
-
#: application/Backend/
|
1977 |
msgid "Define the [default] logout redirect for all the users and roles."
|
1978 |
msgstr ""
|
1979 |
|
1980 |
-
#: application/Backend/
|
1981 |
#, php-format
|
1982 |
msgid "Customize logout redirect for [%s]."
|
1983 |
msgstr ""
|
1984 |
|
1985 |
-
#: application/Backend/
|
1986 |
#, php-format
|
1987 |
msgid ""
|
1988 |
"Manage access to the backend main menu for [%s]. For more information check "
|
1989 |
"%sHow to manage WordPress backend menu%s."
|
1990 |
msgstr ""
|
1991 |
|
1992 |
-
#: application/Backend/
|
1993 |
msgid "Menu URI:"
|
1994 |
msgstr ""
|
1995 |
|
1996 |
-
#: application/Backend/
|
1997 |
-
#: application/Backend/
|
1998 |
-
#: application/Backend/
|
1999 |
msgid "more details"
|
2000 |
msgstr ""
|
2001 |
|
2002 |
-
#: application/Backend/
|
2003 |
msgid ""
|
2004 |
"Dashboard menu cannot be restricted because it is the default page all users "
|
2005 |
"are redirected after login. You can restrict only Dashboard submenus if any."
|
2006 |
msgstr ""
|
2007 |
|
2008 |
-
#: application/Backend/
|
2009 |
msgid ""
|
2010 |
"Current user does not have enough capabilities to access any available "
|
2011 |
"backend menu."
|
2012 |
msgstr ""
|
2013 |
|
2014 |
-
#: application/Backend/
|
2015 |
msgid "Dashboard Lockdown"
|
2016 |
msgstr ""
|
2017 |
|
2018 |
-
#: application/Backend/
|
2019 |
msgid "You cannot restrict access to the Dashboard Home page."
|
2020 |
msgstr ""
|
2021 |
|
2022 |
-
#: application/Backend/
|
2023 |
#, php-format
|
2024 |
msgid ""
|
2025 |
"The [Dashboard Home] is the default page that every user is redirected to "
|
@@ -2027,58 +1758,63 @@ msgid ""
|
|
2027 |
"lockdown WordPress backend%s article."
|
2028 |
msgstr ""
|
2029 |
|
2030 |
-
#: application/Backend/
|
2031 |
msgid "OK"
|
2032 |
msgstr ""
|
2033 |
|
2034 |
-
#: application/Backend/
|
2035 |
msgid "Menu Details"
|
2036 |
msgstr ""
|
2037 |
|
2038 |
-
#: application/Backend/
|
2039 |
-
#: application/Backend/
|
2040 |
msgid "Name"
|
2041 |
msgstr ""
|
2042 |
|
2043 |
-
#: application/Backend/
|
2044 |
-
#: application/Backend/
|
2045 |
-
#: application/Backend/
|
2046 |
msgid "URI"
|
2047 |
msgstr ""
|
2048 |
|
2049 |
-
#: application/Backend/
|
2050 |
-
|
|
|
|
|
|
|
|
|
|
|
2051 |
msgid ""
|
2052 |
"Manage classic (not Gutenberg) metaboxes and widgets visibility for [%s]. "
|
2053 |
"For more information please check %sHow to hide WordPress metaboxes and "
|
2054 |
"widgets%s."
|
2055 |
msgstr ""
|
2056 |
|
2057 |
-
#: application/Backend/
|
2058 |
msgid "Refresh"
|
2059 |
msgstr ""
|
2060 |
|
2061 |
-
#: application/Backend/
|
2062 |
msgid "Init URL"
|
2063 |
msgstr ""
|
2064 |
|
2065 |
-
#: application/Backend/
|
2066 |
msgid "Dashboard Widgets"
|
2067 |
msgstr ""
|
2068 |
|
2069 |
-
#: application/Backend/
|
2070 |
msgid "Frontend Widgets [(including Appearance->Widgets)]"
|
2071 |
msgstr ""
|
2072 |
|
2073 |
-
#: application/Backend/
|
2074 |
msgid "The list is not initialized. Click Refresh button above."
|
2075 |
msgstr ""
|
2076 |
|
2077 |
-
#: application/Backend/
|
2078 |
msgid "Initialize URL"
|
2079 |
msgstr ""
|
2080 |
|
2081 |
-
#: application/Backend/
|
2082 |
msgid ""
|
2083 |
"Some metaboxes are \"conditional\" and appear on the edit screen when "
|
2084 |
"certain conditions are met. For example metabox \"Comments\" appears only "
|
@@ -2087,69 +1823,74 @@ msgid ""
|
|
2087 |
"appears."
|
2088 |
msgstr ""
|
2089 |
|
2090 |
-
#: application/Backend/
|
2091 |
msgid "Backend page URL"
|
2092 |
msgstr ""
|
2093 |
|
2094 |
-
#: application/Backend/
|
2095 |
msgid "Insert valid URL"
|
2096 |
msgstr ""
|
2097 |
|
2098 |
-
#: application/Backend/
|
2099 |
msgid "Metabox/Widget Details"
|
2100 |
msgstr ""
|
2101 |
|
2102 |
-
#: application/Backend/
|
2103 |
-
#: application/Backend/
|
2104 |
msgid "Title"
|
2105 |
msgstr ""
|
2106 |
|
2107 |
-
#: application/Backend/
|
2108 |
msgid "Screen ID"
|
2109 |
msgstr ""
|
2110 |
|
2111 |
-
#: application/Backend/
|
|
|
|
|
|
|
|
|
2112 |
#, php-format
|
2113 |
msgid ""
|
2114 |
"Manage access and security policies for [%s]. For more information check "
|
2115 |
"%sAccess & Security Policy%s page."
|
2116 |
msgstr ""
|
2117 |
|
2118 |
-
#: application/Backend/
|
2119 |
msgid "Policies are customized"
|
2120 |
msgstr ""
|
2121 |
|
2122 |
-
#: application/Backend/
|
2123 |
msgid "Reset To Default"
|
2124 |
msgstr ""
|
2125 |
|
2126 |
-
#: application/Backend/
|
|
|
2127 |
msgid "Policy"
|
2128 |
msgstr ""
|
2129 |
|
2130 |
-
#: application/Backend/
|
2131 |
#, php-format
|
2132 |
msgid ""
|
2133 |
"%s[AAM Plus Package]%s extension is required in order to apply Access & "
|
2134 |
"Security Policies to everybody all together."
|
2135 |
msgstr ""
|
2136 |
|
2137 |
-
#: application/Backend/
|
2138 |
msgid "Root"
|
2139 |
msgstr ""
|
2140 |
|
2141 |
-
#: application/Backend/
|
2142 |
-
#: application/Backend/
|
2143 |
msgid "Go Back"
|
2144 |
msgstr ""
|
2145 |
|
2146 |
-
#: application/Backend/
|
2147 |
msgid ""
|
2148 |
"Define the [default] redirect for all users, roles and visitors when access "
|
2149 |
"is denied to any restricted resources on your website."
|
2150 |
msgstr ""
|
2151 |
|
2152 |
-
#: application/Backend/
|
2153 |
#, php-format
|
2154 |
msgid ""
|
2155 |
"Customize redirect for %s when access is denied to restricted resources like "
|
@@ -2157,48 +1898,48 @@ msgid ""
|
|
2157 |
"please check %sHow to redirect WordPress user when access is denied%s."
|
2158 |
msgstr ""
|
2159 |
|
2160 |
-
#: application/Backend/
|
2161 |
msgid "Frontend Redirect"
|
2162 |
msgstr ""
|
2163 |
|
2164 |
-
#: application/Backend/
|
2165 |
msgid "Backend Redirect"
|
2166 |
msgstr ""
|
2167 |
|
2168 |
-
#: application/Backend/
|
2169 |
-
#: application/Backend/
|
2170 |
msgid "Default [(\"Access Denied\" message)]"
|
2171 |
msgstr ""
|
2172 |
|
2173 |
-
#: application/Backend/
|
2174 |
-
#: application/Backend/
|
2175 |
-
#: application/Backend/
|
2176 |
msgid "Show customized message [(plain text or HTML)]"
|
2177 |
msgstr ""
|
2178 |
|
2179 |
-
#: application/Backend/
|
2180 |
-
#: application/Backend/
|
2181 |
-
#: application/Backend/
|
2182 |
msgid "Redirected to local URL [(enter valid URL starting from http or https)]"
|
2183 |
msgstr ""
|
2184 |
|
2185 |
-
#: application/Backend/
|
2186 |
-
#: application/Backend/
|
2187 |
-
#: application/Backend/
|
2188 |
msgid "Customized Message"
|
2189 |
msgstr ""
|
2190 |
|
2191 |
-
#: application/Backend/
|
2192 |
-
#: application/Backend/
|
2193 |
-
#: application/Backend/
|
2194 |
msgid "Enter message..."
|
2195 |
msgstr ""
|
2196 |
|
2197 |
-
#: application/Backend/
|
2198 |
msgid "Redirected to existing frontend page [(select from the drop-down)]"
|
2199 |
msgstr ""
|
2200 |
|
2201 |
-
#: application/Backend/
|
2202 |
#, php-format
|
2203 |
msgid ""
|
2204 |
"Manage access to the website API routes for [%s]. For the full RESTful API "
|
@@ -2206,23 +1947,23 @@ msgid ""
|
|
2206 |
"in AAM."
|
2207 |
msgstr ""
|
2208 |
|
2209 |
-
#: application/Backend/
|
2210 |
msgid "Routes are customized"
|
2211 |
msgstr ""
|
2212 |
|
2213 |
-
#: application/Backend/
|
2214 |
msgid "Method"
|
2215 |
msgstr ""
|
2216 |
|
2217 |
-
#: application/Backend/
|
2218 |
msgid "Route"
|
2219 |
msgstr ""
|
2220 |
|
2221 |
-
#: application/Backend/
|
2222 |
msgid "Deny"
|
2223 |
msgstr ""
|
2224 |
|
2225 |
-
#: application/Backend/
|
2226 |
msgid ""
|
2227 |
"[Note!] Admin Toolbar service is not intended to restrict direct access to "
|
2228 |
"linked pages. It used only to remove unnecessary items from the top admin "
|
@@ -2230,19 +1971,19 @@ msgid ""
|
|
2230 |
"or utilize the great power of capabilities."
|
2231 |
msgstr ""
|
2232 |
|
2233 |
-
#: application/Backend/
|
2234 |
msgid "Item ID:"
|
2235 |
msgstr ""
|
2236 |
|
2237 |
-
#: application/Backend/
|
2238 |
msgid "Item Details"
|
2239 |
msgstr ""
|
2240 |
|
2241 |
-
#: application/Backend/
|
2242 |
msgid "The list of top admin bar items is not initialized. Reload the page."
|
2243 |
msgstr ""
|
2244 |
|
2245 |
-
#: application/Backend/
|
2246 |
#, php-format
|
2247 |
msgid ""
|
2248 |
"Manage access to the website URL(s) for the [%s]. Note! All entered URLs "
|
@@ -2251,55 +1992,55 @@ msgid ""
|
|
2251 |
"website URL%s."
|
2252 |
msgstr ""
|
2253 |
|
2254 |
-
#: application/Backend/
|
2255 |
msgid "URI Access Rule"
|
2256 |
msgstr ""
|
2257 |
|
2258 |
-
#: application/Backend/
|
2259 |
msgid "Enter URL [(wildcard * is available with Plus Package extension)]"
|
2260 |
msgstr ""
|
2261 |
|
2262 |
-
#: application/Backend/
|
2263 |
msgid "How to redirect user when match?"
|
2264 |
msgstr ""
|
2265 |
|
2266 |
-
#: application/Backend/
|
2267 |
msgid "Allow Access"
|
2268 |
msgstr ""
|
2269 |
|
2270 |
-
#: application/Backend/
|
2271 |
msgid "Deny Access [(show \"Access Denied\" message)]"
|
2272 |
msgstr ""
|
2273 |
|
2274 |
-
#: application/Backend/
|
2275 |
msgid "The Valid Redirect URL"
|
2276 |
msgstr ""
|
2277 |
|
2278 |
-
#: application/Backend/
|
2279 |
msgid "HTTP Code (Default 307)"
|
2280 |
msgstr ""
|
2281 |
|
2282 |
-
#: application/Backend/
|
2283 |
msgid "302 - Found"
|
2284 |
msgstr ""
|
2285 |
|
2286 |
-
#: application/Backend/
|
2287 |
msgid "307 - Temporary Redirect"
|
2288 |
msgstr ""
|
2289 |
|
2290 |
-
#: application/Backend/
|
2291 |
msgid "Delete URI Rule"
|
2292 |
msgstr ""
|
2293 |
|
2294 |
-
#: application/Backend/
|
2295 |
msgid "You are about to delete the URI Rule. Please confirm!"
|
2296 |
msgstr ""
|
2297 |
|
2298 |
-
#: application/Backend/
|
2299 |
msgid "Type"
|
2300 |
msgstr ""
|
2301 |
|
2302 |
-
#: application/Backend/
|
2303 |
msgid ""
|
2304 |
"Thank you for using the Advanced Access Manager (aka AAM) plugin. With "
|
2305 |
"strong knowledge and experience in WordPress core, AAM becomes a very "
|
@@ -2307,11 +2048,11 @@ msgid ""
|
|
2307 |
"backend, and RESTful API."
|
2308 |
msgstr ""
|
2309 |
|
2310 |
-
#: application/Backend/
|
2311 |
msgid "Note!"
|
2312 |
msgstr ""
|
2313 |
|
2314 |
-
#: application/Backend/
|
2315 |
#, php-format
|
2316 |
msgid ""
|
2317 |
"Power comes with responsibility. Make sure you have a good understanding of "
|
@@ -2322,7 +2063,7 @@ msgid ""
|
|
2322 |
"server and never did."
|
2323 |
msgstr ""
|
2324 |
|
2325 |
-
#: application/Backend/
|
2326 |
msgid ""
|
2327 |
"AAM is thoroughly tested on the fresh installation of the latest WordPress "
|
2328 |
"and in the latest versions of Chrome, Safari, IE, and Firefox. If you have "
|
@@ -2330,7 +2071,7 @@ msgid ""
|
|
2330 |
"themes."
|
2331 |
msgstr ""
|
2332 |
|
2333 |
-
#: application/Backend/
|
2334 |
#, php-format
|
2335 |
msgid ""
|
2336 |
"If you are not sure where to start, please check our %s\"Get Started\"%s "
|
@@ -2338,68 +2079,406 @@ msgid ""
|
|
2338 |
"your WordPress website more effectively."
|
2339 |
msgstr ""
|
2340 |
|
2341 |
-
#: application/Backend/
|
2342 |
msgid "Go To The \"Get Started\" Page"
|
2343 |
msgstr ""
|
2344 |
|
2345 |
-
#: application/Backend/
|
2346 |
#, php-format
|
2347 |
msgid ""
|
2348 |
"Fore more information about AAM configurations check %sAAM Configurations%s "
|
2349 |
"article."
|
2350 |
msgstr ""
|
2351 |
|
2352 |
-
#: application/Backend/
|
|
|
|
|
|
|
|
|
2353 |
msgid "Service Name/Description"
|
2354 |
msgstr ""
|
2355 |
|
2356 |
-
#: application/Backend/
|
2357 |
msgid "Status"
|
2358 |
msgstr ""
|
2359 |
|
2360 |
-
#: application/Backend/
|
2361 |
msgid "Login Title"
|
2362 |
msgstr ""
|
2363 |
|
2364 |
-
#: application/Backend/
|
2365 |
msgid "Logged In Title"
|
2366 |
msgstr ""
|
2367 |
|
2368 |
-
#: application/Backend/
|
2369 |
#, php-format
|
2370 |
msgid ""
|
2371 |
"For more advanced setup like login/logout redirects, security enhancement or "
|
2372 |
"custom styling, please refer to %sHow does AAM Secure Login works%s article."
|
2373 |
msgstr ""
|
2374 |
|
2375 |
-
#: application/Backend/
|
2376 |
msgid "Username or Email Address"
|
2377 |
msgstr ""
|
2378 |
|
2379 |
-
#: application/Backend/
|
2380 |
msgid "Remember Me"
|
2381 |
msgstr ""
|
2382 |
|
2383 |
-
#: application/Backend/
|
2384 |
msgid "Log In"
|
2385 |
msgstr ""
|
2386 |
|
2387 |
-
#: application/Backend/
|
2388 |
msgid "Register"
|
2389 |
msgstr ""
|
2390 |
|
2391 |
-
#: application/Backend/
|
2392 |
msgid "Lost your password?"
|
2393 |
msgstr ""
|
2394 |
|
2395 |
-
#: application/Backend/
|
2396 |
msgid "Dashboard"
|
2397 |
msgstr ""
|
2398 |
|
2399 |
-
#: application/Backend/
|
2400 |
msgid "Edit My Profile"
|
2401 |
msgstr ""
|
2402 |
|
2403 |
-
#: application/Backend/
|
2404 |
msgid "Log Out"
|
2405 |
msgstr ""
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
msgid ""
|
2 |
msgstr ""
|
3 |
"Project-Id-Version: Advanced Access Manager\n"
|
4 |
+
"POT-Creation-Date: 2019-10-24 20:16-0400\n"
|
5 |
"PO-Revision-Date: \n"
|
6 |
"Last-Translator: \n"
|
7 |
"Language-Team: AAMPlugin <support@aamplugin.com>\n"
|
24 |
msgid "WP 4.7.0 or higher is required."
|
25 |
msgstr ""
|
26 |
|
27 |
+
#: application/Addon/Repository.php:108
|
28 |
+
msgid ""
|
29 |
+
"Manage access to your WordPress website posts, pages, media, custom post "
|
30 |
+
"types, categories, tags and custom taxonomies for any role, individual user, "
|
31 |
+
"visitors or even define default access for everybody; and do this separately "
|
32 |
+
"for frontend, backend or API levels."
|
33 |
+
msgstr ""
|
34 |
+
|
35 |
+
#: application/Addon/Repository.php:113
|
36 |
+
msgid ""
|
37 |
+
"Manage access to your WordPress website by users IP address or referred host "
|
38 |
+
"and completely lock down the entire website if necessary. Define the "
|
39 |
+
"unlimited number of whitelisted or blacklisted IPs or hosts."
|
40 |
+
msgstr ""
|
41 |
+
|
42 |
+
#: application/Addon/Repository.php:118
|
43 |
+
msgid ""
|
44 |
+
"Define and manage complex WordPress role hierarchy where all the access "
|
45 |
+
"settings are propagated down the tree with the ability to override any "
|
46 |
+
"settings for any specific role."
|
47 |
+
msgstr ""
|
48 |
+
|
49 |
+
#: application/Addon/Repository.php:133
|
50 |
+
msgid ""
|
51 |
+
"Get the complete list of all premium AAM addons in one package and all "
|
52 |
+
"future premium addons will be included for now additional cost."
|
53 |
+
msgstr ""
|
54 |
+
|
55 |
#: application/Backend/Feature/Main/404Redirect.php:71
|
56 |
#: application/Service/NotFoundRedirect.php:52
|
57 |
msgid "404 Redirect"
|
65 |
msgid "Permission denied to delete this capability"
|
66 |
msgstr ""
|
67 |
|
68 |
+
#: application/Backend/Feature/Main/Capability.php:335
|
69 |
+
#: application/Backend/Feature/Main/Capability.php:356
|
70 |
msgid "System"
|
71 |
msgstr ""
|
72 |
|
73 |
+
#: application/Backend/Feature/Main/Capability.php:336
|
74 |
+
#: application/Backend/Feature/Main/Capability.php:358
|
75 |
msgid "Posts & Pages"
|
76 |
msgstr ""
|
77 |
|
78 |
+
#: application/Backend/Feature/Main/Capability.php:337
|
79 |
+
#: application/Backend/Feature/Main/Capability.php:360
|
80 |
msgid "Backend"
|
81 |
msgstr ""
|
82 |
|
83 |
+
#: application/Backend/Feature/Main/Capability.php:338
|
84 |
+
#: application/Backend/Feature/Main/Capability.php:362
|
85 |
msgid "AAM Interface"
|
86 |
msgstr ""
|
87 |
|
88 |
+
#: application/Backend/Feature/Main/Capability.php:339
|
89 |
+
#: application/Backend/Feature/Main/Capability.php:364
|
90 |
msgid "Miscellaneous"
|
91 |
msgstr ""
|
92 |
|
93 |
+
#: application/Backend/Feature/Main/Capability.php:383
|
94 |
#: application/Service/Capability.php:52
|
95 |
msgid "Capabilities"
|
96 |
msgstr ""
|
121 |
msgid "Backend Menu"
|
122 |
msgstr ""
|
123 |
|
124 |
+
#: application/Backend/Feature/Main/Metabox.php:263
|
125 |
#: application/Service/Metabox.php:42
|
126 |
msgid "Metaboxes & Widgets"
|
127 |
msgstr ""
|
128 |
|
129 |
+
#: application/Backend/Feature/Main/Policy.php:214
|
|
|
|
|
|
|
|
|
130 |
msgid "(no title)"
|
131 |
msgstr ""
|
132 |
|
133 |
+
#: application/Backend/Feature/Main/Policy.php:307
|
134 |
+
#: application/Service/AccessPolicy.php:66
|
135 |
+
#: application/Service/AccessPolicy.php:169
|
136 |
msgid "Access Policies"
|
137 |
msgstr ""
|
138 |
|
141 |
msgstr ""
|
142 |
|
143 |
#: application/Backend/Feature/Main/Post.php:215
|
144 |
+
#: application/Backend/tmpl/service/uri.php:95
|
145 |
msgid "301 - Moved Permanently"
|
146 |
msgstr ""
|
147 |
|
148 |
#: application/Backend/Feature/Main/Post.php:216
|
149 |
+
#: application/Backend/tmpl/service/uri.php:97
|
150 |
msgid "303 - See Other"
|
151 |
msgstr ""
|
152 |
|
155 |
msgid "%d times"
|
156 |
msgstr ""
|
157 |
|
158 |
+
#: application/Backend/Feature/Main/Post.php:333
|
159 |
#, php-format
|
160 |
msgid "\"%s\" page"
|
161 |
msgstr ""
|
162 |
|
163 |
+
#: application/Backend/Feature/Main/Post.php:339
|
164 |
#, php-format
|
165 |
msgid "%s URL"
|
166 |
msgstr ""
|
167 |
|
168 |
+
#: application/Backend/Feature/Main/Post.php:343
|
169 |
msgid "Login page"
|
170 |
msgstr ""
|
171 |
|
172 |
+
#: application/Backend/Feature/Main/Post.php:1000
|
173 |
+
#: application/Service/Content.php:72
|
174 |
msgid "Posts & Terms"
|
175 |
msgstr ""
|
176 |
|
189 |
msgid "Admin Toolbar"
|
190 |
msgstr ""
|
191 |
|
192 |
+
#: application/Backend/Feature/Main/Uri.php:135 application/Service/Uri.php:53
|
193 |
msgid "URI Access"
|
194 |
msgstr ""
|
195 |
|
274 |
msgid "Services"
|
275 |
msgstr ""
|
276 |
|
277 |
+
#: application/Backend/Feature/Subject/Role.php:118
|
278 |
+
#: application/Backend/Feature/Subject/Role.php:187
|
279 |
+
#: application/Backend/Feature/Subject/Role.php:271
|
280 |
+
#: application/Backend/Feature/Subject/Role.php:297
|
281 |
#: application/Backend/Feature/Subject/User.php:80
|
282 |
msgid "Unauthorized operation"
|
283 |
msgstr ""
|
284 |
|
285 |
+
#: application/Backend/Feature/Subject/Role.php:294
|
286 |
msgid "Failed to delete the role"
|
287 |
msgstr ""
|
288 |
|
290 |
msgid "Cannot manage yourself"
|
291 |
msgstr ""
|
292 |
|
293 |
+
#: application/Backend/Feature/Subject/User.php:210
|
294 |
+
#: application/Backend/Feature/Subject/User.php:235
|
295 |
+
#: application/Backend/View/Localization.php:141 media/js/aam.js:4694
|
296 |
msgid "Unexpected application error"
|
297 |
msgstr ""
|
298 |
|
304 |
msgid "You are not allowed to manage AAM subjects"
|
305 |
msgstr ""
|
306 |
|
307 |
+
#: application/Backend/View/Localization.php:32 media/js/aam.js:1992
|
|
|
|
|
|
|
|
|
|
|
308 |
msgid "Search Capability"
|
309 |
msgstr ""
|
310 |
|
311 |
+
#: application/Backend/View/Localization.php:33 media/js/aam.js:1993
|
312 |
msgid "_TOTAL_ capability(s)"
|
313 |
msgstr ""
|
314 |
|
315 |
+
#: application/Backend/View/Localization.php:34 media/js/aam.js:410
|
316 |
+
#: media/js/aam.js:471 media/js/aam.js:1029 media/js/aam.js:2140
|
317 |
+
#: media/js/aam.js:2182 media/js/aam.js:2381 media/js/aam.js:2400
|
318 |
+
#: media/js/aam.js:2470 media/js/aam.js:2492 media/js/aam.js:2511
|
319 |
+
#: media/js/aam.js:3477
|
320 |
msgid "Saving..."
|
321 |
msgstr ""
|
322 |
|
323 |
+
#: application/Backend/View/Localization.php:35 media/js/aam.js:2148
|
324 |
msgid "Failed to add new capability"
|
325 |
msgstr ""
|
326 |
|
328 |
msgid "Application error"
|
329 |
msgstr ""
|
330 |
|
331 |
+
#: application/Backend/View/Localization.php:37 media/js/aam.js:2156
|
332 |
msgid "Add Capability"
|
333 |
msgstr ""
|
334 |
|
335 |
+
#: application/Backend/View/Localization.php:38
|
336 |
+
#: application/Backend/tmpl/service/capability.php:76 media/js/aam.js:2198
|
337 |
msgid "Update Capability"
|
338 |
msgstr ""
|
339 |
|
340 |
+
#: application/Backend/View/Localization.php:39
|
341 |
+
#: application/Backend/tmpl/service/menu.php:93
|
342 |
+
#: application/Backend/tmpl/service/toolbar.php:70 media/js/aam.js:1476
|
343 |
+
#: media/js/aam.js:1607
|
344 |
msgid "Show Menu"
|
345 |
msgstr ""
|
346 |
|
347 |
+
#: application/Backend/View/Localization.php:40
|
348 |
+
#: application/Backend/tmpl/service/menu.php:97
|
349 |
+
#: application/Backend/tmpl/service/toolbar.php:74 media/js/aam.js:1486
|
350 |
+
#: media/js/aam.js:1617
|
351 |
msgid "Restrict Menu"
|
352 |
msgstr ""
|
353 |
|
354 |
+
#: application/Backend/View/Localization.php:41 media/js/aam.js:1787
|
355 |
msgid "Failed to retrieve mataboxes"
|
356 |
msgstr ""
|
357 |
|
358 |
+
#: application/Backend/View/Localization.php:42 media/js/aam.js:2651
|
359 |
+
#: media/js/aam.js:3364 media/js/aam.js:3556 media/js/aam.js:3779
|
360 |
msgid "Search"
|
361 |
msgstr ""
|
362 |
|
363 |
+
#: application/Backend/View/Localization.php:43 media/js/aam.js:2652
|
364 |
msgid "_TOTAL_ object(s)"
|
365 |
msgstr ""
|
366 |
|
368 |
msgid "Failed"
|
369 |
msgstr ""
|
370 |
|
371 |
+
#: application/Backend/View/Localization.php:45 media/js/aam.js:64
|
372 |
+
#: media/js/aam.js:4336
|
373 |
msgid "Loading..."
|
374 |
msgstr ""
|
375 |
|
376 |
+
#: application/Backend/View/Localization.php:46 media/js/aam.js:69
|
377 |
msgid "No role"
|
378 |
msgstr ""
|
379 |
|
380 |
+
#: application/Backend/View/Localization.php:47 media/js/aam.js:149
|
381 |
msgid "Create New Role"
|
382 |
msgstr ""
|
383 |
|
385 |
msgid "Search Role"
|
386 |
msgstr ""
|
387 |
|
388 |
+
#: application/Backend/View/Localization.php:49 media/js/aam.js:133
|
389 |
msgid "_TOTAL_ role(s)"
|
390 |
msgstr ""
|
391 |
|
392 |
+
#: application/Backend/View/Localization.php:50
|
393 |
+
#: application/Backend/tmpl/page/subject-panel-advanced.php:19
|
394 |
+
#: application/Backend/tmpl/service/capability.php:30
|
395 |
+
#: application/Backend/tmpl/service/capability.php:64
|
396 |
+
#: application/Backend/tmpl/service/jwt.php:84 media/js/aam.js:1319
|
397 |
+
#: media/js/aam.js:3567 media/js/aam.js:3794 media/js/aam.js:3879
|
398 |
msgid "Create"
|
399 |
msgstr ""
|
400 |
|
401 |
+
#: application/Backend/View/Localization.php:51
|
402 |
+
#: application/Backend/tmpl/page/subject-panel.php:17 media/js/aam.js:171
|
403 |
msgid "Users"
|
404 |
msgstr ""
|
405 |
|
411 |
msgid "Add Role"
|
412 |
msgstr ""
|
413 |
|
414 |
+
#: application/Backend/View/Localization.php:54 media/js/aam.js:478
|
415 |
msgid "Failed to update role"
|
416 |
msgstr ""
|
417 |
|
418 |
+
#: application/Backend/View/Localization.php:55
|
419 |
+
#: application/Backend/tmpl/page/subject-panel-advanced.php:41
|
420 |
+
#: application/Backend/tmpl/service/capability.php:90 media/js/aam.js:487
|
421 |
msgid "Update"
|
422 |
msgstr ""
|
423 |
|
424 |
+
#: application/Backend/View/Localization.php:56
|
425 |
+
#: application/Backend/tmpl/page/subject-panel-advanced.php:110
|
426 |
+
#: application/Backend/tmpl/partial/post-access-form.php:89
|
427 |
+
#: media/js/aam.js:1076 media/js/aam.js:2454
|
428 |
msgid "Reset"
|
429 |
msgstr ""
|
430 |
|
432 |
msgid "Update..."
|
433 |
msgstr ""
|
434 |
|
435 |
+
#: application/Backend/View/Localization.php:58 media/js/aam.js:510
|
436 |
+
#: media/js/aam.js:1941 media/js/aam.js:3515 media/js/aam.js:3897
|
437 |
msgid "Deleting..."
|
438 |
msgstr ""
|
439 |
|
440 |
+
#: application/Backend/View/Localization.php:59 media/js/aam.js:516
|
441 |
msgid "Failed to delete role"
|
442 |
msgstr ""
|
443 |
|
444 |
#: application/Backend/View/Localization.php:60
|
445 |
+
#: application/Backend/tmpl/page/subject-panel-advanced.php:53
|
446 |
msgid "Delete Role"
|
447 |
msgstr ""
|
448 |
|
449 |
+
#: application/Backend/View/Localization.php:61 media/js/aam.js:610
|
450 |
msgid "Failed to lock user"
|
451 |
msgstr ""
|
452 |
|
453 |
+
#: application/Backend/View/Localization.php:62 media/js/aam.js:701
|
454 |
msgid "Search user"
|
455 |
msgstr ""
|
456 |
|
457 |
+
#: application/Backend/View/Localization.php:63 media/js/aam.js:2443
|
458 |
+
msgid "Counter was reset successfully"
|
459 |
+
msgstr ""
|
460 |
+
|
461 |
+
#: application/Backend/View/Localization.php:64 media/js/aam.js:702
|
462 |
msgid "_TOTAL_ user(s)"
|
463 |
msgstr ""
|
464 |
|
465 |
+
#: application/Backend/View/Localization.php:65 media/js/aam.js:717
|
466 |
msgid "Create New User"
|
467 |
msgstr ""
|
468 |
|
469 |
+
#: application/Backend/View/Localization.php:66
|
470 |
+
#: application/Backend/tmpl/page/subject-panel.php:38 media/js/aam.js:765
|
471 |
msgid "Role"
|
472 |
msgstr ""
|
473 |
|
474 |
+
#: application/Backend/View/Localization.php:67
|
475 |
+
#: application/Core/Subject/Default.php:36 media/js/aam.js:1189
|
476 |
msgid "All Users, Roles and Visitor"
|
477 |
msgstr ""
|
478 |
|
479 |
+
#: application/Backend/View/Localization.php:68 media/js/aam.js:1160
|
480 |
+
#: media/js/aam.js:1235 media/js/aam.js:4305
|
481 |
msgid "Failed to apply policy changes"
|
482 |
msgstr ""
|
483 |
|
484 |
+
#: application/Backend/View/Localization.php:69
|
485 |
+
#: application/Backend/tmpl/partial/visitor-principal-subject-tab.php:14
|
486 |
+
#: media/js/aam.js:1154 media/js/aam.js:1163
|
487 |
msgid "Attach Policy To Visitors"
|
488 |
msgstr ""
|
489 |
|
490 |
+
#: application/Backend/View/Localization.php:70
|
491 |
+
#: application/Backend/tmpl/partial/visitor-principal-subject-tab.php:12
|
492 |
+
#: media/js/aam.js:1152 media/js/aam.js:1165
|
493 |
msgid "Detach Policy From Visitors"
|
494 |
msgstr ""
|
495 |
|
496 |
+
#: application/Backend/View/Localization.php:71 media/js/aam.js:648
|
497 |
+
#: media/js/aam.js:3686
|
|
|
498 |
msgid "Generating URL..."
|
499 |
msgstr ""
|
500 |
|
501 |
+
#: application/Backend/View/Localization.php:72
|
502 |
+
#: application/Core/Subject/Visitor.php:43 media/js/aam.js:1115
|
503 |
msgid "Anonymous"
|
504 |
msgstr ""
|
505 |
|
506 |
+
#: application/Backend/View/Localization.php:73 media/js/aam.js:1141
|
507 |
+
#: media/js/aam.js:1216 media/js/aam.js:1807 media/js/aam.js:4151
|
508 |
msgid "Processing..."
|
509 |
msgstr ""
|
510 |
|
511 |
+
#: application/Backend/View/Localization.php:74 media/js/aam.js:726
|
512 |
msgid "Loading roles..."
|
513 |
msgstr ""
|
514 |
|
515 |
+
#: application/Backend/View/Localization.php:75 media/js/aam.js:658
|
516 |
+
#: media/js/aam.js:3696
|
|
|
517 |
msgid "Failed to generate JWT token"
|
518 |
msgstr ""
|
519 |
|
520 |
+
#: application/Backend/View/Localization.php:76 media/js/aam.js:1909
|
521 |
+
msgid "Failed to process request"
|
522 |
+
msgstr ""
|
523 |
+
|
524 |
+
#: application/Backend/View/Localization.php:77
|
525 |
msgid "Current user"
|
526 |
msgstr ""
|
527 |
|
528 |
+
#: application/Backend/View/Localization.php:78
|
529 |
msgid "Current role"
|
530 |
msgstr ""
|
531 |
|
532 |
+
#: application/Backend/View/Localization.php:79 media/js/aam.js:2841
|
533 |
msgid "Manage Access"
|
534 |
msgstr ""
|
535 |
|
536 |
+
#: application/Backend/View/Localization.php:80 media/js/aam.js:743
|
537 |
msgid "Filter by role"
|
538 |
msgstr ""
|
539 |
|
540 |
+
#: application/Backend/View/Localization.php:81
|
541 |
+
#: application/Backend/View/PostOptionList.php:76 media/js/aam.js:2853
|
542 |
msgid "Edit"
|
543 |
msgstr ""
|
544 |
|
545 |
+
#: application/Backend/View/Localization.php:82
|
546 |
+
#: application/Backend/tmpl/page/subject-panel-advanced.php:111
|
547 |
+
#: application/Backend/tmpl/partial/post-access-form.php:60
|
548 |
+
#: application/Backend/tmpl/partial/post-access-form.php:90
|
549 |
+
#: application/Backend/tmpl/partial/post-access-form.php:163
|
550 |
+
#: application/Backend/tmpl/partial/post-access-form.php:184
|
551 |
+
#: application/Backend/tmpl/partial/post-access-form.php:205
|
552 |
+
#: application/Backend/tmpl/service/uri.php:108 media/js/aam.js:1043
|
553 |
+
#: media/js/aam.js:3494
|
554 |
msgid "Save"
|
555 |
msgstr ""
|
556 |
|
557 |
+
#: application/Backend/View/Localization.php:83 media/js/aam.js:217
|
558 |
msgid "Manage role"
|
559 |
msgstr ""
|
560 |
|
561 |
+
#: application/Backend/View/Localization.php:84 media/js/aam.js:238
|
562 |
msgid "Edit role"
|
563 |
msgstr ""
|
564 |
|
565 |
+
#: application/Backend/View/Localization.php:85 media/js/aam.js:291
|
566 |
+
#: media/js/aam.js:524
|
567 |
msgid "Delete role"
|
568 |
msgstr ""
|
569 |
|
570 |
+
#: application/Backend/View/Localization.php:86 media/js/aam.js:262
|
571 |
msgid "Clone role"
|
572 |
msgstr ""
|
573 |
|
574 |
+
#: application/Backend/View/Localization.php:87 media/js/aam.js:804
|
575 |
msgid "Manage user"
|
576 |
msgstr ""
|
577 |
|
578 |
+
#: application/Backend/View/Localization.php:88 media/js/aam.js:853
|
579 |
msgid "Edit user"
|
580 |
msgstr ""
|
581 |
|
582 |
+
#: application/Backend/View/Localization.php:89 media/js/aam.js:605
|
583 |
+
#: media/js/aam.js:606 media/js/aam.js:874 media/js/aam.js:885
|
584 |
msgid "Lock user"
|
585 |
msgstr ""
|
586 |
|
587 |
+
#: application/Backend/View/Localization.php:90 media/js/aam.js:599
|
588 |
+
#: media/js/aam.js:600 media/js/aam.js:898 media/js/aam.js:909
|
589 |
msgid "Unlock user"
|
590 |
msgstr ""
|
591 |
|
592 |
+
#: application/Backend/View/Localization.php:91 media/js/aam.js:1903
|
593 |
msgid "WordPress core does not allow to grant this capability"
|
594 |
msgstr ""
|
595 |
|
596 |
+
#: application/Backend/View/Localization.php:92 media/js/aam.js:1227
|
597 |
+
#: media/js/aam.js:1240
|
598 |
msgid "Detach Policy From Everybody"
|
599 |
msgstr ""
|
600 |
|
601 |
+
#: application/Backend/View/Localization.php:93 media/js/aam.js:1229
|
602 |
+
#: media/js/aam.js:1238
|
603 |
msgid "Attach Policy To Everybody"
|
604 |
msgstr ""
|
605 |
|
606 |
+
#: application/Backend/View/Localization.php:94 media/js/aam.js:1308
|
607 |
msgid "Search Policy"
|
608 |
msgstr ""
|
609 |
|
610 |
+
#: application/Backend/View/Localization.php:95 media/js/aam.js:1309
|
611 |
msgid "_TOTAL_ Policies"
|
612 |
msgstr ""
|
613 |
|
614 |
+
#: application/Backend/View/Localization.php:96 media/js/aam.js:1342
|
615 |
msgid "Apply Policy"
|
616 |
msgstr ""
|
617 |
|
618 |
+
#: application/Backend/View/Localization.php:97 media/js/aam.js:1362
|
619 |
msgid "Revoke Policy"
|
620 |
msgstr ""
|
621 |
|
622 |
+
#: application/Backend/View/Localization.php:98
|
623 |
+
#: application/Service/AccessPolicy.php:170 media/js/aam.js:1379
|
624 |
msgid "Edit Policy"
|
625 |
msgstr ""
|
626 |
|
627 |
+
#: application/Backend/View/Localization.php:99
|
628 |
+
#: application/Backend/tmpl/service/menu.php:79
|
629 |
+
#: application/Backend/tmpl/service/toolbar.php:60 media/js/aam.js:1516
|
630 |
msgid "Uncheck to allow"
|
631 |
msgstr ""
|
632 |
|
633 |
+
#: application/Backend/View/Localization.php:100
|
634 |
+
#: application/Backend/tmpl/service/menu.php:79
|
635 |
+
#: application/Backend/tmpl/service/toolbar.php:60 media/js/aam.js:1518
|
636 |
msgid "Check to restrict"
|
637 |
msgstr ""
|
638 |
|
639 |
+
#: application/Backend/View/Localization.php:101
|
640 |
+
#: application/Backend/tmpl/service/metabox.php:78 media/js/aam.js:1652
|
641 |
+
#: media/js/aam.js:1841
|
642 |
msgid "Uncheck to show"
|
643 |
msgstr ""
|
644 |
|
645 |
+
#: application/Backend/View/Localization.php:102
|
646 |
+
#: application/Backend/tmpl/service/metabox.php:78 media/js/aam.js:1654
|
647 |
+
#: media/js/aam.js:1843
|
648 |
msgid "Check to hide"
|
649 |
msgstr ""
|
650 |
|
651 |
+
#: application/Backend/View/Localization.php:103
|
652 |
+
#: application/Backend/tmpl/service/metabox.php:114 media/js/aam.js:1810
|
653 |
msgid "Initialize"
|
654 |
msgstr ""
|
655 |
|
656 |
+
#: application/Backend/View/Localization.php:104 media/js/aam.js:1995
|
657 |
msgid "No capabilities"
|
658 |
msgstr ""
|
659 |
|
660 |
+
#: application/Backend/View/Localization.php:105 media/js/aam.js:2673
|
661 |
msgid "Post Type"
|
662 |
msgstr ""
|
663 |
|
664 |
+
#: application/Backend/View/Localization.php:106 media/js/aam.js:2678
|
665 |
msgid "Hierarchical Taxonomy"
|
666 |
msgstr ""
|
667 |
|
668 |
+
#: application/Backend/View/Localization.php:107 media/js/aam.js:2683
|
669 |
msgid "Hierarchical Term"
|
670 |
msgstr ""
|
671 |
|
672 |
+
#: application/Backend/View/Localization.php:108 media/js/aam.js:2688
|
673 |
msgid "Tag Taxonomy"
|
674 |
msgstr ""
|
675 |
|
676 |
+
#: application/Backend/View/Localization.php:109 media/js/aam.js:2693
|
677 |
msgid "Tag"
|
678 |
msgstr ""
|
679 |
|
680 |
+
#: application/Backend/View/Localization.php:110 media/js/aam.js:2704
|
681 |
msgid "Customized Settings"
|
682 |
msgstr ""
|
683 |
|
684 |
+
#: application/Backend/View/Localization.php:111 media/js/aam.js:2774
|
685 |
+
#: media/js/aam.js:2796
|
686 |
msgid "Parent"
|
687 |
msgstr ""
|
688 |
|
689 |
+
#: application/Backend/View/Localization.php:112 media/js/aam.js:2827
|
690 |
msgid "Drill-Down"
|
691 |
msgstr ""
|
692 |
|
693 |
+
#: application/Backend/View/Localization.php:113 media/js/aam.js:3365
|
694 |
msgid "_TOTAL_ route(s)"
|
695 |
msgstr ""
|
696 |
|
697 |
+
#: application/Backend/View/Localization.php:114 media/js/aam.js:3367
|
698 |
msgid "No API endpoints found. You might have APIs disabled."
|
699 |
msgstr ""
|
700 |
|
701 |
+
#: application/Backend/View/Localization.php:115 media/js/aam.js:3368
|
702 |
+
#: media/js/aam.js:3783 media/js/aam.js:4105
|
703 |
msgid "Nothing to show"
|
704 |
msgstr ""
|
705 |
|
706 |
+
#: application/Backend/View/Localization.php:116 media/js/aam.js:3485
|
707 |
msgid "Failed to save URI rule"
|
708 |
msgstr ""
|
709 |
|
710 |
+
#: application/Backend/View/Localization.php:117 media/js/aam.js:3521
|
711 |
msgid "Failed to delete URI rule"
|
712 |
msgstr ""
|
713 |
|
714 |
+
#: application/Backend/View/Localization.php:118 media/js/aam.js:3557
|
715 |
msgid "_TOTAL_ URI(s)"
|
716 |
msgstr ""
|
717 |
|
718 |
+
#: application/Backend/View/Localization.php:119 media/js/aam.js:3596
|
719 |
msgid "Edit Rule"
|
720 |
msgstr ""
|
721 |
|
722 |
+
#: application/Backend/View/Localization.php:120 media/js/aam.js:3608
|
723 |
msgid "Delete Rule"
|
724 |
msgstr ""
|
725 |
|
726 |
+
#: application/Backend/View/Localization.php:121 media/js/aam.js:3623
|
727 |
msgid "Denied"
|
728 |
msgstr ""
|
729 |
|
730 |
+
#: application/Backend/View/Localization.php:122 media/js/aam.js:3630
|
731 |
msgid "Redirected"
|
732 |
msgstr ""
|
733 |
|
734 |
+
#: application/Backend/View/Localization.php:123 media/js/aam.js:3635
|
735 |
msgid "Callback"
|
736 |
msgstr ""
|
737 |
|
738 |
+
#: application/Backend/View/Localization.php:124 media/js/aam.js:3640
|
739 |
msgid "Allowed"
|
740 |
msgstr ""
|
741 |
|
742 |
+
#: application/Backend/View/Localization.php:125 media/js/aam.js:3685
|
743 |
msgid "Generating token..."
|
744 |
msgstr ""
|
745 |
|
746 |
+
#: application/Backend/View/Localization.php:126 media/js/aam.js:3780
|
747 |
msgid "_TOTAL_ token(s)"
|
748 |
msgstr ""
|
749 |
|
750 |
+
#: application/Backend/View/Localization.php:127 media/js/aam.js:3782
|
751 |
msgid "No JWT tokens have been generated."
|
752 |
msgstr ""
|
753 |
|
754 |
+
#: application/Backend/View/Localization.php:128 media/js/aam.js:3827
|
755 |
msgid "Delete Token"
|
756 |
msgstr ""
|
757 |
|
758 |
+
#: application/Backend/View/Localization.php:129 media/js/aam.js:3840
|
759 |
msgid "View Token"
|
760 |
msgstr ""
|
761 |
|
762 |
+
#: application/Backend/View/Localization.php:130 media/js/aam.js:3865
|
763 |
msgid "Creating..."
|
764 |
msgstr ""
|
765 |
|
766 |
+
#: application/Backend/View/Localization.php:131 media/js/aam.js:4102
|
767 |
msgid "Search Service"
|
768 |
msgstr ""
|
769 |
|
770 |
+
#: application/Backend/View/Localization.php:132 media/js/aam.js:4103
|
771 |
msgid "_TOTAL_ service(s)"
|
772 |
msgstr ""
|
773 |
|
774 |
+
#: application/Backend/View/Localization.php:133
|
775 |
+
#: application/Backend/tmpl/settings/content.php:19
|
776 |
+
#: application/Backend/tmpl/settings/core.php:16
|
777 |
+
#: application/Backend/tmpl/settings/security.php:16 media/js/aam.js:4115
|
778 |
msgid "Enabled"
|
779 |
msgstr ""
|
780 |
|
781 |
+
#: application/Backend/View/Localization.php:134
|
782 |
+
#: application/Backend/tmpl/settings/content.php:19
|
783 |
+
#: application/Backend/tmpl/settings/core.php:16
|
784 |
+
#: application/Backend/tmpl/settings/security.php:16 media/js/aam.js:4115
|
785 |
msgid "Disabled"
|
786 |
msgstr ""
|
787 |
|
788 |
+
#: application/Backend/View/Localization.php:135 media/js/aam.js:4157
|
789 |
msgid "All settings has been cleared successfully"
|
790 |
msgstr ""
|
791 |
|
792 |
+
#: application/Backend/View/Localization.php:136
|
793 |
+
#: application/Backend/tmpl/index.php:92 media/js/aam.js:4169
|
794 |
msgid "Clear"
|
795 |
msgstr ""
|
796 |
|
797 |
+
#: application/Backend/View/Localization.php:137
|
798 |
+
#: application/Backend/tmpl/page/subject-panel-advanced.php:102
|
799 |
+
#: application/Backend/tmpl/partial/role-inheritance.php:7 media/js/aam.js:4341
|
800 |
msgid "Select Role"
|
801 |
msgstr ""
|
802 |
|
803 |
+
#: application/Backend/View/Localization.php:138 media/js/aam.js:4616
|
804 |
msgid "Data has been saved to clipboard"
|
805 |
msgstr ""
|
806 |
|
807 |
+
#: application/Backend/View/Localization.php:139 media/js/aam.js:4620
|
808 |
msgid "Failed to save data to clipboard"
|
809 |
msgstr ""
|
810 |
|
811 |
+
#: application/Backend/View/Localization.php:140 media/js/aam.js:4690
|
812 |
msgid "Operation completed successfully"
|
813 |
msgstr ""
|
814 |
|
833 |
msgstr ""
|
834 |
|
835 |
#: application/Backend/View/PostOptionList.php:41
|
836 |
+
#: application/Backend/tmpl/partial/post-access-form.php:50
|
837 |
msgid "Teaser Message"
|
838 |
msgstr ""
|
839 |
|
886 |
msgstr ""
|
887 |
|
888 |
#: application/Backend/View/PostOptionList.php:64
|
889 |
+
#: application/Backend/tmpl/partial/post-access-form.php:175
|
890 |
msgid "Password Protected"
|
891 |
msgstr ""
|
892 |
|
893 |
#: application/Backend/View/PostOptionList.php:65
|
894 |
+
#: application/Backend/tmpl/partial/post-access-form.php:179
|
895 |
+
#: application/Backend/tmpl/widget/login-frontend.php:29
|
896 |
msgid "Password"
|
897 |
msgstr ""
|
898 |
|
926 |
msgid "Restrict access to edit the post."
|
927 |
msgstr ""
|
928 |
|
929 |
+
#: application/Backend/View/PostOptionList.php:81
|
930 |
+
#: application/Backend/tmpl/page/subject-panel-advanced.php:59
|
931 |
+
#: application/Backend/tmpl/service/jwt.php:136
|
932 |
+
#: application/Backend/tmpl/service/uri.php:130 media/js/aam.js:3529
|
933 |
+
#: media/js/aam.js:3911
|
934 |
msgid "Delete"
|
935 |
msgstr ""
|
936 |
|
964 |
msgid "Howdy, %username%"
|
965 |
msgstr ""
|
966 |
|
967 |
+
#: application/Backend/tmpl/index.php:23
|
968 |
+
msgid "Notifications"
|
969 |
msgstr ""
|
970 |
|
971 |
+
#: application/Backend/tmpl/index.php:44
|
972 |
+
msgid "Access"
|
|
|
973 |
msgstr ""
|
974 |
|
975 |
+
#: application/Backend/tmpl/index.php:49
|
976 |
+
msgid "Settings"
|
977 |
msgstr ""
|
978 |
|
979 |
+
#: application/Backend/tmpl/index.php:55
|
980 |
+
msgid "Add-Ons"
|
981 |
msgstr ""
|
982 |
|
983 |
+
#: application/Backend/tmpl/index.php:61
|
984 |
+
msgid "Help"
|
|
|
985 |
msgstr ""
|
986 |
|
987 |
+
#: application/Backend/tmpl/index.php:75
|
988 |
+
msgid "Reset AAM Settings"
|
989 |
msgstr ""
|
990 |
|
991 |
+
#: application/Backend/tmpl/index.php:85
|
992 |
+
#: application/Backend/tmpl/page/addon-panel.php:70
|
993 |
+
#: application/Backend/tmpl/page/addon-panel.php:81
|
994 |
+
#: application/Backend/tmpl/page/addon-panel.php:91
|
995 |
+
#: application/Backend/tmpl/page/addon-panel.php:104
|
996 |
+
#: application/Backend/tmpl/page/subject-panel-advanced.php:8
|
997 |
+
#: application/Backend/tmpl/page/subject-panel-advanced.php:20
|
998 |
+
#: application/Backend/tmpl/page/subject-panel-advanced.php:30
|
999 |
+
#: application/Backend/tmpl/page/subject-panel-advanced.php:42
|
1000 |
+
#: application/Backend/tmpl/page/subject-panel-advanced.php:52
|
1001 |
+
#: application/Backend/tmpl/page/subject-panel-advanced.php:60
|
1002 |
+
#: application/Backend/tmpl/page/subject-panel-advanced.php:70
|
1003 |
+
#: application/Backend/tmpl/page/subject-panel-advanced.php:112
|
1004 |
+
#: application/Backend/tmpl/partial/post-access-form.php:49
|
1005 |
+
#: application/Backend/tmpl/partial/post-access-form.php:61
|
1006 |
+
#: application/Backend/tmpl/partial/post-access-form.php:71
|
1007 |
+
#: application/Backend/tmpl/partial/post-access-form.php:91
|
1008 |
+
#: application/Backend/tmpl/partial/post-access-form.php:101
|
1009 |
+
#: application/Backend/tmpl/partial/post-access-form.php:164
|
1010 |
+
#: application/Backend/tmpl/partial/post-access-form.php:174
|
1011 |
+
#: application/Backend/tmpl/partial/post-access-form.php:185
|
1012 |
+
#: application/Backend/tmpl/partial/post-access-form.php:195
|
1013 |
+
#: application/Backend/tmpl/partial/post-access-form.php:206
|
1014 |
+
#: application/Backend/tmpl/service/capability.php:49
|
1015 |
+
#: application/Backend/tmpl/service/capability.php:65
|
1016 |
+
#: application/Backend/tmpl/service/capability.php:75
|
1017 |
+
#: application/Backend/tmpl/service/capability.php:91
|
1018 |
+
#: application/Backend/tmpl/service/capability.php:101
|
1019 |
+
#: application/Backend/tmpl/service/capability.php:110
|
1020 |
+
#: application/Backend/tmpl/service/jwt.php:36
|
1021 |
+
#: application/Backend/tmpl/service/jwt.php:85
|
1022 |
+
#: application/Backend/tmpl/service/jwt.php:95
|
1023 |
+
#: application/Backend/tmpl/service/jwt.php:119
|
1024 |
+
#: application/Backend/tmpl/service/jwt.php:129
|
1025 |
+
#: application/Backend/tmpl/service/jwt.php:137
|
1026 |
+
#: application/Backend/tmpl/service/menu.php:124
|
1027 |
+
#: application/Backend/tmpl/service/menu.php:144
|
1028 |
+
#: application/Backend/tmpl/service/menu.php:170
|
1029 |
+
#: application/Backend/tmpl/service/metabox.php:101
|
1030 |
+
#: application/Backend/tmpl/service/metabox.php:115
|
1031 |
+
#: application/Backend/tmpl/service/metabox.php:125
|
1032 |
+
#: application/Backend/tmpl/service/metabox.php:147
|
1033 |
+
#: application/Backend/tmpl/service/toolbar.php:86
|
1034 |
+
#: application/Backend/tmpl/service/toolbar.php:108
|
1035 |
+
#: application/Backend/tmpl/service/uri.php:26
|
1036 |
+
#: application/Backend/tmpl/service/uri.php:109
|
1037 |
+
#: application/Backend/tmpl/service/uri.php:119
|
1038 |
+
#: application/Backend/tmpl/service/uri.php:131
|
1039 |
+
msgid "Close"
|
1040 |
msgstr ""
|
1041 |
|
1042 |
+
#: application/Backend/tmpl/index.php:86
|
1043 |
+
msgid "Clear all settings"
|
1044 |
msgstr ""
|
1045 |
|
1046 |
+
#: application/Backend/tmpl/index.php:89
|
1047 |
+
msgid "All AAM settings will be removed."
|
1048 |
msgstr ""
|
1049 |
|
1050 |
+
#: application/Backend/tmpl/index.php:93
|
1051 |
+
msgid "Cancel"
|
1052 |
msgstr ""
|
1053 |
|
1054 |
+
#: application/Backend/tmpl/index.php:105
|
1055 |
+
msgid ""
|
1056 |
+
"With the [Enterprise Package] get our dedicated support channel and all the "
|
1057 |
+
"premium add-ons for [50+ live websites]"
|
1058 |
msgstr ""
|
1059 |
|
1060 |
+
#: application/Backend/tmpl/index.php:106
|
1061 |
+
#: application/Backend/tmpl/page/addon-panel.php:55
|
1062 |
+
msgid "Read More"
|
1063 |
msgstr ""
|
1064 |
|
1065 |
+
#: application/Backend/tmpl/metabox/policy-metabox.php:23
|
1066 |
+
#, php-format
|
1067 |
+
msgid ""
|
1068 |
+
"To learn more about Access & Security policy document, please check "
|
1069 |
+
"[%sAccess & Security Policy%s] page."
|
1070 |
msgstr ""
|
1071 |
|
1072 |
+
#: application/Backend/tmpl/metabox/policy-metabox.php:51
|
1073 |
+
msgid "Syntax Error"
|
1074 |
+
msgstr ""
|
1075 |
+
|
1076 |
+
#: application/Backend/tmpl/page/addon-panel.php:8
|
1077 |
msgid ""
|
1078 |
+
"By purchasing any of the premium addon(s) below, you obtain the license that "
|
1079 |
+
"allows you to install and use AAM software for one physical WordPress "
|
1080 |
+
"installation only. Exceptions are websites where URL is either [localhost] "
|
1081 |
+
"or starts with [dev.], [staging.], [test.] or [demo.] They are considered as "
|
1082 |
+
"development websites and you can use the purchased license unlimited number "
|
1083 |
+
"of times before it is activated on a production website. [Money back "
|
1084 |
+
"guaranteed] within 30 day from the time of purchase."
|
1085 |
msgstr ""
|
1086 |
|
1087 |
+
#: application/Backend/tmpl/page/addon-panel.php:13
|
1088 |
+
msgid "Download Addon"
|
1089 |
msgstr ""
|
1090 |
|
1091 |
+
#: application/Backend/tmpl/page/addon-panel.php:17
|
1092 |
+
msgid "Enter The License Key"
|
|
|
|
|
|
|
|
|
1093 |
msgstr ""
|
1094 |
|
1095 |
+
#: application/Backend/tmpl/page/addon-panel.php:21
|
1096 |
+
msgid "Download"
|
|
|
|
|
|
|
1097 |
msgstr ""
|
1098 |
|
1099 |
+
#: application/Backend/tmpl/page/addon-panel.php:29
|
1100 |
+
msgid "Premium"
|
1101 |
msgstr ""
|
1102 |
|
1103 |
+
#: application/Backend/tmpl/page/addon-panel.php:41
|
1104 |
+
#: application/Backend/tmpl/page/addon-panel.php:43
|
1105 |
+
msgid "License"
|
1106 |
msgstr ""
|
1107 |
|
1108 |
+
#: application/Backend/tmpl/page/addon-panel.php:43
|
1109 |
+
msgid "unregistered version"
|
|
|
|
|
|
|
1110 |
msgstr ""
|
1111 |
|
1112 |
+
#: application/Backend/tmpl/page/addon-panel.php:51
|
1113 |
+
msgid "Active"
|
1114 |
msgstr ""
|
1115 |
|
1116 |
+
#: application/Backend/tmpl/page/addon-panel.php:53
|
1117 |
+
msgid "Inactive"
|
|
|
|
|
1118 |
msgstr ""
|
1119 |
|
1120 |
+
#: application/Backend/tmpl/page/addon-panel.php:71
|
1121 |
+
msgid "License Key Info"
|
|
|
|
|
|
|
1122 |
msgstr ""
|
1123 |
|
1124 |
+
#: application/Backend/tmpl/page/addon-panel.php:75
|
1125 |
+
msgid ""
|
1126 |
+
"Insert license key that you received after the payment (find the email "
|
1127 |
+
"example below). It might take up to 2 hours to process the payment."
|
1128 |
msgstr ""
|
1129 |
|
1130 |
+
#: application/Backend/tmpl/page/addon-panel.php:92
|
1131 |
+
msgid "Plugin Installation"
|
1132 |
msgstr ""
|
1133 |
|
1134 |
+
#: application/Backend/tmpl/page/addon-panel.php:96
|
1135 |
+
msgid "The plugin has been successfully downloaded from our server."
|
1136 |
msgstr ""
|
1137 |
|
1138 |
+
#: application/Backend/tmpl/page/addon-panel.php:100
|
1139 |
+
#, php-format
|
1140 |
msgid ""
|
1141 |
+
"With AAM v6.0.0 or higher, all premium addons are [regular WordPress "
|
1142 |
+
"plugins] that you can upload by going to the %sPlugins%s page or extract "
|
1143 |
+
"downloaded ZIP archive to the [/wp-content/plugins] folder."
|
1144 |
msgstr ""
|
1145 |
|
1146 |
+
#: application/Backend/tmpl/page/main-panel.php:33
|
1147 |
+
msgid "You are not allowed to manage any of the existing services."
|
|
|
|
|
1148 |
msgstr ""
|
1149 |
|
1150 |
+
#: application/Backend/tmpl/page/subject-panel-advanced.php:9
|
1151 |
+
msgid "Create Role"
|
|
|
|
|
|
|
|
|
1152 |
msgstr ""
|
1153 |
|
1154 |
+
#: application/Backend/tmpl/page/subject-panel-advanced.php:13
|
1155 |
+
#: application/Backend/tmpl/page/subject-panel-advanced.php:35
|
1156 |
+
msgid "Role Name"
|
|
|
1157 |
msgstr ""
|
1158 |
|
1159 |
+
#: application/Backend/tmpl/page/subject-panel-advanced.php:14
|
1160 |
+
#: application/Backend/tmpl/page/subject-panel-advanced.php:36
|
1161 |
+
msgid "Enter Role Name"
|
|
|
|
|
1162 |
msgstr ""
|
1163 |
|
1164 |
+
#: application/Backend/tmpl/page/subject-panel-advanced.php:31
|
1165 |
+
msgid "Update Role"
|
1166 |
msgstr ""
|
1167 |
|
1168 |
+
#: application/Backend/tmpl/page/subject-panel-advanced.php:56
|
1169 |
#, php-format
|
1170 |
+
msgid "Are you sure that you want to delete the %s role?"
|
|
|
|
|
1171 |
msgstr ""
|
1172 |
|
1173 |
+
#: application/Backend/tmpl/page/subject-panel-advanced.php:71
|
1174 |
+
msgid "Manage User"
|
1175 |
msgstr ""
|
1176 |
|
1177 |
+
#: application/Backend/tmpl/page/subject-panel-advanced.php:74
|
|
|
1178 |
msgid ""
|
1179 |
+
"Define for how long user can access the website and what action needs to be "
|
1180 |
+
"taken after access expires."
|
1181 |
msgstr ""
|
1182 |
|
1183 |
+
#: application/Backend/tmpl/page/subject-panel-advanced.php:83
|
1184 |
+
msgid "Action After Expiration"
|
1185 |
msgstr ""
|
1186 |
|
1187 |
+
#: application/Backend/tmpl/page/subject-panel-advanced.php:86
|
1188 |
+
msgid "Select Action"
|
1189 |
msgstr ""
|
1190 |
|
1191 |
+
#: application/Backend/tmpl/page/subject-panel-advanced.php:87
|
1192 |
+
msgid "Logout User"
|
|
|
|
|
|
|
1193 |
msgstr ""
|
1194 |
|
1195 |
+
#: application/Backend/tmpl/page/subject-panel-advanced.php:88
|
1196 |
+
msgid "Delete Account"
|
1197 |
msgstr ""
|
1198 |
|
1199 |
+
#: application/Backend/tmpl/page/subject-panel-advanced.php:89
|
1200 |
+
msgid "Change User Role"
|
1201 |
msgstr ""
|
1202 |
|
1203 |
+
#: application/Backend/tmpl/page/subject-panel-advanced.php:100
|
1204 |
+
msgid "Change To Role"
|
1205 |
msgstr ""
|
1206 |
|
1207 |
+
#: application/Backend/tmpl/page/subject-panel.php:7
|
1208 |
+
msgid "Users/Roles Manager"
|
1209 |
msgstr ""
|
1210 |
|
1211 |
+
#: application/Backend/tmpl/page/subject-panel.php:14
|
1212 |
+
msgid "Roles"
|
1213 |
msgstr ""
|
1214 |
|
1215 |
+
#: application/Backend/tmpl/page/subject-panel.php:20
|
1216 |
+
msgid "Visitor"
|
1217 |
msgstr ""
|
1218 |
|
1219 |
+
#: application/Backend/tmpl/page/subject-panel.php:23
|
1220 |
+
msgid "Default"
|
1221 |
msgstr ""
|
1222 |
|
1223 |
+
#: application/Backend/tmpl/page/subject-panel.php:26
|
1224 |
+
msgid "None"
|
|
|
1225 |
msgstr ""
|
1226 |
|
1227 |
+
#: application/Backend/tmpl/page/subject-panel.php:39
|
1228 |
+
#: application/Backend/tmpl/page/subject-panel.php:55
|
1229 |
+
msgid "Action"
|
1230 |
msgstr ""
|
1231 |
|
1232 |
+
#: application/Backend/tmpl/page/subject-panel.php:54
|
1233 |
+
msgid "Username"
|
|
|
|
|
1234 |
msgstr ""
|
1235 |
|
1236 |
+
#: application/Backend/tmpl/page/subject-panel.php:76
|
1237 |
msgid ""
|
1238 |
+
"You are not allowed to manage any of the existing users, roles, visitors or "
|
1239 |
+
"default access settings."
|
|
|
1240 |
msgstr ""
|
1241 |
|
1242 |
+
#: application/Backend/tmpl/partial/default-principal-subject-tab.php:6
|
1243 |
+
msgid "This feature is allowed only with [Plus Package] addon."
|
1244 |
+
msgstr ""
|
1245 |
+
|
1246 |
+
#: application/Backend/tmpl/partial/default-subject-tab.php:5
|
1247 |
msgid ""
|
1248 |
+
"Manage default access to your website resources for all users, roles and "
|
1249 |
+
"visitor. This includes Administrator role and your user"
|
|
|
1250 |
msgstr ""
|
1251 |
|
1252 |
+
#: application/Backend/tmpl/partial/default-subject-tab.php:6
|
1253 |
+
msgid "Manage Default Access"
|
1254 |
msgstr ""
|
1255 |
|
1256 |
+
#: application/Backend/tmpl/partial/jwt-login-url.php:6
|
1257 |
+
msgid "Login with URL"
|
|
|
|
|
|
|
1258 |
msgstr ""
|
1259 |
|
1260 |
+
#: application/Backend/tmpl/partial/jwt-login-url.php:7
|
1261 |
+
#: application/Backend/tmpl/service/jwt.php:67
|
1262 |
+
#: application/Backend/tmpl/service/jwt.php:77
|
1263 |
+
#: application/Backend/tmpl/service/jwt.php:102
|
1264 |
+
#: application/Backend/tmpl/service/jwt.php:112
|
1265 |
+
msgid "Copy to clipboard"
|
1266 |
msgstr ""
|
1267 |
|
1268 |
+
#: application/Backend/tmpl/partial/jwt-login-url.php:10
|
1269 |
+
msgid "Login URL has not been requested"
|
1270 |
msgstr ""
|
1271 |
|
1272 |
+
#: application/Backend/tmpl/partial/jwt-login-url.php:12
|
1273 |
+
msgid "Request URL"
|
1274 |
msgstr ""
|
1275 |
|
1276 |
+
#: application/Backend/tmpl/partial/jwt-login-url.php:16
|
1277 |
+
msgid ""
|
1278 |
+
"With this URL user will be automatically logged in until defined date and "
|
1279 |
+
"time. The JWT token associated with URL is [revokable] however not "
|
1280 |
+
"[refreshable]."
|
1281 |
msgstr ""
|
1282 |
|
1283 |
+
#: application/Backend/tmpl/partial/loading-content.php:5
|
1284 |
+
msgid ""
|
1285 |
+
"[Loading AAM UI]. Please wait. If content will not load within next 30 "
|
1286 |
+
"seconds, clear your browser cache and reload the page. If still nothing, it "
|
1287 |
+
"is most likely some sort of JavaScript or CSS conflict with one your active "
|
1288 |
+
"plugins or theme. Try to deactivate all plugins and switch to any default "
|
1289 |
+
"WordPress theme to find out what causes the issue."
|
1290 |
msgstr ""
|
1291 |
|
1292 |
+
#: application/Backend/tmpl/partial/post-access-form.php:5
|
1293 |
+
#: application/Backend/tmpl/service/login-redirect.php:17
|
1294 |
+
#: application/Backend/tmpl/service/logout-redirect.php:17
|
1295 |
+
#: application/Backend/tmpl/service/menu.php:17
|
1296 |
+
#: application/Backend/tmpl/service/metabox.php:23
|
1297 |
+
#: application/Backend/tmpl/service/redirect.php:19
|
1298 |
+
#: application/Backend/tmpl/service/toolbar.php:16
|
1299 |
+
#: application/Backend/tmpl/service/uri.php:16
|
1300 |
+
msgid "Settings are customized"
|
1301 |
msgstr ""
|
1302 |
|
1303 |
+
#: application/Backend/tmpl/partial/post-access-form.php:6
|
1304 |
+
#: application/Backend/tmpl/service/login-redirect.php:18
|
1305 |
+
#: application/Backend/tmpl/service/logout-redirect.php:18
|
1306 |
+
#: application/Backend/tmpl/service/menu.php:18
|
1307 |
+
#: application/Backend/tmpl/service/metabox.php:24
|
1308 |
+
#: application/Backend/tmpl/service/redirect.php:20
|
1309 |
+
#: application/Backend/tmpl/service/route.php:19
|
1310 |
+
#: application/Backend/tmpl/service/toolbar.php:17
|
1311 |
+
#: application/Backend/tmpl/service/uri.php:17
|
1312 |
+
msgid "Reset to default"
|
1313 |
msgstr ""
|
1314 |
|
1315 |
+
#: application/Backend/tmpl/partial/post-access-form.php:23
|
1316 |
+
msgid "change"
|
1317 |
msgstr ""
|
1318 |
|
1319 |
+
#: application/Backend/tmpl/partial/post-access-form.php:54
|
1320 |
+
msgid "Plain text or valid HTML"
|
|
|
1321 |
msgstr ""
|
1322 |
|
1323 |
+
#: application/Backend/tmpl/partial/post-access-form.php:55
|
1324 |
+
msgid "Enter your teaser message..."
|
1325 |
msgstr ""
|
1326 |
|
1327 |
+
#: application/Backend/tmpl/partial/post-access-form.php:56
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1328 |
msgid ""
|
1329 |
"Use [[excerpt]] shortcode to insert post excerpt to the teaser "
|
1330 |
"message."
|
1331 |
msgstr ""
|
1332 |
|
1333 |
+
#: application/Backend/tmpl/partial/post-access-form.php:72
|
1334 |
msgid "Define Access Limit"
|
1335 |
msgstr ""
|
1336 |
|
1337 |
+
#: application/Backend/tmpl/partial/post-access-form.php:76
|
1338 |
msgid "Access Limit Threshold"
|
1339 |
msgstr ""
|
1340 |
|
1341 |
+
#: application/Backend/tmpl/partial/post-access-form.php:77
|
1342 |
msgid "Enter digital number"
|
1343 |
msgstr ""
|
1344 |
|
1345 |
+
#: application/Backend/tmpl/partial/post-access-form.php:84
|
1346 |
+
#, php-format
|
1347 |
+
msgid "The user can access content [%d] times."
|
1348 |
+
msgstr ""
|
1349 |
+
|
1350 |
+
#: application/Backend/tmpl/partial/post-access-form.php:102
|
1351 |
msgid "Access Redirect"
|
1352 |
msgstr ""
|
1353 |
|
1354 |
+
#: application/Backend/tmpl/partial/post-access-form.php:105
|
1355 |
msgid ""
|
1356 |
"Use REDIRECT option only if you want to redirect user to a different "
|
1357 |
"location either temporary or permanently. Do not use it as a way to protect "
|
1358 |
"access to avoid inconsistent user experience."
|
1359 |
msgstr ""
|
1360 |
|
1361 |
+
#: application/Backend/tmpl/partial/post-access-form.php:110
|
1362 |
+
#: application/Backend/tmpl/service/404redirect.php:26
|
1363 |
+
#: application/Backend/tmpl/service/login-redirect.php:33
|
1364 |
+
#: application/Backend/tmpl/service/logout-redirect.php:33
|
1365 |
+
#: application/Backend/tmpl/service/redirect.php:54
|
1366 |
+
#: application/Backend/tmpl/service/uri.php:57
|
1367 |
msgid "Redirected to existing page [(select from the drop-down)]"
|
1368 |
msgstr ""
|
1369 |
|
1370 |
+
#: application/Backend/tmpl/partial/post-access-form.php:114
|
1371 |
+
#: application/Backend/tmpl/service/logout-redirect.php:37
|
1372 |
msgid "Redirected to the URL [(enter full URL starting from http or https)]"
|
1373 |
msgstr ""
|
1374 |
|
1375 |
+
#: application/Backend/tmpl/partial/post-access-form.php:119
|
1376 |
+
#: application/Backend/tmpl/service/redirect.php:49
|
1377 |
+
#: application/Backend/tmpl/service/uri.php:52
|
1378 |
msgid ""
|
1379 |
"Redirect to the login page [(after login, user will be redirected back to "
|
1380 |
"the restricted page)]"
|
1381 |
msgstr ""
|
1382 |
|
1383 |
+
#: application/Backend/tmpl/partial/post-access-form.php:124
|
1384 |
+
#: application/Backend/tmpl/service/404redirect.php:34
|
1385 |
+
#: application/Backend/tmpl/service/login-redirect.php:41
|
1386 |
+
#: application/Backend/tmpl/service/logout-redirect.php:41
|
1387 |
+
#: application/Backend/tmpl/service/redirect.php:62
|
1388 |
+
#: application/Backend/tmpl/service/redirect.php:114
|
1389 |
+
#: application/Backend/tmpl/service/uri.php:65
|
1390 |
#, php-format
|
1391 |
msgid "Trigger PHP callback function [(valid %sPHP callback%s is required)]"
|
1392 |
msgstr ""
|
1393 |
|
1394 |
+
#: application/Backend/tmpl/partial/post-access-form.php:128
|
1395 |
+
#: application/Backend/tmpl/service/404redirect.php:38
|
1396 |
+
#: application/Backend/tmpl/service/login-redirect.php:45
|
1397 |
+
#: application/Backend/tmpl/service/logout-redirect.php:45
|
1398 |
+
#: application/Backend/tmpl/service/redirect.php:71
|
1399 |
+
#: application/Backend/tmpl/service/redirect.php:123
|
1400 |
+
#: application/Backend/tmpl/service/uri.php:74
|
1401 |
msgid "Existing Page"
|
1402 |
msgstr ""
|
1403 |
|
1404 |
+
#: application/Backend/tmpl/partial/post-access-form.php:136
|
1405 |
+
#: application/Backend/tmpl/service/404redirect.php:47
|
1406 |
+
#: application/Backend/tmpl/service/login-redirect.php:54
|
1407 |
+
#: application/Backend/tmpl/service/logout-redirect.php:54
|
1408 |
+
#: application/Backend/tmpl/service/redirect.php:80
|
1409 |
+
#: application/Backend/tmpl/service/redirect.php:132
|
1410 |
+
#: application/Backend/tmpl/service/uri.php:81
|
1411 |
msgid "-- Select Page --"
|
1412 |
msgstr ""
|
1413 |
|
1414 |
+
#: application/Backend/tmpl/partial/post-access-form.php:142
|
1415 |
+
#: application/Backend/tmpl/service/404redirect.php:53
|
1416 |
+
#: application/Backend/tmpl/service/login-redirect.php:60
|
1417 |
+
#: application/Backend/tmpl/service/logout-redirect.php:60
|
1418 |
+
#: application/Backend/tmpl/service/redirect.php:86
|
1419 |
+
#: application/Backend/tmpl/service/redirect.php:138
|
1420 |
msgid "The URL"
|
1421 |
msgstr ""
|
1422 |
|
1423 |
+
#: application/Backend/tmpl/partial/post-access-form.php:147
|
1424 |
+
#: application/Backend/tmpl/service/404redirect.php:58
|
1425 |
+
#: application/Backend/tmpl/service/login-redirect.php:65
|
1426 |
+
#: application/Backend/tmpl/service/logout-redirect.php:65
|
1427 |
+
#: application/Backend/tmpl/service/redirect.php:91
|
1428 |
+
#: application/Backend/tmpl/service/redirect.php:143
|
1429 |
+
#: application/Backend/tmpl/service/uri.php:103
|
1430 |
msgid "PHP Callback Function"
|
1431 |
msgstr ""
|
1432 |
|
1433 |
+
#: application/Backend/tmpl/partial/post-access-form.php:148
|
1434 |
+
#: application/Backend/tmpl/service/redirect.php:92
|
1435 |
+
#: application/Backend/tmpl/service/redirect.php:144
|
1436 |
msgid "Enter valid callback"
|
1437 |
msgstr ""
|
1438 |
|
1439 |
+
#: application/Backend/tmpl/partial/post-access-form.php:152
|
1440 |
+
#: application/Backend/tmpl/service/uri.php:92
|
1441 |
msgid "HTTP Redirect Code"
|
1442 |
msgstr ""
|
1443 |
|
1444 |
+
#: application/Backend/tmpl/partial/post-access-form.php:180
|
1445 |
msgid "Enter Password"
|
1446 |
msgstr ""
|
1447 |
|
1448 |
+
#: application/Backend/tmpl/partial/post-access-form.php:196
|
1449 |
msgid "Expiration Date/Time"
|
1450 |
msgstr ""
|
1451 |
|
1452 |
+
#: application/Backend/tmpl/partial/posts-terms-help-tips.php:7
|
1453 |
#, php-format
|
1454 |
msgid ""
|
1455 |
"You are allowed to manage access to unlimited number of posts, pages or "
|
1460 |
"to manage access to the WordPress content%s."
|
1461 |
msgstr ""
|
1462 |
|
1463 |
+
#: application/Backend/tmpl/partial/role-inheritance.php:5
|
1464 |
+
msgid "Inherit capabilities from"
|
1465 |
msgstr ""
|
1466 |
|
1467 |
+
#: application/Backend/tmpl/partial/role-inheritance.php:13
|
1468 |
msgid ""
|
1469 |
"Also clone all AAM access settings (admin menu, metaboxes, redirects, etc.)"
|
1470 |
msgstr ""
|
1471 |
|
1472 |
+
#: application/Backend/tmpl/partial/taxonomy-access-form.php:8
|
1473 |
#, php-format
|
1474 |
msgid ""
|
1475 |
"Managing access to the taxonomy \"%s\" is available with the premium %s[Plus "
|
1478 |
"Package add-on."
|
1479 |
msgstr ""
|
1480 |
|
1481 |
+
#: application/Backend/tmpl/partial/term-access-form.php:8
|
1482 |
#, php-format
|
1483 |
msgid ""
|
1484 |
"Managing access to the %s \"%s\" is available with the premium %s[Plus "
|
1487 |
"add-on."
|
1488 |
msgstr ""
|
1489 |
|
1490 |
+
#: application/Backend/tmpl/partial/term-access-form.php:9
|
1491 |
+
#: application/Backend/tmpl/partial/term-access-form.php:13
|
1492 |
msgid "category"
|
1493 |
msgstr ""
|
1494 |
|
1495 |
+
#: application/Backend/tmpl/partial/term-access-form.php:9
|
1496 |
+
#: application/Backend/tmpl/partial/term-access-form.php:13
|
1497 |
msgid "tag"
|
1498 |
msgstr ""
|
1499 |
|
1500 |
+
#: application/Backend/tmpl/partial/type-access-form.php:8
|
1501 |
#, php-format
|
1502 |
msgid ""
|
1503 |
"Manage default access to all posts that belong to the post type %s. This "
|
1504 |
"feature is available only with the premium %s[Plus Package]%s add-on."
|
1505 |
msgstr ""
|
1506 |
|
1507 |
+
#: application/Backend/tmpl/partial/visitor-principal-subject-tab.php:5
|
1508 |
+
msgid ""
|
1509 |
+
"Attach current access & security policy to visitors (any user that is "
|
1510 |
+
"not authenticated)"
|
1511 |
+
msgstr ""
|
1512 |
+
|
1513 |
+
#: application/Backend/tmpl/partial/visitor-subject-tab.php:5
|
1514 |
+
msgid ""
|
1515 |
+
"Manage access to your website for visitors (any user that is not "
|
1516 |
+
"authenticated)"
|
1517 |
+
msgstr ""
|
1518 |
+
|
1519 |
+
#: application/Backend/tmpl/partial/visitor-subject-tab.php:6
|
1520 |
+
msgid "Manage Visitors"
|
1521 |
+
msgstr ""
|
1522 |
+
|
1523 |
+
#: application/Backend/tmpl/service/404redirect.php:9
|
1524 |
msgid "Setup [default] 404 redirect for all none-existing pages."
|
1525 |
msgstr ""
|
1526 |
|
1527 |
+
#: application/Backend/tmpl/service/404redirect.php:22
|
1528 |
msgid "Default WordPress 404 handler"
|
1529 |
msgstr ""
|
1530 |
|
1531 |
+
#: application/Backend/tmpl/service/404redirect.php:30
|
1532 |
msgid "Redirected to the URL [(enter valid URL starting from http or https)]"
|
1533 |
msgstr ""
|
1534 |
|
1535 |
+
#: application/Backend/tmpl/service/404redirect.php:62
|
1536 |
msgid ""
|
1537 |
"You cannot setup 404 redirect for specific user, role or visitors. Switch to "
|
1538 |
"[Manage Default Access] and define default 404 redirect for everybody."
|
1539 |
msgstr ""
|
1540 |
|
1541 |
+
#: application/Backend/tmpl/service/capability.php:11
|
1542 |
#, php-format
|
1543 |
msgid ""
|
1544 |
"[Be careful!] On this tab, you can manage capabilities for [%s]. Any changes "
|
1548 |
"article."
|
1549 |
msgstr ""
|
1550 |
|
1551 |
+
#: application/Backend/tmpl/service/capability.php:20
|
1552 |
msgid "Filter"
|
1553 |
msgstr ""
|
1554 |
|
1555 |
+
#: application/Backend/tmpl/service/capability.php:27
|
1556 |
msgid "All Capabilities"
|
1557 |
msgstr ""
|
1558 |
|
1559 |
+
#: application/Backend/tmpl/service/capability.php:37
|
1560 |
msgid "Category"
|
1561 |
msgstr ""
|
1562 |
|
1563 |
+
#: application/Backend/tmpl/service/capability.php:38
|
1564 |
+
#: application/Backend/tmpl/service/capability.php:54
|
1565 |
+
#: application/Backend/tmpl/service/capability.php:80
|
1566 |
+
#: application/Backend/tmpl/service/menu.php:155
|
1567 |
msgid "Capability"
|
1568 |
msgstr ""
|
1569 |
|
1570 |
+
#: application/Backend/tmpl/service/capability.php:39
|
1571 |
+
#: application/Backend/tmpl/service/jwt.php:24
|
1572 |
+
#: application/Backend/tmpl/service/policy.php:28
|
1573 |
+
#: application/Backend/tmpl/service/post.php:22
|
1574 |
+
#: application/Backend/tmpl/service/uri.php:146
|
1575 |
msgid "Actions"
|
1576 |
msgstr ""
|
1577 |
|
1578 |
+
#: application/Backend/tmpl/service/capability.php:50
|
1579 |
msgid "Create Capability"
|
1580 |
msgstr ""
|
1581 |
|
1582 |
+
#: application/Backend/tmpl/service/capability.php:55
|
1583 |
+
#: application/Backend/tmpl/service/capability.php:81
|
1584 |
msgid "Enter Capability"
|
1585 |
msgstr ""
|
1586 |
|
1587 |
+
#: application/Backend/tmpl/service/capability.php:59
|
1588 |
msgid "Also assign this capability to me"
|
1589 |
msgstr ""
|
1590 |
|
1591 |
+
#: application/Backend/tmpl/service/capability.php:85
|
1592 |
msgid "Update this capability for me too"
|
1593 |
msgstr ""
|
1594 |
|
1595 |
+
#: application/Backend/tmpl/service/capability.php:102
|
1596 |
msgid "Delete Capability"
|
1597 |
msgstr ""
|
1598 |
|
1599 |
+
#: application/Backend/tmpl/service/capability.php:105
|
1600 |
msgid ""
|
1601 |
"You are about to delete the %s capability. Any functionality that depends on "
|
1602 |
"this capability will no longer be accessible by %n."
|
1603 |
msgstr ""
|
1604 |
|
1605 |
+
#: application/Backend/tmpl/service/capability.php:108
|
1606 |
msgid "Delete For %n Only"
|
1607 |
msgstr ""
|
1608 |
|
1609 |
+
#: application/Backend/tmpl/service/capability.php:109
|
1610 |
msgid "Delete For All Roles"
|
1611 |
msgstr ""
|
1612 |
|
1613 |
+
#: application/Backend/tmpl/service/jwt.php:10
|
1614 |
#, php-format
|
1615 |
msgid ""
|
1616 |
"Manage list of all valid JWT tokens to the website for [%s] account. For "
|
1618 |
"WordPress JWT authentication%s article."
|
1619 |
msgstr ""
|
1620 |
|
1621 |
+
#: application/Backend/tmpl/service/jwt.php:23
|
1622 |
msgid "Expires"
|
1623 |
msgstr ""
|
1624 |
|
1625 |
+
#: application/Backend/tmpl/service/jwt.php:37
|
1626 |
msgid "Create JWT Token"
|
1627 |
msgstr ""
|
1628 |
|
1629 |
+
#: application/Backend/tmpl/service/jwt.php:42
|
1630 |
msgid "JWT Expires"
|
1631 |
msgstr ""
|
1632 |
|
1633 |
+
#: application/Backend/tmpl/service/jwt.php:52
|
1634 |
msgid "Is token refreshable?"
|
1635 |
msgstr ""
|
1636 |
|
1637 |
+
#: application/Backend/tmpl/service/jwt.php:54
|
1638 |
msgid ""
|
1639 |
"Whether this token, before expires, can be used to obtain a new token for "
|
1640 |
"the same time duration or not."
|
1641 |
msgstr ""
|
1642 |
|
1643 |
+
#: application/Backend/tmpl/service/jwt.php:66
|
1644 |
+
#: application/Backend/tmpl/service/jwt.php:101
|
1645 |
+
msgid "JWT Token (for API request)"
|
1646 |
msgstr ""
|
1647 |
|
1648 |
+
#: application/Backend/tmpl/service/jwt.php:76
|
1649 |
msgid "Passwordless Login URL"
|
1650 |
msgstr ""
|
1651 |
|
1652 |
+
#: application/Backend/tmpl/service/jwt.php:80
|
1653 |
msgid ""
|
1654 |
"With this URL account will be automatically logged in as long as JWT token "
|
1655 |
"is valid."
|
1656 |
msgstr ""
|
1657 |
|
1658 |
+
#: application/Backend/tmpl/service/jwt.php:96
|
1659 |
msgid "View JWT Token"
|
1660 |
msgstr ""
|
1661 |
|
1662 |
+
#: application/Backend/tmpl/service/jwt.php:111
|
1663 |
msgid "Passwordless Login URL (with JWT token)"
|
1664 |
msgstr ""
|
1665 |
|
1666 |
+
#: application/Backend/tmpl/service/jwt.php:115
|
1667 |
msgid ""
|
1668 |
"Use this URL to authenticate account without the need to enter username/"
|
1669 |
"password."
|
1670 |
msgstr ""
|
1671 |
|
1672 |
+
#: application/Backend/tmpl/service/jwt.php:130
|
1673 |
msgid "Delete JWT Token"
|
1674 |
msgstr ""
|
1675 |
|
1676 |
+
#: application/Backend/tmpl/service/jwt.php:133
|
1677 |
msgid ""
|
1678 |
"You are about to delete already issued JWT token. Any application or user "
|
1679 |
"that has this token, will no longer be able to use it. Please confirm."
|
1680 |
msgstr ""
|
1681 |
|
1682 |
+
#: application/Backend/tmpl/service/login-redirect.php:9
|
1683 |
msgid ""
|
1684 |
"Define the [default] login redirect for all the users and roles when "
|
1685 |
"authentication is completed successfully."
|
1686 |
msgstr ""
|
1687 |
|
1688 |
+
#: application/Backend/tmpl/service/login-redirect.php:13
|
1689 |
#, php-format
|
1690 |
msgid ""
|
1691 |
"Customize login redirect for [%s] when the authentication is completed "
|
1694 |
"login solutions."
|
1695 |
msgstr ""
|
1696 |
|
1697 |
+
#: application/Backend/tmpl/service/login-redirect.php:29
|
1698 |
+
#: application/Backend/tmpl/service/logout-redirect.php:29
|
1699 |
msgid "WordPress default behavior"
|
1700 |
msgstr ""
|
1701 |
|
1702 |
+
#: application/Backend/tmpl/service/login-redirect.php:37
|
1703 |
msgid ""
|
1704 |
"Redirected to the local URL [(enter full URL starting from http or https)]"
|
1705 |
msgstr ""
|
1706 |
|
1707 |
+
#: application/Backend/tmpl/service/logout-redirect.php:9
|
1708 |
msgid "Define the [default] logout redirect for all the users and roles."
|
1709 |
msgstr ""
|
1710 |
|
1711 |
+
#: application/Backend/tmpl/service/logout-redirect.php:13
|
1712 |
#, php-format
|
1713 |
msgid "Customize logout redirect for [%s]."
|
1714 |
msgstr ""
|
1715 |
|
1716 |
+
#: application/Backend/tmpl/service/menu.php:9
|
1717 |
#, php-format
|
1718 |
msgid ""
|
1719 |
"Manage access to the backend main menu for [%s]. For more information check "
|
1720 |
"%sHow to manage WordPress backend menu%s."
|
1721 |
msgstr ""
|
1722 |
|
1723 |
+
#: application/Backend/tmpl/service/menu.php:56
|
1724 |
msgid "Menu URI:"
|
1725 |
msgstr ""
|
1726 |
|
1727 |
+
#: application/Backend/tmpl/service/menu.php:76
|
1728 |
+
#: application/Backend/tmpl/service/metabox.php:74
|
1729 |
+
#: application/Backend/tmpl/service/toolbar.php:57
|
1730 |
msgid "more details"
|
1731 |
msgstr ""
|
1732 |
|
1733 |
+
#: application/Backend/tmpl/service/menu.php:103
|
1734 |
msgid ""
|
1735 |
"Dashboard menu cannot be restricted because it is the default page all users "
|
1736 |
"are redirected after login. You can restrict only Dashboard submenus if any."
|
1737 |
msgstr ""
|
1738 |
|
1739 |
+
#: application/Backend/tmpl/service/menu.php:113
|
1740 |
msgid ""
|
1741 |
"Current user does not have enough capabilities to access any available "
|
1742 |
"backend menu."
|
1743 |
msgstr ""
|
1744 |
|
1745 |
+
#: application/Backend/tmpl/service/menu.php:125
|
1746 |
msgid "Dashboard Lockdown"
|
1747 |
msgstr ""
|
1748 |
|
1749 |
+
#: application/Backend/tmpl/service/menu.php:129
|
1750 |
msgid "You cannot restrict access to the Dashboard Home page."
|
1751 |
msgstr ""
|
1752 |
|
1753 |
+
#: application/Backend/tmpl/service/menu.php:130
|
1754 |
#, php-format
|
1755 |
msgid ""
|
1756 |
"The [Dashboard Home] is the default page that every user is redirected to "
|
1758 |
"lockdown WordPress backend%s article."
|
1759 |
msgstr ""
|
1760 |
|
1761 |
+
#: application/Backend/tmpl/service/menu.php:134
|
1762 |
msgid "OK"
|
1763 |
msgstr ""
|
1764 |
|
1765 |
+
#: application/Backend/tmpl/service/menu.php:145
|
1766 |
msgid "Menu Details"
|
1767 |
msgstr ""
|
1768 |
|
1769 |
+
#: application/Backend/tmpl/service/menu.php:151
|
1770 |
+
#: application/Backend/tmpl/service/toolbar.php:93
|
1771 |
msgid "Name"
|
1772 |
msgstr ""
|
1773 |
|
1774 |
+
#: application/Backend/tmpl/service/menu.php:159
|
1775 |
+
#: application/Backend/tmpl/service/toolbar.php:97
|
1776 |
+
#: application/Backend/tmpl/service/uri.php:142
|
1777 |
msgid "URI"
|
1778 |
msgstr ""
|
1779 |
|
1780 |
+
#: application/Backend/tmpl/service/menu.php:163
|
1781 |
+
#: application/Backend/tmpl/service/toolbar.php:101 media/js/aam.js:765
|
1782 |
+
msgid "ID"
|
1783 |
+
msgstr ""
|
1784 |
+
|
1785 |
+
#: application/Backend/tmpl/service/metabox.php:9
|
1786 |
+
#, php-format
|
1787 |
msgid ""
|
1788 |
"Manage classic (not Gutenberg) metaboxes and widgets visibility for [%s]. "
|
1789 |
"For more information please check %sHow to hide WordPress metaboxes and "
|
1790 |
"widgets%s."
|
1791 |
msgstr ""
|
1792 |
|
1793 |
+
#: application/Backend/tmpl/service/metabox.php:16
|
1794 |
msgid "Refresh"
|
1795 |
msgstr ""
|
1796 |
|
1797 |
+
#: application/Backend/tmpl/service/metabox.php:17
|
1798 |
msgid "Init URL"
|
1799 |
msgstr ""
|
1800 |
|
1801 |
+
#: application/Backend/tmpl/service/metabox.php:49
|
1802 |
msgid "Dashboard Widgets"
|
1803 |
msgstr ""
|
1804 |
|
1805 |
+
#: application/Backend/tmpl/service/metabox.php:53
|
1806 |
msgid "Frontend Widgets [(including Appearance->Widgets)]"
|
1807 |
msgstr ""
|
1808 |
|
1809 |
+
#: application/Backend/tmpl/service/metabox.php:91
|
1810 |
msgid "The list is not initialized. Click Refresh button above."
|
1811 |
msgstr ""
|
1812 |
|
1813 |
+
#: application/Backend/tmpl/service/metabox.php:102
|
1814 |
msgid "Initialize URL"
|
1815 |
msgstr ""
|
1816 |
|
1817 |
+
#: application/Backend/tmpl/service/metabox.php:106
|
1818 |
msgid ""
|
1819 |
"Some metaboxes are \"conditional\" and appear on the edit screen when "
|
1820 |
"certain conditions are met. For example metabox \"Comments\" appears only "
|
1823 |
"appears."
|
1824 |
msgstr ""
|
1825 |
|
1826 |
+
#: application/Backend/tmpl/service/metabox.php:109
|
1827 |
msgid "Backend page URL"
|
1828 |
msgstr ""
|
1829 |
|
1830 |
+
#: application/Backend/tmpl/service/metabox.php:110
|
1831 |
msgid "Insert valid URL"
|
1832 |
msgstr ""
|
1833 |
|
1834 |
+
#: application/Backend/tmpl/service/metabox.php:126
|
1835 |
msgid "Metabox/Widget Details"
|
1836 |
msgstr ""
|
1837 |
|
1838 |
+
#: application/Backend/tmpl/service/metabox.php:132
|
1839 |
+
#: application/Backend/tmpl/service/post.php:21
|
1840 |
msgid "Title"
|
1841 |
msgstr ""
|
1842 |
|
1843 |
+
#: application/Backend/tmpl/service/metabox.php:136
|
1844 |
msgid "Screen ID"
|
1845 |
msgstr ""
|
1846 |
|
1847 |
+
#: application/Backend/tmpl/service/metabox.php:140
|
1848 |
+
msgid "Internal ID"
|
1849 |
+
msgstr ""
|
1850 |
+
|
1851 |
+
#: application/Backend/tmpl/service/policy.php:7
|
1852 |
#, php-format
|
1853 |
msgid ""
|
1854 |
"Manage access and security policies for [%s]. For more information check "
|
1855 |
"%sAccess & Security Policy%s page."
|
1856 |
msgstr ""
|
1857 |
|
1858 |
+
#: application/Backend/tmpl/service/policy.php:15
|
1859 |
msgid "Policies are customized"
|
1860 |
msgstr ""
|
1861 |
|
1862 |
+
#: application/Backend/tmpl/service/policy.php:16
|
1863 |
msgid "Reset To Default"
|
1864 |
msgstr ""
|
1865 |
|
1866 |
+
#: application/Backend/tmpl/service/policy.php:27
|
1867 |
+
#: application/Service/AccessPolicy.php:171
|
1868 |
msgid "Policy"
|
1869 |
msgstr ""
|
1870 |
|
1871 |
+
#: application/Backend/tmpl/service/policy.php:40
|
1872 |
#, php-format
|
1873 |
msgid ""
|
1874 |
"%s[AAM Plus Package]%s extension is required in order to apply Access & "
|
1875 |
"Security Policies to everybody all together."
|
1876 |
msgstr ""
|
1877 |
|
1878 |
+
#: application/Backend/tmpl/service/post.php:11
|
1879 |
msgid "Root"
|
1880 |
msgstr ""
|
1881 |
|
1882 |
+
#: application/Backend/tmpl/service/post.php:31
|
1883 |
+
#: application/Backend/tmpl/service/post.php:34
|
1884 |
msgid "Go Back"
|
1885 |
msgstr ""
|
1886 |
|
1887 |
+
#: application/Backend/tmpl/service/redirect.php:11
|
1888 |
msgid ""
|
1889 |
"Define the [default] redirect for all users, roles and visitors when access "
|
1890 |
"is denied to any restricted resources on your website."
|
1891 |
msgstr ""
|
1892 |
|
1893 |
+
#: application/Backend/tmpl/service/redirect.php:15
|
1894 |
#, php-format
|
1895 |
msgid ""
|
1896 |
"Customize redirect for %s when access is denied to restricted resources like "
|
1898 |
"please check %sHow to redirect WordPress user when access is denied%s."
|
1899 |
msgstr ""
|
1900 |
|
1901 |
+
#: application/Backend/tmpl/service/redirect.php:29
|
1902 |
msgid "Frontend Redirect"
|
1903 |
msgstr ""
|
1904 |
|
1905 |
+
#: application/Backend/tmpl/service/redirect.php:30
|
1906 |
msgid "Backend Redirect"
|
1907 |
msgstr ""
|
1908 |
|
1909 |
+
#: application/Backend/tmpl/service/redirect.php:40
|
1910 |
+
#: application/Backend/tmpl/service/redirect.php:98
|
1911 |
msgid "Default [(\"Access Denied\" message)]"
|
1912 |
msgstr ""
|
1913 |
|
1914 |
+
#: application/Backend/tmpl/service/redirect.php:44
|
1915 |
+
#: application/Backend/tmpl/service/redirect.php:102
|
1916 |
+
#: application/Backend/tmpl/service/uri.php:47
|
1917 |
msgid "Show customized message [(plain text or HTML)]"
|
1918 |
msgstr ""
|
1919 |
|
1920 |
+
#: application/Backend/tmpl/service/redirect.php:58
|
1921 |
+
#: application/Backend/tmpl/service/redirect.php:110
|
1922 |
+
#: application/Backend/tmpl/service/uri.php:61
|
1923 |
msgid "Redirected to local URL [(enter valid URL starting from http or https)]"
|
1924 |
msgstr ""
|
1925 |
|
1926 |
+
#: application/Backend/tmpl/service/redirect.php:66
|
1927 |
+
#: application/Backend/tmpl/service/redirect.php:118
|
1928 |
+
#: application/Backend/tmpl/service/uri.php:69
|
1929 |
msgid "Customized Message"
|
1930 |
msgstr ""
|
1931 |
|
1932 |
+
#: application/Backend/tmpl/service/redirect.php:67
|
1933 |
+
#: application/Backend/tmpl/service/redirect.php:119
|
1934 |
+
#: application/Backend/tmpl/service/uri.php:70
|
1935 |
msgid "Enter message..."
|
1936 |
msgstr ""
|
1937 |
|
1938 |
+
#: application/Backend/tmpl/service/redirect.php:106
|
1939 |
msgid "Redirected to existing frontend page [(select from the drop-down)]"
|
1940 |
msgstr ""
|
1941 |
|
1942 |
+
#: application/Backend/tmpl/service/route.php:10
|
1943 |
#, php-format
|
1944 |
msgid ""
|
1945 |
"Manage access to the website API routes for [%s]. For the full RESTful API "
|
1947 |
"in AAM."
|
1948 |
msgstr ""
|
1949 |
|
1950 |
+
#: application/Backend/tmpl/service/route.php:18
|
1951 |
msgid "Routes are customized"
|
1952 |
msgstr ""
|
1953 |
|
1954 |
+
#: application/Backend/tmpl/service/route.php:29
|
1955 |
msgid "Method"
|
1956 |
msgstr ""
|
1957 |
|
1958 |
+
#: application/Backend/tmpl/service/route.php:30
|
1959 |
msgid "Route"
|
1960 |
msgstr ""
|
1961 |
|
1962 |
+
#: application/Backend/tmpl/service/route.php:31
|
1963 |
msgid "Deny"
|
1964 |
msgstr ""
|
1965 |
|
1966 |
+
#: application/Backend/tmpl/service/toolbar.php:8
|
1967 |
msgid ""
|
1968 |
"[Note!] Admin Toolbar service is not intended to restrict direct access to "
|
1969 |
"linked pages. It used only to remove unnecessary items from the top admin "
|
1971 |
"or utilize the great power of capabilities."
|
1972 |
msgstr ""
|
1973 |
|
1974 |
+
#: application/Backend/tmpl/service/toolbar.php:46
|
1975 |
msgid "Item ID:"
|
1976 |
msgstr ""
|
1977 |
|
1978 |
+
#: application/Backend/tmpl/service/toolbar.php:87
|
1979 |
msgid "Item Details"
|
1980 |
msgstr ""
|
1981 |
|
1982 |
+
#: application/Backend/tmpl/service/toolbar.php:118
|
1983 |
msgid "The list of top admin bar items is not initialized. Reload the page."
|
1984 |
msgstr ""
|
1985 |
|
1986 |
+
#: application/Backend/tmpl/service/uri.php:8
|
1987 |
#, php-format
|
1988 |
msgid ""
|
1989 |
"Manage access to the website URL(s) for the [%s]. Note! All entered URLs "
|
1992 |
"website URL%s."
|
1993 |
msgstr ""
|
1994 |
|
1995 |
+
#: application/Backend/tmpl/service/uri.php:27
|
1996 |
msgid "URI Access Rule"
|
1997 |
msgstr ""
|
1998 |
|
1999 |
+
#: application/Backend/tmpl/service/uri.php:31
|
2000 |
msgid "Enter URL [(wildcard * is available with Plus Package extension)]"
|
2001 |
msgstr ""
|
2002 |
|
2003 |
+
#: application/Backend/tmpl/service/uri.php:35
|
2004 |
msgid "How to redirect user when match?"
|
2005 |
msgstr ""
|
2006 |
|
2007 |
+
#: application/Backend/tmpl/service/uri.php:39
|
2008 |
msgid "Allow Access"
|
2009 |
msgstr ""
|
2010 |
|
2011 |
+
#: application/Backend/tmpl/service/uri.php:43
|
2012 |
msgid "Deny Access [(show \"Access Denied\" message)]"
|
2013 |
msgstr ""
|
2014 |
|
2015 |
+
#: application/Backend/tmpl/service/uri.php:87
|
2016 |
msgid "The Valid Redirect URL"
|
2017 |
msgstr ""
|
2018 |
|
2019 |
+
#: application/Backend/tmpl/service/uri.php:94
|
2020 |
msgid "HTTP Code (Default 307)"
|
2021 |
msgstr ""
|
2022 |
|
2023 |
+
#: application/Backend/tmpl/service/uri.php:96
|
2024 |
msgid "302 - Found"
|
2025 |
msgstr ""
|
2026 |
|
2027 |
+
#: application/Backend/tmpl/service/uri.php:98
|
2028 |
msgid "307 - Temporary Redirect"
|
2029 |
msgstr ""
|
2030 |
|
2031 |
+
#: application/Backend/tmpl/service/uri.php:120
|
2032 |
msgid "Delete URI Rule"
|
2033 |
msgstr ""
|
2034 |
|
2035 |
+
#: application/Backend/tmpl/service/uri.php:125
|
2036 |
msgid "You are about to delete the URI Rule. Please confirm!"
|
2037 |
msgstr ""
|
2038 |
|
2039 |
+
#: application/Backend/tmpl/service/uri.php:143
|
2040 |
msgid "Type"
|
2041 |
msgstr ""
|
2042 |
|
2043 |
+
#: application/Backend/tmpl/service/welcome.php:11
|
2044 |
msgid ""
|
2045 |
"Thank you for using the Advanced Access Manager (aka AAM) plugin. With "
|
2046 |
"strong knowledge and experience in WordPress core, AAM becomes a very "
|
2048 |
"backend, and RESTful API."
|
2049 |
msgstr ""
|
2050 |
|
2051 |
+
#: application/Backend/tmpl/service/welcome.php:12
|
2052 |
msgid "Note!"
|
2053 |
msgstr ""
|
2054 |
|
2055 |
+
#: application/Backend/tmpl/service/welcome.php:12
|
2056 |
#, php-format
|
2057 |
msgid ""
|
2058 |
"Power comes with responsibility. Make sure you have a good understanding of "
|
2063 |
"server and never did."
|
2064 |
msgstr ""
|
2065 |
|
2066 |
+
#: application/Backend/tmpl/service/welcome.php:13
|
2067 |
msgid ""
|
2068 |
"AAM is thoroughly tested on the fresh installation of the latest WordPress "
|
2069 |
"and in the latest versions of Chrome, Safari, IE, and Firefox. If you have "
|
2071 |
"themes."
|
2072 |
msgstr ""
|
2073 |
|
2074 |
+
#: application/Backend/tmpl/service/welcome.php:14
|
2075 |
#, php-format
|
2076 |
msgid ""
|
2077 |
"If you are not sure where to start, please check our %s\"Get Started\"%s "
|
2079 |
"your WordPress website more effectively."
|
2080 |
msgstr ""
|
2081 |
|
2082 |
+
#: application/Backend/tmpl/service/welcome.php:16
|
2083 |
msgid "Go To The \"Get Started\" Page"
|
2084 |
msgstr ""
|
2085 |
|
2086 |
+
#: application/Backend/tmpl/settings/configpress.php:8
|
2087 |
#, php-format
|
2088 |
msgid ""
|
2089 |
"Fore more information about AAM configurations check %sAAM Configurations%s "
|
2090 |
"article."
|
2091 |
msgstr ""
|
2092 |
|
2093 |
+
#: application/Backend/tmpl/settings/content.php:24
|
2094 |
+
msgid "There are no settings associated with content service."
|
2095 |
+
msgstr ""
|
2096 |
+
|
2097 |
+
#: application/Backend/tmpl/settings/service.php:10
|
2098 |
msgid "Service Name/Description"
|
2099 |
msgstr ""
|
2100 |
|
2101 |
+
#: application/Backend/tmpl/settings/service.php:11
|
2102 |
msgid "Status"
|
2103 |
msgstr ""
|
2104 |
|
2105 |
+
#: application/Backend/tmpl/widget/login-backend.php:5
|
2106 |
msgid "Login Title"
|
2107 |
msgstr ""
|
2108 |
|
2109 |
+
#: application/Backend/tmpl/widget/login-backend.php:10
|
2110 |
msgid "Logged In Title"
|
2111 |
msgstr ""
|
2112 |
|
2113 |
+
#: application/Backend/tmpl/widget/login-backend.php:15
|
2114 |
#, php-format
|
2115 |
msgid ""
|
2116 |
"For more advanced setup like login/logout redirects, security enhancement or "
|
2117 |
"custom styling, please refer to %sHow does AAM Secure Login works%s article."
|
2118 |
msgstr ""
|
2119 |
|
2120 |
+
#: application/Backend/tmpl/widget/login-frontend.php:23
|
2121 |
msgid "Username or Email Address"
|
2122 |
msgstr ""
|
2123 |
|
2124 |
+
#: application/Backend/tmpl/widget/login-frontend.php:38
|
2125 |
msgid "Remember Me"
|
2126 |
msgstr ""
|
2127 |
|
2128 |
+
#: application/Backend/tmpl/widget/login-frontend.php:43
|
2129 |
msgid "Log In"
|
2130 |
msgstr ""
|
2131 |
|
2132 |
+
#: application/Backend/tmpl/widget/login-frontend.php:51
|
2133 |
msgid "Register"
|
2134 |
msgstr ""
|
2135 |
|
2136 |
+
#: application/Backend/tmpl/widget/login-frontend.php:56
|
2137 |
msgid "Lost your password?"
|
2138 |
msgstr ""
|
2139 |
|
2140 |
+
#: application/Backend/tmpl/widget/login-frontend.php:102
|
2141 |
msgid "Dashboard"
|
2142 |
msgstr ""
|
2143 |
|
2144 |
+
#: application/Backend/tmpl/widget/login-frontend.php:103
|
2145 |
msgid "Edit My Profile"
|
2146 |
msgstr ""
|
2147 |
|
2148 |
+
#: application/Backend/tmpl/widget/login-frontend.php:105
|
2149 |
msgid "Log Out"
|
2150 |
msgstr ""
|
2151 |
+
|
2152 |
+
#: application/Core/Jwt/Issuer.php:55
|
2153 |
+
msgid "Token has been revoked"
|
2154 |
+
msgstr ""
|
2155 |
+
|
2156 |
+
#: application/Core/Object.php:141
|
2157 |
+
#, php-format
|
2158 |
+
msgid "AAM object function %s is not defined"
|
2159 |
+
msgstr ""
|
2160 |
+
|
2161 |
+
#: application/Core/Policy/Validator.php:107
|
2162 |
+
#: tests/Service/AccessPolicy/PolicyValidationTest.php:54
|
2163 |
+
msgid "The policy is not valid JSON object"
|
2164 |
+
msgstr ""
|
2165 |
+
|
2166 |
+
#: application/Core/Policy/Validator.php:126
|
2167 |
+
#: tests/Service/AccessPolicy/PolicyValidationTest.php:37
|
2168 |
+
msgid "The policy document is empty"
|
2169 |
+
msgstr ""
|
2170 |
+
|
2171 |
+
#: application/Core/Redirect.php:74
|
2172 |
+
#: application/Service/ExtendedCapabilities.php:126
|
2173 |
+
#: application/Service/Route.php:216
|
2174 |
+
msgid "Access Denied"
|
2175 |
+
msgstr ""
|
2176 |
+
|
2177 |
+
#: application/Service/AccessPolicy.php:67
|
2178 |
+
msgid ""
|
2179 |
+
"Manage access to the website with well documented JSON access policies for "
|
2180 |
+
"any user, role or visitors. Keep the paper-trail of all the access changes "
|
2181 |
+
"with policy revisions."
|
2182 |
+
msgstr ""
|
2183 |
+
|
2184 |
+
#: application/Service/AccessPolicy.php:97
|
2185 |
+
msgid "Access Policy Document"
|
2186 |
+
msgstr ""
|
2187 |
+
|
2188 |
+
#: application/Service/AccessPolicy.php:108
|
2189 |
+
msgid "Access Policy Assignee"
|
2190 |
+
msgstr ""
|
2191 |
+
|
2192 |
+
#: application/Service/AccessPolicy.php:167
|
2193 |
+
msgid "Access Policy"
|
2194 |
+
msgstr ""
|
2195 |
+
|
2196 |
+
#: application/Service/AccessPolicy.php:172
|
2197 |
+
msgid "Add New Policy"
|
2198 |
+
msgstr ""
|
2199 |
+
|
2200 |
+
#: application/Service/AccessPolicy.php:173
|
2201 |
+
msgid "New Policy"
|
2202 |
+
msgstr ""
|
2203 |
+
|
2204 |
+
#: application/Service/AccessPolicy.php:175
|
2205 |
+
msgid "Access and security policy"
|
2206 |
+
msgstr ""
|
2207 |
+
|
2208 |
+
#: application/Service/AdminMenu.php:59
|
2209 |
+
msgid "Admin Menu"
|
2210 |
+
msgstr ""
|
2211 |
+
|
2212 |
+
#: application/Service/AdminMenu.php:60
|
2213 |
+
msgid ""
|
2214 |
+
"Manage access to the admin (backend) main menu for any role or individual "
|
2215 |
+
"user. The service removes restricted menu items and protects direct access "
|
2216 |
+
"to them."
|
2217 |
+
msgstr ""
|
2218 |
+
|
2219 |
+
#: application/Service/AdminMenu.php:275
|
2220 |
+
msgid "Sorry, you are not allowed to view this page."
|
2221 |
+
msgstr ""
|
2222 |
+
|
2223 |
+
#: application/Service/Capability.php:53
|
2224 |
+
msgid ""
|
2225 |
+
"Manage list of all the registered with WordPress core capabilities for any "
|
2226 |
+
"role or individual user. The service allows to create new or update and "
|
2227 |
+
"delete existing capabilities. Very powerful set of tools for more advanced "
|
2228 |
+
"user/role access management."
|
2229 |
+
msgstr ""
|
2230 |
+
|
2231 |
+
#: application/Service/Content.php:73
|
2232 |
+
msgid ""
|
2233 |
+
"Manage access to your website content for any user, role or visitor. This "
|
2234 |
+
"include access to posts, pages, media attachment, custom post types, "
|
2235 |
+
"categories, tags, custom taxonomies and terms."
|
2236 |
+
msgstr ""
|
2237 |
+
|
2238 |
+
#: application/Service/Content.php:118
|
2239 |
+
msgid "Access Manager"
|
2240 |
+
msgstr ""
|
2241 |
+
|
2242 |
+
#: application/Service/Content.php:579
|
2243 |
+
msgid "[No teaser message provided]"
|
2244 |
+
msgstr ""
|
2245 |
+
|
2246 |
+
#: application/Service/DeniedRedirect.php:64
|
2247 |
+
msgid ""
|
2248 |
+
"Manage the default access denied redirect when access gets denied for any "
|
2249 |
+
"protected website resource. The service hooks into the WordPress core wp_die "
|
2250 |
+
"function and redirect any frontend or backend denied requests accordingly."
|
2251 |
+
msgstr ""
|
2252 |
+
|
2253 |
+
#: application/Service/ExtendedCapabilities.php:48
|
2254 |
+
msgid "Additional Caps"
|
2255 |
+
msgstr ""
|
2256 |
+
|
2257 |
+
#: application/Service/ExtendedCapabilities.php:49
|
2258 |
+
msgid ""
|
2259 |
+
"Extend the WordPress core collection of capabilities that allow more "
|
2260 |
+
"granular access control to the backend core features."
|
2261 |
+
msgstr ""
|
2262 |
+
|
2263 |
+
#: application/Service/Jwt.php:54
|
2264 |
+
msgid ""
|
2265 |
+
"Manage the website authentication with JWT Bearer token. The service "
|
2266 |
+
"facilitates the ability to manage the list of issued JWT token for any user, "
|
2267 |
+
"revoke them or issue new on demand."
|
2268 |
+
msgstr ""
|
2269 |
+
|
2270 |
+
#: application/Service/Jwt.php:99
|
2271 |
+
msgid "Issue JWT Token"
|
2272 |
+
msgstr ""
|
2273 |
+
|
2274 |
+
#: application/Service/Jwt.php:146 application/Service/Jwt.php:158
|
2275 |
+
msgid "JWT token."
|
2276 |
+
msgstr ""
|
2277 |
+
|
2278 |
+
#: application/Service/Jwt.php:225
|
2279 |
+
msgid "JWT token is not refreshable"
|
2280 |
+
msgstr ""
|
2281 |
+
|
2282 |
+
#: application/Service/LoginRedirect.php:53
|
2283 |
+
msgid ""
|
2284 |
+
"Manage login redirect for any group of users or individual user when "
|
2285 |
+
"authentication is completed successfully."
|
2286 |
+
msgstr ""
|
2287 |
+
|
2288 |
+
#: application/Service/LogoutRedirect.php:53
|
2289 |
+
msgid ""
|
2290 |
+
"Manage logout redirect for any group of users or individual user after user "
|
2291 |
+
"logged out successfully."
|
2292 |
+
msgstr ""
|
2293 |
+
|
2294 |
+
#: application/Service/Metabox.php:43
|
2295 |
+
msgid ""
|
2296 |
+
"Manage visibility for the classic (not Gutenberg blocks) backend metaboxes, "
|
2297 |
+
"dashboard and frontend widgets for any role, user or visitors. The service "
|
2298 |
+
"ONLY removes unwanted metaboxes and widgets and does not prevent from direct "
|
2299 |
+
"data spoofing."
|
2300 |
+
msgstr ""
|
2301 |
+
|
2302 |
+
#: application/Service/NotFoundRedirect.php:53
|
2303 |
+
msgid ""
|
2304 |
+
"Manage frontend 404 (Not Found) redirect for any group of users or "
|
2305 |
+
"individual user."
|
2306 |
+
msgstr ""
|
2307 |
+
|
2308 |
+
#: application/Service/Route.php:67
|
2309 |
+
msgid ""
|
2310 |
+
"Manage access to any individual RESTful endpoint for any role, user or "
|
2311 |
+
"unauthenticated application request. The service works great with JWT "
|
2312 |
+
"service that authenticate requests with JWT Bearer token."
|
2313 |
+
msgstr ""
|
2314 |
+
|
2315 |
+
#: application/Service/Route.php:95
|
2316 |
+
msgid "XML-RPC WordPress API"
|
2317 |
+
msgstr ""
|
2318 |
+
|
2319 |
+
#: application/Service/Route.php:96
|
2320 |
+
#, php-format
|
2321 |
+
msgid ""
|
2322 |
+
"Remote procedure call (RPC) interface is used to manage WordPress website "
|
2323 |
+
"content and features. For more information check %sXML-RPC Support%s article."
|
2324 |
+
msgstr ""
|
2325 |
+
|
2326 |
+
#: application/Service/Route.php:100
|
2327 |
+
msgid "RESTful WordPress API"
|
2328 |
+
msgstr ""
|
2329 |
+
|
2330 |
+
#: application/Service/Route.php:101
|
2331 |
+
#, php-format
|
2332 |
+
msgid ""
|
2333 |
+
"RESTful interface that is used to manage WordPress website content and "
|
2334 |
+
"features. For more information check %sREST API handbook%s."
|
2335 |
+
msgstr ""
|
2336 |
+
|
2337 |
+
#: application/Service/Route.php:127
|
2338 |
+
msgid "RESTful API is disabled"
|
2339 |
+
msgstr ""
|
2340 |
+
|
2341 |
+
#: application/Service/SecureLogin.php:46
|
2342 |
+
msgid "Secure Login"
|
2343 |
+
msgstr ""
|
2344 |
+
|
2345 |
+
#: application/Service/SecureLogin.php:47
|
2346 |
+
msgid ""
|
2347 |
+
"Enhance default WordPress authentication process with more secure login "
|
2348 |
+
"mechanism. The service registers frontend AJAX Login widget as well as "
|
2349 |
+
"additional endpoints for the RESTful API authentication."
|
2350 |
+
msgstr ""
|
2351 |
+
|
2352 |
+
#: application/Service/SecureLogin.php:108
|
2353 |
+
msgid "Block User Account"
|
2354 |
+
msgstr ""
|
2355 |
+
|
2356 |
+
#: application/Service/SecureLogin.php:139
|
2357 |
+
msgid "Valid username."
|
2358 |
+
msgstr ""
|
2359 |
+
|
2360 |
+
#: application/Service/SecureLogin.php:143
|
2361 |
+
msgid "Valid password."
|
2362 |
+
msgstr ""
|
2363 |
+
|
2364 |
+
#: application/Service/SecureLogin.php:147
|
2365 |
+
msgid "Redirect URL after authentication."
|
2366 |
+
msgstr ""
|
2367 |
+
|
2368 |
+
#: application/Service/SecureLogin.php:151
|
2369 |
+
msgid "Prolong the user session."
|
2370 |
+
msgstr ""
|
2371 |
+
|
2372 |
+
#: application/Service/SecureLogin.php:315
|
2373 |
+
msgid "Exceeded maximum number for authentication attempts. Try again later."
|
2374 |
+
msgstr ""
|
2375 |
+
|
2376 |
+
#: application/Service/SecureLogin.php:342
|
2377 |
+
msgid "[ERROR]: User is locked. Contact website administrator."
|
2378 |
+
msgstr ""
|
2379 |
+
|
2380 |
+
#: application/Service/SecureLogin.php:365
|
2381 |
+
#, php-format
|
2382 |
+
msgid "%sAccess is restricted. Login to get access.%s"
|
2383 |
+
msgstr ""
|
2384 |
+
|
2385 |
+
#: application/Service/Shortcode.php:45
|
2386 |
+
msgid "Shortcodes"
|
2387 |
+
msgstr ""
|
2388 |
+
|
2389 |
+
#: application/Service/Shortcode.php:46
|
2390 |
+
msgid ""
|
2391 |
+
"Classic WordPress shortcodes that allow to manage access to parts of a "
|
2392 |
+
"frontent content as well as some UI helpers."
|
2393 |
+
msgstr ""
|
2394 |
+
|
2395 |
+
#: application/Service/Toolbar.php:67
|
2396 |
+
msgid ""
|
2397 |
+
"Manage access to the top admin toolbar items for any role or individual "
|
2398 |
+
"user. The service only removes restricted items but does not actually "
|
2399 |
+
"protect from direct access via link."
|
2400 |
+
msgstr ""
|
2401 |
+
|
2402 |
+
#: application/Service/Uri.php:54
|
2403 |
+
msgid ""
|
2404 |
+
"Manage direct access to the website URIs for any role or individual user. "
|
2405 |
+
"Define either explicit URI or wildcard (with Plus Package addon) as well as "
|
2406 |
+
"how to manage user request (allow, deny, redirect, etc.)."
|
2407 |
+
msgstr ""
|
2408 |
+
|
2409 |
+
#: application/Service/UserLevelFilter.php:45
|
2410 |
+
msgid "User Level Filter"
|
2411 |
+
msgstr ""
|
2412 |
+
|
2413 |
+
#: application/Service/UserLevelFilter.php:46
|
2414 |
+
msgid ""
|
2415 |
+
"Extend default WordPress core users and roles handling, and make sure that "
|
2416 |
+
"users with lower user level cannot see or manager users and roles with "
|
2417 |
+
"higher level."
|
2418 |
+
msgstr ""
|
2419 |
+
|
2420 |
+
#: application/Service/Welcome.php:53
|
2421 |
+
msgid ""
|
2422 |
+
"Introduction panel to the AAM functionality. This is just a simple tab that "
|
2423 |
+
"contains some introductory material to the AAM plugin and its capabilities."
|
2424 |
+
msgstr ""
|
2425 |
+
|
2426 |
+
#: application/Shortcode/Handler/LoginRedirect.php:86
|
2427 |
+
msgid "Login to continue"
|
2428 |
+
msgstr ""
|
2429 |
+
|
2430 |
+
#: media/js/aam.js:132
|
2431 |
+
msgid "Search role"
|
2432 |
+
msgstr ""
|
2433 |
+
|
2434 |
+
#: media/js/aam.js:433
|
2435 |
+
msgid "Add role"
|
2436 |
+
msgstr ""
|
2437 |
+
|
2438 |
+
#: media/js/aam.js:1062 media/js/aam.js:2363 media/js/aam.js:2434
|
2439 |
+
#: media/js/aam.js:4730
|
2440 |
+
msgid "Resetting..."
|
2441 |
+
msgstr ""
|
2442 |
+
|
2443 |
+
#: media/js/aam.js:2668
|
2444 |
+
msgid "Post"
|
2445 |
+
msgstr ""
|
2446 |
+
|
2447 |
+
#: media/js/aam.js:2734
|
2448 |
+
msgid "post type"
|
2449 |
+
msgstr ""
|
2450 |
+
|
2451 |
+
#: media/js/aam.js:2739 media/js/aam.js:2765 media/js/aam.js:2778
|
2452 |
+
#: media/js/aam.js:2787 media/js/aam.js:2800
|
2453 |
+
msgid "ID:"
|
2454 |
+
msgstr ""
|
2455 |
+
|
2456 |
+
#: media/js/aam.js:2761
|
2457 |
+
msgid "taxonomy"
|
2458 |
+
msgstr ""
|
2459 |
+
|
2460 |
+
#: media/js/vendor.js:597
|
2461 |
+
msgid ": "
|
2462 |
+
msgstr ""
|
2463 |
+
|
2464 |
+
#: tests/Addon/PlusPackage/ContentAccessTest.php:185
|
2465 |
+
msgid "AAM Test"
|
2466 |
+
msgstr ""
|
2467 |
+
|
2468 |
+
#: tests/Addon/PlusPackage/ContentAccessTest.php:186
|
2469 |
+
msgid "Just for testing purposes"
|
2470 |
+
msgstr ""
|
2471 |
+
|
2472 |
+
#: tests/Service/AccessPolicy/PolicyValidationTest.php:76
|
2473 |
+
msgid "The plugin [advanced-access-manager-x] is required by the policy"
|
2474 |
+
msgstr ""
|
2475 |
+
|
2476 |
+
#: tests/Service/AccessPolicy/PolicyValidationTest.php:100
|
2477 |
+
msgid ""
|
2478 |
+
"The dependency [advanced-access-manager] does not satisfy version "
|
2479 |
+
"requirement by the policy"
|
2480 |
+
msgstr ""
|
2481 |
+
|
2482 |
+
#: tests/Service/Core/CoreServiceTest.php:39
|
2483 |
+
msgid "<script>alert(1);</script>"
|
2484 |
+
msgstr ""
|
media/css/aam.css
CHANGED
@@ -275,6 +275,10 @@ html, body {
|
|
275 |
position: relative;
|
276 |
}
|
277 |
|
|
|
|
|
|
|
|
|
278 |
a:focus, a:active {
|
279 |
outline: none;
|
280 |
box-shadow: none;
|
@@ -463,6 +467,18 @@ a.btn:focus, a.btn:active {
|
|
463 |
color: #3c763d;
|
464 |
}
|
465 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
466 |
.aam-api-method.post {
|
467 |
color: #F5AA2E;
|
468 |
}
|
275 |
position: relative;
|
276 |
}
|
277 |
|
278 |
+
.tooltip{
|
279 |
+
z-index:9999;
|
280 |
+
}
|
281 |
+
|
282 |
a:focus, a:active {
|
283 |
outline: none;
|
284 |
box-shadow: none;
|
467 |
color: #3c763d;
|
468 |
}
|
469 |
|
470 |
+
.aam-iframe .aam-subject-title {
|
471 |
+
display: none;
|
472 |
+
}
|
473 |
+
|
474 |
+
.aam-iframe .postbox .hndle {
|
475 |
+
display: none;
|
476 |
+
}
|
477 |
+
|
478 |
+
.aam-subject-title {
|
479 |
+
margin-left: 4px;
|
480 |
+
}
|
481 |
+
|
482 |
.aam-api-method.post {
|
483 |
color: #F5AA2E;
|
484 |
}
|
media/css/vendor.min.css
CHANGED
@@ -3,7 +3,7 @@
|
|
3 |
* Copyright 2011-2015 Twitter, Inc.
|
4 |
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
|
5 |
*//*! normalize.css v3.0.3 | MIT License | github.com/necolas/normalize.css */
|
6 |
-
html{font-family:sans-serif;-webkit-text-size-adjust:100%;-ms-text-size-adjust:100%}body{margin:0}article,aside,details,figcaption,figure,footer,header,hgroup,main,menu,nav,section,summary{display:block}audio,canvas,progress,video{display:inline-block;vertical-align:baseline}audio:not([controls]){display:none;height:0}[hidden],template{display:none}a{background-color:transparent}a:active,a:hover{outline:0}abbr[title]{border-bottom:1px dotted}b,strong{font-weight:700}dfn{font-style:italic}h1{margin:.67em 0;font-size:2em}mark{color:#000;background:#ff0}small{font-size:80%}sub,sup{position:relative;font-size:75%;line-height:0;vertical-align:baseline}sup{top:-.5em}sub{bottom:-.25em}img{border:0}svg:not(:root){overflow:hidden}figure{margin:1em 40px}hr{height:0;-webkit-box-sizing:content-box;-moz-box-sizing:content-box;box-sizing:content-box}pre{overflow:auto}code,kbd,pre,samp{font-family:monospace,monospace;font-size:1em}button,input,optgroup,select,textarea{margin:0;font:inherit;color:inherit}button{overflow:visible}button,select{text-transform:none}button,html input[type=button],input[type=reset],input[type=submit]{-webkit-appearance:button;cursor:pointer}button[disabled],html input[disabled]{cursor:default}button::-moz-focus-inner,input::-moz-focus-inner{padding:0;border:0}input{line-height:normal}input[type=checkbox],input[type=radio]{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;padding:0}input[type=number]::-webkit-inner-spin-button,input[type=number]::-webkit-outer-spin-button{height:auto}input[type=search]{-webkit-box-sizing:content-box;-moz-box-sizing:content-box;box-sizing:content-box;-webkit-appearance:textfield}input[type=search]::-webkit-search-cancel-button,input[type=search]::-webkit-search-decoration{-webkit-appearance:none}fieldset{padding:.35em .625em .75em;margin:0 2px;border:1px solid silver}legend{padding:0;border:0}textarea{overflow:auto}optgroup{font-weight:700}table{border-spacing:0;border-collapse:collapse}td,th{padding:0}/*! Source: https://github.com/h5bp/html5-boilerplate/blob/master/src/css/main.css */@media print{*,:after,:before{color:#000!important;text-shadow:none!important;background:0 0!important;-webkit-box-shadow:none!important;box-shadow:none!important}a,a:visited{text-decoration:underline}a[href]:after{content:" (" attr(href) ")"}abbr[title]:after{content:" (" attr(title) ")"}a[href^="javascript:"]:after,a[href^="#"]:after{content:""}blockquote,pre{border:1px solid #999;page-break-inside:avoid}thead{display:table-header-group}img,tr{page-break-inside:avoid}img{max-width:100%!important}h2,h3,p{orphans:3;widows:3}h2,h3{page-break-after:avoid}.navbar{display:none}.btn>.caret,.dropup>.btn>.caret{border-top-color:#000!important}.label{border:1px solid #000}.table{border-collapse:collapse!important}.table td,.table th{background-color:#fff!important}.table-bordered td,.table-bordered th{border:1px solid #ddd!important}}@font-face{font-family:'Glyphicons Halflings';src:url(../fonts/glyphicons-halflings-regular.eot);src:url(../fonts/glyphicons-halflings-regular.eot?#iefix) format('embedded-opentype'),url(../fonts/glyphicons-halflings-regular.woff2) format('woff2'),url(../fonts/glyphicons-halflings-regular.woff) format('woff'),url(../fonts/glyphicons-halflings-regular.ttf) format('truetype'),url(../fonts/glyphicons-halflings-regular.svg#glyphicons_halflingsregular) format('svg')}.glyphicon{position:relative;top:1px;display:inline-block;font-family:'Glyphicons Halflings';font-style:normal;font-weight:400;line-height:1;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}.glyphicon-asterisk:before{content:"\2a"}.glyphicon-plus:before{content:"\2b"}.glyphicon-eur:before,.glyphicon-euro:before{content:"\20ac"}.glyphicon-minus:before{content:"\2212"}.glyphicon-cloud:before{content:"\2601"}.glyphicon-envelope:before{content:"\2709"}.glyphicon-pencil:before{content:"\270f"}.glyphicon-glass:before{content:"\e001"}.glyphicon-music:before{content:"\e002"}.glyphicon-search:before{content:"\e003"}.glyphicon-heart:before{content:"\e005"}.glyphicon-star:before{content:"\e006"}.glyphicon-star-empty:before{content:"\e007"}.glyphicon-user:before{content:"\e008"}.glyphicon-film:before{content:"\e009"}.glyphicon-th-large:before{content:"\e010"}.glyphicon-th:before{content:"\e011"}.glyphicon-th-list:before{content:"\e012"}.glyphicon-ok:before{content:"\e013"}.glyphicon-remove:before{content:"\e014"}.glyphicon-zoom-in:before{content:"\e015"}.glyphicon-zoom-out:before{content:"\e016"}.glyphicon-off:before{content:"\e017"}.glyphicon-signal:before{content:"\e018"}.glyphicon-cog:before{content:"\e019"}.glyphicon-trash:before{content:"\e020"}.glyphicon-home:before{content:"\e021"}.glyphicon-file:before{content:"\e022"}.glyphicon-time:before{content:"\e023"}.glyphicon-road:before{content:"\e024"}.glyphicon-download-alt:before{content:"\e025"}.glyphicon-download:before{content:"\e026"}.glyphicon-upload:before{content:"\e027"}.glyphicon-inbox:before{content:"\e028"}.glyphicon-play-circle:before{content:"\e029"}.glyphicon-repeat:before{content:"\e030"}.glyphicon-refresh:before{content:"\e031"}.glyphicon-list-alt:before{content:"\e032"}.glyphicon-lock:before{content:"\e033"}.glyphicon-flag:before{content:"\e034"}.glyphicon-headphones:before{content:"\e035"}.glyphicon-volume-off:before{content:"\e036"}.glyphicon-volume-down:before{content:"\e037"}.glyphicon-volume-up:before{content:"\e038"}.glyphicon-qrcode:before{content:"\e039"}.glyphicon-barcode:before{content:"\e040"}.glyphicon-tag:before{content:"\e041"}.glyphicon-tags:before{content:"\e042"}.glyphicon-book:before{content:"\e043"}.glyphicon-bookmark:before{content:"\e044"}.glyphicon-print:before{content:"\e045"}.glyphicon-camera:before{content:"\e046"}.glyphicon-font:before{content:"\e047"}.glyphicon-bold:before{content:"\e048"}.glyphicon-italic:before{content:"\e049"}.glyphicon-text-height:before{content:"\e050"}.glyphicon-text-width:before{content:"\e051"}.glyphicon-align-left:before{content:"\e052"}.glyphicon-align-center:before{content:"\e053"}.glyphicon-align-right:before{content:"\e054"}.glyphicon-align-justify:before{content:"\e055"}.glyphicon-list:before{content:"\e056"}.glyphicon-indent-left:before{content:"\e057"}.glyphicon-indent-right:before{content:"\e058"}.glyphicon-facetime-video:before{content:"\e059"}.glyphicon-picture:before{content:"\e060"}.glyphicon-map-marker:before{content:"\e062"}.glyphicon-adjust:before{content:"\e063"}.glyphicon-tint:before{content:"\e064"}.glyphicon-edit:before{content:"\e065"}.glyphicon-share:before{content:"\e066"}.glyphicon-check:before{content:"\e067"}.glyphicon-move:before{content:"\e068"}.glyphicon-step-backward:before{content:"\e069"}.glyphicon-fast-backward:before{content:"\e070"}.glyphicon-backward:before{content:"\e071"}.glyphicon-play:before{content:"\e072"}.glyphicon-pause:before{content:"\e073"}.glyphicon-stop:before{content:"\e074"}.glyphicon-forward:before{content:"\e075"}.glyphicon-fast-forward:before{content:"\e076"}.glyphicon-step-forward:before{content:"\e077"}.glyphicon-eject:before{content:"\e078"}.glyphicon-chevron-left:before{content:"\e079"}.glyphicon-chevron-right:before{content:"\e080"}.glyphicon-plus-sign:before{content:"\e081"}.glyphicon-minus-sign:before{content:"\e082"}.glyphicon-remove-sign:before{content:"\e083"}.glyphicon-ok-sign:before{content:"\e084"}.glyphicon-question-sign:before{content:"\e085"}.glyphicon-info-sign:before{content:"\e086"}.glyphicon-screenshot:before{content:"\e087"}.glyphicon-remove-circle:before{content:"\e088"}.glyphicon-ok-circle:before{content:"\e089"}.glyphicon-ban-circle:before{content:"\e090"}.glyphicon-arrow-left:before{content:"\e091"}.glyphicon-arrow-right:before{content:"\e092"}.glyphicon-arrow-up:before{content:"\e093"}.glyphicon-arrow-down:before{content:"\e094"}.glyphicon-share-alt:before{content:"\e095"}.glyphicon-resize-full:before{content:"\e096"}.glyphicon-resize-small:before{content:"\e097"}.glyphicon-exclamation-sign:before{content:"\e101"}.glyphicon-gift:before{content:"\e102"}.glyphicon-leaf:before{content:"\e103"}.glyphicon-fire:before{content:"\e104"}.glyphicon-eye-open:before{content:"\e105"}.glyphicon-eye-close:before{content:"\e106"}.glyphicon-warning-sign:before{content:"\e107"}.glyphicon-plane:before{content:"\e108"}.glyphicon-calendar:before{content:"\e109"}.glyphicon-random:before{content:"\e110"}.glyphicon-comment:before{content:"\e111"}.glyphicon-magnet:before{content:"\e112"}.glyphicon-chevron-up:before{content:"\e113"}.glyphicon-chevron-down:before{content:"\e114"}.glyphicon-retweet:before{content:"\e115"}.glyphicon-shopping-cart:before{content:"\e116"}.glyphicon-folder-close:before{content:"\e117"}.glyphicon-folder-open:before{content:"\e118"}.glyphicon-resize-vertical:before{content:"\e119"}.glyphicon-resize-horizontal:before{content:"\e120"}.glyphicon-hdd:before{content:"\e121"}.glyphicon-bullhorn:before{content:"\e122"}.glyphicon-bell:before{content:"\e123"}.glyphicon-certificate:before{content:"\e124"}.glyphicon-thumbs-up:before{content:"\e125"}.glyphicon-thumbs-down:before{content:"\e126"}.glyphicon-hand-right:before{content:"\e127"}.glyphicon-hand-left:before{content:"\e128"}.glyphicon-hand-up:before{content:"\e129"}.glyphicon-hand-down:before{content:"\e130"}.glyphicon-circle-arrow-right:before{content:"\e131"}.glyphicon-circle-arrow-left:before{content:"\e132"}.glyphicon-circle-arrow-up:before{content:"\e133"}.glyphicon-circle-arrow-down:before{content:"\e134"}.glyphicon-globe:before{content:"\e135"}.glyphicon-wrench:before{content:"\e136"}.glyphicon-tasks:before{content:"\e137"}.glyphicon-filter:before{content:"\e138"}.glyphicon-briefcase:before{content:"\e139"}.glyphicon-fullscreen:before{content:"\e140"}.glyphicon-dashboard:before{content:"\e141"}.glyphicon-paperclip:before{content:"\e142"}.glyphicon-heart-empty:before{content:"\e143"}.glyphicon-link:before{content:"\e144"}.glyphicon-phone:before{content:"\e145"}.glyphicon-pushpin:before{content:"\e146"}.glyphicon-usd:before{content:"\e148"}.glyphicon-gbp:before{content:"\e149"}.glyphicon-sort:before{content:"\e150"}.glyphicon-sort-by-alphabet:before{content:"\e151"}.glyphicon-sort-by-alphabet-alt:before{content:"\e152"}.glyphicon-sort-by-order:before{content:"\e153"}.glyphicon-sort-by-order-alt:before{content:"\e154"}.glyphicon-sort-by-attributes:before{content:"\e155"}.glyphicon-sort-by-attributes-alt:before{content:"\e156"}.glyphicon-unchecked:before{content:"\e157"}.glyphicon-expand:before{content:"\e158"}.glyphicon-collapse-down:before{content:"\e159"}.glyphicon-collapse-up:before{content:"\e160"}.glyphicon-log-in:before{content:"\e161"}.glyphicon-flash:before{content:"\e162"}.glyphicon-log-out:before{content:"\e163"}.glyphicon-new-window:before{content:"\e164"}.glyphicon-record:before{content:"\e165"}.glyphicon-save:before{content:"\e166"}.glyphicon-open:before{content:"\e167"}.glyphicon-saved:before{content:"\e168"}.glyphicon-import:before{content:"\e169"}.glyphicon-export:before{content:"\e170"}.glyphicon-send:before{content:"\e171"}.glyphicon-floppy-disk:before{content:"\e172"}.glyphicon-floppy-saved:before{content:"\e173"}.glyphicon-floppy-remove:before{content:"\e174"}.glyphicon-floppy-save:before{content:"\e175"}.glyphicon-floppy-open:before{content:"\e176"}.glyphicon-credit-card:before{content:"\e177"}.glyphicon-transfer:before{content:"\e178"}.glyphicon-cutlery:before{content:"\e179"}.glyphicon-header:before{content:"\e180"}.glyphicon-compressed:before{content:"\e181"}.glyphicon-earphone:before{content:"\e182"}.glyphicon-phone-alt:before{content:"\e183"}.glyphicon-tower:before{content:"\e184"}.glyphicon-stats:before{content:"\e185"}.glyphicon-sd-video:before{content:"\e186"}.glyphicon-hd-video:before{content:"\e187"}.glyphicon-subtitles:before{content:"\e188"}.glyphicon-sound-stereo:before{content:"\e189"}.glyphicon-sound-dolby:before{content:"\e190"}.glyphicon-sound-5-1:before{content:"\e191"}.glyphicon-sound-6-1:before{content:"\e192"}.glyphicon-sound-7-1:before{content:"\e193"}.glyphicon-copyright-mark:before{content:"\e194"}.glyphicon-registration-mark:before{content:"\e195"}.glyphicon-cloud-download:before{content:"\e197"}.glyphicon-cloud-upload:before{content:"\e198"}.glyphicon-tree-conifer:before{content:"\e199"}.glyphicon-tree-deciduous:before{content:"\e200"}.glyphicon-cd:before{content:"\e201"}.glyphicon-save-file:before{content:"\e202"}.glyphicon-open-file:before{content:"\e203"}.glyphicon-level-up:before{content:"\e204"}.glyphicon-copy:before{content:"\e205"}.glyphicon-paste:before{content:"\e206"}.glyphicon-alert:before{content:"\e209"}.glyphicon-equalizer:before{content:"\e210"}.glyphicon-king:before{content:"\e211"}.glyphicon-queen:before{content:"\e212"}.glyphicon-pawn:before{content:"\e213"}.glyphicon-bishop:before{content:"\e214"}.glyphicon-knight:before{content:"\e215"}.glyphicon-baby-formula:before{content:"\e216"}.glyphicon-tent:before{content:"\26fa"}.glyphicon-blackboard:before{content:"\e218"}.glyphicon-bed:before{content:"\e219"}.glyphicon-apple:before{content:"\f8ff"}.glyphicon-erase:before{content:"\e221"}.glyphicon-hourglass:before{content:"\231b"}.glyphicon-lamp:before{content:"\e223"}.glyphicon-duplicate:before{content:"\e224"}.glyphicon-piggy-bank:before{content:"\e225"}.glyphicon-scissors:before{content:"\e226"}.glyphicon-bitcoin:before{content:"\e227"}.glyphicon-btc:before{content:"\e227"}.glyphicon-xbt:before{content:"\e227"}.glyphicon-yen:before{content:"\00a5"}.glyphicon-jpy:before{content:"\00a5"}.glyphicon-ruble:before{content:"\20bd"}.glyphicon-rub:before{content:"\20bd"}.glyphicon-scale:before{content:"\e230"}.glyphicon-ice-lolly:before{content:"\e231"}.glyphicon-ice-lolly-tasted:before{content:"\e232"}.glyphicon-education:before{content:"\e233"}.glyphicon-option-horizontal:before{content:"\e234"}.glyphicon-option-vertical:before{content:"\e235"}.glyphicon-menu-hamburger:before{content:"\e236"}.glyphicon-modal-window:before{content:"\e237"}.glyphicon-oil:before{content:"\e238"}.glyphicon-grain:before{content:"\e239"}.glyphicon-sunglasses:before{content:"\e240"}.glyphicon-text-size:before{content:"\e241"}.glyphicon-text-color:before{content:"\e242"}.glyphicon-text-background:before{content:"\e243"}.glyphicon-object-align-top:before{content:"\e244"}.glyphicon-object-align-bottom:before{content:"\e245"}.glyphicon-object-align-horizontal:before{content:"\e246"}.glyphicon-object-align-left:before{content:"\e247"}.glyphicon-object-align-vertical:before{content:"\e248"}.glyphicon-object-align-right:before{content:"\e249"}.glyphicon-triangle-right:before{content:"\e250"}.glyphicon-triangle-left:before{content:"\e251"}.glyphicon-triangle-bottom:before{content:"\e252"}.glyphicon-triangle-top:before{content:"\e253"}.glyphicon-console:before{content:"\e254"}.glyphicon-superscript:before{content:"\e255"}.glyphicon-subscript:before{content:"\e256"}.glyphicon-menu-left:before{content:"\e257"}.glyphicon-menu-right:before{content:"\e258"}.glyphicon-menu-down:before{content:"\e259"}.glyphicon-menu-up:before{content:"\e260"}*{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}:after,:before{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}html{font-size:10px;-webkit-tap-highlight-color:rgba(0,0,0,0)}body{font-family:"Helvetica Neue",Helvetica,Arial,sans-serif;font-size:14px;line-height:1.42857143;color:#333;background-color:#fff}button,input,select,textarea{font-family:inherit;font-size:inherit;line-height:inherit}a{color:#337ab7;text-decoration:none}a:focus,a:hover{color:#23527c;text-decoration:underline}a:focus{outline:thin dotted;outline:5px auto -webkit-focus-ring-color;outline-offset:-2px}figure{margin:0}img{vertical-align:middle}.carousel-inner>.item>a>img,.carousel-inner>.item>img,.img-responsive,.thumbnail a>img,.thumbnail>img{display:block;max-width:100%;height:auto}.img-rounded{border-radius:6px}.img-thumbnail{display:inline-block;max-width:100%;height:auto;padding:4px;line-height:1.42857143;background-color:#fff;border:1px solid #ddd;border-radius:4px;-webkit-transition:all .2s ease-in-out;-o-transition:all .2s ease-in-out;transition:all .2s ease-in-out}.img-circle{border-radius:50%}hr{margin-top:20px;margin-bottom:20px;border:0;border-top:1px solid #eee}.sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);border:0}.sr-only-focusable:active,.sr-only-focusable:focus{position:static;width:auto;height:auto;margin:0;overflow:visible;clip:auto}[role=button]{cursor:pointer}.h1,.h2,.h3,.h4,.h5,.h6,h1,h2,h3,h4,h5,h6{font-family:inherit;font-weight:500;line-height:1.1;color:inherit}.h1 .small,.h1 small,.h2 .small,.h2 small,.h3 .small,.h3 small,.h4 .small,.h4 small,.h5 .small,.h5 small,.h6 .small,.h6 small,h1 .small,h1 small,h2 .small,h2 small,h3 .small,h3 small,h4 .small,h4 small,h5 .small,h5 small,h6 .small,h6 small{font-weight:400;line-height:1;color:#777}.h1,.h2,.h3,h1,h2,h3{margin-top:20px;margin-bottom:10px}.h1 .small,.h1 small,.h2 .small,.h2 small,.h3 .small,.h3 small,h1 .small,h1 small,h2 .small,h2 small,h3 .small,h3 small{font-size:65%}.h4,.h5,.h6,h4,h5,h6{margin-top:10px;margin-bottom:10px}.h4 .small,.h4 small,.h5 .small,.h5 small,.h6 .small,.h6 small,h4 .small,h4 small,h5 .small,h5 small,h6 .small,h6 small{font-size:75%}.h1,h1{font-size:36px}.h2,h2{font-size:30px}.h3,h3{font-size:24px}.h4,h4{font-size:18px}.h5,h5{font-size:14px}.h6,h6{font-size:12px}p{margin:0 0 10px}.lead{margin-bottom:20px;font-size:16px;font-weight:300;line-height:1.4}@media (min-width:768px){.lead{font-size:21px}}.small,small{font-size:85%}.mark,mark{padding:.2em;background-color:#fcf8e3}.text-left{text-align:left}.text-right{text-align:right}.text-center{text-align:center}.text-justify{text-align:justify}.text-nowrap{white-space:nowrap}.text-lowercase{text-transform:lowercase}.text-uppercase{text-transform:uppercase}.text-capitalize{text-transform:capitalize}.text-muted{color:#777}.text-primary{color:#337ab7}a.text-primary:focus,a.text-primary:hover{color:#286090}.text-success{color:#3c763d}a.text-success:focus,a.text-success:hover{color:#2b542c}.text-info{color:#31708f}a.text-info:focus,a.text-info:hover{color:#245269}.text-warning{color:#8a6d3b}a.text-warning:focus,a.text-warning:hover{color:#66512c}.text-danger{color:#a94442}a.text-danger:focus,a.text-danger:hover{color:#843534}.bg-primary{color:#fff;background-color:#337ab7}a.bg-primary:focus,a.bg-primary:hover{background-color:#286090}.bg-success{background-color:#dff0d8}a.bg-success:focus,a.bg-success:hover{background-color:#c1e2b3}.bg-info{background-color:#d9edf7}a.bg-info:focus,a.bg-info:hover{background-color:#afd9ee}.bg-warning{background-color:#fcf8e3}a.bg-warning:focus,a.bg-warning:hover{background-color:#f7ecb5}.bg-danger{background-color:#f2dede}a.bg-danger:focus,a.bg-danger:hover{background-color:#e4b9b9}.page-header{padding-bottom:9px;margin:40px 0 20px;border-bottom:1px solid #eee}ol,ul{margin-top:0;margin-bottom:10px}ol ol,ol ul,ul ol,ul ul{margin-bottom:0}.list-unstyled{padding-left:0;list-style:none}.list-inline{padding-left:0;margin-left:-5px;list-style:none}.list-inline>li{display:inline-block;padding-right:5px;padding-left:5px}dl{margin-top:0;margin-bottom:20px}dd,dt{line-height:1.42857143}dt{font-weight:700}dd{margin-left:0}@media (min-width:768px){.dl-horizontal dt{float:left;width:160px;overflow:hidden;clear:left;text-align:right;text-overflow:ellipsis;white-space:nowrap}.dl-horizontal dd{margin-left:180px}}abbr[data-original-title],abbr[title]{cursor:help;border-bottom:1px dotted #777}.initialism{font-size:90%;text-transform:uppercase}blockquote{padding:10px 20px;margin:0 0 20px;font-size:17.5px;border-left:5px solid #eee}blockquote ol:last-child,blockquote p:last-child,blockquote ul:last-child{margin-bottom:0}blockquote .small,blockquote footer,blockquote small{display:block;font-size:80%;line-height:1.42857143;color:#777}blockquote .small:before,blockquote footer:before,blockquote small:before{content:'\2014 \00A0'}.blockquote-reverse,blockquote.pull-right{padding-right:15px;padding-left:0;text-align:right;border-right:5px solid #eee;border-left:0}.blockquote-reverse .small:before,.blockquote-reverse footer:before,.blockquote-reverse small:before,blockquote.pull-right .small:before,blockquote.pull-right footer:before,blockquote.pull-right small:before{content:''}.blockquote-reverse .small:after,.blockquote-reverse footer:after,.blockquote-reverse small:after,blockquote.pull-right .small:after,blockquote.pull-right footer:after,blockquote.pull-right small:after{content:'\00A0 \2014'}address{margin-bottom:20px;font-style:normal;line-height:1.42857143}code,kbd,pre,samp{font-family:Menlo,Monaco,Consolas,"Courier New",monospace}code{padding:2px 4px;font-size:90%;color:#c7254e;background-color:#f9f2f4;border-radius:4px}kbd{padding:2px 4px;font-size:90%;color:#fff;background-color:#333;border-radius:3px;-webkit-box-shadow:inset 0 -1px 0 rgba(0,0,0,.25);box-shadow:inset 0 -1px 0 rgba(0,0,0,.25)}kbd kbd{padding:0;font-size:100%;font-weight:700;-webkit-box-shadow:none;box-shadow:none}pre{display:block;padding:9.5px;margin:0 0 10px;font-size:13px;line-height:1.42857143;color:#333;word-break:break-all;word-wrap:break-word;background-color:#f5f5f5;border:1px solid #ccc;border-radius:4px}pre code{padding:0;font-size:inherit;color:inherit;white-space:pre-wrap;background-color:transparent;border-radius:0}.pre-scrollable{max-height:340px;overflow-y:scroll}.container{padding-right:15px;padding-left:15px;margin-right:auto;margin-left:auto}@media (min-width:768px){.container{width:750px}}@media (min-width:992px){.container{width:970px}}@media (min-width:1200px){.container{width:1170px}}.container-fluid{padding-right:15px;padding-left:15px;margin-right:auto;margin-left:auto}.row{margin-right:-15px;margin-left:-15px}.col-lg-1,.col-lg-10,.col-lg-11,.col-lg-12,.col-lg-2,.col-lg-3,.col-lg-4,.col-lg-5,.col-lg-6,.col-lg-7,.col-lg-8,.col-lg-9,.col-md-1,.col-md-10,.col-md-11,.col-md-12,.col-md-2,.col-md-3,.col-md-4,.col-md-5,.col-md-6,.col-md-7,.col-md-8,.col-md-9,.col-sm-1,.col-sm-10,.col-sm-11,.col-sm-12,.col-sm-2,.col-sm-3,.col-sm-4,.col-sm-5,.col-sm-6,.col-sm-7,.col-sm-8,.col-sm-9,.col-xs-1,.col-xs-10,.col-xs-11,.col-xs-12,.col-xs-2,.col-xs-3,.col-xs-4,.col-xs-5,.col-xs-6,.col-xs-7,.col-xs-8,.col-xs-9{position:relative;min-height:1px;padding-right:15px;padding-left:15px}.col-xs-1,.col-xs-10,.col-xs-11,.col-xs-12,.col-xs-2,.col-xs-3,.col-xs-4,.col-xs-5,.col-xs-6,.col-xs-7,.col-xs-8,.col-xs-9{float:left}.col-xs-12{width:100%}.col-xs-11{width:91.66666667%}.col-xs-10{width:83.33333333%}.col-xs-9{width:75%}.col-xs-8{width:66.66666667%}.col-xs-7{width:58.33333333%}.col-xs-6{width:50%}.col-xs-5{width:41.66666667%}.col-xs-4{width:33.33333333%}.col-xs-3{width:25%}.col-xs-2{width:16.66666667%}.col-xs-1{width:8.33333333%}.col-xs-pull-12{right:100%}.col-xs-pull-11{right:91.66666667%}.col-xs-pull-10{right:83.33333333%}.col-xs-pull-9{right:75%}.col-xs-pull-8{right:66.66666667%}.col-xs-pull-7{right:58.33333333%}.col-xs-pull-6{right:50%}.col-xs-pull-5{right:41.66666667%}.col-xs-pull-4{right:33.33333333%}.col-xs-pull-3{right:25%}.col-xs-pull-2{right:16.66666667%}.col-xs-pull-1{right:8.33333333%}.col-xs-pull-0{right:auto}.col-xs-push-12{left:100%}.col-xs-push-11{left:91.66666667%}.col-xs-push-10{left:83.33333333%}.col-xs-push-9{left:75%}.col-xs-push-8{left:66.66666667%}.col-xs-push-7{left:58.33333333%}.col-xs-push-6{left:50%}.col-xs-push-5{left:41.66666667%}.col-xs-push-4{left:33.33333333%}.col-xs-push-3{left:25%}.col-xs-push-2{left:16.66666667%}.col-xs-push-1{left:8.33333333%}.col-xs-push-0{left:auto}.col-xs-offset-12{margin-left:100%}.col-xs-offset-11{margin-left:91.66666667%}.col-xs-offset-10{margin-left:83.33333333%}.col-xs-offset-9{margin-left:75%}.col-xs-offset-8{margin-left:66.66666667%}.col-xs-offset-7{margin-left:58.33333333%}.col-xs-offset-6{margin-left:50%}.col-xs-offset-5{margin-left:41.66666667%}.col-xs-offset-4{margin-left:33.33333333%}.col-xs-offset-3{margin-left:25%}.col-xs-offset-2{margin-left:16.66666667%}.col-xs-offset-1{margin-left:8.33333333%}.col-xs-offset-0{margin-left:0}@media (min-width:768px){.col-sm-1,.col-sm-10,.col-sm-11,.col-sm-12,.col-sm-2,.col-sm-3,.col-sm-4,.col-sm-5,.col-sm-6,.col-sm-7,.col-sm-8,.col-sm-9{float:left}.col-sm-12{width:100%}.col-sm-11{width:91.66666667%}.col-sm-10{width:83.33333333%}.col-sm-9{width:75%}.col-sm-8{width:66.66666667%}.col-sm-7{width:58.33333333%}.col-sm-6{width:50%}.col-sm-5{width:41.66666667%}.col-sm-4{width:33.33333333%}.col-sm-3{width:25%}.col-sm-2{width:16.66666667%}.col-sm-1{width:8.33333333%}.col-sm-pull-12{right:100%}.col-sm-pull-11{right:91.66666667%}.col-sm-pull-10{right:83.33333333%}.col-sm-pull-9{right:75%}.col-sm-pull-8{right:66.66666667%}.col-sm-pull-7{right:58.33333333%}.col-sm-pull-6{right:50%}.col-sm-pull-5{right:41.66666667%}.col-sm-pull-4{right:33.33333333%}.col-sm-pull-3{right:25%}.col-sm-pull-2{right:16.66666667%}.col-sm-pull-1{right:8.33333333%}.col-sm-pull-0{right:auto}.col-sm-push-12{left:100%}.col-sm-push-11{left:91.66666667%}.col-sm-push-10{left:83.33333333%}.col-sm-push-9{left:75%}.col-sm-push-8{left:66.66666667%}.col-sm-push-7{left:58.33333333%}.col-sm-push-6{left:50%}.col-sm-push-5{left:41.66666667%}.col-sm-push-4{left:33.33333333%}.col-sm-push-3{left:25%}.col-sm-push-2{left:16.66666667%}.col-sm-push-1{left:8.33333333%}.col-sm-push-0{left:auto}.col-sm-offset-12{margin-left:100%}.col-sm-offset-11{margin-left:91.66666667%}.col-sm-offset-10{margin-left:83.33333333%}.col-sm-offset-9{margin-left:75%}.col-sm-offset-8{margin-left:66.66666667%}.col-sm-offset-7{margin-left:58.33333333%}.col-sm-offset-6{margin-left:50%}.col-sm-offset-5{margin-left:41.66666667%}.col-sm-offset-4{margin-left:33.33333333%}.col-sm-offset-3{margin-left:25%}.col-sm-offset-2{margin-left:16.66666667%}.col-sm-offset-1{margin-left:8.33333333%}.col-sm-offset-0{margin-left:0}}@media (min-width:992px){.col-md-1,.col-md-10,.col-md-11,.col-md-12,.col-md-2,.col-md-3,.col-md-4,.col-md-5,.col-md-6,.col-md-7,.col-md-8,.col-md-9{float:left}.col-md-12{width:100%}.col-md-11{width:91.66666667%}.col-md-10{width:83.33333333%}.col-md-9{width:75%}.col-md-8{width:66.66666667%}.col-md-7{width:58.33333333%}.col-md-6{width:50%}.col-md-5{width:41.66666667%}.col-md-4{width:33.33333333%}.col-md-3{width:25%}.col-md-2{width:16.66666667%}.col-md-1{width:8.33333333%}.col-md-pull-12{right:100%}.col-md-pull-11{right:91.66666667%}.col-md-pull-10{right:83.33333333%}.col-md-pull-9{right:75%}.col-md-pull-8{right:66.66666667%}.col-md-pull-7{right:58.33333333%}.col-md-pull-6{right:50%}.col-md-pull-5{right:41.66666667%}.col-md-pull-4{right:33.33333333%}.col-md-pull-3{right:25%}.col-md-pull-2{right:16.66666667%}.col-md-pull-1{right:8.33333333%}.col-md-pull-0{right:auto}.col-md-push-12{left:100%}.col-md-push-11{left:91.66666667%}.col-md-push-10{left:83.33333333%}.col-md-push-9{left:75%}.col-md-push-8{left:66.66666667%}.col-md-push-7{left:58.33333333%}.col-md-push-6{left:50%}.col-md-push-5{left:41.66666667%}.col-md-push-4{left:33.33333333%}.col-md-push-3{left:25%}.col-md-push-2{left:16.66666667%}.col-md-push-1{left:8.33333333%}.col-md-push-0{left:auto}.col-md-offset-12{margin-left:100%}.col-md-offset-11{margin-left:91.66666667%}.col-md-offset-10{margin-left:83.33333333%}.col-md-offset-9{margin-left:75%}.col-md-offset-8{margin-left:66.66666667%}.col-md-offset-7{margin-left:58.33333333%}.col-md-offset-6{margin-left:50%}.col-md-offset-5{margin-left:41.66666667%}.col-md-offset-4{margin-left:33.33333333%}.col-md-offset-3{margin-left:25%}.col-md-offset-2{margin-left:16.66666667%}.col-md-offset-1{margin-left:8.33333333%}.col-md-offset-0{margin-left:0}}@media (min-width:1200px){.col-lg-1,.col-lg-10,.col-lg-11,.col-lg-12,.col-lg-2,.col-lg-3,.col-lg-4,.col-lg-5,.col-lg-6,.col-lg-7,.col-lg-8,.col-lg-9{float:left}.col-lg-12{width:100%}.col-lg-11{width:91.66666667%}.col-lg-10{width:83.33333333%}.col-lg-9{width:75%}.col-lg-8{width:66.66666667%}.col-lg-7{width:58.33333333%}.col-lg-6{width:50%}.col-lg-5{width:41.66666667%}.col-lg-4{width:33.33333333%}.col-lg-3{width:25%}.col-lg-2{width:16.66666667%}.col-lg-1{width:8.33333333%}.col-lg-pull-12{right:100%}.col-lg-pull-11{right:91.66666667%}.col-lg-pull-10{right:83.33333333%}.col-lg-pull-9{right:75%}.col-lg-pull-8{right:66.66666667%}.col-lg-pull-7{right:58.33333333%}.col-lg-pull-6{right:50%}.col-lg-pull-5{right:41.66666667%}.col-lg-pull-4{right:33.33333333%}.col-lg-pull-3{right:25%}.col-lg-pull-2{right:16.66666667%}.col-lg-pull-1{right:8.33333333%}.col-lg-pull-0{right:auto}.col-lg-push-12{left:100%}.col-lg-push-11{left:91.66666667%}.col-lg-push-10{left:83.33333333%}.col-lg-push-9{left:75%}.col-lg-push-8{left:66.66666667%}.col-lg-push-7{left:58.33333333%}.col-lg-push-6{left:50%}.col-lg-push-5{left:41.66666667%}.col-lg-push-4{left:33.33333333%}.col-lg-push-3{left:25%}.col-lg-push-2{left:16.66666667%}.col-lg-push-1{left:8.33333333%}.col-lg-push-0{left:auto}.col-lg-offset-12{margin-left:100%}.col-lg-offset-11{margin-left:91.66666667%}.col-lg-offset-10{margin-left:83.33333333%}.col-lg-offset-9{margin-left:75%}.col-lg-offset-8{margin-left:66.66666667%}.col-lg-offset-7{margin-left:58.33333333%}.col-lg-offset-6{margin-left:50%}.col-lg-offset-5{margin-left:41.66666667%}.col-lg-offset-4{margin-left:33.33333333%}.col-lg-offset-3{margin-left:25%}.col-lg-offset-2{margin-left:16.66666667%}.col-lg-offset-1{margin-left:8.33333333%}.col-lg-offset-0{margin-left:0}}table{background-color:transparent}caption{padding-top:8px;padding-bottom:8px;color:#777;text-align:left}th{text-align:left}.table{width:100%;max-width:100%;margin-bottom:20px}.table>tbody>tr>td,.table>tbody>tr>th,.table>tfoot>tr>td,.table>tfoot>tr>th,.table>thead>tr>td,.table>thead>tr>th{padding:8px;line-height:1.42857143;vertical-align:top;border-top:1px solid #ddd}.table>thead>tr>th{vertical-align:bottom;border-bottom:2px solid #ddd}.table>caption+thead>tr:first-child>td,.table>caption+thead>tr:first-child>th,.table>colgroup+thead>tr:first-child>td,.table>colgroup+thead>tr:first-child>th,.table>thead:first-child>tr:first-child>td,.table>thead:first-child>tr:first-child>th{border-top:0}.table>tbody+tbody{border-top:2px solid #ddd}.table .table{background-color:#fff}.table-condensed>tbody>tr>td,.table-condensed>tbody>tr>th,.table-condensed>tfoot>tr>td,.table-condensed>tfoot>tr>th,.table-condensed>thead>tr>td,.table-condensed>thead>tr>th{padding:5px}.table-bordered{border:1px solid #ddd}.table-bordered>tbody>tr>td,.table-bordered>tbody>tr>th,.table-bordered>tfoot>tr>td,.table-bordered>tfoot>tr>th,.table-bordered>thead>tr>td,.table-bordered>thead>tr>th{border:1px solid #ddd}.table-bordered>thead>tr>td,.table-bordered>thead>tr>th{border-bottom-width:2px}.table-striped>tbody>tr:nth-of-type(odd){background-color:#f9f9f9}.table-hover>tbody>tr:hover{background-color:#f5f5f5}table col[class*=col-]{position:static;display:table-column;float:none}table td[class*=col-],table th[class*=col-]{position:static;display:table-cell;float:none}.table>tbody>tr.active>td,.table>tbody>tr.active>th,.table>tbody>tr>td.active,.table>tbody>tr>th.active,.table>tfoot>tr.active>td,.table>tfoot>tr.active>th,.table>tfoot>tr>td.active,.table>tfoot>tr>th.active,.table>thead>tr.active>td,.table>thead>tr.active>th,.table>thead>tr>td.active,.table>thead>tr>th.active{background-color:#f5f5f5}.table-hover>tbody>tr.active:hover>td,.table-hover>tbody>tr.active:hover>th,.table-hover>tbody>tr:hover>.active,.table-hover>tbody>tr>td.active:hover,.table-hover>tbody>tr>th.active:hover{background-color:#e8e8e8}.table>tbody>tr.success>td,.table>tbody>tr.success>th,.table>tbody>tr>td.success,.table>tbody>tr>th.success,.table>tfoot>tr.success>td,.table>tfoot>tr.success>th,.table>tfoot>tr>td.success,.table>tfoot>tr>th.success,.table>thead>tr.success>td,.table>thead>tr.success>th,.table>thead>tr>td.success,.table>thead>tr>th.success{background-color:#dff0d8}.table-hover>tbody>tr.success:hover>td,.table-hover>tbody>tr.success:hover>th,.table-hover>tbody>tr:hover>.success,.table-hover>tbody>tr>td.success:hover,.table-hover>tbody>tr>th.success:hover{background-color:#d0e9c6}.table>tbody>tr.info>td,.table>tbody>tr.info>th,.table>tbody>tr>td.info,.table>tbody>tr>th.info,.table>tfoot>tr.info>td,.table>tfoot>tr.info>th,.table>tfoot>tr>td.info,.table>tfoot>tr>th.info,.table>thead>tr.info>td,.table>thead>tr.info>th,.table>thead>tr>td.info,.table>thead>tr>th.info{background-color:#d9edf7}.table-hover>tbody>tr.info:hover>td,.table-hover>tbody>tr.info:hover>th,.table-hover>tbody>tr:hover>.info,.table-hover>tbody>tr>td.info:hover,.table-hover>tbody>tr>th.info:hover{background-color:#c4e3f3}.table>tbody>tr.warning>td,.table>tbody>tr.warning>th,.table>tbody>tr>td.warning,.table>tbody>tr>th.warning,.table>tfoot>tr.warning>td,.table>tfoot>tr.warning>th,.table>tfoot>tr>td.warning,.table>tfoot>tr>th.warning,.table>thead>tr.warning>td,.table>thead>tr.warning>th,.table>thead>tr>td.warning,.table>thead>tr>th.warning{background-color:#fcf8e3}.table-hover>tbody>tr.warning:hover>td,.table-hover>tbody>tr.warning:hover>th,.table-hover>tbody>tr:hover>.warning,.table-hover>tbody>tr>td.warning:hover,.table-hover>tbody>tr>th.warning:hover{background-color:#faf2cc}.table>tbody>tr.danger>td,.table>tbody>tr.danger>th,.table>tbody>tr>td.danger,.table>tbody>tr>th.danger,.table>tfoot>tr.danger>td,.table>tfoot>tr.danger>th,.table>tfoot>tr>td.danger,.table>tfoot>tr>th.danger,.table>thead>tr.danger>td,.table>thead>tr.danger>th,.table>thead>tr>td.danger,.table>thead>tr>th.danger{background-color:#f2dede}.table-hover>tbody>tr.danger:hover>td,.table-hover>tbody>tr.danger:hover>th,.table-hover>tbody>tr:hover>.danger,.table-hover>tbody>tr>td.danger:hover,.table-hover>tbody>tr>th.danger:hover{background-color:#ebcccc}.table-responsive{min-height:.01%;overflow-x:auto}@media screen and (max-width:767px){.table-responsive{width:100%;margin-bottom:15px;overflow-y:hidden;-ms-overflow-style:-ms-autohiding-scrollbar;border:1px solid #ddd}.table-responsive>.table{margin-bottom:0}.table-responsive>.table>tbody>tr>td,.table-responsive>.table>tbody>tr>th,.table-responsive>.table>tfoot>tr>td,.table-responsive>.table>tfoot>tr>th,.table-responsive>.table>thead>tr>td,.table-responsive>.table>thead>tr>th{white-space:nowrap}.table-responsive>.table-bordered{border:0}.table-responsive>.table-bordered>tbody>tr>td:first-child,.table-responsive>.table-bordered>tbody>tr>th:first-child,.table-responsive>.table-bordered>tfoot>tr>td:first-child,.table-responsive>.table-bordered>tfoot>tr>th:first-child,.table-responsive>.table-bordered>thead>tr>td:first-child,.table-responsive>.table-bordered>thead>tr>th:first-child{border-left:0}.table-responsive>.table-bordered>tbody>tr>td:last-child,.table-responsive>.table-bordered>tbody>tr>th:last-child,.table-responsive>.table-bordered>tfoot>tr>td:last-child,.table-responsive>.table-bordered>tfoot>tr>th:last-child,.table-responsive>.table-bordered>thead>tr>td:last-child,.table-responsive>.table-bordered>thead>tr>th:last-child{border-right:0}.table-responsive>.table-bordered>tbody>tr:last-child>td,.table-responsive>.table-bordered>tbody>tr:last-child>th,.table-responsive>.table-bordered>tfoot>tr:last-child>td,.table-responsive>.table-bordered>tfoot>tr:last-child>th{border-bottom:0}}fieldset{min-width:0;padding:0;margin:0;border:0}legend{display:block;width:100%;padding:0;margin-bottom:20px;font-size:21px;line-height:inherit;color:#333;border:0;border-bottom:1px solid #e5e5e5}label{display:inline-block;max-width:100%;margin-bottom:5px;font-weight:700}input[type=search]{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}input[type=checkbox],input[type=radio]{margin:4px 0 0;margin-top:1px\9;line-height:normal}input[type=file]{display:block}input[type=range]{display:block;width:100%}select[multiple],select[size]{height:auto}input[type=file]:focus,input[type=checkbox]:focus,input[type=radio]:focus{outline:thin dotted;outline:5px auto -webkit-focus-ring-color;outline-offset:-2px}output{display:block;padding-top:7px;font-size:14px;line-height:1.42857143;color:#555}.form-control{display:block;width:100%;height:34px;padding:6px 12px;font-size:14px;line-height:1.42857143;color:#555;background-color:#fff;background-image:none;border:1px solid #ccc;border-radius:4px;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075);box-shadow:inset 0 1px 1px rgba(0,0,0,.075);-webkit-transition:border-color ease-in-out .15s,-webkit-box-shadow ease-in-out .15s;-o-transition:border-color ease-in-out .15s,box-shadow ease-in-out .15s;transition:border-color ease-in-out .15s,box-shadow ease-in-out .15s}.form-control:focus{border-color:#66afe9;outline:0;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 8px rgba(102,175,233,.6);box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 8px rgba(102,175,233,.6)}.form-control::-moz-placeholder{color:#999;opacity:1}.form-control:-ms-input-placeholder{color:#999}.form-control::-webkit-input-placeholder{color:#999}.form-control[disabled],.form-control[readonly],fieldset[disabled] .form-control{background-color:#eee;opacity:1}.form-control[disabled],fieldset[disabled] .form-control{cursor:not-allowed}textarea.form-control{height:auto}input[type=search]{-webkit-appearance:none}@media screen and (-webkit-min-device-pixel-ratio:0){input[type=date].form-control,input[type=time].form-control,input[type=datetime-local].form-control,input[type=month].form-control{line-height:34px}.input-group-sm input[type=date],.input-group-sm input[type=time],.input-group-sm input[type=datetime-local],.input-group-sm input[type=month],input[type=date].input-sm,input[type=time].input-sm,input[type=datetime-local].input-sm,input[type=month].input-sm{line-height:30px}.input-group-lg input[type=date],.input-group-lg input[type=time],.input-group-lg input[type=datetime-local],.input-group-lg input[type=month],input[type=date].input-lg,input[type=time].input-lg,input[type=datetime-local].input-lg,input[type=month].input-lg{line-height:46px}}.form-group{margin-bottom:15px}.checkbox,.radio{position:relative;display:block;margin-top:10px;margin-bottom:10px}.checkbox label,.radio label{min-height:20px;padding-left:20px;margin-bottom:0;font-weight:400;cursor:pointer}.checkbox input[type=checkbox],.checkbox-inline input[type=checkbox],.radio input[type=radio],.radio-inline input[type=radio]{position:absolute;margin-top:4px\9;margin-left:-20px}.checkbox+.checkbox,.radio+.radio{margin-top:-5px}.checkbox-inline,.radio-inline{position:relative;display:inline-block;padding-left:20px;margin-bottom:0;font-weight:400;vertical-align:middle;cursor:pointer}.checkbox-inline+.checkbox-inline,.radio-inline+.radio-inline{margin-top:0;margin-left:10px}fieldset[disabled] input[type=checkbox],fieldset[disabled] input[type=radio],input[type=checkbox].disabled,input[type=checkbox][disabled],input[type=radio].disabled,input[type=radio][disabled]{cursor:not-allowed}.checkbox-inline.disabled,.radio-inline.disabled,fieldset[disabled] .checkbox-inline,fieldset[disabled] .radio-inline{cursor:not-allowed}.checkbox.disabled label,.radio.disabled label,fieldset[disabled] .checkbox label,fieldset[disabled] .radio label{cursor:not-allowed}.form-control-static{min-height:34px;padding-top:7px;padding-bottom:7px;margin-bottom:0}.form-control-static.input-lg,.form-control-static.input-sm{padding-right:0;padding-left:0}.input-sm{height:30px;padding:5px 10px;font-size:12px;line-height:1.5;border-radius:3px}select.input-sm{height:30px;line-height:30px}select[multiple].input-sm,textarea.input-sm{height:auto}.form-group-sm .form-control{height:30px;padding:5px 10px;font-size:12px;line-height:1.5;border-radius:3px}.form-group-sm select.form-control{height:30px;line-height:30px}.form-group-sm select[multiple].form-control,.form-group-sm textarea.form-control{height:auto}.form-group-sm .form-control-static{height:30px;min-height:32px;padding:6px 10px;font-size:12px;line-height:1.5}.input-lg{height:46px;padding:10px 16px;font-size:18px;line-height:1.3333333;border-radius:6px}select.input-lg{height:46px;line-height:46px}select[multiple].input-lg,textarea.input-lg{height:auto}.form-group-lg .form-control{height:46px;padding:10px 16px;font-size:18px;line-height:1.3333333;border-radius:6px}.form-group-lg select.form-control{height:46px;line-height:46px}.form-group-lg select[multiple].form-control,.form-group-lg textarea.form-control{height:auto}.form-group-lg .form-control-static{height:46px;min-height:38px;padding:11px 16px;font-size:18px;line-height:1.3333333}.has-feedback{position:relative}.has-feedback .form-control{padding-right:42.5px}.form-control-feedback{position:absolute;top:0;right:0;z-index:2;display:block;width:34px;height:34px;line-height:34px;text-align:center;pointer-events:none}.form-group-lg .form-control+.form-control-feedback,.input-group-lg+.form-control-feedback,.input-lg+.form-control-feedback{width:46px;height:46px;line-height:46px}.form-group-sm .form-control+.form-control-feedback,.input-group-sm+.form-control-feedback,.input-sm+.form-control-feedback{width:30px;height:30px;line-height:30px}.has-success .checkbox,.has-success .checkbox-inline,.has-success .control-label,.has-success .help-block,.has-success .radio,.has-success .radio-inline,.has-success.checkbox label,.has-success.checkbox-inline label,.has-success.radio label,.has-success.radio-inline label{color:#3c763d}.has-success .form-control{border-color:#3c763d;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075);box-shadow:inset 0 1px 1px rgba(0,0,0,.075)}.has-success .form-control:focus{border-color:#2b542c;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 6px #67b168;box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 6px #67b168}.has-success .input-group-addon{color:#3c763d;background-color:#dff0d8;border-color:#3c763d}.has-success .form-control-feedback{color:#3c763d}.has-warning .checkbox,.has-warning .checkbox-inline,.has-warning .control-label,.has-warning .help-block,.has-warning .radio,.has-warning .radio-inline,.has-warning.checkbox label,.has-warning.checkbox-inline label,.has-warning.radio label,.has-warning.radio-inline label{color:#8a6d3b}.has-warning .form-control{border-color:#8a6d3b;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075);box-shadow:inset 0 1px 1px rgba(0,0,0,.075)}.has-warning .form-control:focus{border-color:#66512c;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 6px #c0a16b;box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 6px #c0a16b}.has-warning .input-group-addon{color:#8a6d3b;background-color:#fcf8e3;border-color:#8a6d3b}.has-warning .form-control-feedback{color:#8a6d3b}.has-error .checkbox,.has-error .checkbox-inline,.has-error .control-label,.has-error .help-block,.has-error .radio,.has-error .radio-inline,.has-error.checkbox label,.has-error.checkbox-inline label,.has-error.radio label,.has-error.radio-inline label{color:#a94442}.has-error .form-control{border-color:#a94442;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075);box-shadow:inset 0 1px 1px rgba(0,0,0,.075)}.has-error .form-control:focus{border-color:#843534;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 6px #ce8483;box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 6px #ce8483}.has-error .input-group-addon{color:#a94442;background-color:#f2dede;border-color:#a94442}.has-error .form-control-feedback{color:#a94442}.has-feedback label~.form-control-feedback{top:25px}.has-feedback label.sr-only~.form-control-feedback{top:0}.help-block{display:block;margin-top:5px;margin-bottom:10px;color:#737373}@media (min-width:768px){.form-inline .form-group{display:inline-block;margin-bottom:0;vertical-align:middle}.form-inline .form-control{display:inline-block;width:auto;vertical-align:middle}.form-inline .form-control-static{display:inline-block}.form-inline .input-group{display:inline-table;vertical-align:middle}.form-inline .input-group .form-control,.form-inline .input-group .input-group-addon,.form-inline .input-group .input-group-btn{width:auto}.form-inline .input-group>.form-control{width:100%}.form-inline .control-label{margin-bottom:0;vertical-align:middle}.form-inline .checkbox,.form-inline .radio{display:inline-block;margin-top:0;margin-bottom:0;vertical-align:middle}.form-inline .checkbox label,.form-inline .radio label{padding-left:0}.form-inline .checkbox input[type=checkbox],.form-inline .radio input[type=radio]{position:relative;margin-left:0}.form-inline .has-feedback .form-control-feedback{top:0}}.form-horizontal .checkbox,.form-horizontal .checkbox-inline,.form-horizontal .radio,.form-horizontal .radio-inline{padding-top:7px;margin-top:0;margin-bottom:0}.form-horizontal .checkbox,.form-horizontal .radio{min-height:27px}.form-horizontal .form-group{margin-right:-15px;margin-left:-15px}@media (min-width:768px){.form-horizontal .control-label{padding-top:7px;margin-bottom:0;text-align:right}}.form-horizontal .has-feedback .form-control-feedback{right:15px}@media (min-width:768px){.form-horizontal .form-group-lg .control-label{padding-top:14.33px;font-size:18px}}@media (min-width:768px){.form-horizontal .form-group-sm .control-label{padding-top:6px;font-size:12px}}.btn{display:inline-block;padding:6px 12px;margin-bottom:0;font-size:14px;font-weight:400;line-height:1.42857143;text-align:center;white-space:nowrap;vertical-align:middle;-ms-touch-action:manipulation;touch-action:manipulation;cursor:pointer;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;background-image:none;border:1px solid transparent;border-radius:4px}.btn.active.focus,.btn.active:focus,.btn.focus,.btn:active.focus,.btn:active:focus,.btn:focus{outline:thin dotted;outline:5px auto -webkit-focus-ring-color;outline-offset:-2px}.btn.focus,.btn:focus,.btn:hover{color:#333;text-decoration:none}.btn.active,.btn:active{background-image:none;outline:0;-webkit-box-shadow:inset 0 3px 5px rgba(0,0,0,.125);box-shadow:inset 0 3px 5px rgba(0,0,0,.125)}.btn.disabled,.btn[disabled],fieldset[disabled] .btn{cursor:not-allowed;filter:alpha(opacity=65);-webkit-box-shadow:none;box-shadow:none;opacity:.65}a.btn.disabled,fieldset[disabled] a.btn{pointer-events:none}.btn-default{color:#333;background-color:#fff;border-color:#ccc}.btn-default.focus,.btn-default:focus{color:#333;background-color:#e6e6e6;border-color:#8c8c8c}.btn-default:hover{color:#333;background-color:#e6e6e6;border-color:#adadad}.btn-default.active,.btn-default:active,.open>.dropdown-toggle.btn-default{color:#333;background-color:#e6e6e6;border-color:#adadad}.btn-default.active.focus,.btn-default.active:focus,.btn-default.active:hover,.btn-default:active.focus,.btn-default:active:focus,.btn-default:active:hover,.open>.dropdown-toggle.btn-default.focus,.open>.dropdown-toggle.btn-default:focus,.open>.dropdown-toggle.btn-default:hover{color:#333;background-color:#d4d4d4;border-color:#8c8c8c}.btn-default.active,.btn-default:active,.open>.dropdown-toggle.btn-default{background-image:none}.btn-default.disabled,.btn-default.disabled.active,.btn-default.disabled.focus,.btn-default.disabled:active,.btn-default.disabled:focus,.btn-default.disabled:hover,.btn-default[disabled],.btn-default[disabled].active,.btn-default[disabled].focus,.btn-default[disabled]:active,.btn-default[disabled]:focus,.btn-default[disabled]:hover,fieldset[disabled] .btn-default,fieldset[disabled] .btn-default.active,fieldset[disabled] .btn-default.focus,fieldset[disabled] .btn-default:active,fieldset[disabled] .btn-default:focus,fieldset[disabled] .btn-default:hover{background-color:#fff;border-color:#ccc}.btn-default .badge{color:#fff;background-color:#333}.btn-primary{color:#fff;background-color:#337ab7;border-color:#2e6da4}.btn-primary.focus,.btn-primary:focus{color:#fff;background-color:#286090;border-color:#122b40}.btn-primary:hover{color:#fff;background-color:#286090;border-color:#204d74}.btn-primary.active,.btn-primary:active,.open>.dropdown-toggle.btn-primary{color:#fff;background-color:#286090;border-color:#204d74}.btn-primary.active.focus,.btn-primary.active:focus,.btn-primary.active:hover,.btn-primary:active.focus,.btn-primary:active:focus,.btn-primary:active:hover,.open>.dropdown-toggle.btn-primary.focus,.open>.dropdown-toggle.btn-primary:focus,.open>.dropdown-toggle.btn-primary:hover{color:#fff;background-color:#204d74;border-color:#122b40}.btn-primary.active,.btn-primary:active,.open>.dropdown-toggle.btn-primary{background-image:none}.btn-primary.disabled,.btn-primary.disabled.active,.btn-primary.disabled.focus,.btn-primary.disabled:active,.btn-primary.disabled:focus,.btn-primary.disabled:hover,.btn-primary[disabled],.btn-primary[disabled].active,.btn-primary[disabled].focus,.btn-primary[disabled]:active,.btn-primary[disabled]:focus,.btn-primary[disabled]:hover,fieldset[disabled] .btn-primary,fieldset[disabled] .btn-primary.active,fieldset[disabled] .btn-primary.focus,fieldset[disabled] .btn-primary:active,fieldset[disabled] .btn-primary:focus,fieldset[disabled] .btn-primary:hover{background-color:#337ab7;border-color:#2e6da4}.btn-primary .badge{color:#337ab7;background-color:#fff}.btn-success{color:#fff;background-color:#5cb85c;border-color:#4cae4c}.btn-success.focus,.btn-success:focus{color:#fff;background-color:#449d44;border-color:#255625}.btn-success:hover{color:#fff;background-color:#449d44;border-color:#398439}.btn-success.active,.btn-success:active,.open>.dropdown-toggle.btn-success{color:#fff;background-color:#449d44;border-color:#398439}.btn-success.active.focus,.btn-success.active:focus,.btn-success.active:hover,.btn-success:active.focus,.btn-success:active:focus,.btn-success:active:hover,.open>.dropdown-toggle.btn-success.focus,.open>.dropdown-toggle.btn-success:focus,.open>.dropdown-toggle.btn-success:hover{color:#fff;background-color:#398439;border-color:#255625}.btn-success.active,.btn-success:active,.open>.dropdown-toggle.btn-success{background-image:none}.btn-success.disabled,.btn-success.disabled.active,.btn-success.disabled.focus,.btn-success.disabled:active,.btn-success.disabled:focus,.btn-success.disabled:hover,.btn-success[disabled],.btn-success[disabled].active,.btn-success[disabled].focus,.btn-success[disabled]:active,.btn-success[disabled]:focus,.btn-success[disabled]:hover,fieldset[disabled] .btn-success,fieldset[disabled] .btn-success.active,fieldset[disabled] .btn-success.focus,fieldset[disabled] .btn-success:active,fieldset[disabled] .btn-success:focus,fieldset[disabled] .btn-success:hover{background-color:#5cb85c;border-color:#4cae4c}.btn-success .badge{color:#5cb85c;background-color:#fff}.btn-info{color:#fff;background-color:#5bc0de;border-color:#46b8da}.btn-info.focus,.btn-info:focus{color:#fff;background-color:#31b0d5;border-color:#1b6d85}.btn-info:hover{color:#fff;background-color:#31b0d5;border-color:#269abc}.btn-info.active,.btn-info:active,.open>.dropdown-toggle.btn-info{color:#fff;background-color:#31b0d5;border-color:#269abc}.btn-info.active.focus,.btn-info.active:focus,.btn-info.active:hover,.btn-info:active.focus,.btn-info:active:focus,.btn-info:active:hover,.open>.dropdown-toggle.btn-info.focus,.open>.dropdown-toggle.btn-info:focus,.open>.dropdown-toggle.btn-info:hover{color:#fff;background-color:#269abc;border-color:#1b6d85}.btn-info.active,.btn-info:active,.open>.dropdown-toggle.btn-info{background-image:none}.btn-info.disabled,.btn-info.disabled.active,.btn-info.disabled.focus,.btn-info.disabled:active,.btn-info.disabled:focus,.btn-info.disabled:hover,.btn-info[disabled],.btn-info[disabled].active,.btn-info[disabled].focus,.btn-info[disabled]:active,.btn-info[disabled]:focus,.btn-info[disabled]:hover,fieldset[disabled] .btn-info,fieldset[disabled] .btn-info.active,fieldset[disabled] .btn-info.focus,fieldset[disabled] .btn-info:active,fieldset[disabled] .btn-info:focus,fieldset[disabled] .btn-info:hover{background-color:#5bc0de;border-color:#46b8da}.btn-info .badge{color:#5bc0de;background-color:#fff}.btn-warning{color:#fff;background-color:#f0ad4e;border-color:#eea236}.btn-warning.focus,.btn-warning:focus{color:#fff;background-color:#ec971f;border-color:#985f0d}.btn-warning:hover{color:#fff;background-color:#ec971f;border-color:#d58512}.btn-warning.active,.btn-warning:active,.open>.dropdown-toggle.btn-warning{color:#fff;background-color:#ec971f;border-color:#d58512}.btn-warning.active.focus,.btn-warning.active:focus,.btn-warning.active:hover,.btn-warning:active.focus,.btn-warning:active:focus,.btn-warning:active:hover,.open>.dropdown-toggle.btn-warning.focus,.open>.dropdown-toggle.btn-warning:focus,.open>.dropdown-toggle.btn-warning:hover{color:#fff;background-color:#d58512;border-color:#985f0d}.btn-warning.active,.btn-warning:active,.open>.dropdown-toggle.btn-warning{background-image:none}.btn-warning.disabled,.btn-warning.disabled.active,.btn-warning.disabled.focus,.btn-warning.disabled:active,.btn-warning.disabled:focus,.btn-warning.disabled:hover,.btn-warning[disabled],.btn-warning[disabled].active,.btn-warning[disabled].focus,.btn-warning[disabled]:active,.btn-warning[disabled]:focus,.btn-warning[disabled]:hover,fieldset[disabled] .btn-warning,fieldset[disabled] .btn-warning.active,fieldset[disabled] .btn-warning.focus,fieldset[disabled] .btn-warning:active,fieldset[disabled] .btn-warning:focus,fieldset[disabled] .btn-warning:hover{background-color:#f0ad4e;border-color:#eea236}.btn-warning .badge{color:#f0ad4e;background-color:#fff}.btn-danger{color:#fff;background-color:#d9534f;border-color:#d43f3a}.btn-danger.focus,.btn-danger:focus{color:#fff;background-color:#c9302c;border-color:#761c19}.btn-danger:hover{color:#fff;background-color:#c9302c;border-color:#ac2925}.btn-danger.active,.btn-danger:active,.open>.dropdown-toggle.btn-danger{color:#fff;background-color:#c9302c;border-color:#ac2925}.btn-danger.active.focus,.btn-danger.active:focus,.btn-danger.active:hover,.btn-danger:active.focus,.btn-danger:active:focus,.btn-danger:active:hover,.open>.dropdown-toggle.btn-danger.focus,.open>.dropdown-toggle.btn-danger:focus,.open>.dropdown-toggle.btn-danger:hover{color:#fff;background-color:#ac2925;border-color:#761c19}.btn-danger.active,.btn-danger:active,.open>.dropdown-toggle.btn-danger{background-image:none}.btn-danger.disabled,.btn-danger.disabled.active,.btn-danger.disabled.focus,.btn-danger.disabled:active,.btn-danger.disabled:focus,.btn-danger.disabled:hover,.btn-danger[disabled],.btn-danger[disabled].active,.btn-danger[disabled].focus,.btn-danger[disabled]:active,.btn-danger[disabled]:focus,.btn-danger[disabled]:hover,fieldset[disabled] .btn-danger,fieldset[disabled] .btn-danger.active,fieldset[disabled] .btn-danger.focus,fieldset[disabled] .btn-danger:active,fieldset[disabled] .btn-danger:focus,fieldset[disabled] .btn-danger:hover{background-color:#d9534f;border-color:#d43f3a}.btn-danger .badge{color:#d9534f;background-color:#fff}.btn-link{font-weight:400;color:#337ab7;border-radius:0}.btn-link,.btn-link.active,.btn-link:active,.btn-link[disabled],fieldset[disabled] .btn-link{background-color:transparent;-webkit-box-shadow:none;box-shadow:none}.btn-link,.btn-link:active,.btn-link:focus,.btn-link:hover{border-color:transparent}.btn-link:focus,.btn-link:hover{color:#23527c;text-decoration:underline;background-color:transparent}.btn-link[disabled]:focus,.btn-link[disabled]:hover,fieldset[disabled] .btn-link:focus,fieldset[disabled] .btn-link:hover{color:#777;text-decoration:none}.btn-group-lg>.btn,.btn-lg{padding:10px 16px;font-size:18px;line-height:1.3333333;border-radius:6px}.btn-group-sm>.btn,.btn-sm{padding:5px 10px;font-size:12px;line-height:1.5;border-radius:3px}.btn-group-xs>.btn,.btn-xs{padding:1px 5px;font-size:12px;line-height:1.5;border-radius:3px}.btn-block{display:block;width:100%}.btn-block+.btn-block{margin-top:5px}input[type=button].btn-block,input[type=reset].btn-block,input[type=submit].btn-block{width:100%}.fade{opacity:0;-webkit-transition:opacity .15s linear;-o-transition:opacity .15s linear;transition:opacity .15s linear}.fade.in{opacity:1}.collapse{display:none}.collapse.in{display:block}tr.collapse.in{display:table-row}tbody.collapse.in{display:table-row-group}.collapsing{position:relative;height:0;overflow:hidden;-webkit-transition-timing-function:ease;-o-transition-timing-function:ease;transition-timing-function:ease;-webkit-transition-duration:.35s;-o-transition-duration:.35s;transition-duration:.35s;-webkit-transition-property:height,visibility;-o-transition-property:height,visibility;transition-property:height,visibility}.caret{display:inline-block;width:0;height:0;margin-left:2px;vertical-align:middle;border-top:4px dashed;border-top:4px solid\9;border-right:4px solid transparent;border-left:4px solid transparent}.dropdown,.dropup{position:relative}.dropdown-toggle:focus{outline:0}.dropdown-menu{position:absolute;top:100%;left:0;z-index:1000;display:none;float:left;min-width:160px;padding:5px 0;margin:2px 0 0;font-size:14px;text-align:left;list-style:none;background-color:#fff;-webkit-background-clip:padding-box;background-clip:padding-box;border:1px solid #ccc;border:1px solid rgba(0,0,0,.15);border-radius:4px;-webkit-box-shadow:0 6px 12px rgba(0,0,0,.175);box-shadow:0 6px 12px rgba(0,0,0,.175)}.dropdown-menu.pull-right{right:0;left:auto}.dropdown-menu .divider{height:1px;margin:9px 0;overflow:hidden;background-color:#e5e5e5}.dropdown-menu>li>a{display:block;padding:3px 20px;clear:both;font-weight:400;line-height:1.42857143;color:#333;white-space:nowrap}.dropdown-menu>li>a:focus,.dropdown-menu>li>a:hover{color:#262626;text-decoration:none;background-color:#f5f5f5}.dropdown-menu>.active>a,.dropdown-menu>.active>a:focus,.dropdown-menu>.active>a:hover{color:#fff;text-decoration:none;background-color:#337ab7;outline:0}.dropdown-menu>.disabled>a,.dropdown-menu>.disabled>a:focus,.dropdown-menu>.disabled>a:hover{color:#777}.dropdown-menu>.disabled>a:focus,.dropdown-menu>.disabled>a:hover{text-decoration:none;cursor:not-allowed;background-color:transparent;background-image:none;filter:progid:DXImageTransform.Microsoft.gradient(enabled=false)}.open>.dropdown-menu{display:block}.open>a{outline:0}.dropdown-menu-right{right:0;left:auto}.dropdown-menu-left{right:auto;left:0}.dropdown-header{display:block;padding:3px 20px;font-size:12px;line-height:1.42857143;color:#777;white-space:nowrap}.dropdown-backdrop{position:fixed;top:0;right:0;bottom:0;left:0;z-index:990}.pull-right>.dropdown-menu{right:0;left:auto}.dropup .caret,.navbar-fixed-bottom .dropdown .caret{content:"";border-top:0;border-bottom:4px dashed;border-bottom:4px solid\9}.dropup .dropdown-menu,.navbar-fixed-bottom .dropdown .dropdown-menu{top:auto;bottom:100%;margin-bottom:2px}@media (min-width:768px){.navbar-right .dropdown-menu{right:0;left:auto}.navbar-right .dropdown-menu-left{right:auto;left:0}}.btn-group,.btn-group-vertical{position:relative;display:inline-block;vertical-align:middle}.btn-group-vertical>.btn,.btn-group>.btn{position:relative;float:left}.btn-group-vertical>.btn.active,.btn-group-vertical>.btn:active,.btn-group-vertical>.btn:focus,.btn-group-vertical>.btn:hover,.btn-group>.btn.active,.btn-group>.btn:active,.btn-group>.btn:focus,.btn-group>.btn:hover{z-index:2}.btn-group .btn+.btn,.btn-group .btn+.btn-group,.btn-group .btn-group+.btn,.btn-group .btn-group+.btn-group{margin-left:-1px}.btn-toolbar{margin-left:-5px}.btn-toolbar .btn,.btn-toolbar .btn-group,.btn-toolbar .input-group{float:left}.btn-toolbar>.btn,.btn-toolbar>.btn-group,.btn-toolbar>.input-group{margin-left:5px}.btn-group>.btn:not(:first-child):not(:last-child):not(.dropdown-toggle){border-radius:0}.btn-group>.btn:first-child{margin-left:0}.btn-group>.btn:first-child:not(:last-child):not(.dropdown-toggle){border-top-right-radius:0;border-bottom-right-radius:0}.btn-group>.btn:last-child:not(:first-child),.btn-group>.dropdown-toggle:not(:first-child){border-top-left-radius:0;border-bottom-left-radius:0}.btn-group>.btn-group{float:left}.btn-group>.btn-group:not(:first-child):not(:last-child)>.btn{border-radius:0}.btn-group>.btn-group:first-child:not(:last-child)>.btn:last-child,.btn-group>.btn-group:first-child:not(:last-child)>.dropdown-toggle{border-top-right-radius:0;border-bottom-right-radius:0}.btn-group>.btn-group:last-child:not(:first-child)>.btn:first-child{border-top-left-radius:0;border-bottom-left-radius:0}.btn-group .dropdown-toggle:active,.btn-group.open .dropdown-toggle{outline:0}.btn-group>.btn+.dropdown-toggle{padding-right:8px;padding-left:8px}.btn-group>.btn-lg+.dropdown-toggle{padding-right:12px;padding-left:12px}.btn-group.open .dropdown-toggle{-webkit-box-shadow:inset 0 3px 5px rgba(0,0,0,.125);box-shadow:inset 0 3px 5px rgba(0,0,0,.125)}.btn-group.open .dropdown-toggle.btn-link{-webkit-box-shadow:none;box-shadow:none}.btn .caret{margin-left:0}.btn-lg .caret{border-width:5px 5px 0;border-bottom-width:0}.dropup .btn-lg .caret{border-width:0 5px 5px}.btn-group-vertical>.btn,.btn-group-vertical>.btn-group,.btn-group-vertical>.btn-group>.btn{display:block;float:none;width:100%;max-width:100%}.btn-group-vertical>.btn-group>.btn{float:none}.btn-group-vertical>.btn+.btn,.btn-group-vertical>.btn+.btn-group,.btn-group-vertical>.btn-group+.btn,.btn-group-vertical>.btn-group+.btn-group{margin-top:-1px;margin-left:0}.btn-group-vertical>.btn:not(:first-child):not(:last-child){border-radius:0}.btn-group-vertical>.btn:first-child:not(:last-child){border-top-right-radius:4px;border-bottom-right-radius:0;border-bottom-left-radius:0}.btn-group-vertical>.btn:last-child:not(:first-child){border-top-left-radius:0;border-top-right-radius:0;border-bottom-left-radius:4px}.btn-group-vertical>.btn-group:not(:first-child):not(:last-child)>.btn{border-radius:0}.btn-group-vertical>.btn-group:first-child:not(:last-child)>.btn:last-child,.btn-group-vertical>.btn-group:first-child:not(:last-child)>.dropdown-toggle{border-bottom-right-radius:0;border-bottom-left-radius:0}.btn-group-vertical>.btn-group:last-child:not(:first-child)>.btn:first-child{border-top-left-radius:0;border-top-right-radius:0}.btn-group-justified{display:table;width:100%;table-layout:fixed;border-collapse:separate}.btn-group-justified>.btn,.btn-group-justified>.btn-group{display:table-cell;float:none;width:1%}.btn-group-justified>.btn-group .btn{width:100%}.btn-group-justified>.btn-group .dropdown-menu{left:auto}[data-toggle=buttons]>.btn input[type=checkbox],[data-toggle=buttons]>.btn input[type=radio],[data-toggle=buttons]>.btn-group>.btn input[type=checkbox],[data-toggle=buttons]>.btn-group>.btn input[type=radio]{position:absolute;clip:rect(0,0,0,0);pointer-events:none}.input-group{position:relative;display:table;border-collapse:separate}.input-group[class*=col-]{float:none;padding-right:0;padding-left:0}.input-group .form-control{position:relative;z-index:2;float:left;width:100%;margin-bottom:0}.input-group-lg>.form-control,.input-group-lg>.input-group-addon,.input-group-lg>.input-group-btn>.btn{height:46px;padding:10px 16px;font-size:18px;line-height:1.3333333;border-radius:6px}select.input-group-lg>.form-control,select.input-group-lg>.input-group-addon,select.input-group-lg>.input-group-btn>.btn{height:46px;line-height:46px}select[multiple].input-group-lg>.form-control,select[multiple].input-group-lg>.input-group-addon,select[multiple].input-group-lg>.input-group-btn>.btn,textarea.input-group-lg>.form-control,textarea.input-group-lg>.input-group-addon,textarea.input-group-lg>.input-group-btn>.btn{height:auto}.input-group-sm>.form-control,.input-group-sm>.input-group-addon,.input-group-sm>.input-group-btn>.btn{height:30px;padding:5px 10px;font-size:12px;line-height:1.5;border-radius:3px}select.input-group-sm>.form-control,select.input-group-sm>.input-group-addon,select.input-group-sm>.input-group-btn>.btn{height:30px;line-height:30px}select[multiple].input-group-sm>.form-control,select[multiple].input-group-sm>.input-group-addon,select[multiple].input-group-sm>.input-group-btn>.btn,textarea.input-group-sm>.form-control,textarea.input-group-sm>.input-group-addon,textarea.input-group-sm>.input-group-btn>.btn{height:auto}.input-group .form-control,.input-group-addon,.input-group-btn{display:table-cell}.input-group .form-control:not(:first-child):not(:last-child),.input-group-addon:not(:first-child):not(:last-child),.input-group-btn:not(:first-child):not(:last-child){border-radius:0}.input-group-addon,.input-group-btn{width:1%;white-space:nowrap;vertical-align:middle}.input-group-addon{padding:6px 12px;font-size:14px;font-weight:400;line-height:1;color:#555;text-align:center;background-color:#eee;border:1px solid #ccc;border-radius:4px}.input-group-addon.input-sm{padding:5px 10px;font-size:12px;border-radius:3px}.input-group-addon.input-lg{padding:10px 16px;font-size:18px;border-radius:6px}.input-group-addon input[type=checkbox],.input-group-addon input[type=radio]{margin-top:0}.input-group .form-control:first-child,.input-group-addon:first-child,.input-group-btn:first-child>.btn,.input-group-btn:first-child>.btn-group>.btn,.input-group-btn:first-child>.dropdown-toggle,.input-group-btn:last-child>.btn-group:not(:last-child)>.btn,.input-group-btn:last-child>.btn:not(:last-child):not(.dropdown-toggle){border-top-right-radius:0;border-bottom-right-radius:0}.input-group-addon:first-child{border-right:0}.input-group .form-control:last-child,.input-group-addon:last-child,.input-group-btn:first-child>.btn-group:not(:first-child)>.btn,.input-group-btn:first-child>.btn:not(:first-child),.input-group-btn:last-child>.btn,.input-group-btn:last-child>.btn-group>.btn,.input-group-btn:last-child>.dropdown-toggle{border-top-left-radius:0;border-bottom-left-radius:0}.input-group-addon:last-child{border-left:0}.input-group-btn{position:relative;font-size:0;white-space:nowrap}.input-group-btn>.btn{position:relative}.input-group-btn>.btn+.btn{margin-left:-1px}.input-group-btn>.btn:active,.input-group-btn>.btn:focus,.input-group-btn>.btn:hover{z-index:2}.input-group-btn:first-child>.btn,.input-group-btn:first-child>.btn-group{margin-right:-1px}.input-group-btn:last-child>.btn,.input-group-btn:last-child>.btn-group{z-index:2;margin-left:-1px}.nav{padding-left:0;margin-bottom:0;list-style:none}.nav>li{position:relative;display:block}.nav>li>a{position:relative;display:block;padding:10px 15px}.nav>li>a:focus,.nav>li>a:hover{text-decoration:none;background-color:#eee}.nav>li.disabled>a{color:#777}.nav>li.disabled>a:focus,.nav>li.disabled>a:hover{color:#777;text-decoration:none;cursor:not-allowed;background-color:transparent}.nav .open>a,.nav .open>a:focus,.nav .open>a:hover{background-color:#eee;border-color:#337ab7}.nav .nav-divider{height:1px;margin:9px 0;overflow:hidden;background-color:#e5e5e5}.nav>li>a>img{max-width:none}.nav-tabs{border-bottom:1px solid #ddd}.nav-tabs>li{float:left;margin-bottom:-1px}.nav-tabs>li>a{margin-right:2px;line-height:1.42857143;border:1px solid transparent;border-radius:4px 4px 0 0}.nav-tabs>li>a:hover{border-color:#eee #eee #ddd}.nav-tabs>li.active>a,.nav-tabs>li.active>a:focus,.nav-tabs>li.active>a:hover{color:#555;cursor:default;background-color:#fff;border:1px solid #ddd;border-bottom-color:transparent}.nav-tabs.nav-justified{width:100%;border-bottom:0}.nav-tabs.nav-justified>li{float:none}.nav-tabs.nav-justified>li>a{margin-bottom:5px;text-align:center}.nav-tabs.nav-justified>.dropdown .dropdown-menu{top:auto;left:auto}@media (min-width:768px){.nav-tabs.nav-justified>li{display:table-cell;width:1%}.nav-tabs.nav-justified>li>a{margin-bottom:0}}.nav-tabs.nav-justified>li>a{margin-right:0;border-radius:4px}.nav-tabs.nav-justified>.active>a,.nav-tabs.nav-justified>.active>a:focus,.nav-tabs.nav-justified>.active>a:hover{border:1px solid #ddd}@media (min-width:768px){.nav-tabs.nav-justified>li>a{border-bottom:1px solid #ddd;border-radius:4px 4px 0 0}.nav-tabs.nav-justified>.active>a,.nav-tabs.nav-justified>.active>a:focus,.nav-tabs.nav-justified>.active>a:hover{border-bottom-color:#fff}}.nav-pills>li{float:left}.nav-pills>li>a{border-radius:4px}.nav-pills>li+li{margin-left:2px}.nav-pills>li.active>a,.nav-pills>li.active>a:focus,.nav-pills>li.active>a:hover{color:#fff;background-color:#337ab7}.nav-stacked>li{float:none}.nav-stacked>li+li{margin-top:2px;margin-left:0}.nav-justified{width:100%}.nav-justified>li{float:none}.nav-justified>li>a{margin-bottom:5px;text-align:center}.nav-justified>.dropdown .dropdown-menu{top:auto;left:auto}@media (min-width:768px){.nav-justified>li{display:table-cell;width:1%}.nav-justified>li>a{margin-bottom:0}}.nav-tabs-justified{border-bottom:0}.nav-tabs-justified>li>a{margin-right:0;border-radius:4px}.nav-tabs-justified>.active>a,.nav-tabs-justified>.active>a:focus,.nav-tabs-justified>.active>a:hover{border:1px solid #ddd}@media (min-width:768px){.nav-tabs-justified>li>a{border-bottom:1px solid #ddd;border-radius:4px 4px 0 0}.nav-tabs-justified>.active>a,.nav-tabs-justified>.active>a:focus,.nav-tabs-justified>.active>a:hover{border-bottom-color:#fff}}.tab-content>.tab-pane{display:none}.tab-content>.active{display:block}.nav-tabs .dropdown-menu{margin-top:-1px;border-top-left-radius:0;border-top-right-radius:0}.navbar{position:relative;min-height:50px;margin-bottom:20px;border:1px solid transparent}@media (min-width:768px){.navbar{border-radius:4px}}@media (min-width:768px){.navbar-header{float:left}}.navbar-collapse{padding-right:15px;padding-left:15px;overflow-x:visible;-webkit-overflow-scrolling:touch;border-top:1px solid transparent;-webkit-box-shadow:inset 0 1px 0 rgba(255,255,255,.1);box-shadow:inset 0 1px 0 rgba(255,255,255,.1)}.navbar-collapse.in{overflow-y:auto}@media (min-width:768px){.navbar-collapse{width:auto;border-top:0;-webkit-box-shadow:none;box-shadow:none}.navbar-collapse.collapse{display:block!important;height:auto!important;padding-bottom:0;overflow:visible!important}.navbar-collapse.in{overflow-y:visible}.navbar-fixed-bottom .navbar-collapse,.navbar-fixed-top .navbar-collapse,.navbar-static-top .navbar-collapse{padding-right:0;padding-left:0}}.navbar-fixed-bottom .navbar-collapse,.navbar-fixed-top .navbar-collapse{max-height:340px}@media (max-device-width:480px) and (orientation:landscape){.navbar-fixed-bottom .navbar-collapse,.navbar-fixed-top .navbar-collapse{max-height:200px}}.container-fluid>.navbar-collapse,.container-fluid>.navbar-header,.container>.navbar-collapse,.container>.navbar-header{margin-right:-15px;margin-left:-15px}@media (min-width:768px){.container-fluid>.navbar-collapse,.container-fluid>.navbar-header,.container>.navbar-collapse,.container>.navbar-header{margin-right:0;margin-left:0}}.navbar-static-top{z-index:1000;border-width:0 0 1px}@media (min-width:768px){.navbar-static-top{border-radius:0}}.navbar-fixed-bottom,.navbar-fixed-top{position:fixed;right:0;left:0;z-index:1030}@media (min-width:768px){.navbar-fixed-bottom,.navbar-fixed-top{border-radius:0}}.navbar-fixed-top{top:0;border-width:0 0 1px}.navbar-fixed-bottom{bottom:0;margin-bottom:0;border-width:1px 0 0}.navbar-brand{float:left;height:50px;padding:15px 15px;font-size:18px;line-height:20px}.navbar-brand:focus,.navbar-brand:hover{text-decoration:none}.navbar-brand>img{display:block}@media (min-width:768px){.navbar>.container .navbar-brand,.navbar>.container-fluid .navbar-brand{margin-left:-15px}}.navbar-toggle{position:relative;float:right;padding:9px 10px;margin-top:8px;margin-right:15px;margin-bottom:8px;background-color:transparent;background-image:none;border:1px solid transparent;border-radius:4px}.navbar-toggle:focus{outline:0}.navbar-toggle .icon-bar{display:block;width:22px;height:2px;border-radius:1px}.navbar-toggle .icon-bar+.icon-bar{margin-top:4px}@media (min-width:768px){.navbar-toggle{display:none}}.navbar-nav{margin:7.5px -15px}.navbar-nav>li>a{padding-top:10px;padding-bottom:10px;line-height:20px}@media (max-width:767px){.navbar-nav .open .dropdown-menu{position:static;float:none;width:auto;margin-top:0;background-color:transparent;border:0;-webkit-box-shadow:none;box-shadow:none}.navbar-nav .open .dropdown-menu .dropdown-header,.navbar-nav .open .dropdown-menu>li>a{padding:5px 15px 5px 25px}.navbar-nav .open .dropdown-menu>li>a{line-height:20px}.navbar-nav .open .dropdown-menu>li>a:focus,.navbar-nav .open .dropdown-menu>li>a:hover{background-image:none}}@media (min-width:768px){.navbar-nav{float:left;margin:0}.navbar-nav>li{float:left}.navbar-nav>li>a{padding-top:15px;padding-bottom:15px}}.navbar-form{padding:10px 15px;margin-top:8px;margin-right:-15px;margin-bottom:8px;margin-left:-15px;border-top:1px solid transparent;border-bottom:1px solid transparent;-webkit-box-shadow:inset 0 1px 0 rgba(255,255,255,.1),0 1px 0 rgba(255,255,255,.1);box-shadow:inset 0 1px 0 rgba(255,255,255,.1),0 1px 0 rgba(255,255,255,.1)}@media (min-width:768px){.navbar-form .form-group{display:inline-block;margin-bottom:0;vertical-align:middle}.navbar-form .form-control{display:inline-block;width:auto;vertical-align:middle}.navbar-form .form-control-static{display:inline-block}.navbar-form .input-group{display:inline-table;vertical-align:middle}.navbar-form .input-group .form-control,.navbar-form .input-group .input-group-addon,.navbar-form .input-group .input-group-btn{width:auto}.navbar-form .input-group>.form-control{width:100%}.navbar-form .control-label{margin-bottom:0;vertical-align:middle}.navbar-form .checkbox,.navbar-form .radio{display:inline-block;margin-top:0;margin-bottom:0;vertical-align:middle}.navbar-form .checkbox label,.navbar-form .radio label{padding-left:0}.navbar-form .checkbox input[type=checkbox],.navbar-form .radio input[type=radio]{position:relative;margin-left:0}.navbar-form .has-feedback .form-control-feedback{top:0}}@media (max-width:767px){.navbar-form .form-group{margin-bottom:5px}.navbar-form .form-group:last-child{margin-bottom:0}}@media (min-width:768px){.navbar-form{width:auto;padding-top:0;padding-bottom:0;margin-right:0;margin-left:0;border:0;-webkit-box-shadow:none;box-shadow:none}}.navbar-nav>li>.dropdown-menu{margin-top:0;border-top-left-radius:0;border-top-right-radius:0}.navbar-fixed-bottom .navbar-nav>li>.dropdown-menu{margin-bottom:0;border-top-left-radius:4px;border-top-right-radius:4px;border-bottom-right-radius:0;border-bottom-left-radius:0}.navbar-btn{margin-top:8px;margin-bottom:8px}.navbar-btn.btn-sm{margin-top:10px;margin-bottom:10px}.navbar-btn.btn-xs{margin-top:14px;margin-bottom:14px}.navbar-text{margin-top:15px;margin-bottom:15px}@media (min-width:768px){.navbar-text{float:left;margin-right:15px;margin-left:15px}}@media (min-width:768px){.navbar-left{float:left!important}.navbar-right{float:right!important;margin-right:-15px}.navbar-right~.navbar-right{margin-right:0}}.navbar-default{background-color:#f8f8f8;border-color:#e7e7e7}.navbar-default .navbar-brand{color:#777}.navbar-default .navbar-brand:focus,.navbar-default .navbar-brand:hover{color:#5e5e5e;background-color:transparent}.navbar-default .navbar-text{color:#777}.navbar-default .navbar-nav>li>a{color:#777}.navbar-default .navbar-nav>li>a:focus,.navbar-default .navbar-nav>li>a:hover{color:#333;background-color:transparent}.navbar-default .navbar-nav>.active>a,.navbar-default .navbar-nav>.active>a:focus,.navbar-default .navbar-nav>.active>a:hover{color:#555;background-color:#e7e7e7}.navbar-default .navbar-nav>.disabled>a,.navbar-default .navbar-nav>.disabled>a:focus,.navbar-default .navbar-nav>.disabled>a:hover{color:#ccc;background-color:transparent}.navbar-default .navbar-toggle{border-color:#ddd}.navbar-default .navbar-toggle:focus,.navbar-default .navbar-toggle:hover{background-color:#ddd}.navbar-default .navbar-toggle .icon-bar{background-color:#888}.navbar-default .navbar-collapse,.navbar-default .navbar-form{border-color:#e7e7e7}.navbar-default .navbar-nav>.open>a,.navbar-default .navbar-nav>.open>a:focus,.navbar-default .navbar-nav>.open>a:hover{color:#555;background-color:#e7e7e7}@media (max-width:767px){.navbar-default .navbar-nav .open .dropdown-menu>li>a{color:#777}.navbar-default .navbar-nav .open .dropdown-menu>li>a:focus,.navbar-default .navbar-nav .open .dropdown-menu>li>a:hover{color:#333;background-color:transparent}.navbar-default .navbar-nav .open .dropdown-menu>.active>a,.navbar-default .navbar-nav .open .dropdown-menu>.active>a:focus,.navbar-default .navbar-nav .open .dropdown-menu>.active>a:hover{color:#555;background-color:#e7e7e7}.navbar-default .navbar-nav .open .dropdown-menu>.disabled>a,.navbar-default .navbar-nav .open .dropdown-menu>.disabled>a:focus,.navbar-default .navbar-nav .open .dropdown-menu>.disabled>a:hover{color:#ccc;background-color:transparent}}.navbar-default .navbar-link{color:#777}.navbar-default .navbar-link:hover{color:#333}.navbar-default .btn-link{color:#777}.navbar-default .btn-link:focus,.navbar-default .btn-link:hover{color:#333}.navbar-default .btn-link[disabled]:focus,.navbar-default .btn-link[disabled]:hover,fieldset[disabled] .navbar-default .btn-link:focus,fieldset[disabled] .navbar-default .btn-link:hover{color:#ccc}.navbar-inverse{background-color:#222;border-color:#080808}.navbar-inverse .navbar-brand{color:#9d9d9d}.navbar-inverse .navbar-brand:focus,.navbar-inverse .navbar-brand:hover{color:#fff;background-color:transparent}.navbar-inverse .navbar-text{color:#9d9d9d}.navbar-inverse .navbar-nav>li>a{color:#9d9d9d}.navbar-inverse .navbar-nav>li>a:focus,.navbar-inverse .navbar-nav>li>a:hover{color:#fff;background-color:transparent}.navbar-inverse .navbar-nav>.active>a,.navbar-inverse .navbar-nav>.active>a:focus,.navbar-inverse .navbar-nav>.active>a:hover{color:#fff;background-color:#080808}.navbar-inverse .navbar-nav>.disabled>a,.navbar-inverse .navbar-nav>.disabled>a:focus,.navbar-inverse .navbar-nav>.disabled>a:hover{color:#444;background-color:transparent}.navbar-inverse .navbar-toggle{border-color:#333}.navbar-inverse .navbar-toggle:focus,.navbar-inverse .navbar-toggle:hover{background-color:#333}.navbar-inverse .navbar-toggle .icon-bar{background-color:#fff}.navbar-inverse .navbar-collapse,.navbar-inverse .navbar-form{border-color:#101010}.navbar-inverse .navbar-nav>.open>a,.navbar-inverse .navbar-nav>.open>a:focus,.navbar-inverse .navbar-nav>.open>a:hover{color:#fff;background-color:#080808}@media (max-width:767px){.navbar-inverse .navbar-nav .open .dropdown-menu>.dropdown-header{border-color:#080808}.navbar-inverse .navbar-nav .open .dropdown-menu .divider{background-color:#080808}.navbar-inverse .navbar-nav .open .dropdown-menu>li>a{color:#9d9d9d}.navbar-inverse .navbar-nav .open .dropdown-menu>li>a:focus,.navbar-inverse .navbar-nav .open .dropdown-menu>li>a:hover{color:#fff;background-color:transparent}.navbar-inverse .navbar-nav .open .dropdown-menu>.active>a,.navbar-inverse .navbar-nav .open .dropdown-menu>.active>a:focus,.navbar-inverse .navbar-nav .open .dropdown-menu>.active>a:hover{color:#fff;background-color:#080808}.navbar-inverse .navbar-nav .open .dropdown-menu>.disabled>a,.navbar-inverse .navbar-nav .open .dropdown-menu>.disabled>a:focus,.navbar-inverse .navbar-nav .open .dropdown-menu>.disabled>a:hover{color:#444;background-color:transparent}}.navbar-inverse .navbar-link{color:#9d9d9d}.navbar-inverse .navbar-link:hover{color:#fff}.navbar-inverse .btn-link{color:#9d9d9d}.navbar-inverse .btn-link:focus,.navbar-inverse .btn-link:hover{color:#fff}.navbar-inverse .btn-link[disabled]:focus,.navbar-inverse .btn-link[disabled]:hover,fieldset[disabled] .navbar-inverse .btn-link:focus,fieldset[disabled] .navbar-inverse .btn-link:hover{color:#444}.breadcrumb{padding:8px 15px;margin-bottom:20px;list-style:none;background-color:#f5f5f5;border-radius:4px}.breadcrumb>li{display:inline-block}.breadcrumb>li+li:before{padding:0 5px;color:#ccc;content:"/\00a0"}.breadcrumb>.active{color:#777}.pagination{display:inline-block;padding-left:0;margin:20px 0;border-radius:4px}.pagination>li{display:inline}.pagination>li>a,.pagination>li>span{position:relative;float:left;padding:6px 12px;margin-left:-1px;line-height:1.42857143;color:#337ab7;text-decoration:none;background-color:#fff;border:1px solid #ddd}.pagination>li:first-child>a,.pagination>li:first-child>span{margin-left:0;border-top-left-radius:4px;border-bottom-left-radius:4px}.pagination>li:last-child>a,.pagination>li:last-child>span{border-top-right-radius:4px;border-bottom-right-radius:4px}.pagination>li>a:focus,.pagination>li>a:hover,.pagination>li>span:focus,.pagination>li>span:hover{z-index:3;color:#23527c;background-color:#eee;border-color:#ddd}.pagination>.active>a,.pagination>.active>a:focus,.pagination>.active>a:hover,.pagination>.active>span,.pagination>.active>span:focus,.pagination>.active>span:hover{z-index:2;color:#fff;cursor:default;background-color:#337ab7;border-color:#337ab7}.pagination>.disabled>a,.pagination>.disabled>a:focus,.pagination>.disabled>a:hover,.pagination>.disabled>span,.pagination>.disabled>span:focus,.pagination>.disabled>span:hover{color:#777;cursor:not-allowed;background-color:#fff;border-color:#ddd}.pagination-lg>li>a,.pagination-lg>li>span{padding:10px 16px;font-size:18px;line-height:1.3333333}.pagination-lg>li:first-child>a,.pagination-lg>li:first-child>span{border-top-left-radius:6px;border-bottom-left-radius:6px}.pagination-lg>li:last-child>a,.pagination-lg>li:last-child>span{border-top-right-radius:6px;border-bottom-right-radius:6px}.pagination-sm>li>a,.pagination-sm>li>span{padding:5px 10px;font-size:12px;line-height:1.5}.pagination-sm>li:first-child>a,.pagination-sm>li:first-child>span{border-top-left-radius:3px;border-bottom-left-radius:3px}.pagination-sm>li:last-child>a,.pagination-sm>li:last-child>span{border-top-right-radius:3px;border-bottom-right-radius:3px}.pager{padding-left:0;margin:20px 0;text-align:center;list-style:none}.pager li{display:inline}.pager li>a,.pager li>span{display:inline-block;padding:5px 14px;background-color:#fff;border:1px solid #ddd;border-radius:15px}.pager li>a:focus,.pager li>a:hover{text-decoration:none;background-color:#eee}.pager .next>a,.pager .next>span{float:right}.pager .previous>a,.pager .previous>span{float:left}.pager .disabled>a,.pager .disabled>a:focus,.pager .disabled>a:hover,.pager .disabled>span{color:#777;cursor:not-allowed;background-color:#fff}.label{display:inline;padding:.2em .6em .3em;font-size:75%;font-weight:700;line-height:1;color:#fff;text-align:center;white-space:nowrap;vertical-align:baseline;border-radius:.25em}a.label:focus,a.label:hover{color:#fff;text-decoration:none;cursor:pointer}.label:empty{display:none}.btn .label{position:relative;top:-1px}.label-default{background-color:#777}.label-default[href]:focus,.label-default[href]:hover{background-color:#5e5e5e}.label-primary{background-color:#337ab7}.label-primary[href]:focus,.label-primary[href]:hover{background-color:#286090}.label-success{background-color:#5cb85c}.label-success[href]:focus,.label-success[href]:hover{background-color:#449d44}.label-info{background-color:#5bc0de}.label-info[href]:focus,.label-info[href]:hover{background-color:#31b0d5}.label-warning{background-color:#f0ad4e}.label-warning[href]:focus,.label-warning[href]:hover{background-color:#ec971f}.label-danger{background-color:#d9534f}.label-danger[href]:focus,.label-danger[href]:hover{background-color:#c9302c}.badge{display:inline-block;min-width:10px;padding:3px 7px;font-size:12px;font-weight:700;line-height:1;color:#fff;text-align:center;white-space:nowrap;vertical-align:middle;background-color:#777;border-radius:10px}.badge:empty{display:none}.btn .badge{position:relative;top:-1px}.btn-group-xs>.btn .badge,.btn-xs .badge{top:0;padding:1px 5px}a.badge:focus,a.badge:hover{color:#fff;text-decoration:none;cursor:pointer}.list-group-item.active>.badge,.nav-pills>.active>a>.badge{color:#337ab7;background-color:#fff}.list-group-item>.badge{float:right}.list-group-item>.badge+.badge{margin-right:5px}.nav-pills>li>a>.badge{margin-left:3px}.jumbotron{padding-top:30px;padding-bottom:30px;margin-bottom:30px;color:inherit;background-color:#eee}.jumbotron .h1,.jumbotron h1{color:inherit}.jumbotron p{margin-bottom:15px;font-size:21px;font-weight:200}.jumbotron>hr{border-top-color:#d5d5d5}.container .jumbotron,.container-fluid .jumbotron{border-radius:6px}.jumbotron .container{max-width:100%}@media screen and (min-width:768px){.jumbotron{padding-top:48px;padding-bottom:48px}.container .jumbotron,.container-fluid .jumbotron{padding-right:60px;padding-left:60px}.jumbotron .h1,.jumbotron h1{font-size:63px}}.thumbnail{display:block;padding:4px;margin-bottom:20px;line-height:1.42857143;background-color:#fff;border:1px solid #ddd;border-radius:4px;-webkit-transition:border .2s ease-in-out;-o-transition:border .2s ease-in-out;transition:border .2s ease-in-out}.thumbnail a>img,.thumbnail>img{margin-right:auto;margin-left:auto}a.thumbnail.active,a.thumbnail:focus,a.thumbnail:hover{border-color:#337ab7}.thumbnail .caption{padding:9px;color:#333}.alert{padding:15px;margin-bottom:20px;border:1px solid transparent;border-radius:4px}.alert h4{margin-top:0;color:inherit}.alert .alert-link{font-weight:700}.alert>p,.alert>ul{margin-bottom:0}.alert>p+p{margin-top:5px}.alert-dismissable,.alert-dismissible{padding-right:35px}.alert-dismissable .close,.alert-dismissible .close{position:relative;top:-2px;right:-21px;color:inherit}.alert-success{color:#3c763d;background-color:#dff0d8;border-color:#d6e9c6}.alert-success hr{border-top-color:#c9e2b3}.alert-success .alert-link{color:#2b542c}.alert-info{color:#31708f;background-color:#d9edf7;border-color:#bce8f1}.alert-info hr{border-top-color:#a6e1ec}.alert-info .alert-link{color:#245269}.alert-warning{color:#8a6d3b;background-color:#fcf8e3;border-color:#faebcc}.alert-warning hr{border-top-color:#f7e1b5}.alert-warning .alert-link{color:#66512c}.alert-danger{color:#a94442;background-color:#f2dede;border-color:#ebccd1}.alert-danger hr{border-top-color:#e4b9c0}.alert-danger .alert-link{color:#843534}@-webkit-keyframes progress-bar-stripes{from{background-position:40px 0}to{background-position:0 0}}@-o-keyframes progress-bar-stripes{from{background-position:40px 0}to{background-position:0 0}}@keyframes progress-bar-stripes{from{background-position:40px 0}to{background-position:0 0}}.progress{height:20px;margin-bottom:20px;overflow:hidden;background-color:#f5f5f5;border-radius:4px;-webkit-box-shadow:inset 0 1px 2px rgba(0,0,0,.1);box-shadow:inset 0 1px 2px rgba(0,0,0,.1)}.progress-bar{float:left;width:0;height:100%;font-size:12px;line-height:20px;color:#fff;text-align:center;background-color:#337ab7;-webkit-box-shadow:inset 0 -1px 0 rgba(0,0,0,.15);box-shadow:inset 0 -1px 0 rgba(0,0,0,.15);-webkit-transition:width .6s ease;-o-transition:width .6s ease;transition:width .6s ease}.progress-bar-striped,.progress-striped .progress-bar{background-image:-webkit-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:-o-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);-webkit-background-size:40px 40px;background-size:40px 40px}.progress-bar.active,.progress.active .progress-bar{-webkit-animation:progress-bar-stripes 2s linear infinite;-o-animation:progress-bar-stripes 2s linear infinite;animation:progress-bar-stripes 2s linear infinite}.progress-bar-success{background-color:#5cb85c}.progress-striped .progress-bar-success{background-image:-webkit-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:-o-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent)}.progress-bar-info{background-color:#5bc0de}.progress-striped .progress-bar-info{background-image:-webkit-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:-o-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent)}.progress-bar-warning{background-color:#f0ad4e}.progress-striped .progress-bar-warning{background-image:-webkit-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:-o-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent)}.progress-bar-danger{background-color:#d9534f}.progress-striped .progress-bar-danger{background-image:-webkit-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:-o-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent)}.media{margin-top:15px}.media:first-child{margin-top:0}.media,.media-body{overflow:hidden;zoom:1}.media-body{width:10000px}.media-object{display:block}.media-object.img-thumbnail{max-width:none}.media-right,.media>.pull-right{padding-left:10px}.media-left,.media>.pull-left{padding-right:10px}.media-body,.media-left,.media-right{display:table-cell;vertical-align:top}.media-middle{vertical-align:middle}.media-bottom{vertical-align:bottom}.media-heading{margin-top:0;margin-bottom:5px}.media-list{padding-left:0;list-style:none}.list-group{padding-left:0;margin-bottom:20px}.list-group-item{position:relative;display:block;padding:10px 15px;margin-bottom:-1px;background-color:#fff;border:1px solid #ddd}.list-group-item:first-child{border-top-left-radius:4px;border-top-right-radius:4px}.list-group-item:last-child{margin-bottom:0;border-bottom-right-radius:4px;border-bottom-left-radius:4px}a.list-group-item,button.list-group-item{color:#555}a.list-group-item .list-group-item-heading,button.list-group-item .list-group-item-heading{color:#333}a.list-group-item:focus,a.list-group-item:hover,button.list-group-item:focus,button.list-group-item:hover{color:#555;text-decoration:none;background-color:#f5f5f5}button.list-group-item{width:100%;text-align:left}.list-group-item.disabled,.list-group-item.disabled:focus,.list-group-item.disabled:hover{color:#777;cursor:not-allowed;background-color:#eee}.list-group-item.disabled .list-group-item-heading,.list-group-item.disabled:focus .list-group-item-heading,.list-group-item.disabled:hover .list-group-item-heading{color:inherit}.list-group-item.disabled .list-group-item-text,.list-group-item.disabled:focus .list-group-item-text,.list-group-item.disabled:hover .list-group-item-text{color:#777}.list-group-item.active,.list-group-item.active:focus,.list-group-item.active:hover{z-index:2;color:#fff;background-color:#337ab7;border-color:#337ab7}.list-group-item.active .list-group-item-heading,.list-group-item.active .list-group-item-heading>.small,.list-group-item.active .list-group-item-heading>small,.list-group-item.active:focus .list-group-item-heading,.list-group-item.active:focus .list-group-item-heading>.small,.list-group-item.active:focus .list-group-item-heading>small,.list-group-item.active:hover .list-group-item-heading,.list-group-item.active:hover .list-group-item-heading>.small,.list-group-item.active:hover .list-group-item-heading>small{color:inherit}.list-group-item.active .list-group-item-text,.list-group-item.active:focus .list-group-item-text,.list-group-item.active:hover .list-group-item-text{color:#c7ddef}.list-group-item-success{color:#3c763d;background-color:#dff0d8}a.list-group-item-success,button.list-group-item-success{color:#3c763d}a.list-group-item-success .list-group-item-heading,button.list-group-item-success .list-group-item-heading{color:inherit}a.list-group-item-success:focus,a.list-group-item-success:hover,button.list-group-item-success:focus,button.list-group-item-success:hover{color:#3c763d;background-color:#d0e9c6}a.list-group-item-success.active,a.list-group-item-success.active:focus,a.list-group-item-success.active:hover,button.list-group-item-success.active,button.list-group-item-success.active:focus,button.list-group-item-success.active:hover{color:#fff;background-color:#3c763d;border-color:#3c763d}.list-group-item-info{color:#31708f;background-color:#d9edf7}a.list-group-item-info,button.list-group-item-info{color:#31708f}a.list-group-item-info .list-group-item-heading,button.list-group-item-info .list-group-item-heading{color:inherit}a.list-group-item-info:focus,a.list-group-item-info:hover,button.list-group-item-info:focus,button.list-group-item-info:hover{color:#31708f;background-color:#c4e3f3}a.list-group-item-info.active,a.list-group-item-info.active:focus,a.list-group-item-info.active:hover,button.list-group-item-info.active,button.list-group-item-info.active:focus,button.list-group-item-info.active:hover{color:#fff;background-color:#31708f;border-color:#31708f}.list-group-item-warning{color:#8a6d3b;background-color:#fcf8e3}a.list-group-item-warning,button.list-group-item-warning{color:#8a6d3b}a.list-group-item-warning .list-group-item-heading,button.list-group-item-warning .list-group-item-heading{color:inherit}a.list-group-item-warning:focus,a.list-group-item-warning:hover,button.list-group-item-warning:focus,button.list-group-item-warning:hover{color:#8a6d3b;background-color:#faf2cc}a.list-group-item-warning.active,a.list-group-item-warning.active:focus,a.list-group-item-warning.active:hover,button.list-group-item-warning.active,button.list-group-item-warning.active:focus,button.list-group-item-warning.active:hover{color:#fff;background-color:#8a6d3b;border-color:#8a6d3b}.list-group-item-danger{color:#a94442;background-color:#f2dede}a.list-group-item-danger,button.list-group-item-danger{color:#a94442}a.list-group-item-danger .list-group-item-heading,button.list-group-item-danger .list-group-item-heading{color:inherit}a.list-group-item-danger:focus,a.list-group-item-danger:hover,button.list-group-item-danger:focus,button.list-group-item-danger:hover{color:#a94442;background-color:#ebcccc}a.list-group-item-danger.active,a.list-group-item-danger.active:focus,a.list-group-item-danger.active:hover,button.list-group-item-danger.active,button.list-group-item-danger.active:focus,button.list-group-item-danger.active:hover{color:#fff;background-color:#a94442;border-color:#a94442}.list-group-item-heading{margin-top:0;margin-bottom:5px}.list-group-item-text{margin-bottom:0;line-height:1.3}.panel{margin-bottom:20px;background-color:#fff;border:1px solid transparent;border-radius:4px;-webkit-box-shadow:0 1px 1px rgba(0,0,0,.05);box-shadow:0 1px 1px rgba(0,0,0,.05)}.panel-body{padding:15px}.panel-heading{padding:10px 15px;border-bottom:1px solid transparent;border-top-left-radius:3px;border-top-right-radius:3px}.panel-heading>.dropdown .dropdown-toggle{color:inherit}.panel-title{margin-top:0;margin-bottom:0;font-size:16px;color:inherit}.panel-title>.small,.panel-title>.small>a,.panel-title>a,.panel-title>small,.panel-title>small>a{color:inherit}.panel-footer{padding:10px 15px;background-color:#f5f5f5;border-top:1px solid #ddd;border-bottom-right-radius:3px;border-bottom-left-radius:3px}.panel>.list-group,.panel>.panel-collapse>.list-group{margin-bottom:0}.panel>.list-group .list-group-item,.panel>.panel-collapse>.list-group .list-group-item{border-width:1px 0;border-radius:0}.panel>.list-group:first-child .list-group-item:first-child,.panel>.panel-collapse>.list-group:first-child .list-group-item:first-child{border-top:0;border-top-left-radius:3px;border-top-right-radius:3px}.panel>.list-group:last-child .list-group-item:last-child,.panel>.panel-collapse>.list-group:last-child .list-group-item:last-child{border-bottom:0;border-bottom-right-radius:3px;border-bottom-left-radius:3px}.panel>.panel-heading+.panel-collapse>.list-group .list-group-item:first-child{border-top-left-radius:0;border-top-right-radius:0}.panel-heading+.list-group .list-group-item:first-child{border-top-width:0}.list-group+.panel-footer{border-top-width:0}.panel>.panel-collapse>.table,.panel>.table,.panel>.table-responsive>.table{margin-bottom:0}.panel>.panel-collapse>.table caption,.panel>.table caption,.panel>.table-responsive>.table caption{padding-right:15px;padding-left:15px}.panel>.table-responsive:first-child>.table:first-child,.panel>.table:first-child{border-top-left-radius:3px;border-top-right-radius:3px}.panel>.table-responsive:first-child>.table:first-child>tbody:first-child>tr:first-child,.panel>.table-responsive:first-child>.table:first-child>thead:first-child>tr:first-child,.panel>.table:first-child>tbody:first-child>tr:first-child,.panel>.table:first-child>thead:first-child>tr:first-child{border-top-left-radius:3px;border-top-right-radius:3px}.panel>.table-responsive:first-child>.table:first-child>tbody:first-child>tr:first-child td:first-child,.panel>.table-responsive:first-child>.table:first-child>tbody:first-child>tr:first-child th:first-child,.panel>.table-responsive:first-child>.table:first-child>thead:first-child>tr:first-child td:first-child,.panel>.table-responsive:first-child>.table:first-child>thead:first-child>tr:first-child th:first-child,.panel>.table:first-child>tbody:first-child>tr:first-child td:first-child,.panel>.table:first-child>tbody:first-child>tr:first-child th:first-child,.panel>.table:first-child>thead:first-child>tr:first-child td:first-child,.panel>.table:first-child>thead:first-child>tr:first-child th:first-child{border-top-left-radius:3px}.panel>.table-responsive:first-child>.table:first-child>tbody:first-child>tr:first-child td:last-child,.panel>.table-responsive:first-child>.table:first-child>tbody:first-child>tr:first-child th:last-child,.panel>.table-responsive:first-child>.table:first-child>thead:first-child>tr:first-child td:last-child,.panel>.table-responsive:first-child>.table:first-child>thead:first-child>tr:first-child th:last-child,.panel>.table:first-child>tbody:first-child>tr:first-child td:last-child,.panel>.table:first-child>tbody:first-child>tr:first-child th:last-child,.panel>.table:first-child>thead:first-child>tr:first-child td:last-child,.panel>.table:first-child>thead:first-child>tr:first-child th:last-child{border-top-right-radius:3px}.panel>.table-responsive:last-child>.table:last-child,.panel>.table:last-child{border-bottom-right-radius:3px;border-bottom-left-radius:3px}.panel>.table-responsive:last-child>.table:last-child>tbody:last-child>tr:last-child,.panel>.table-responsive:last-child>.table:last-child>tfoot:last-child>tr:last-child,.panel>.table:last-child>tbody:last-child>tr:last-child,.panel>.table:last-child>tfoot:last-child>tr:last-child{border-bottom-right-radius:3px;border-bottom-left-radius:3px}.panel>.table-responsive:last-child>.table:last-child>tbody:last-child>tr:last-child td:first-child,.panel>.table-responsive:last-child>.table:last-child>tbody:last-child>tr:last-child th:first-child,.panel>.table-responsive:last-child>.table:last-child>tfoot:last-child>tr:last-child td:first-child,.panel>.table-responsive:last-child>.table:last-child>tfoot:last-child>tr:last-child th:first-child,.panel>.table:last-child>tbody:last-child>tr:last-child td:first-child,.panel>.table:last-child>tbody:last-child>tr:last-child th:first-child,.panel>.table:last-child>tfoot:last-child>tr:last-child td:first-child,.panel>.table:last-child>tfoot:last-child>tr:last-child th:first-child{border-bottom-left-radius:3px}.panel>.table-responsive:last-child>.table:last-child>tbody:last-child>tr:last-child td:last-child,.panel>.table-responsive:last-child>.table:last-child>tbody:last-child>tr:last-child th:last-child,.panel>.table-responsive:last-child>.table:last-child>tfoot:last-child>tr:last-child td:last-child,.panel>.table-responsive:last-child>.table:last-child>tfoot:last-child>tr:last-child th:last-child,.panel>.table:last-child>tbody:last-child>tr:last-child td:last-child,.panel>.table:last-child>tbody:last-child>tr:last-child th:last-child,.panel>.table:last-child>tfoot:last-child>tr:last-child td:last-child,.panel>.table:last-child>tfoot:last-child>tr:last-child th:last-child{border-bottom-right-radius:3px}.panel>.panel-body+.table,.panel>.panel-body+.table-responsive,.panel>.table+.panel-body,.panel>.table-responsive+.panel-body{border-top:1px solid #ddd}.panel>.table>tbody:first-child>tr:first-child td,.panel>.table>tbody:first-child>tr:first-child th{border-top:0}.panel>.table-bordered,.panel>.table-responsive>.table-bordered{border:0}.panel>.table-bordered>tbody>tr>td:first-child,.panel>.table-bordered>tbody>tr>th:first-child,.panel>.table-bordered>tfoot>tr>td:first-child,.panel>.table-bordered>tfoot>tr>th:first-child,.panel>.table-bordered>thead>tr>td:first-child,.panel>.table-bordered>thead>tr>th:first-child,.panel>.table-responsive>.table-bordered>tbody>tr>td:first-child,.panel>.table-responsive>.table-bordered>tbody>tr>th:first-child,.panel>.table-responsive>.table-bordered>tfoot>tr>td:first-child,.panel>.table-responsive>.table-bordered>tfoot>tr>th:first-child,.panel>.table-responsive>.table-bordered>thead>tr>td:first-child,.panel>.table-responsive>.table-bordered>thead>tr>th:first-child{border-left:0}.panel>.table-bordered>tbody>tr>td:last-child,.panel>.table-bordered>tbody>tr>th:last-child,.panel>.table-bordered>tfoot>tr>td:last-child,.panel>.table-bordered>tfoot>tr>th:last-child,.panel>.table-bordered>thead>tr>td:last-child,.panel>.table-bordered>thead>tr>th:last-child,.panel>.table-responsive>.table-bordered>tbody>tr>td:last-child,.panel>.table-responsive>.table-bordered>tbody>tr>th:last-child,.panel>.table-responsive>.table-bordered>tfoot>tr>td:last-child,.panel>.table-responsive>.table-bordered>tfoot>tr>th:last-child,.panel>.table-responsive>.table-bordered>thead>tr>td:last-child,.panel>.table-responsive>.table-bordered>thead>tr>th:last-child{border-right:0}.panel>.table-bordered>tbody>tr:first-child>td,.panel>.table-bordered>tbody>tr:first-child>th,.panel>.table-bordered>thead>tr:first-child>td,.panel>.table-bordered>thead>tr:first-child>th,.panel>.table-responsive>.table-bordered>tbody>tr:first-child>td,.panel>.table-responsive>.table-bordered>tbody>tr:first-child>th,.panel>.table-responsive>.table-bordered>thead>tr:first-child>td,.panel>.table-responsive>.table-bordered>thead>tr:first-child>th{border-bottom:0}.panel>.table-bordered>tbody>tr:last-child>td,.panel>.table-bordered>tbody>tr:last-child>th,.panel>.table-bordered>tfoot>tr:last-child>td,.panel>.table-bordered>tfoot>tr:last-child>th,.panel>.table-responsive>.table-bordered>tbody>tr:last-child>td,.panel>.table-responsive>.table-bordered>tbody>tr:last-child>th,.panel>.table-responsive>.table-bordered>tfoot>tr:last-child>td,.panel>.table-responsive>.table-bordered>tfoot>tr:last-child>th{border-bottom:0}.panel>.table-responsive{margin-bottom:0;border:0}.panel-group{margin-bottom:20px}.panel-group .panel{margin-bottom:0;border-radius:4px}.panel-group .panel+.panel{margin-top:5px}.panel-group .panel-heading{border-bottom:0}.panel-group .panel-heading+.panel-collapse>.list-group,.panel-group .panel-heading+.panel-collapse>.panel-body{border-top:1px solid #ddd}.panel-group .panel-footer{border-top:0}.panel-group .panel-footer+.panel-collapse .panel-body{border-bottom:1px solid #ddd}.panel-default{border-color:#ddd}.panel-default>.panel-heading{color:#333;background-color:#f5f5f5;border-color:#ddd}.panel-default>.panel-heading+.panel-collapse>.panel-body{border-top-color:#ddd}.panel-default>.panel-heading .badge{color:#f5f5f5;background-color:#333}.panel-default>.panel-footer+.panel-collapse>.panel-body{border-bottom-color:#ddd}.panel-primary{border-color:#337ab7}.panel-primary>.panel-heading{color:#fff;background-color:#337ab7;border-color:#337ab7}.panel-primary>.panel-heading+.panel-collapse>.panel-body{border-top-color:#337ab7}.panel-primary>.panel-heading .badge{color:#337ab7;background-color:#fff}.panel-primary>.panel-footer+.panel-collapse>.panel-body{border-bottom-color:#337ab7}.panel-success{border-color:#d6e9c6}.panel-success>.panel-heading{color:#3c763d;background-color:#dff0d8;border-color:#d6e9c6}.panel-success>.panel-heading+.panel-collapse>.panel-body{border-top-color:#d6e9c6}.panel-success>.panel-heading .badge{color:#dff0d8;background-color:#3c763d}.panel-success>.panel-footer+.panel-collapse>.panel-body{border-bottom-color:#d6e9c6}.panel-info{border-color:#bce8f1}.panel-info>.panel-heading{color:#31708f;background-color:#d9edf7;border-color:#bce8f1}.panel-info>.panel-heading+.panel-collapse>.panel-body{border-top-color:#bce8f1}.panel-info>.panel-heading .badge{color:#d9edf7;background-color:#31708f}.panel-info>.panel-footer+.panel-collapse>.panel-body{border-bottom-color:#bce8f1}.panel-warning{border-color:#faebcc}.panel-warning>.panel-heading{color:#8a6d3b;background-color:#fcf8e3;border-color:#faebcc}.panel-warning>.panel-heading+.panel-collapse>.panel-body{border-top-color:#faebcc}.panel-warning>.panel-heading .badge{color:#fcf8e3;background-color:#8a6d3b}.panel-warning>.panel-footer+.panel-collapse>.panel-body{border-bottom-color:#faebcc}.panel-danger{border-color:#ebccd1}.panel-danger>.panel-heading{color:#a94442;background-color:#f2dede;border-color:#ebccd1}.panel-danger>.panel-heading+.panel-collapse>.panel-body{border-top-color:#ebccd1}.panel-danger>.panel-heading .badge{color:#f2dede;background-color:#a94442}.panel-danger>.panel-footer+.panel-collapse>.panel-body{border-bottom-color:#ebccd1}.embed-responsive{position:relative;display:block;height:0;padding:0;overflow:hidden}.embed-responsive .embed-responsive-item,.embed-responsive embed,.embed-responsive iframe,.embed-responsive object,.embed-responsive video{position:absolute;top:0;bottom:0;left:0;width:100%;height:100%;border:0}.embed-responsive-16by9{padding-bottom:56.25%}.embed-responsive-4by3{padding-bottom:75%}.well{min-height:20px;padding:19px;margin-bottom:20px;background-color:#f5f5f5;border:1px solid #e3e3e3;border-radius:4px;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.05);box-shadow:inset 0 1px 1px rgba(0,0,0,.05)}.well blockquote{border-color:#ddd;border-color:rgba(0,0,0,.15)}.well-lg{padding:24px;border-radius:6px}.well-sm{padding:9px;border-radius:3px}.close{float:right;font-size:21px;font-weight:700;line-height:1;color:#000;text-shadow:0 1px 0 #fff;filter:alpha(opacity=20);opacity:.2}.close:focus,.close:hover{color:#000;text-decoration:none;cursor:pointer;filter:alpha(opacity=50);opacity:.5}button.close{-webkit-appearance:none;padding:0;cursor:pointer;background:0 0;border:0}.modal-open{overflow:hidden}.modal{position:fixed;top:0;right:0;bottom:0;left:0;z-index:1050;display:none;overflow:hidden;-webkit-overflow-scrolling:touch;outline:0}.modal.fade .modal-dialog{-webkit-transition:-webkit-transform .3s ease-out;-o-transition:-o-transform .3s ease-out;transition:transform .3s ease-out;-webkit-transform:translate(0,-25%);-ms-transform:translate(0,-25%);-o-transform:translate(0,-25%);transform:translate(0,-25%)}.modal.in .modal-dialog{-webkit-transform:translate(0,0);-ms-transform:translate(0,0);-o-transform:translate(0,0);transform:translate(0,0)}.modal-open .modal{overflow-x:hidden;overflow-y:auto}.modal-dialog{position:relative;width:auto;margin:10px}.modal-content{position:relative;background-color:#fff;-webkit-background-clip:padding-box;background-clip:padding-box;border:1px solid #999;border:1px solid rgba(0,0,0,.2);border-radius:6px;outline:0;-webkit-box-shadow:0 3px 9px rgba(0,0,0,.5);box-shadow:0 3px 9px rgba(0,0,0,.5)}.modal-backdrop{position:fixed;top:0;right:0;bottom:0;left:0;z-index:1040;background-color:#000}.modal-backdrop.fade{filter:alpha(opacity=0);opacity:0}.modal-backdrop.in{filter:alpha(opacity=50);opacity:.5}.modal-header{min-height:16.43px;padding:15px;border-bottom:1px solid #e5e5e5}.modal-header .close{margin-top:-2px}.modal-title{margin:0;line-height:1.42857143}.modal-body{position:relative;padding:15px}.modal-footer{padding:15px;text-align:right;border-top:1px solid #e5e5e5}.modal-footer .btn+.btn{margin-bottom:0;margin-left:5px}.modal-footer .btn-group .btn+.btn{margin-left:-1px}.modal-footer .btn-block+.btn-block{margin-left:0}.modal-scrollbar-measure{position:absolute;top:-9999px;width:50px;height:50px;overflow:scroll}@media (min-width:768px){.modal-dialog{width:600px;margin:30px auto}.modal-content{-webkit-box-shadow:0 5px 15px rgba(0,0,0,.5);box-shadow:0 5px 15px rgba(0,0,0,.5)}.modal-sm{width:300px}}@media (min-width:992px){.modal-lg{width:900px}}.tooltip{position:absolute;z-index:1070;display:block;font-family:"Helvetica Neue",Helvetica,Arial,sans-serif;font-size:12px;font-style:normal;font-weight:400;line-height:1.42857143;text-align:left;text-align:start;text-decoration:none;text-shadow:none;text-transform:none;letter-spacing:normal;word-break:normal;word-spacing:normal;word-wrap:normal;white-space:normal;filter:alpha(opacity=0);opacity:0;line-break:auto}.tooltip.in{filter:alpha(opacity=90);opacity:.9}.tooltip.top{padding:5px 0;margin-top:-3px}.tooltip.right{padding:0 5px;margin-left:3px}.tooltip.bottom{padding:5px 0;margin-top:3px}.tooltip.left{padding:0 5px;margin-left:-3px}.tooltip-inner{max-width:200px;padding:3px 8px;color:#fff;text-align:center;background-color:#000;border-radius:4px}.tooltip-arrow{position:absolute;width:0;height:0;border-color:transparent;border-style:solid}.tooltip.top .tooltip-arrow{bottom:0;left:50%;margin-left:-5px;border-width:5px 5px 0;border-top-color:#000}.tooltip.top-left .tooltip-arrow{right:5px;bottom:0;margin-bottom:-5px;border-width:5px 5px 0;border-top-color:#000}.tooltip.top-right .tooltip-arrow{bottom:0;left:5px;margin-bottom:-5px;border-width:5px 5px 0;border-top-color:#000}.tooltip.right .tooltip-arrow{top:50%;left:0;margin-top:-5px;border-width:5px 5px 5px 0;border-right-color:#000}.tooltip.left .tooltip-arrow{top:50%;right:0;margin-top:-5px;border-width:5px 0 5px 5px;border-left-color:#000}.tooltip.bottom .tooltip-arrow{top:0;left:50%;margin-left:-5px;border-width:0 5px 5px;border-bottom-color:#000}.tooltip.bottom-left .tooltip-arrow{top:0;right:5px;margin-top:-5px;border-width:0 5px 5px;border-bottom-color:#000}.tooltip.bottom-right .tooltip-arrow{top:0;left:5px;margin-top:-5px;border-width:0 5px 5px;border-bottom-color:#000}.popover{position:absolute;top:0;left:0;z-index:1060;display:none;max-width:276px;padding:1px;font-family:"Helvetica Neue",Helvetica,Arial,sans-serif;font-size:14px;font-style:normal;font-weight:400;line-height:1.42857143;text-align:left;text-align:start;text-decoration:none;text-shadow:none;text-transform:none;letter-spacing:normal;word-break:normal;word-spacing:normal;word-wrap:normal;white-space:normal;background-color:#fff;-webkit-background-clip:padding-box;background-clip:padding-box;border:1px solid #ccc;border:1px solid rgba(0,0,0,.2);border-radius:6px;-webkit-box-shadow:0 5px 10px rgba(0,0,0,.2);box-shadow:0 5px 10px rgba(0,0,0,.2);line-break:auto}.popover.top{margin-top:-10px}.popover.right{margin-left:10px}.popover.bottom{margin-top:10px}.popover.left{margin-left:-10px}.popover-title{padding:8px 14px;margin:0;font-size:14px;background-color:#f7f7f7;border-bottom:1px solid #ebebeb;border-radius:5px 5px 0 0}.popover-content{padding:9px 14px}.popover>.arrow,.popover>.arrow:after{position:absolute;display:block;width:0;height:0;border-color:transparent;border-style:solid}.popover>.arrow{border-width:11px}.popover>.arrow:after{content:"";border-width:10px}.popover.top>.arrow{bottom:-11px;left:50%;margin-left:-11px;border-top-color:#999;border-top-color:rgba(0,0,0,.25);border-bottom-width:0}.popover.top>.arrow:after{bottom:1px;margin-left:-10px;content:" ";border-top-color:#fff;border-bottom-width:0}.popover.right>.arrow{top:50%;left:-11px;margin-top:-11px;border-right-color:#999;border-right-color:rgba(0,0,0,.25);border-left-width:0}.popover.right>.arrow:after{bottom:-10px;left:1px;content:" ";border-right-color:#fff;border-left-width:0}.popover.bottom>.arrow{top:-11px;left:50%;margin-left:-11px;border-top-width:0;border-bottom-color:#999;border-bottom-color:rgba(0,0,0,.25)}.popover.bottom>.arrow:after{top:1px;margin-left:-10px;content:" ";border-top-width:0;border-bottom-color:#fff}.popover.left>.arrow{top:50%;right:-11px;margin-top:-11px;border-right-width:0;border-left-color:#999;border-left-color:rgba(0,0,0,.25)}.popover.left>.arrow:after{right:1px;bottom:-10px;content:" ";border-right-width:0;border-left-color:#fff}.carousel{position:relative}.carousel-inner{position:relative;width:100%;overflow:hidden}.carousel-inner>.item{position:relative;display:none;-webkit-transition:.6s ease-in-out left;-o-transition:.6s ease-in-out left;transition:.6s ease-in-out left}.carousel-inner>.item>a>img,.carousel-inner>.item>img{line-height:1}@media all and (transform-3d),(-webkit-transform-3d){.carousel-inner>.item{-webkit-transition:-webkit-transform .6s ease-in-out;-o-transition:-o-transform .6s ease-in-out;transition:transform .6s ease-in-out;-webkit-backface-visibility:hidden;backface-visibility:hidden;-webkit-perspective:1000px;perspective:1000px}.carousel-inner>.item.active.right,.carousel-inner>.item.next{left:0;-webkit-transform:translate3d(100%,0,0);transform:translate3d(100%,0,0)}.carousel-inner>.item.active.left,.carousel-inner>.item.prev{left:0;-webkit-transform:translate3d(-100%,0,0);transform:translate3d(-100%,0,0)}.carousel-inner>.item.active,.carousel-inner>.item.next.left,.carousel-inner>.item.prev.right{left:0;-webkit-transform:translate3d(0,0,0);transform:translate3d(0,0,0)}}.carousel-inner>.active,.carousel-inner>.next,.carousel-inner>.prev{display:block}.carousel-inner>.active{left:0}.carousel-inner>.next,.carousel-inner>.prev{position:absolute;top:0;width:100%}.carousel-inner>.next{left:100%}.carousel-inner>.prev{left:-100%}.carousel-inner>.next.left,.carousel-inner>.prev.right{left:0}.carousel-inner>.active.left{left:-100%}.carousel-inner>.active.right{left:100%}.carousel-control{position:absolute;top:0;bottom:0;left:0;width:15%;font-size:20px;color:#fff;text-align:center;text-shadow:0 1px 2px rgba(0,0,0,.6);filter:alpha(opacity=50);opacity:.5}.carousel-control.left{background-image:-webkit-linear-gradient(left,rgba(0,0,0,.5) 0,rgba(0,0,0,.0001) 100%);background-image:-o-linear-gradient(left,rgba(0,0,0,.5) 0,rgba(0,0,0,.0001) 100%);background-image:-webkit-gradient(linear,left top,right top,from(rgba(0,0,0,.5)),to(rgba(0,0,0,.0001)));background-image:linear-gradient(to right,rgba(0,0,0,.5) 0,rgba(0,0,0,.0001) 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#80000000', endColorstr='#00000000', GradientType=1);background-repeat:repeat-x}.carousel-control.right{right:0;left:auto;background-image:-webkit-linear-gradient(left,rgba(0,0,0,.0001) 0,rgba(0,0,0,.5) 100%);background-image:-o-linear-gradient(left,rgba(0,0,0,.0001) 0,rgba(0,0,0,.5) 100%);background-image:-webkit-gradient(linear,left top,right top,from(rgba(0,0,0,.0001)),to(rgba(0,0,0,.5)));background-image:linear-gradient(to right,rgba(0,0,0,.0001) 0,rgba(0,0,0,.5) 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#00000000', endColorstr='#80000000', GradientType=1);background-repeat:repeat-x}.carousel-control:focus,.carousel-control:hover{color:#fff;text-decoration:none;filter:alpha(opacity=90);outline:0;opacity:.9}.carousel-control .glyphicon-chevron-left,.carousel-control .glyphicon-chevron-right,.carousel-control .icon-next,.carousel-control .icon-prev{position:absolute;top:50%;z-index:5;display:inline-block;margin-top:-10px}.carousel-control .glyphicon-chevron-left,.carousel-control .icon-prev{left:50%;margin-left:-10px}.carousel-control .glyphicon-chevron-right,.carousel-control .icon-next{right:50%;margin-right:-10px}.carousel-control .icon-next,.carousel-control .icon-prev{width:20px;height:20px;font-family:serif;line-height:1}.carousel-control .icon-prev:before{content:'\2039'}.carousel-control .icon-next:before{content:'\203a'}.carousel-indicators{position:absolute;bottom:10px;left:50%;z-index:15;width:60%;padding-left:0;margin-left:-30%;text-align:center;list-style:none}.carousel-indicators li{display:inline-block;width:10px;height:10px;margin:1px;text-indent:-999px;cursor:pointer;background-color:#000\9;background-color:rgba(0,0,0,0);border:1px solid #fff;border-radius:10px}.carousel-indicators .active{width:12px;height:12px;margin:0;background-color:#fff}.carousel-caption{position:absolute;right:15%;bottom:20px;left:15%;z-index:10;padding-top:20px;padding-bottom:20px;color:#fff;text-align:center;text-shadow:0 1px 2px rgba(0,0,0,.6)}.carousel-caption .btn{text-shadow:none}@media screen and (min-width:768px){.carousel-control .glyphicon-chevron-left,.carousel-control .glyphicon-chevron-right,.carousel-control .icon-next,.carousel-control .icon-prev{width:30px;height:30px;margin-top:-15px;font-size:30px}.carousel-control .glyphicon-chevron-left,.carousel-control .icon-prev{margin-left:-15px}.carousel-control .glyphicon-chevron-right,.carousel-control .icon-next{margin-right:-15px}.carousel-caption{right:20%;left:20%;padding-bottom:30px}.carousel-indicators{bottom:20px}}.btn-group-vertical>.btn-group:after,.btn-group-vertical>.btn-group:before,.btn-toolbar:after,.btn-toolbar:before,.clearfix:after,.clearfix:before,.container-fluid:after,.container-fluid:before,.container:after,.container:before,.dl-horizontal dd:after,.dl-horizontal dd:before,.form-horizontal .form-group:after,.form-horizontal .form-group:before,.modal-footer:after,.modal-footer:before,.nav:after,.nav:before,.navbar-collapse:after,.navbar-collapse:before,.navbar-header:after,.navbar-header:before,.navbar:after,.navbar:before,.pager:after,.pager:before,.panel-body:after,.panel-body:before,.row:after,.row:before{display:table;content:" "}.btn-group-vertical>.btn-group:after,.btn-toolbar:after,.clearfix:after,.container-fluid:after,.container:after,.dl-horizontal dd:after,.form-horizontal .form-group:after,.modal-footer:after,.nav:after,.navbar-collapse:after,.navbar-header:after,.navbar:after,.pager:after,.panel-body:after,.row:after{clear:both}.center-block{display:block;margin-right:auto;margin-left:auto}.pull-right{float:right!important}.pull-left{float:left!important}.hide{display:none!important}.show{display:block!important}.invisible{visibility:hidden}.text-hide{font:0/0 a;color:transparent;text-shadow:none;background-color:transparent;border:0}.hidden{display:none!important}.affix{position:fixed}@-ms-viewport{width:device-width}.visible-lg,.visible-md,.visible-sm,.visible-xs{display:none!important}.visible-lg-block,.visible-lg-inline,.visible-lg-inline-block,.visible-md-block,.visible-md-inline,.visible-md-inline-block,.visible-sm-block,.visible-sm-inline,.visible-sm-inline-block,.visible-xs-block,.visible-xs-inline,.visible-xs-inline-block{display:none!important}@media (max-width:767px){.visible-xs{display:block!important}table.visible-xs{display:table!important}tr.visible-xs{display:table-row!important}td.visible-xs,th.visible-xs{display:table-cell!important}}@media (max-width:767px){.visible-xs-block{display:block!important}}@media (max-width:767px){.visible-xs-inline{display:inline!important}}@media (max-width:767px){.visible-xs-inline-block{display:inline-block!important}}@media (min-width:768px) and (max-width:991px){.visible-sm{display:block!important}table.visible-sm{display:table!important}tr.visible-sm{display:table-row!important}td.visible-sm,th.visible-sm{display:table-cell!important}}@media (min-width:768px) and (max-width:991px){.visible-sm-block{display:block!important}}@media (min-width:768px) and (max-width:991px){.visible-sm-inline{display:inline!important}}@media (min-width:768px) and (max-width:991px){.visible-sm-inline-block{display:inline-block!important}}@media (min-width:992px) and (max-width:1199px){.visible-md{display:block!important}table.visible-md{display:table!important}tr.visible-md{display:table-row!important}td.visible-md,th.visible-md{display:table-cell!important}}@media (min-width:992px) and (max-width:1199px){.visible-md-block{display:block!important}}@media (min-width:992px) and (max-width:1199px){.visible-md-inline{display:inline!important}}@media (min-width:992px) and (max-width:1199px){.visible-md-inline-block{display:inline-block!important}}@media (min-width:1200px){.visible-lg{display:block!important}table.visible-lg{display:table!important}tr.visible-lg{display:table-row!important}td.visible-lg,th.visible-lg{display:table-cell!important}}@media (min-width:1200px){.visible-lg-block{display:block!important}}@media (min-width:1200px){.visible-lg-inline{display:inline!important}}@media (min-width:1200px){.visible-lg-inline-block{display:inline-block!important}}@media (max-width:767px){.hidden-xs{display:none!important}}@media (min-width:768px) and (max-width:991px){.hidden-sm{display:none!important}}@media (min-width:992px) and (max-width:1199px){.hidden-md{display:none!important}}@media (min-width:1200px){.hidden-lg{display:none!important}}.visible-print{display:none!important}@media print{.visible-print{display:block!important}table.visible-print{display:table!important}tr.visible-print{display:table-row!important}td.visible-print,th.visible-print{display:table-cell!important}}.visible-print-block{display:none!important}@media print{.visible-print-block{display:block!important}}.visible-print-inline{display:none!important}@media print{.visible-print-inline{display:inline!important}}.visible-print-inline-block{display:none!important}@media print{.visible-print-inline-block{display:inline-block!important}}@media print{.hidden-print{display:none!important}}
|
7 |
|
8 |
|
9 |
/*
|
@@ -121,11 +121,11 @@ div.dataTables_scrollFoot table {
|
|
121 |
border-top: none;
|
122 |
margin-top: 0 !important;
|
123 |
}
|
124 |
-
.table > tbody > tr > td small,
|
125 |
-
.table > tbody > tr > th small,
|
126 |
-
.table > tfoot > tr > td small,
|
127 |
-
.table > tfoot > tr > th small,
|
128 |
-
.table > thead > tr > td small,
|
129 |
.table > thead > tr > th small{
|
130 |
line-height: 1.2em;
|
131 |
display: block;
|
3 |
* Copyright 2011-2015 Twitter, Inc.
|
4 |
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
|
5 |
*//*! normalize.css v3.0.3 | MIT License | github.com/necolas/normalize.css */
|
6 |
+
html{font-family:sans-serif;-webkit-text-size-adjust:100%;-ms-text-size-adjust:100%}body{margin:0}article,aside,details,figcaption,figure,footer,header,hgroup,main,menu,nav,section,summary{display:block}audio,canvas,progress,video{display:inline-block;vertical-align:baseline}audio:not([controls]){display:none;height:0}[hidden],template{display:none}a{background-color:transparent}a:active,a:hover{outline:0}abbr[title]{border-bottom:1px dotted}b,strong{font-weight:700}dfn{font-style:italic}h1{margin:.67em 0;font-size:2em}mark{color:#000;background:#ff0}small{font-size:80%}sub,sup{position:relative;font-size:75%;line-height:0;vertical-align:baseline}sup{top:-.5em}sub{bottom:-.25em}img{border:0}svg:not(:root){overflow:hidden}figure{margin:1em 40px}hr{height:0;-webkit-box-sizing:content-box;-moz-box-sizing:content-box;box-sizing:content-box}pre{overflow:auto}code,kbd,pre,samp{font-family:monospace,monospace;font-size:1em}button,input,optgroup,select,textarea{margin:0;font:inherit;color:inherit}button{overflow:visible}button,select{text-transform:none}button,html input[type=button],input[type=reset],input[type=submit]{-webkit-appearance:button;cursor:pointer}button[disabled],html input[disabled]{cursor:default}button::-moz-focus-inner,input::-moz-focus-inner{padding:0;border:0}input{line-height:normal}input[type=checkbox],input[type=radio]{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;padding:0}input[type=number]::-webkit-inner-spin-button,input[type=number]::-webkit-outer-spin-button{height:auto}input[type=search]{-webkit-box-sizing:content-box;-moz-box-sizing:content-box;box-sizing:content-box;-webkit-appearance:textfield}input[type=search]::-webkit-search-cancel-button,input[type=search]::-webkit-search-decoration{-webkit-appearance:none}fieldset{padding:.35em .625em .75em;margin:0 2px;border:1px solid silver}legend{padding:0;border:0}textarea{overflow:auto}optgroup{font-weight:700}table{border-spacing:0;border-collapse:collapse}td,th{padding:0}/*! Source: https://github.com/h5bp/html5-boilerplate/blob/master/src/css/main.css */@media print{*,:after,:before{color:#000!important;text-shadow:none!important;background:0 0!important;-webkit-box-shadow:none!important;box-shadow:none!important}a,a:visited{text-decoration:underline}a[href]:after{content:" (" attr(href) ")"}abbr[title]:after{content:" (" attr(title) ")"}a[href^="javascript:"]:after,a[href^="#"]:after{content:""}blockquote,pre{border:1px solid #999;page-break-inside:avoid}thead{display:table-header-group}img,tr{page-break-inside:avoid}img{max-width:100%!important}h2,h3,p{orphans:3;widows:3}h2,h3{page-break-after:avoid}.navbar{display:none}.btn>.caret,.dropup>.btn>.caret{border-top-color:#000!important}.label{border:1px solid #000}.table{border-collapse:collapse!important}.table td,.table th{background-color:#fff!important}.table-bordered td,.table-bordered th{border:1px solid #ddd!important}}@font-face{font-family:'Glyphicons Halflings';src:url(../fonts/glyphicons-halflings-regular.eot);src:url(../fonts/glyphicons-halflings-regular.eot?#iefix) format('embedded-opentype'),url(../fonts/glyphicons-halflings-regular.woff2) format('woff2'),url(../fonts/glyphicons-halflings-regular.woff) format('woff'),url(../fonts/glyphicons-halflings-regular.ttf) format('truetype'),url(../fonts/glyphicons-halflings-regular.svg#glyphicons_halflingsregular) format('svg')}.glyphicon{position:relative;top:1px;display:inline-block;font-family:'Glyphicons Halflings';font-style:normal;font-weight:400;line-height:1;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}.glyphicon-asterisk:before{content:"\2a"}.glyphicon-plus:before{content:"\2b"}.glyphicon-eur:before,.glyphicon-euro:before{content:"\20ac"}.glyphicon-minus:before{content:"\2212"}.glyphicon-cloud:before{content:"\2601"}.glyphicon-envelope:before{content:"\2709"}.glyphicon-pencil:before{content:"\270f"}.glyphicon-glass:before{content:"\e001"}.glyphicon-music:before{content:"\e002"}.glyphicon-search:before{content:"\e003"}.glyphicon-heart:before{content:"\e005"}.glyphicon-star:before{content:"\e006"}.glyphicon-star-empty:before{content:"\e007"}.glyphicon-user:before{content:"\e008"}.glyphicon-film:before{content:"\e009"}.glyphicon-th-large:before{content:"\e010"}.glyphicon-th:before{content:"\e011"}.glyphicon-th-list:before{content:"\e012"}.glyphicon-ok:before{content:"\e013"}.glyphicon-remove:before{content:"\e014"}.glyphicon-zoom-in:before{content:"\e015"}.glyphicon-zoom-out:before{content:"\e016"}.glyphicon-off:before{content:"\e017"}.glyphicon-signal:before{content:"\e018"}.glyphicon-cog:before{content:"\e019"}.glyphicon-trash:before{content:"\e020"}.glyphicon-home:before{content:"\e021"}.glyphicon-file:before{content:"\e022"}.glyphicon-time:before{content:"\e023"}.glyphicon-road:before{content:"\e024"}.glyphicon-download-alt:before{content:"\e025"}.glyphicon-download:before{content:"\e026"}.glyphicon-upload:before{content:"\e027"}.glyphicon-inbox:before{content:"\e028"}.glyphicon-play-circle:before{content:"\e029"}.glyphicon-repeat:before{content:"\e030"}.glyphicon-refresh:before{content:"\e031"}.glyphicon-list-alt:before{content:"\e032"}.glyphicon-lock:before{content:"\e033"}.glyphicon-flag:before{content:"\e034"}.glyphicon-headphones:before{content:"\e035"}.glyphicon-volume-off:before{content:"\e036"}.glyphicon-volume-down:before{content:"\e037"}.glyphicon-volume-up:before{content:"\e038"}.glyphicon-qrcode:before{content:"\e039"}.glyphicon-barcode:before{content:"\e040"}.glyphicon-tag:before{content:"\e041"}.glyphicon-tags:before{content:"\e042"}.glyphicon-book:before{content:"\e043"}.glyphicon-bookmark:before{content:"\e044"}.glyphicon-print:before{content:"\e045"}.glyphicon-camera:before{content:"\e046"}.glyphicon-font:before{content:"\e047"}.glyphicon-bold:before{content:"\e048"}.glyphicon-italic:before{content:"\e049"}.glyphicon-text-height:before{content:"\e050"}.glyphicon-text-width:before{content:"\e051"}.glyphicon-align-left:before{content:"\e052"}.glyphicon-align-center:before{content:"\e053"}.glyphicon-align-right:before{content:"\e054"}.glyphicon-align-justify:before{content:"\e055"}.glyphicon-list:before{content:"\e056"}.glyphicon-indent-left:before{content:"\e057"}.glyphicon-indent-right:before{content:"\e058"}.glyphicon-facetime-video:before{content:"\e059"}.glyphicon-picture:before{content:"\e060"}.glyphicon-map-marker:before{content:"\e062"}.glyphicon-adjust:before{content:"\e063"}.glyphicon-tint:before{content:"\e064"}.glyphicon-edit:before{content:"\e065"}.glyphicon-share:before{content:"\e066"}.glyphicon-check:before{content:"\e067"}.glyphicon-move:before{content:"\e068"}.glyphicon-step-backward:before{content:"\e069"}.glyphicon-fast-backward:before{content:"\e070"}.glyphicon-backward:before{content:"\e071"}.glyphicon-play:before{content:"\e072"}.glyphicon-pause:before{content:"\e073"}.glyphicon-stop:before{content:"\e074"}.glyphicon-forward:before{content:"\e075"}.glyphicon-fast-forward:before{content:"\e076"}.glyphicon-step-forward:before{content:"\e077"}.glyphicon-eject:before{content:"\e078"}.glyphicon-chevron-left:before{content:"\e079"}.glyphicon-chevron-right:before{content:"\e080"}.glyphicon-plus-sign:before{content:"\e081"}.glyphicon-minus-sign:before{content:"\e082"}.glyphicon-remove-sign:before{content:"\e083"}.glyphicon-ok-sign:before{content:"\e084"}.glyphicon-question-sign:before{content:"\e085"}.glyphicon-info-sign:before{content:"\e086"}.glyphicon-screenshot:before{content:"\e087"}.glyphicon-remove-circle:before{content:"\e088"}.glyphicon-ok-circle:before{content:"\e089"}.glyphicon-ban-circle:before{content:"\e090"}.glyphicon-arrow-left:before{content:"\e091"}.glyphicon-arrow-right:before{content:"\e092"}.glyphicon-arrow-up:before{content:"\e093"}.glyphicon-arrow-down:before{content:"\e094"}.glyphicon-share-alt:before{content:"\e095"}.glyphicon-resize-full:before{content:"\e096"}.glyphicon-resize-small:before{content:"\e097"}.glyphicon-exclamation-sign:before{content:"\e101"}.glyphicon-gift:before{content:"\e102"}.glyphicon-leaf:before{content:"\e103"}.glyphicon-fire:before{content:"\e104"}.glyphicon-eye-open:before{content:"\e105"}.glyphicon-eye-close:before{content:"\e106"}.glyphicon-warning-sign:before{content:"\e107"}.glyphicon-plane:before{content:"\e108"}.glyphicon-calendar:before{content:"\e109"}.glyphicon-random:before{content:"\e110"}.glyphicon-comment:before{content:"\e111"}.glyphicon-magnet:before{content:"\e112"}.glyphicon-chevron-up:before{content:"\e113"}.glyphicon-chevron-down:before{content:"\e114"}.glyphicon-retweet:before{content:"\e115"}.glyphicon-shopping-cart:before{content:"\e116"}.glyphicon-folder-close:before{content:"\e117"}.glyphicon-folder-open:before{content:"\e118"}.glyphicon-resize-vertical:before{content:"\e119"}.glyphicon-resize-horizontal:before{content:"\e120"}.glyphicon-hdd:before{content:"\e121"}.glyphicon-bullhorn:before{content:"\e122"}.glyphicon-bell:before{content:"\e123"}.glyphicon-certificate:before{content:"\e124"}.glyphicon-thumbs-up:before{content:"\e125"}.glyphicon-thumbs-down:before{content:"\e126"}.glyphicon-hand-right:before{content:"\e127"}.glyphicon-hand-left:before{content:"\e128"}.glyphicon-hand-up:before{content:"\e129"}.glyphicon-hand-down:before{content:"\e130"}.glyphicon-circle-arrow-right:before{content:"\e131"}.glyphicon-circle-arrow-left:before{content:"\e132"}.glyphicon-circle-arrow-up:before{content:"\e133"}.glyphicon-circle-arrow-down:before{content:"\e134"}.glyphicon-globe:before{content:"\e135"}.glyphicon-wrench:before{content:"\e136"}.glyphicon-tasks:before{content:"\e137"}.glyphicon-filter:before{content:"\e138"}.glyphicon-briefcase:before{content:"\e139"}.glyphicon-fullscreen:before{content:"\e140"}.glyphicon-dashboard:before{content:"\e141"}.glyphicon-paperclip:before{content:"\e142"}.glyphicon-heart-empty:before{content:"\e143"}.glyphicon-link:before{content:"\e144"}.glyphicon-phone:before{content:"\e145"}.glyphicon-pushpin:before{content:"\e146"}.glyphicon-usd:before{content:"\e148"}.glyphicon-gbp:before{content:"\e149"}.glyphicon-sort:before{content:"\e150"}.glyphicon-sort-by-alphabet:before{content:"\e151"}.glyphicon-sort-by-alphabet-alt:before{content:"\e152"}.glyphicon-sort-by-order:before{content:"\e153"}.glyphicon-sort-by-order-alt:before{content:"\e154"}.glyphicon-sort-by-attributes:before{content:"\e155"}.glyphicon-sort-by-attributes-alt:before{content:"\e156"}.glyphicon-unchecked:before{content:"\e157"}.glyphicon-expand:before{content:"\e158"}.glyphicon-collapse-down:before{content:"\e159"}.glyphicon-collapse-up:before{content:"\e160"}.glyphicon-log-in:before{content:"\e161"}.glyphicon-flash:before{content:"\e162"}.glyphicon-log-out:before{content:"\e163"}.glyphicon-new-window:before{content:"\e164"}.glyphicon-record:before{content:"\e165"}.glyphicon-save:before{content:"\e166"}.glyphicon-open:before{content:"\e167"}.glyphicon-saved:before{content:"\e168"}.glyphicon-import:before{content:"\e169"}.glyphicon-export:before{content:"\e170"}.glyphicon-send:before{content:"\e171"}.glyphicon-floppy-disk:before{content:"\e172"}.glyphicon-floppy-saved:before{content:"\e173"}.glyphicon-floppy-remove:before{content:"\e174"}.glyphicon-floppy-save:before{content:"\e175"}.glyphicon-floppy-open:before{content:"\e176"}.glyphicon-credit-card:before{content:"\e177"}.glyphicon-transfer:before{content:"\e178"}.glyphicon-cutlery:before{content:"\e179"}.glyphicon-header:before{content:"\e180"}.glyphicon-compressed:before{content:"\e181"}.glyphicon-earphone:before{content:"\e182"}.glyphicon-phone-alt:before{content:"\e183"}.glyphicon-tower:before{content:"\e184"}.glyphicon-stats:before{content:"\e185"}.glyphicon-sd-video:before{content:"\e186"}.glyphicon-hd-video:before{content:"\e187"}.glyphicon-subtitles:before{content:"\e188"}.glyphicon-sound-stereo:before{content:"\e189"}.glyphicon-sound-dolby:before{content:"\e190"}.glyphicon-sound-5-1:before{content:"\e191"}.glyphicon-sound-6-1:before{content:"\e192"}.glyphicon-sound-7-1:before{content:"\e193"}.glyphicon-copyright-mark:before{content:"\e194"}.glyphicon-registration-mark:before{content:"\e195"}.glyphicon-cloud-download:before{content:"\e197"}.glyphicon-cloud-upload:before{content:"\e198"}.glyphicon-tree-conifer:before{content:"\e199"}.glyphicon-tree-deciduous:before{content:"\e200"}.glyphicon-cd:before{content:"\e201"}.glyphicon-save-file:before{content:"\e202"}.glyphicon-open-file:before{content:"\e203"}.glyphicon-level-up:before{content:"\e204"}.glyphicon-copy:before{content:"\e205"}.glyphicon-paste:before{content:"\e206"}.glyphicon-alert:before{content:"\e209"}.glyphicon-equalizer:before{content:"\e210"}.glyphicon-king:before{content:"\e211"}.glyphicon-queen:before{content:"\e212"}.glyphicon-pawn:before{content:"\e213"}.glyphicon-bishop:before{content:"\e214"}.glyphicon-knight:before{content:"\e215"}.glyphicon-baby-formula:before{content:"\e216"}.glyphicon-tent:before{content:"\26fa"}.glyphicon-blackboard:before{content:"\e218"}.glyphicon-bed:before{content:"\e219"}.glyphicon-apple:before{content:"\f8ff"}.glyphicon-erase:before{content:"\e221"}.glyphicon-hourglass:before{content:"\231b"}.glyphicon-lamp:before{content:"\e223"}.glyphicon-duplicate:before{content:"\e224"}.glyphicon-piggy-bank:before{content:"\e225"}.glyphicon-scissors:before{content:"\e226"}.glyphicon-bitcoin:before{content:"\e227"}.glyphicon-btc:before{content:"\e227"}.glyphicon-xbt:before{content:"\e227"}.glyphicon-yen:before{content:"\00a5"}.glyphicon-jpy:before{content:"\00a5"}.glyphicon-ruble:before{content:"\20bd"}.glyphicon-rub:before{content:"\20bd"}.glyphicon-scale:before{content:"\e230"}.glyphicon-ice-lolly:before{content:"\e231"}.glyphicon-ice-lolly-tasted:before{content:"\e232"}.glyphicon-education:before{content:"\e233"}.glyphicon-option-horizontal:before{content:"\e234"}.glyphicon-option-vertical:before{content:"\e235"}.glyphicon-menu-hamburger:before{content:"\e236"}.glyphicon-modal-window:before{content:"\e237"}.glyphicon-oil:before{content:"\e238"}.glyphicon-grain:before{content:"\e239"}.glyphicon-sunglasses:before{content:"\e240"}.glyphicon-text-size:before{content:"\e241"}.glyphicon-text-color:before{content:"\e242"}.glyphicon-text-background:before{content:"\e243"}.glyphicon-object-align-top:before{content:"\e244"}.glyphicon-object-align-bottom:before{content:"\e245"}.glyphicon-object-align-horizontal:before{content:"\e246"}.glyphicon-object-align-left:before{content:"\e247"}.glyphicon-object-align-vertical:before{content:"\e248"}.glyphicon-object-align-right:before{content:"\e249"}.glyphicon-triangle-right:before{content:"\e250"}.glyphicon-triangle-left:before{content:"\e251"}.glyphicon-triangle-bottom:before{content:"\e252"}.glyphicon-triangle-top:before{content:"\e253"}.glyphicon-console:before{content:"\e254"}.glyphicon-superscript:before{content:"\e255"}.glyphicon-subscript:before{content:"\e256"}.glyphicon-menu-left:before{content:"\e257"}.glyphicon-menu-right:before{content:"\e258"}.glyphicon-menu-down:before{content:"\e259"}.glyphicon-menu-up:before{content:"\e260"}*{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}:after,:before{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}html{font-size:10px;-webkit-tap-highlight-color:rgba(0,0,0,0)}body{font-family:"Helvetica Neue",Helvetica,Arial,sans-serif;font-size:14px;line-height:1.42857143;color:#333;background-color:#fff}button,input,select,textarea{font-family:inherit;font-size:inherit;line-height:inherit}a{color:#337ab7;text-decoration:none}a:focus,a:hover{color:#23527c;text-decoration:underline}a:focus{outline:thin dotted;outline:5px auto -webkit-focus-ring-color;outline-offset:-2px}figure{margin:0}img{vertical-align:middle}.carousel-inner>.item>a>img,.carousel-inner>.item>img,.img-responsive,.thumbnail a>img,.thumbnail>img{display:block;max-width:100%;height:auto}.img-rounded{border-radius:6px}.img-thumbnail{display:inline-block;max-width:100%;height:auto;padding:4px;line-height:1.42857143;background-color:#fff;border:1px solid #ddd;border-radius:4px;-webkit-transition:all .2s ease-in-out;-o-transition:all .2s ease-in-out;transition:all .2s ease-in-out}.img-circle{border-radius:50%}hr{margin-top:20px;margin-bottom:20px;border:0;border-top:1px solid #eee}.sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);border:0}.sr-only-focusable:active,.sr-only-focusable:focus{position:static;width:auto;height:auto;margin:0;overflow:visible;clip:auto}[role=button]{cursor:pointer}.h1,.h2,.h3,.h4,.h5,.h6,h1,h2,h3,h4,h5,h6{font-family:inherit;font-weight:500;line-height:1.1;color:inherit}.h1 .small,.h1 small,.h2 .small,.h2 small,.h3 .small,.h3 small,.h4 .small,.h4 small,.h5 .small,.h5 small,.h6 .small,.h6 small,h1 .small,h1 small,h2 .small,h2 small,h3 .small,h3 small,h4 .small,h4 small,h5 .small,h5 small,h6 .small,h6 small{font-weight:400;line-height:1;color:#777}.h1,.h2,.h3,h1,h2,h3{margin-top:20px;margin-bottom:10px}.h1 .small,.h1 small,.h2 .small,.h2 small,.h3 .small,.h3 small,h1 .small,h1 small,h2 .small,h2 small,h3 .small,h3 small{font-size:65%}.h4,.h5,.h6,h4,h5,h6{margin-top:10px;margin-bottom:10px}.h4 .small,.h4 small,.h5 .small,.h5 small,.h6 .small,.h6 small,h4 .small,h4 small,h5 .small,h5 small,h6 .small,h6 small{font-size:75%}.h1,h1{font-size:36px}.h2,h2{font-size:30px}.h3,h3{font-size:24px}.h4,h4{font-size:18px}.h5,h5{font-size:14px}.h6,h6{font-size:12px}p{margin:0 0 10px}.lead{margin-bottom:20px;font-size:16px;font-weight:300;line-height:1.4}@media (min-width:768px){.lead{font-size:21px}}.small,small{font-size:85%}.mark,mark{padding:.2em;background-color:#fcf8e3}.text-left{text-align:left}.text-right{text-align:right}.text-center{text-align:center}.text-justify{text-align:justify}.text-nowrap{white-space:nowrap}.text-lowercase{text-transform:lowercase}.text-uppercase{text-transform:uppercase}.text-capitalize{text-transform:capitalize}.text-muted{color:#777}.text-primary{color:#337ab7}a.text-primary:focus,a.text-primary:hover{color:#286090}.text-success{color:#3c763d}a.text-success:focus,a.text-success:hover{color:#2b542c}.text-info{color:#31708f}a.text-info:focus,a.text-info:hover{color:#245269}.text-warning{color:#8a6d3b}a.text-warning:focus,a.text-warning:hover{color:#66512c}.text-danger{color:#a94442}a.text-danger:focus,a.text-danger:hover{color:#843534}.bg-primary{color:#fff;background-color:#337ab7}a.bg-primary:focus,a.bg-primary:hover{background-color:#286090}.bg-success{background-color:#dff0d8}a.bg-success:focus,a.bg-success:hover{background-color:#c1e2b3}.bg-info{background-color:#d9edf7}a.bg-info:focus,a.bg-info:hover{background-color:#afd9ee}.bg-warning{background-color:#fcf8e3}a.bg-warning:focus,a.bg-warning:hover{background-color:#f7ecb5}.bg-danger{background-color:#f2dede}a.bg-danger:focus,a.bg-danger:hover{background-color:#e4b9b9}.page-header{padding-bottom:9px;margin:40px 0 20px;border-bottom:1px solid #eee}ol,ul{margin-top:0;margin-bottom:10px}ol ol,ol ul,ul ol,ul ul{margin-bottom:0}.list-unstyled{padding-left:0;list-style:none}.list-inline{padding-left:0;margin-left:-5px;list-style:none}.list-inline>li{display:inline-block;padding-right:5px;padding-left:5px}dl{margin-top:0;margin-bottom:20px}dd,dt{line-height:1.42857143}dt{font-weight:700}dd{margin-left:0}@media (min-width:768px){.dl-horizontal dt{float:left;width:160px;overflow:hidden;clear:left;text-align:right;text-overflow:ellipsis;white-space:nowrap}.dl-horizontal dd{margin-left:180px}}abbr[data-original-title],abbr[title]{cursor:help;border-bottom:1px dotted #777}.initialism{font-size:90%;text-transform:uppercase}blockquote{padding:10px 20px;margin:0 0 20px;font-size:17.5px;border-left:5px solid #eee}blockquote ol:last-child,blockquote p:last-child,blockquote ul:last-child{margin-bottom:0}blockquote .small,blockquote footer,blockquote small{display:block;font-size:80%;line-height:1.42857143;color:#777}blockquote .small:before,blockquote footer:before,blockquote small:before{content:'\2014 \00A0'}.blockquote-reverse,blockquote.pull-right{padding-right:15px;padding-left:0;text-align:right;border-right:5px solid #eee;border-left:0}.blockquote-reverse .small:before,.blockquote-reverse footer:before,.blockquote-reverse small:before,blockquote.pull-right .small:before,blockquote.pull-right footer:before,blockquote.pull-right small:before{content:''}.blockquote-reverse .small:after,.blockquote-reverse footer:after,.blockquote-reverse small:after,blockquote.pull-right .small:after,blockquote.pull-right footer:after,blockquote.pull-right small:after{content:'\00A0 \2014'}address{margin-bottom:20px;font-style:normal;line-height:1.42857143}code,kbd,pre,samp{font-family:Menlo,Monaco,Consolas,"Courier New",monospace}code{padding:2px 4px;font-size:90%;color:#c7254e;background-color:#f9f2f4;border-radius:4px}kbd{padding:2px 4px;font-size:90%;color:#fff;background-color:#333;border-radius:3px;-webkit-box-shadow:inset 0 -1px 0 rgba(0,0,0,.25);box-shadow:inset 0 -1px 0 rgba(0,0,0,.25)}kbd kbd{padding:0;font-size:100%;font-weight:700;-webkit-box-shadow:none;box-shadow:none}pre{display:block;padding:9.5px;margin:0 0 10px;font-size:13px;line-height:1.42857143;color:#333;word-break:break-all;word-wrap:break-word;background-color:#f5f5f5;border:1px solid #ccc;border-radius:4px}pre code{padding:0;font-size:inherit;color:inherit;white-space:pre-wrap;background-color:transparent;border-radius:0}.pre-scrollable{max-height:340px;overflow-y:scroll}.container{padding-right:15px;padding-left:15px;margin-right:auto;margin-left:auto}@media (min-width:768px){.container{width:750px}}@media (min-width:992px){.container{width:970px}}@media (min-width:1200px){.container{width:1170px}}.container-fluid{padding-right:15px;padding-left:15px;margin-right:auto;margin-left:auto}.row{margin-right:-15px;margin-left:-15px}.col-lg-1,.col-lg-10,.col-lg-11,.col-lg-12,.col-lg-2,.col-lg-3,.col-lg-4,.col-lg-5,.col-lg-6,.col-lg-7,.col-lg-8,.col-lg-9,.col-md-1,.col-md-10,.col-md-11,.col-md-12,.col-md-2,.col-md-3,.col-md-4,.col-md-5,.col-md-6,.col-md-7,.col-md-8,.col-md-9,.col-sm-1,.col-sm-10,.col-sm-11,.col-sm-12,.col-sm-2,.col-sm-3,.col-sm-4,.col-sm-5,.col-sm-6,.col-sm-7,.col-sm-8,.col-sm-9,.col-xs-1,.col-xs-10,.col-xs-11,.col-xs-12,.col-xs-2,.col-xs-3,.col-xs-4,.col-xs-5,.col-xs-6,.col-xs-7,.col-xs-8,.col-xs-9{position:relative;min-height:1px;padding-right:15px;padding-left:15px}.col-xs-1,.col-xs-10,.col-xs-11,.col-xs-12,.col-xs-2,.col-xs-3,.col-xs-4,.col-xs-5,.col-xs-6,.col-xs-7,.col-xs-8,.col-xs-9{float:left}.col-xs-12{width:100%}.col-xs-11{width:91.66666667%}.col-xs-10{width:83.33333333%}.col-xs-9{width:75%}.col-xs-8{width:66.66666667%}.col-xs-7{width:58.33333333%}.col-xs-6{width:50%}.col-xs-5{width:41.66666667%}.col-xs-4{width:33.33333333%}.col-xs-3{width:25%}.col-xs-2{width:16.66666667%}.col-xs-1{width:8.33333333%}.col-xs-pull-12{right:100%}.col-xs-pull-11{right:91.66666667%}.col-xs-pull-10{right:83.33333333%}.col-xs-pull-9{right:75%}.col-xs-pull-8{right:66.66666667%}.col-xs-pull-7{right:58.33333333%}.col-xs-pull-6{right:50%}.col-xs-pull-5{right:41.66666667%}.col-xs-pull-4{right:33.33333333%}.col-xs-pull-3{right:25%}.col-xs-pull-2{right:16.66666667%}.col-xs-pull-1{right:8.33333333%}.col-xs-pull-0{right:auto}.col-xs-push-12{left:100%}.col-xs-push-11{left:91.66666667%}.col-xs-push-10{left:83.33333333%}.col-xs-push-9{left:75%}.col-xs-push-8{left:66.66666667%}.col-xs-push-7{left:58.33333333%}.col-xs-push-6{left:50%}.col-xs-push-5{left:41.66666667%}.col-xs-push-4{left:33.33333333%}.col-xs-push-3{left:25%}.col-xs-push-2{left:16.66666667%}.col-xs-push-1{left:8.33333333%}.col-xs-push-0{left:auto}.col-xs-offset-12{margin-left:100%}.col-xs-offset-11{margin-left:91.66666667%}.col-xs-offset-10{margin-left:83.33333333%}.col-xs-offset-9{margin-left:75%}.col-xs-offset-8{margin-left:66.66666667%}.col-xs-offset-7{margin-left:58.33333333%}.col-xs-offset-6{margin-left:50%}.col-xs-offset-5{margin-left:41.66666667%}.col-xs-offset-4{margin-left:33.33333333%}.col-xs-offset-3{margin-left:25%}.col-xs-offset-2{margin-left:16.66666667%}.col-xs-offset-1{margin-left:8.33333333%}.col-xs-offset-0{margin-left:0}@media (min-width:768px){.col-sm-1,.col-sm-10,.col-sm-11,.col-sm-12,.col-sm-2,.col-sm-3,.col-sm-4,.col-sm-5,.col-sm-6,.col-sm-7,.col-sm-8,.col-sm-9{float:left}.col-sm-12{width:100%}.col-sm-11{width:91.66666667%}.col-sm-10{width:83.33333333%}.col-sm-9{width:75%}.col-sm-8{width:66.66666667%}.col-sm-7{width:58.33333333%}.col-sm-6{width:50%}.col-sm-5{width:41.66666667%}.col-sm-4{width:33.33333333%}.col-sm-3{width:25%}.col-sm-2{width:16.66666667%}.col-sm-1{width:8.33333333%}.col-sm-pull-12{right:100%}.col-sm-pull-11{right:91.66666667%}.col-sm-pull-10{right:83.33333333%}.col-sm-pull-9{right:75%}.col-sm-pull-8{right:66.66666667%}.col-sm-pull-7{right:58.33333333%}.col-sm-pull-6{right:50%}.col-sm-pull-5{right:41.66666667%}.col-sm-pull-4{right:33.33333333%}.col-sm-pull-3{right:25%}.col-sm-pull-2{right:16.66666667%}.col-sm-pull-1{right:8.33333333%}.col-sm-pull-0{right:auto}.col-sm-push-12{left:100%}.col-sm-push-11{left:91.66666667%}.col-sm-push-10{left:83.33333333%}.col-sm-push-9{left:75%}.col-sm-push-8{left:66.66666667%}.col-sm-push-7{left:58.33333333%}.col-sm-push-6{left:50%}.col-sm-push-5{left:41.66666667%}.col-sm-push-4{left:33.33333333%}.col-sm-push-3{left:25%}.col-sm-push-2{left:16.66666667%}.col-sm-push-1{left:8.33333333%}.col-sm-push-0{left:auto}.col-sm-offset-12{margin-left:100%}.col-sm-offset-11{margin-left:91.66666667%}.col-sm-offset-10{margin-left:83.33333333%}.col-sm-offset-9{margin-left:75%}.col-sm-offset-8{margin-left:66.66666667%}.col-sm-offset-7{margin-left:58.33333333%}.col-sm-offset-6{margin-left:50%}.col-sm-offset-5{margin-left:41.66666667%}.col-sm-offset-4{margin-left:33.33333333%}.col-sm-offset-3{margin-left:25%}.col-sm-offset-2{margin-left:16.66666667%}.col-sm-offset-1{margin-left:8.33333333%}.col-sm-offset-0{margin-left:0}}@media (min-width:992px){.col-md-1,.col-md-10,.col-md-11,.col-md-12,.col-md-2,.col-md-3,.col-md-4,.col-md-5,.col-md-6,.col-md-7,.col-md-8,.col-md-9{float:left}.col-md-12{width:100%}.col-md-11{width:91.66666667%}.col-md-10{width:83.33333333%}.col-md-9{width:75%}.col-md-8{width:66.66666667%}.col-md-7{width:58.33333333%}.col-md-6{width:50%}.col-md-5{width:41.66666667%}.col-md-4{width:33.33333333%}.col-md-3{width:25%}.col-md-2{width:16.66666667%}.col-md-1{width:8.33333333%}.col-md-pull-12{right:100%}.col-md-pull-11{right:91.66666667%}.col-md-pull-10{right:83.33333333%}.col-md-pull-9{right:75%}.col-md-pull-8{right:66.66666667%}.col-md-pull-7{right:58.33333333%}.col-md-pull-6{right:50%}.col-md-pull-5{right:41.66666667%}.col-md-pull-4{right:33.33333333%}.col-md-pull-3{right:25%}.col-md-pull-2{right:16.66666667%}.col-md-pull-1{right:8.33333333%}.col-md-pull-0{right:auto}.col-md-push-12{left:100%}.col-md-push-11{left:91.66666667%}.col-md-push-10{left:83.33333333%}.col-md-push-9{left:75%}.col-md-push-8{left:66.66666667%}.col-md-push-7{left:58.33333333%}.col-md-push-6{left:50%}.col-md-push-5{left:41.66666667%}.col-md-push-4{left:33.33333333%}.col-md-push-3{left:25%}.col-md-push-2{left:16.66666667%}.col-md-push-1{left:8.33333333%}.col-md-push-0{left:auto}.col-md-offset-12{margin-left:100%}.col-md-offset-11{margin-left:91.66666667%}.col-md-offset-10{margin-left:83.33333333%}.col-md-offset-9{margin-left:75%}.col-md-offset-8{margin-left:66.66666667%}.col-md-offset-7{margin-left:58.33333333%}.col-md-offset-6{margin-left:50%}.col-md-offset-5{margin-left:41.66666667%}.col-md-offset-4{margin-left:33.33333333%}.col-md-offset-3{margin-left:25%}.col-md-offset-2{margin-left:16.66666667%}.col-md-offset-1{margin-left:8.33333333%}.col-md-offset-0{margin-left:0}}@media (min-width:1200px){.col-lg-1,.col-lg-10,.col-lg-11,.col-lg-12,.col-lg-2,.col-lg-3,.col-lg-4,.col-lg-5,.col-lg-6,.col-lg-7,.col-lg-8,.col-lg-9{float:left}.col-lg-12{width:100%}.col-lg-11{width:91.66666667%}.col-lg-10{width:83.33333333%}.col-lg-9{width:75%}.col-lg-8{width:66.66666667%}.col-lg-7{width:58.33333333%}.col-lg-6{width:50%}.col-lg-5{width:41.66666667%}.col-lg-4{width:33.33333333%}.col-lg-3{width:25%}.col-lg-2{width:16.66666667%}.col-lg-1{width:8.33333333%}.col-lg-pull-12{right:100%}.col-lg-pull-11{right:91.66666667%}.col-lg-pull-10{right:83.33333333%}.col-lg-pull-9{right:75%}.col-lg-pull-8{right:66.66666667%}.col-lg-pull-7{right:58.33333333%}.col-lg-pull-6{right:50%}.col-lg-pull-5{right:41.66666667%}.col-lg-pull-4{right:33.33333333%}.col-lg-pull-3{right:25%}.col-lg-pull-2{right:16.66666667%}.col-lg-pull-1{right:8.33333333%}.col-lg-pull-0{right:auto}.col-lg-push-12{left:100%}.col-lg-push-11{left:91.66666667%}.col-lg-push-10{left:83.33333333%}.col-lg-push-9{left:75%}.col-lg-push-8{left:66.66666667%}.col-lg-push-7{left:58.33333333%}.col-lg-push-6{left:50%}.col-lg-push-5{left:41.66666667%}.col-lg-push-4{left:33.33333333%}.col-lg-push-3{left:25%}.col-lg-push-2{left:16.66666667%}.col-lg-push-1{left:8.33333333%}.col-lg-push-0{left:auto}.col-lg-offset-12{margin-left:100%}.col-lg-offset-11{margin-left:91.66666667%}.col-lg-offset-10{margin-left:83.33333333%}.col-lg-offset-9{margin-left:75%}.col-lg-offset-8{margin-left:66.66666667%}.col-lg-offset-7{margin-left:58.33333333%}.col-lg-offset-6{margin-left:50%}.col-lg-offset-5{margin-left:41.66666667%}.col-lg-offset-4{margin-left:33.33333333%}.col-lg-offset-3{margin-left:25%}.col-lg-offset-2{margin-left:16.66666667%}.col-lg-offset-1{margin-left:8.33333333%}.col-lg-offset-0{margin-left:0}}table{background-color:transparent}caption{padding-top:8px;padding-bottom:8px;color:#777;text-align:left}th{text-align:left}.table{width:100%;max-width:100%;margin-bottom:20px}.table>tbody>tr>td,.table>tbody>tr>th,.table>tfoot>tr>td,.table>tfoot>tr>th,.table>thead>tr>td,.table>thead>tr>th{padding:8px;line-height:1.42857143;vertical-align:top;border-top:1px solid #ddd}.table>thead>tr>th{vertical-align:bottom;border-bottom:2px solid #ddd}.table>caption+thead>tr:first-child>td,.table>caption+thead>tr:first-child>th,.table>colgroup+thead>tr:first-child>td,.table>colgroup+thead>tr:first-child>th,.table>thead:first-child>tr:first-child>td,.table>thead:first-child>tr:first-child>th{border-top:0}.table>tbody+tbody{border-top:2px solid #ddd}.table .table{background-color:#fff}.table-condensed>tbody>tr>td,.table-condensed>tbody>tr>th,.table-condensed>tfoot>tr>td,.table-condensed>tfoot>tr>th,.table-condensed>thead>tr>td,.table-condensed>thead>tr>th{padding:5px}.table-bordered{border:1px solid #ddd}.table-bordered>tbody>tr>td,.table-bordered>tbody>tr>th,.table-bordered>tfoot>tr>td,.table-bordered>tfoot>tr>th,.table-bordered>thead>tr>td,.table-bordered>thead>tr>th{border:1px solid #ddd}.table-bordered>thead>tr>td,.table-bordered>thead>tr>th{border-bottom-width:2px}.table-striped>tbody>tr:nth-of-type(odd){background-color:#f9f9f9}.table-hover>tbody>tr:hover{background-color:#f5f5f5}table col[class*=col-]{position:static;display:table-column;float:none}table td[class*=col-],table th[class*=col-]{position:static;display:table-cell;float:none}.table>tbody>tr.active>td,.table>tbody>tr.active>th,.table>tbody>tr>td.active,.table>tbody>tr>th.active,.table>tfoot>tr.active>td,.table>tfoot>tr.active>th,.table>tfoot>tr>td.active,.table>tfoot>tr>th.active,.table>thead>tr.active>td,.table>thead>tr.active>th,.table>thead>tr>td.active,.table>thead>tr>th.active{background-color:#f5f5f5}.table-hover>tbody>tr.active:hover>td,.table-hover>tbody>tr.active:hover>th,.table-hover>tbody>tr:hover>.active,.table-hover>tbody>tr>td.active:hover,.table-hover>tbody>tr>th.active:hover{background-color:#e8e8e8}.table>tbody>tr.success>td,.table>tbody>tr.success>th,.table>tbody>tr>td.success,.table>tbody>tr>th.success,.table>tfoot>tr.success>td,.table>tfoot>tr.success>th,.table>tfoot>tr>td.success,.table>tfoot>tr>th.success,.table>thead>tr.success>td,.table>thead>tr.success>th,.table>thead>tr>td.success,.table>thead>tr>th.success{background-color:#dff0d8}.table-hover>tbody>tr.success:hover>td,.table-hover>tbody>tr.success:hover>th,.table-hover>tbody>tr:hover>.success,.table-hover>tbody>tr>td.success:hover,.table-hover>tbody>tr>th.success:hover{background-color:#d0e9c6}.table>tbody>tr.info>td,.table>tbody>tr.info>th,.table>tbody>tr>td.info,.table>tbody>tr>th.info,.table>tfoot>tr.info>td,.table>tfoot>tr.info>th,.table>tfoot>tr>td.info,.table>tfoot>tr>th.info,.table>thead>tr.info>td,.table>thead>tr.info>th,.table>thead>tr>td.info,.table>thead>tr>th.info{background-color:#d9edf7}.table-hover>tbody>tr.info:hover>td,.table-hover>tbody>tr.info:hover>th,.table-hover>tbody>tr:hover>.info,.table-hover>tbody>tr>td.info:hover,.table-hover>tbody>tr>th.info:hover{background-color:#c4e3f3}.table>tbody>tr.warning>td,.table>tbody>tr.warning>th,.table>tbody>tr>td.warning,.table>tbody>tr>th.warning,.table>tfoot>tr.warning>td,.table>tfoot>tr.warning>th,.table>tfoot>tr>td.warning,.table>tfoot>tr>th.warning,.table>thead>tr.warning>td,.table>thead>tr.warning>th,.table>thead>tr>td.warning,.table>thead>tr>th.warning{background-color:#fcf8e3}.table-hover>tbody>tr.warning:hover>td,.table-hover>tbody>tr.warning:hover>th,.table-hover>tbody>tr:hover>.warning,.table-hover>tbody>tr>td.warning:hover,.table-hover>tbody>tr>th.warning:hover{background-color:#faf2cc}.table>tbody>tr.danger>td,.table>tbody>tr.danger>th,.table>tbody>tr>td.danger,.table>tbody>tr>th.danger,.table>tfoot>tr.danger>td,.table>tfoot>tr.danger>th,.table>tfoot>tr>td.danger,.table>tfoot>tr>th.danger,.table>thead>tr.danger>td,.table>thead>tr.danger>th,.table>thead>tr>td.danger,.table>thead>tr>th.danger{background-color:#f2dede}.table-hover>tbody>tr.danger:hover>td,.table-hover>tbody>tr.danger:hover>th,.table-hover>tbody>tr:hover>.danger,.table-hover>tbody>tr>td.danger:hover,.table-hover>tbody>tr>th.danger:hover{background-color:#ebcccc}.table-responsive{min-height:.01%;overflow-x:auto}@media screen and (max-width:767px){.table-responsive{width:100%;margin-bottom:15px;overflow-y:hidden;-ms-overflow-style:-ms-autohiding-scrollbar;border:1px solid #ddd}.table-responsive>.table{margin-bottom:0}.table-responsive>.table>tbody>tr>td,.table-responsive>.table>tbody>tr>th,.table-responsive>.table>tfoot>tr>td,.table-responsive>.table>tfoot>tr>th,.table-responsive>.table>thead>tr>td,.table-responsive>.table>thead>tr>th{white-space:nowrap}.table-responsive>.table-bordered{border:0}.table-responsive>.table-bordered>tbody>tr>td:first-child,.table-responsive>.table-bordered>tbody>tr>th:first-child,.table-responsive>.table-bordered>tfoot>tr>td:first-child,.table-responsive>.table-bordered>tfoot>tr>th:first-child,.table-responsive>.table-bordered>thead>tr>td:first-child,.table-responsive>.table-bordered>thead>tr>th:first-child{border-left:0}.table-responsive>.table-bordered>tbody>tr>td:last-child,.table-responsive>.table-bordered>tbody>tr>th:last-child,.table-responsive>.table-bordered>tfoot>tr>td:last-child,.table-responsive>.table-bordered>tfoot>tr>th:last-child,.table-responsive>.table-bordered>thead>tr>td:last-child,.table-responsive>.table-bordered>thead>tr>th:last-child{border-right:0}.table-responsive>.table-bordered>tbody>tr:last-child>td,.table-responsive>.table-bordered>tbody>tr:last-child>th,.table-responsive>.table-bordered>tfoot>tr:last-child>td,.table-responsive>.table-bordered>tfoot>tr:last-child>th{border-bottom:0}}fieldset{min-width:0;padding:0;margin:0;border:0}legend{display:block;width:100%;padding:0;margin-bottom:20px;font-size:21px;line-height:inherit;color:#333;border:0;border-bottom:1px solid #e5e5e5}label{display:inline-block;max-width:100%;margin-bottom:5px;font-weight:700}input[type=search]{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}input[type=checkbox],input[type=radio]{margin:4px 0 0;margin-top:1px\9;line-height:normal}input[type=file]{display:block}input[type=range]{display:block;width:100%}select[multiple],select[size]{height:auto}input[type=file]:focus,input[type=checkbox]:focus,input[type=radio]:focus{outline:thin dotted;outline:5px auto -webkit-focus-ring-color;outline-offset:-2px}output{display:block;padding-top:7px;font-size:14px;line-height:1.42857143;color:#555}.form-control{display:block;width:100%;height:34px;padding:6px 12px;font-size:14px;line-height:1.42857143;color:#555;background-color:#fff;background-image:none;border:1px solid #ccc;border-radius:4px;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075);box-shadow:inset 0 1px 1px rgba(0,0,0,.075);-webkit-transition:border-color ease-in-out .15s,-webkit-box-shadow ease-in-out .15s;-o-transition:border-color ease-in-out .15s,box-shadow ease-in-out .15s;transition:border-color ease-in-out .15s,box-shadow ease-in-out .15s}.form-control:focus{border-color:#66afe9;outline:0;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 8px rgba(102,175,233,.6);box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 8px rgba(102,175,233,.6)}.form-control::-moz-placeholder{color:#999;opacity:1}.form-control:-ms-input-placeholder{color:#999}.form-control::-webkit-input-placeholder{color:#999}.form-control[disabled],.form-control[readonly],fieldset[disabled] .form-control{background-color:#eee;opacity:1}.form-control[disabled],fieldset[disabled] .form-control{cursor:not-allowed}textarea.form-control{height:auto}input[type=search]{-webkit-appearance:none}@media screen and (-webkit-min-device-pixel-ratio:0){input[type=date].form-control,input[type=time].form-control,input[type=datetime-local].form-control,input[type=month].form-control{line-height:34px}.input-group-sm input[type=date],.input-group-sm input[type=time],.input-group-sm input[type=datetime-local],.input-group-sm input[type=month],input[type=date].input-sm,input[type=time].input-sm,input[type=datetime-local].input-sm,input[type=month].input-sm{line-height:30px}.input-group-lg input[type=date],.input-group-lg input[type=time],.input-group-lg input[type=datetime-local],.input-group-lg input[type=month],input[type=date].input-lg,input[type=time].input-lg,input[type=datetime-local].input-lg,input[type=month].input-lg{line-height:46px}}.form-group{margin-bottom:15px}.checkbox,.radio{position:relative;display:block;margin-top:10px;margin-bottom:10px}.checkbox label,.radio label{min-height:20px;padding-left:20px;margin-bottom:0;font-weight:400;cursor:pointer}.checkbox input[type=checkbox],.checkbox-inline input[type=checkbox],.radio input[type=radio],.radio-inline input[type=radio]{position:absolute;margin-top:4px\9;margin-left:-20px}.checkbox+.checkbox,.radio+.radio{margin-top:-5px}.checkbox-inline,.radio-inline{position:relative;display:inline-block;padding-left:20px;margin-bottom:0;font-weight:400;vertical-align:middle;cursor:pointer}.checkbox-inline+.checkbox-inline,.radio-inline+.radio-inline{margin-top:0;margin-left:10px}fieldset[disabled] input[type=checkbox],fieldset[disabled] input[type=radio],input[type=checkbox].disabled,input[type=checkbox][disabled],input[type=radio].disabled,input[type=radio][disabled]{cursor:not-allowed}.checkbox-inline.disabled,.radio-inline.disabled,fieldset[disabled] .checkbox-inline,fieldset[disabled] .radio-inline{cursor:not-allowed}.checkbox.disabled label,.radio.disabled label,fieldset[disabled] .checkbox label,fieldset[disabled] .radio label{cursor:not-allowed}.form-control-static{min-height:34px;padding-top:7px;padding-bottom:7px;margin-bottom:0}.form-control-static.input-lg,.form-control-static.input-sm{padding-right:0;padding-left:0}.input-sm{height:30px;padding:5px 10px;font-size:12px;line-height:1.5;border-radius:3px}select.input-sm{height:30px;line-height:30px}select[multiple].input-sm,textarea.input-sm{height:auto}.form-group-sm .form-control{height:30px;padding:5px 10px;font-size:12px;line-height:1.5;border-radius:3px}.form-group-sm select.form-control{height:30px;line-height:30px}.form-group-sm select[multiple].form-control,.form-group-sm textarea.form-control{height:auto}.form-group-sm .form-control-static{height:30px;min-height:32px;padding:6px 10px;font-size:12px;line-height:1.5}.input-lg{height:46px;padding:10px 16px;font-size:18px;line-height:1.3333333;border-radius:6px}select.input-lg{height:46px;line-height:46px}select[multiple].input-lg,textarea.input-lg{height:auto}.form-group-lg .form-control{height:46px;padding:10px 16px;font-size:18px;line-height:1.3333333;border-radius:6px}.form-group-lg select.form-control{height:46px;line-height:46px}.form-group-lg select[multiple].form-control,.form-group-lg textarea.form-control{height:auto}.form-group-lg .form-control-static{height:46px;min-height:38px;padding:11px 16px;font-size:18px;line-height:1.3333333}.has-feedback{position:relative}.has-feedback .form-control{padding-right:42.5px}.form-control-feedback{position:absolute;top:0;right:0;z-index:2;display:block;width:34px;height:34px;line-height:34px;text-align:center;pointer-events:none}.form-group-lg .form-control+.form-control-feedback,.input-group-lg+.form-control-feedback,.input-lg+.form-control-feedback{width:46px;height:46px;line-height:46px}.form-group-sm .form-control+.form-control-feedback,.input-group-sm+.form-control-feedback,.input-sm+.form-control-feedback{width:30px;height:30px;line-height:30px}.has-success .checkbox,.has-success .checkbox-inline,.has-success .control-label,.has-success .help-block,.has-success .radio,.has-success .radio-inline,.has-success.checkbox label,.has-success.checkbox-inline label,.has-success.radio label,.has-success.radio-inline label{color:#3c763d}.has-success .form-control{border-color:#3c763d;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075);box-shadow:inset 0 1px 1px rgba(0,0,0,.075)}.has-success .form-control:focus{border-color:#2b542c;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 6px #67b168;box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 6px #67b168}.has-success .input-group-addon{color:#3c763d;background-color:#dff0d8;border-color:#3c763d}.has-success .form-control-feedback{color:#3c763d}.has-warning .checkbox,.has-warning .checkbox-inline,.has-warning .control-label,.has-warning .help-block,.has-warning .radio,.has-warning .radio-inline,.has-warning.checkbox label,.has-warning.checkbox-inline label,.has-warning.radio label,.has-warning.radio-inline label{color:#8a6d3b}.has-warning .form-control{border-color:#8a6d3b;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075);box-shadow:inset 0 1px 1px rgba(0,0,0,.075)}.has-warning .form-control:focus{border-color:#66512c;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 6px #c0a16b;box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 6px #c0a16b}.has-warning .input-group-addon{color:#8a6d3b;background-color:#fcf8e3;border-color:#8a6d3b}.has-warning .form-control-feedback{color:#8a6d3b}.has-error .checkbox,.has-error .checkbox-inline,.has-error .control-label,.has-error .help-block,.has-error .radio,.has-error .radio-inline,.has-error.checkbox label,.has-error.checkbox-inline label,.has-error.radio label,.has-error.radio-inline label{color:#a94442}.has-error .form-control{border-color:#a94442;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075);box-shadow:inset 0 1px 1px rgba(0,0,0,.075)}.has-error .form-control:focus{border-color:#843534;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 6px #ce8483;box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 6px #ce8483}.has-error .input-group-addon{color:#a94442;background-color:#f2dede;border-color:#a94442}.has-error .form-control-feedback{color:#a94442}.has-feedback label~.form-control-feedback{top:25px}.has-feedback label.sr-only~.form-control-feedback{top:0}.help-block{display:block;margin-top:5px;margin-bottom:10px;color:#737373}@media (min-width:768px){.form-inline .form-group{display:inline-block;margin-bottom:0;vertical-align:middle}.form-inline .form-control{display:inline-block;width:auto;vertical-align:middle}.form-inline .form-control-static{display:inline-block}.form-inline .input-group{display:inline-table;vertical-align:middle}.form-inline .input-group .form-control,.form-inline .input-group .input-group-addon,.form-inline .input-group .input-group-btn{width:auto}.form-inline .input-group>.form-control{width:100%}.form-inline .control-label{margin-bottom:0;vertical-align:middle}.form-inline .checkbox,.form-inline .radio{display:inline-block;margin-top:0;margin-bottom:0;vertical-align:middle}.form-inline .checkbox label,.form-inline .radio label{padding-left:0}.form-inline .checkbox input[type=checkbox],.form-inline .radio input[type=radio]{position:relative;margin-left:0}.form-inline .has-feedback .form-control-feedback{top:0}}.form-horizontal .checkbox,.form-horizontal .checkbox-inline,.form-horizontal .radio,.form-horizontal .radio-inline{padding-top:7px;margin-top:0;margin-bottom:0}.form-horizontal .checkbox,.form-horizontal .radio{min-height:27px}.form-horizontal .form-group{margin-right:-15px;margin-left:-15px}@media (min-width:768px){.form-horizontal .control-label{padding-top:7px;margin-bottom:0;text-align:right}}.form-horizontal .has-feedback .form-control-feedback{right:15px}@media (min-width:768px){.form-horizontal .form-group-lg .control-label{padding-top:14.33px;font-size:18px}}@media (min-width:768px){.form-horizontal .form-group-sm .control-label{padding-top:6px;font-size:12px}}.btn{display:inline-block;padding:6px 12px;margin-bottom:0;font-size:14px;font-weight:400;line-height:1.42857143;text-align:center;white-space:nowrap;vertical-align:middle;-ms-touch-action:manipulation;touch-action:manipulation;cursor:pointer;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;background-image:none;border:1px solid transparent;border-radius:4px}.btn.active.focus,.btn.active:focus,.btn.focus,.btn:active.focus,.btn:active:focus,.btn:focus{outline:thin dotted;outline:5px auto -webkit-focus-ring-color;outline-offset:-2px}.btn.focus,.btn:focus,.btn:hover{color:#333;text-decoration:none}.btn.active,.btn:active{background-image:none;outline:0;-webkit-box-shadow:inset 0 3px 5px rgba(0,0,0,.125);box-shadow:inset 0 3px 5px rgba(0,0,0,.125)}.btn.disabled,.btn[disabled],fieldset[disabled] .btn{cursor:not-allowed;filter:alpha(opacity=65);-webkit-box-shadow:none;box-shadow:none;opacity:.65}a.btn.disabled,fieldset[disabled] a.btn{pointer-events:none}.btn-default{color:#333;background-color:#fff;border-color:#ccc}.btn-default.focus,.btn-default:focus{color:#333;background-color:#e6e6e6;border-color:#8c8c8c}.btn-default:hover{color:#333;background-color:#e6e6e6;border-color:#adadad}.btn-default.active,.btn-default:active,.open>.dropdown-toggle.btn-default{color:#333;background-color:#e6e6e6;border-color:#adadad}.btn-default.active.focus,.btn-default.active:focus,.btn-default.active:hover,.btn-default:active.focus,.btn-default:active:focus,.btn-default:active:hover,.open>.dropdown-toggle.btn-default.focus,.open>.dropdown-toggle.btn-default:focus,.open>.dropdown-toggle.btn-default:hover{color:#333;background-color:#d4d4d4;border-color:#8c8c8c}.btn-default.active,.btn-default:active,.open>.dropdown-toggle.btn-default{background-image:none}.btn-default.disabled,.btn-default.disabled.active,.btn-default.disabled.focus,.btn-default.disabled:active,.btn-default.disabled:focus,.btn-default.disabled:hover,.btn-default[disabled],.btn-default[disabled].active,.btn-default[disabled].focus,.btn-default[disabled]:active,.btn-default[disabled]:focus,.btn-default[disabled]:hover,fieldset[disabled] .btn-default,fieldset[disabled] .btn-default.active,fieldset[disabled] .btn-default.focus,fieldset[disabled] .btn-default:active,fieldset[disabled] .btn-default:focus,fieldset[disabled] .btn-default:hover{background-color:#fff;border-color:#ccc}.btn-default .badge{color:#fff;background-color:#333}.btn-primary{color:#fff;background-color:#337ab7;border-color:#2e6da4}.btn-primary.focus,.btn-primary:focus{color:#fff;background-color:#286090;border-color:#122b40}.btn-primary:hover{color:#fff;background-color:#286090;border-color:#204d74}.btn-primary.active,.btn-primary:active,.open>.dropdown-toggle.btn-primary{color:#fff;background-color:#286090;border-color:#204d74}.btn-primary.active.focus,.btn-primary.active:focus,.btn-primary.active:hover,.btn-primary:active.focus,.btn-primary:active:focus,.btn-primary:active:hover,.open>.dropdown-toggle.btn-primary.focus,.open>.dropdown-toggle.btn-primary:focus,.open>.dropdown-toggle.btn-primary:hover{color:#fff;background-color:#204d74;border-color:#122b40}.btn-primary.active,.btn-primary:active,.open>.dropdown-toggle.btn-primary{background-image:none}.btn-primary.disabled,.btn-primary.disabled.active,.btn-primary.disabled.focus,.btn-primary.disabled:active,.btn-primary.disabled:focus,.btn-primary.disabled:hover,.btn-primary[disabled],.btn-primary[disabled].active,.btn-primary[disabled].focus,.btn-primary[disabled]:active,.btn-primary[disabled]:focus,.btn-primary[disabled]:hover,fieldset[disabled] .btn-primary,fieldset[disabled] .btn-primary.active,fieldset[disabled] .btn-primary.focus,fieldset[disabled] .btn-primary:active,fieldset[disabled] .btn-primary:focus,fieldset[disabled] .btn-primary:hover{background-color:#337ab7;border-color:#2e6da4}.btn-primary .badge{color:#337ab7;background-color:#fff}.btn-success{color:#fff;background-color:#5cb85c;border-color:#4cae4c}.btn-success.focus,.btn-success:focus{color:#fff;background-color:#449d44;border-color:#255625}.btn-success:hover{color:#fff;background-color:#449d44;border-color:#398439}.btn-success.active,.btn-success:active,.open>.dropdown-toggle.btn-success{color:#fff;background-color:#449d44;border-color:#398439}.btn-success.active.focus,.btn-success.active:focus,.btn-success.active:hover,.btn-success:active.focus,.btn-success:active:focus,.btn-success:active:hover,.open>.dropdown-toggle.btn-success.focus,.open>.dropdown-toggle.btn-success:focus,.open>.dropdown-toggle.btn-success:hover{color:#fff;background-color:#398439;border-color:#255625}.btn-success.active,.btn-success:active,.open>.dropdown-toggle.btn-success{background-image:none}.btn-success.disabled,.btn-success.disabled.active,.btn-success.disabled.focus,.btn-success.disabled:active,.btn-success.disabled:focus,.btn-success.disabled:hover,.btn-success[disabled],.btn-success[disabled].active,.btn-success[disabled].focus,.btn-success[disabled]:active,.btn-success[disabled]:focus,.btn-success[disabled]:hover,fieldset[disabled] .btn-success,fieldset[disabled] .btn-success.active,fieldset[disabled] .btn-success.focus,fieldset[disabled] .btn-success:active,fieldset[disabled] .btn-success:focus,fieldset[disabled] .btn-success:hover{background-color:#5cb85c;border-color:#4cae4c}.btn-success .badge{color:#5cb85c;background-color:#fff}.btn-info{color:#fff;background-color:#5bc0de;border-color:#46b8da}.btn-info.focus,.btn-info:focus{color:#fff;background-color:#31b0d5;border-color:#1b6d85}.btn-info:hover{color:#fff;background-color:#31b0d5;border-color:#269abc}.btn-info.active,.btn-info:active,.open>.dropdown-toggle.btn-info{color:#fff;background-color:#31b0d5;border-color:#269abc}.btn-info.active.focus,.btn-info.active:focus,.btn-info.active:hover,.btn-info:active.focus,.btn-info:active:focus,.btn-info:active:hover,.open>.dropdown-toggle.btn-info.focus,.open>.dropdown-toggle.btn-info:focus,.open>.dropdown-toggle.btn-info:hover{color:#fff;background-color:#269abc;border-color:#1b6d85}.btn-info.active,.btn-info:active,.open>.dropdown-toggle.btn-info{background-image:none}.btn-info.disabled,.btn-info.disabled.active,.btn-info.disabled.focus,.btn-info.disabled:active,.btn-info.disabled:focus,.btn-info.disabled:hover,.btn-info[disabled],.btn-info[disabled].active,.btn-info[disabled].focus,.btn-info[disabled]:active,.btn-info[disabled]:focus,.btn-info[disabled]:hover,fieldset[disabled] .btn-info,fieldset[disabled] .btn-info.active,fieldset[disabled] .btn-info.focus,fieldset[disabled] .btn-info:active,fieldset[disabled] .btn-info:focus,fieldset[disabled] .btn-info:hover{background-color:#5bc0de;border-color:#46b8da}.btn-info .badge{color:#5bc0de;background-color:#fff}.btn-warning{color:#fff;background-color:#f0ad4e;border-color:#eea236}.btn-warning.focus,.btn-warning:focus{color:#fff;background-color:#ec971f;border-color:#985f0d}.btn-warning:hover{color:#fff;background-color:#ec971f;border-color:#d58512}.btn-warning.active,.btn-warning:active,.open>.dropdown-toggle.btn-warning{color:#fff;background-color:#ec971f;border-color:#d58512}.btn-warning.active.focus,.btn-warning.active:focus,.btn-warning.active:hover,.btn-warning:active.focus,.btn-warning:active:focus,.btn-warning:active:hover,.open>.dropdown-toggle.btn-warning.focus,.open>.dropdown-toggle.btn-warning:focus,.open>.dropdown-toggle.btn-warning:hover{color:#fff;background-color:#d58512;border-color:#985f0d}.btn-warning.active,.btn-warning:active,.open>.dropdown-toggle.btn-warning{background-image:none}.btn-warning.disabled,.btn-warning.disabled.active,.btn-warning.disabled.focus,.btn-warning.disabled:active,.btn-warning.disabled:focus,.btn-warning.disabled:hover,.btn-warning[disabled],.btn-warning[disabled].active,.btn-warning[disabled].focus,.btn-warning[disabled]:active,.btn-warning[disabled]:focus,.btn-warning[disabled]:hover,fieldset[disabled] .btn-warning,fieldset[disabled] .btn-warning.active,fieldset[disabled] .btn-warning.focus,fieldset[disabled] .btn-warning:active,fieldset[disabled] .btn-warning:focus,fieldset[disabled] .btn-warning:hover{background-color:#f0ad4e;border-color:#eea236}.btn-warning .badge{color:#f0ad4e;background-color:#fff}.btn-danger{color:#fff;background-color:#d9534f;border-color:#d43f3a}.btn-danger.focus,.btn-danger:focus{color:#fff;background-color:#c9302c;border-color:#761c19}.btn-danger:hover{color:#fff;background-color:#c9302c;border-color:#ac2925}.btn-danger.active,.btn-danger:active,.open>.dropdown-toggle.btn-danger{color:#fff;background-color:#c9302c;border-color:#ac2925}.btn-danger.active.focus,.btn-danger.active:focus,.btn-danger.active:hover,.btn-danger:active.focus,.btn-danger:active:focus,.btn-danger:active:hover,.open>.dropdown-toggle.btn-danger.focus,.open>.dropdown-toggle.btn-danger:focus,.open>.dropdown-toggle.btn-danger:hover{color:#fff;background-color:#ac2925;border-color:#761c19}.btn-danger.active,.btn-danger:active,.open>.dropdown-toggle.btn-danger{background-image:none}.btn-danger.disabled,.btn-danger.disabled.active,.btn-danger.disabled.focus,.btn-danger.disabled:active,.btn-danger.disabled:focus,.btn-danger.disabled:hover,.btn-danger[disabled],.btn-danger[disabled].active,.btn-danger[disabled].focus,.btn-danger[disabled]:active,.btn-danger[disabled]:focus,.btn-danger[disabled]:hover,fieldset[disabled] .btn-danger,fieldset[disabled] .btn-danger.active,fieldset[disabled] .btn-danger.focus,fieldset[disabled] .btn-danger:active,fieldset[disabled] .btn-danger:focus,fieldset[disabled] .btn-danger:hover{background-color:#d9534f;border-color:#d43f3a}.btn-danger .badge{color:#d9534f;background-color:#fff}.btn-link{font-weight:400;color:#337ab7;border-radius:0}.btn-link,.btn-link.active,.btn-link:active,.btn-link[disabled],fieldset[disabled] .btn-link{background-color:transparent;-webkit-box-shadow:none;box-shadow:none}.btn-link,.btn-link:active,.btn-link:focus,.btn-link:hover{border-color:transparent}.btn-link:focus,.btn-link:hover{color:#23527c;text-decoration:underline;background-color:transparent}.btn-link[disabled]:focus,.btn-link[disabled]:hover,fieldset[disabled] .btn-link:focus,fieldset[disabled] .btn-link:hover{color:#777;text-decoration:none}.btn-group-lg>.btn,.btn-lg{padding:10px 16px;font-size:18px;line-height:1.3333333;border-radius:6px}.btn-group-sm>.btn,.btn-sm{padding:5px 10px;font-size:12px;line-height:1.5;border-radius:3px}.btn-group-xs>.btn,.btn-xs{padding:1px 5px;font-size:12px;line-height:1.5;border-radius:3px}.btn-block{display:block;width:100%}.btn-block+.btn-block{margin-top:5px}input[type=button].btn-block,input[type=reset].btn-block,input[type=submit].btn-block{width:100%}.fade{opacity:0;-webkit-transition:opacity .15s linear;-o-transition:opacity .15s linear;transition:opacity .15s linear}.fade.in{opacity:1}.collapse{display:none}.collapse.in{display:block}tr.collapse.in{display:table-row}tbody.collapse.in{display:table-row-group}.collapsing{position:relative;height:0;overflow:hidden;-webkit-transition-timing-function:ease;-o-transition-timing-function:ease;transition-timing-function:ease;-webkit-transition-duration:.35s;-o-transition-duration:.35s;transition-duration:.35s;-webkit-transition-property:height,visibility;-o-transition-property:height,visibility;transition-property:height,visibility}.caret{display:inline-block;width:0;height:0;margin-left:2px;vertical-align:middle;border-top:4px dashed;border-top:4px solid\9;border-right:4px solid transparent;border-left:4px solid transparent}.dropdown,.dropup{position:relative}.dropdown-toggle:focus{outline:0}.dropdown-menu{position:absolute;top:100%;left:0;z-index:1000;display:none;float:left;min-width:160px;padding:5px 0;margin:2px 0 0;font-size:14px;text-align:left;list-style:none;background-color:#fff;-webkit-background-clip:padding-box;background-clip:padding-box;border:1px solid #ccc;border:1px solid rgba(0,0,0,.15);border-radius:4px;-webkit-box-shadow:0 6px 12px rgba(0,0,0,.175);box-shadow:0 6px 12px rgba(0,0,0,.175)}.dropdown-menu.pull-right{right:0;left:auto}.dropdown-menu .divider{height:1px;margin:9px 0;overflow:hidden;background-color:#e5e5e5}.dropdown-menu>li>a{display:block;padding:3px 20px;clear:both;font-weight:400;line-height:1.42857143;color:#333;white-space:nowrap}.dropdown-menu>li>a:focus,.dropdown-menu>li>a:hover{color:#262626;text-decoration:none;background-color:#f5f5f5}.dropdown-menu>.active>a,.dropdown-menu>.active>a:focus,.dropdown-menu>.active>a:hover{color:#fff;text-decoration:none;background-color:#337ab7;outline:0}.dropdown-menu>.disabled>a,.dropdown-menu>.disabled>a:focus,.dropdown-menu>.disabled>a:hover{color:#777}.dropdown-menu>.disabled>a:focus,.dropdown-menu>.disabled>a:hover{text-decoration:none;cursor:not-allowed;background-color:transparent;background-image:none;filter:progid:DXImageTransform.Microsoft.gradient(enabled=false)}.open>.dropdown-menu{display:block}.open>a{outline:0}.dropdown-menu-right{right:0;left:auto}.dropdown-menu-left{right:auto;left:0}.dropdown-header{display:block;padding:3px 20px;font-size:12px;line-height:1.42857143;color:#777;white-space:nowrap}.dropdown-backdrop{position:fixed;top:0;right:0;bottom:0;left:0;z-index:990}.pull-right>.dropdown-menu{right:0;left:auto}.dropup .caret,.navbar-fixed-bottom .dropdown .caret{content:"";border-top:0;border-bottom:4px dashed;border-bottom:4px solid\9}.dropup .dropdown-menu,.navbar-fixed-bottom .dropdown .dropdown-menu{top:auto;bottom:100%;margin-bottom:2px}@media (min-width:768px){.navbar-right .dropdown-menu{right:0;left:auto}.navbar-right .dropdown-menu-left{right:auto;left:0}}.btn-group,.btn-group-vertical{position:relative;display:inline-block;vertical-align:middle}.btn-group-vertical>.btn,.btn-group>.btn{position:relative;float:left}.btn-group-vertical>.btn.active,.btn-group-vertical>.btn:active,.btn-group-vertical>.btn:focus,.btn-group-vertical>.btn:hover,.btn-group>.btn.active,.btn-group>.btn:active,.btn-group>.btn:focus,.btn-group>.btn:hover{z-index:2}.btn-group .btn+.btn,.btn-group .btn+.btn-group,.btn-group .btn-group+.btn,.btn-group .btn-group+.btn-group{margin-left:-1px}.btn-toolbar{margin-left:-5px}.btn-toolbar .btn,.btn-toolbar .btn-group,.btn-toolbar .input-group{float:left}.btn-toolbar>.btn,.btn-toolbar>.btn-group,.btn-toolbar>.input-group{margin-left:5px}.btn-group>.btn:not(:first-child):not(:last-child):not(.dropdown-toggle){border-radius:0}.btn-group>.btn:first-child{margin-left:0}.btn-group>.btn:first-child:not(:last-child):not(.dropdown-toggle){border-top-right-radius:0;border-bottom-right-radius:0}.btn-group>.btn:last-child:not(:first-child),.btn-group>.dropdown-toggle:not(:first-child){border-top-left-radius:0;border-bottom-left-radius:0}.btn-group>.btn-group{float:left}.btn-group>.btn-group:not(:first-child):not(:last-child)>.btn{border-radius:0}.btn-group>.btn-group:first-child:not(:last-child)>.btn:last-child,.btn-group>.btn-group:first-child:not(:last-child)>.dropdown-toggle{border-top-right-radius:0;border-bottom-right-radius:0}.btn-group>.btn-group:last-child:not(:first-child)>.btn:first-child{border-top-left-radius:0;border-bottom-left-radius:0}.btn-group .dropdown-toggle:active,.btn-group.open .dropdown-toggle{outline:0}.btn-group>.btn+.dropdown-toggle{padding-right:8px;padding-left:8px}.btn-group>.btn-lg+.dropdown-toggle{padding-right:12px;padding-left:12px}.btn-group.open .dropdown-toggle{-webkit-box-shadow:inset 0 3px 5px rgba(0,0,0,.125);box-shadow:inset 0 3px 5px rgba(0,0,0,.125)}.btn-group.open .dropdown-toggle.btn-link{-webkit-box-shadow:none;box-shadow:none}.btn .caret{margin-left:0}.btn-lg .caret{border-width:5px 5px 0;border-bottom-width:0}.dropup .btn-lg .caret{border-width:0 5px 5px}.btn-group-vertical>.btn,.btn-group-vertical>.btn-group,.btn-group-vertical>.btn-group>.btn{display:block;float:none;width:100%;max-width:100%}.btn-group-vertical>.btn-group>.btn{float:none}.btn-group-vertical>.btn+.btn,.btn-group-vertical>.btn+.btn-group,.btn-group-vertical>.btn-group+.btn,.btn-group-vertical>.btn-group+.btn-group{margin-top:-1px;margin-left:0}.btn-group-vertical>.btn:not(:first-child):not(:last-child){border-radius:0}.btn-group-vertical>.btn:first-child:not(:last-child){border-top-right-radius:4px;border-bottom-right-radius:0;border-bottom-left-radius:0}.btn-group-vertical>.btn:last-child:not(:first-child){border-top-left-radius:0;border-top-right-radius:0;border-bottom-left-radius:4px}.btn-group-vertical>.btn-group:not(:first-child):not(:last-child)>.btn{border-radius:0}.btn-group-vertical>.btn-group:first-child:not(:last-child)>.btn:last-child,.btn-group-vertical>.btn-group:first-child:not(:last-child)>.dropdown-toggle{border-bottom-right-radius:0;border-bottom-left-radius:0}.btn-group-vertical>.btn-group:last-child:not(:first-child)>.btn:first-child{border-top-left-radius:0;border-top-right-radius:0}.btn-group-justified{display:table;width:100%;table-layout:fixed;border-collapse:separate}.btn-group-justified>.btn,.btn-group-justified>.btn-group{display:table-cell;float:none;width:1%}.btn-group-justified>.btn-group .btn{width:100%}.btn-group-justified>.btn-group .dropdown-menu{left:auto}[data-toggle=buttons]>.btn input[type=checkbox],[data-toggle=buttons]>.btn input[type=radio],[data-toggle=buttons]>.btn-group>.btn input[type=checkbox],[data-toggle=buttons]>.btn-group>.btn input[type=radio]{position:absolute;clip:rect(0,0,0,0);pointer-events:none}.input-group{position:relative;display:table;border-collapse:separate}.input-group[class*=col-]{float:none;padding-right:0;padding-left:0}.input-group .form-control{position:relative;z-index:2;float:left;width:100%;margin-bottom:0}.input-group-lg>.form-control,.input-group-lg>.input-group-addon,.input-group-lg>.input-group-btn>.btn{height:46px;padding:10px 16px;font-size:18px;line-height:1.3333333;border-radius:6px}select.input-group-lg>.form-control,select.input-group-lg>.input-group-addon,select.input-group-lg>.input-group-btn>.btn{height:46px;line-height:46px}select[multiple].input-group-lg>.form-control,select[multiple].input-group-lg>.input-group-addon,select[multiple].input-group-lg>.input-group-btn>.btn,textarea.input-group-lg>.form-control,textarea.input-group-lg>.input-group-addon,textarea.input-group-lg>.input-group-btn>.btn{height:auto}.input-group-sm>.form-control,.input-group-sm>.input-group-addon,.input-group-sm>.input-group-btn>.btn{height:30px;padding:5px 10px;font-size:12px;line-height:1.5;border-radius:3px}select.input-group-sm>.form-control,select.input-group-sm>.input-group-addon,select.input-group-sm>.input-group-btn>.btn{height:30px;line-height:30px}select[multiple].input-group-sm>.form-control,select[multiple].input-group-sm>.input-group-addon,select[multiple].input-group-sm>.input-group-btn>.btn,textarea.input-group-sm>.form-control,textarea.input-group-sm>.input-group-addon,textarea.input-group-sm>.input-group-btn>.btn{height:auto}.input-group .form-control,.input-group-addon,.input-group-btn{display:table-cell}.input-group .form-control:not(:first-child):not(:last-child),.input-group-addon:not(:first-child):not(:last-child),.input-group-btn:not(:first-child):not(:last-child){border-radius:0}.input-group-addon,.input-group-btn{width:1%;white-space:nowrap;vertical-align:middle}.input-group-addon{padding:6px 12px;font-size:14px;font-weight:400;line-height:1;color:#555;text-align:center;background-color:#eee;border:1px solid #ccc;border-radius:4px}.input-group-addon.input-sm{padding:5px 10px;font-size:12px;border-radius:3px}.input-group-addon.input-lg{padding:10px 16px;font-size:18px;border-radius:6px}.input-group-addon input[type=checkbox],.input-group-addon input[type=radio]{margin-top:0}.input-group .form-control:first-child,.input-group-addon:first-child,.input-group-btn:first-child>.btn,.input-group-btn:first-child>.btn-group>.btn,.input-group-btn:first-child>.dropdown-toggle,.input-group-btn:last-child>.btn-group:not(:last-child)>.btn,.input-group-btn:last-child>.btn:not(:last-child):not(.dropdown-toggle){border-top-right-radius:0;border-bottom-right-radius:0}.input-group-addon:first-child{border-right:0}.input-group .form-control:last-child,.input-group-addon:last-child,.input-group-btn:first-child>.btn-group:not(:first-child)>.btn,.input-group-btn:first-child>.btn:not(:first-child),.input-group-btn:last-child>.btn,.input-group-btn:last-child>.btn-group>.btn,.input-group-btn:last-child>.dropdown-toggle{border-top-left-radius:0;border-bottom-left-radius:0}.input-group-addon:last-child{border-left:0}.input-group-btn{position:relative;font-size:0;white-space:nowrap}.input-group-btn>.btn{position:relative}.input-group-btn>.btn+.btn{margin-left:-1px}.input-group-btn>.btn:active,.input-group-btn>.btn:focus,.input-group-btn>.btn:hover{z-index:2}.input-group-btn:first-child>.btn,.input-group-btn:first-child>.btn-group{margin-right:-1px}.input-group-btn:last-child>.btn,.input-group-btn:last-child>.btn-group{z-index:2;margin-left:-1px}.nav{padding-left:0;margin-bottom:0;list-style:none}.nav>li{position:relative;display:block}.nav>li>a{position:relative;display:block;padding:10px 15px}.nav>li>a:focus,.nav>li>a:hover{text-decoration:none;background-color:#eee}.nav>li.disabled>a{color:#777}.nav>li.disabled>a:focus,.nav>li.disabled>a:hover{color:#777;text-decoration:none;cursor:not-allowed;background-color:transparent}.nav .open>a,.nav .open>a:focus,.nav .open>a:hover{background-color:#eee;border-color:#337ab7}.nav .nav-divider{height:1px;margin:9px 0;overflow:hidden;background-color:#e5e5e5}.nav>li>a>img{max-width:none}.nav-tabs{border-bottom:1px solid #ddd}.nav-tabs>li{float:left;margin-bottom:-1px}.nav-tabs>li>a{margin-right:2px;line-height:1.42857143;border:1px solid transparent;border-radius:4px 4px 0 0}.nav-tabs>li>a:hover{border-color:#eee #eee #ddd}.nav-tabs>li.active>a,.nav-tabs>li.active>a:focus,.nav-tabs>li.active>a:hover{color:#555;cursor:default;background-color:#fff;border:1px solid #ddd;border-bottom-color:transparent}.nav-tabs.nav-justified{width:100%;border-bottom:0}.nav-tabs.nav-justified>li{float:none}.nav-tabs.nav-justified>li>a{margin-bottom:5px;text-align:center}.nav-tabs.nav-justified>.dropdown .dropdown-menu{top:auto;left:auto}@media (min-width:768px){.nav-tabs.nav-justified>li{display:table-cell;width:1%}.nav-tabs.nav-justified>li>a{margin-bottom:0}}.nav-tabs.nav-justified>li>a{margin-right:0;border-radius:4px}.nav-tabs.nav-justified>.active>a,.nav-tabs.nav-justified>.active>a:focus,.nav-tabs.nav-justified>.active>a:hover{border:1px solid #ddd}@media (min-width:768px){.nav-tabs.nav-justified>li>a{border-bottom:1px solid #ddd;border-radius:4px 4px 0 0}.nav-tabs.nav-justified>.active>a,.nav-tabs.nav-justified>.active>a:focus,.nav-tabs.nav-justified>.active>a:hover{border-bottom-color:#fff}}.nav-pills>li{float:left}.nav-pills>li>a{border-radius:4px}.nav-pills>li+li{margin-left:2px}.nav-pills>li.active>a,.nav-pills>li.active>a:focus,.nav-pills>li.active>a:hover{color:#fff;background-color:#337ab7}.nav-stacked>li{float:none}.nav-stacked>li+li{margin-top:2px;margin-left:0}.nav-justified{width:100%}.nav-justified>li{float:none}.nav-justified>li>a{margin-bottom:5px;text-align:center}.nav-justified>.dropdown .dropdown-menu{top:auto;left:auto}@media (min-width:768px){.nav-justified>li{display:table-cell;width:1%}.nav-justified>li>a{margin-bottom:0}}.nav-tabs-justified{border-bottom:0}.nav-tabs-justified>li>a{margin-right:0;border-radius:4px}.nav-tabs-justified>.active>a,.nav-tabs-justified>.active>a:focus,.nav-tabs-justified>.active>a:hover{border:1px solid #ddd}@media (min-width:768px){.nav-tabs-justified>li>a{border-bottom:1px solid #ddd;border-radius:4px 4px 0 0}.nav-tabs-justified>.active>a,.nav-tabs-justified>.active>a:focus,.nav-tabs-justified>.active>a:hover{border-bottom-color:#fff}}.tab-content>.tab-pane{display:none}.tab-content>.active{display:block}.nav-tabs .dropdown-menu{margin-top:-1px;border-top-left-radius:0;border-top-right-radius:0}.navbar{position:relative;min-height:50px;margin-bottom:20px;border:1px solid transparent}@media (min-width:768px){.navbar{border-radius:4px}}@media (min-width:768px){.navbar-header{float:left}}.navbar-collapse{padding-right:15px;padding-left:15px;overflow-x:visible;-webkit-overflow-scrolling:touch;border-top:1px solid transparent;-webkit-box-shadow:inset 0 1px 0 rgba(255,255,255,.1);box-shadow:inset 0 1px 0 rgba(255,255,255,.1)}.navbar-collapse.in{overflow-y:auto}@media (min-width:768px){.navbar-collapse{width:auto;border-top:0;-webkit-box-shadow:none;box-shadow:none}.navbar-collapse.collapse{display:block!important;height:auto!important;padding-bottom:0;overflow:visible!important}.navbar-collapse.in{overflow-y:visible}.navbar-fixed-bottom .navbar-collapse,.navbar-fixed-top .navbar-collapse,.navbar-static-top .navbar-collapse{padding-right:0;padding-left:0}}.navbar-fixed-bottom .navbar-collapse,.navbar-fixed-top .navbar-collapse{max-height:340px}@media (max-device-width:480px) and (orientation:landscape){.navbar-fixed-bottom .navbar-collapse,.navbar-fixed-top .navbar-collapse{max-height:200px}}.container-fluid>.navbar-collapse,.container-fluid>.navbar-header,.container>.navbar-collapse,.container>.navbar-header{margin-right:-15px;margin-left:-15px}@media (min-width:768px){.container-fluid>.navbar-collapse,.container-fluid>.navbar-header,.container>.navbar-collapse,.container>.navbar-header{margin-right:0;margin-left:0}}.navbar-static-top{z-index:1000;border-width:0 0 1px}@media (min-width:768px){.navbar-static-top{border-radius:0}}.navbar-fixed-bottom,.navbar-fixed-top{position:fixed;right:0;left:0;z-index:1030}@media (min-width:768px){.navbar-fixed-bottom,.navbar-fixed-top{border-radius:0}}.navbar-fixed-top{top:0;border-width:0 0 1px}.navbar-fixed-bottom{bottom:0;margin-bottom:0;border-width:1px 0 0}.navbar-brand{float:left;height:50px;padding:15px 15px;font-size:18px;line-height:20px}.navbar-brand:focus,.navbar-brand:hover{text-decoration:none}.navbar-brand>img{display:block}@media (min-width:768px){.navbar>.container .navbar-brand,.navbar>.container-fluid .navbar-brand{margin-left:-15px}}.navbar-toggle{position:relative;float:right;padding:9px 10px;margin-top:8px;margin-right:15px;margin-bottom:8px;background-color:transparent;background-image:none;border:1px solid transparent;border-radius:4px}.navbar-toggle:focus{outline:0}.navbar-toggle .icon-bar{display:block;width:22px;height:2px;border-radius:1px}.navbar-toggle .icon-bar+.icon-bar{margin-top:4px}@media (min-width:768px){.navbar-toggle{display:none}}.navbar-nav{margin:7.5px -15px}.navbar-nav>li>a{padding-top:10px;padding-bottom:10px;line-height:20px}@media (max-width:767px){.navbar-nav .open .dropdown-menu{position:static;float:none;width:auto;margin-top:0;background-color:transparent;border:0;-webkit-box-shadow:none;box-shadow:none}.navbar-nav .open .dropdown-menu .dropdown-header,.navbar-nav .open .dropdown-menu>li>a{padding:5px 15px 5px 25px}.navbar-nav .open .dropdown-menu>li>a{line-height:20px}.navbar-nav .open .dropdown-menu>li>a:focus,.navbar-nav .open .dropdown-menu>li>a:hover{background-image:none}}@media (min-width:768px){.navbar-nav{float:left;margin:0}.navbar-nav>li{float:left}.navbar-nav>li>a{padding-top:15px;padding-bottom:15px}}.navbar-form{padding:10px 15px;margin-top:8px;margin-right:-15px;margin-bottom:8px;margin-left:-15px;border-top:1px solid transparent;border-bottom:1px solid transparent;-webkit-box-shadow:inset 0 1px 0 rgba(255,255,255,.1),0 1px 0 rgba(255,255,255,.1);box-shadow:inset 0 1px 0 rgba(255,255,255,.1),0 1px 0 rgba(255,255,255,.1)}@media (min-width:768px){.navbar-form .form-group{display:inline-block;margin-bottom:0;vertical-align:middle}.navbar-form .form-control{display:inline-block;width:auto;vertical-align:middle}.navbar-form .form-control-static{display:inline-block}.navbar-form .input-group{display:inline-table;vertical-align:middle}.navbar-form .input-group .form-control,.navbar-form .input-group .input-group-addon,.navbar-form .input-group .input-group-btn{width:auto}.navbar-form .input-group>.form-control{width:100%}.navbar-form .control-label{margin-bottom:0;vertical-align:middle}.navbar-form .checkbox,.navbar-form .radio{display:inline-block;margin-top:0;margin-bottom:0;vertical-align:middle}.navbar-form .checkbox label,.navbar-form .radio label{padding-left:0}.navbar-form .checkbox input[type=checkbox],.navbar-form .radio input[type=radio]{position:relative;margin-left:0}.navbar-form .has-feedback .form-control-feedback{top:0}}@media (max-width:767px){.navbar-form .form-group{margin-bottom:5px}.navbar-form .form-group:last-child{margin-bottom:0}}@media (min-width:768px){.navbar-form{width:auto;padding-top:0;padding-bottom:0;margin-right:0;margin-left:0;border:0;-webkit-box-shadow:none;box-shadow:none}}.navbar-nav>li>.dropdown-menu{margin-top:0;border-top-left-radius:0;border-top-right-radius:0}.navbar-fixed-bottom .navbar-nav>li>.dropdown-menu{margin-bottom:0;border-top-left-radius:4px;border-top-right-radius:4px;border-bottom-right-radius:0;border-bottom-left-radius:0}.navbar-btn{margin-top:8px;margin-bottom:8px}.navbar-btn.btn-sm{margin-top:10px;margin-bottom:10px}.navbar-btn.btn-xs{margin-top:14px;margin-bottom:14px}.navbar-text{margin-top:15px;margin-bottom:15px}@media (min-width:768px){.navbar-text{float:left;margin-right:15px;margin-left:15px}}@media (min-width:768px){.navbar-left{float:left!important}.navbar-right{float:right!important;margin-right:-15px}.navbar-right~.navbar-right{margin-right:0}}.navbar-default{background-color:#f8f8f8;border-color:#e7e7e7}.navbar-default .navbar-brand{color:#777}.navbar-default .navbar-brand:focus,.navbar-default .navbar-brand:hover{color:#5e5e5e;background-color:transparent}.navbar-default .navbar-text{color:#777}.navbar-default .navbar-nav>li>a{color:#777}.navbar-default .navbar-nav>li>a:focus,.navbar-default .navbar-nav>li>a:hover{color:#333;background-color:transparent}.navbar-default .navbar-nav>.active>a,.navbar-default .navbar-nav>.active>a:focus,.navbar-default .navbar-nav>.active>a:hover{color:#555;background-color:#e7e7e7}.navbar-default .navbar-nav>.disabled>a,.navbar-default .navbar-nav>.disabled>a:focus,.navbar-default .navbar-nav>.disabled>a:hover{color:#ccc;background-color:transparent}.navbar-default .navbar-toggle{border-color:#ddd}.navbar-default .navbar-toggle:focus,.navbar-default .navbar-toggle:hover{background-color:#ddd}.navbar-default .navbar-toggle .icon-bar{background-color:#888}.navbar-default .navbar-collapse,.navbar-default .navbar-form{border-color:#e7e7e7}.navbar-default .navbar-nav>.open>a,.navbar-default .navbar-nav>.open>a:focus,.navbar-default .navbar-nav>.open>a:hover{color:#555;background-color:#e7e7e7}@media (max-width:767px){.navbar-default .navbar-nav .open .dropdown-menu>li>a{color:#777}.navbar-default .navbar-nav .open .dropdown-menu>li>a:focus,.navbar-default .navbar-nav .open .dropdown-menu>li>a:hover{color:#333;background-color:transparent}.navbar-default .navbar-nav .open .dropdown-menu>.active>a,.navbar-default .navbar-nav .open .dropdown-menu>.active>a:focus,.navbar-default .navbar-nav .open .dropdown-menu>.active>a:hover{color:#555;background-color:#e7e7e7}.navbar-default .navbar-nav .open .dropdown-menu>.disabled>a,.navbar-default .navbar-nav .open .dropdown-menu>.disabled>a:focus,.navbar-default .navbar-nav .open .dropdown-menu>.disabled>a:hover{color:#ccc;background-color:transparent}}.navbar-default .navbar-link{color:#777}.navbar-default .navbar-link:hover{color:#333}.navbar-default .btn-link{color:#777}.navbar-default .btn-link:focus,.navbar-default .btn-link:hover{color:#333}.navbar-default .btn-link[disabled]:focus,.navbar-default .btn-link[disabled]:hover,fieldset[disabled] .navbar-default .btn-link:focus,fieldset[disabled] .navbar-default .btn-link:hover{color:#ccc}.navbar-inverse{background-color:#222;border-color:#080808}.navbar-inverse .navbar-brand{color:#9d9d9d}.navbar-inverse .navbar-brand:focus,.navbar-inverse .navbar-brand:hover{color:#fff;background-color:transparent}.navbar-inverse .navbar-text{color:#9d9d9d}.navbar-inverse .navbar-nav>li>a{color:#9d9d9d}.navbar-inverse .navbar-nav>li>a:focus,.navbar-inverse .navbar-nav>li>a:hover{color:#fff;background-color:transparent}.navbar-inverse .navbar-nav>.active>a,.navbar-inverse .navbar-nav>.active>a:focus,.navbar-inverse .navbar-nav>.active>a:hover{color:#fff;background-color:#080808}.navbar-inverse .navbar-nav>.disabled>a,.navbar-inverse .navbar-nav>.disabled>a:focus,.navbar-inverse .navbar-nav>.disabled>a:hover{color:#444;background-color:transparent}.navbar-inverse .navbar-toggle{border-color:#333}.navbar-inverse .navbar-toggle:focus,.navbar-inverse .navbar-toggle:hover{background-color:#333}.navbar-inverse .navbar-toggle .icon-bar{background-color:#fff}.navbar-inverse .navbar-collapse,.navbar-inverse .navbar-form{border-color:#101010}.navbar-inverse .navbar-nav>.open>a,.navbar-inverse .navbar-nav>.open>a:focus,.navbar-inverse .navbar-nav>.open>a:hover{color:#fff;background-color:#080808}@media (max-width:767px){.navbar-inverse .navbar-nav .open .dropdown-menu>.dropdown-header{border-color:#080808}.navbar-inverse .navbar-nav .open .dropdown-menu .divider{background-color:#080808}.navbar-inverse .navbar-nav .open .dropdown-menu>li>a{color:#9d9d9d}.navbar-inverse .navbar-nav .open .dropdown-menu>li>a:focus,.navbar-inverse .navbar-nav .open .dropdown-menu>li>a:hover{color:#fff;background-color:transparent}.navbar-inverse .navbar-nav .open .dropdown-menu>.active>a,.navbar-inverse .navbar-nav .open .dropdown-menu>.active>a:focus,.navbar-inverse .navbar-nav .open .dropdown-menu>.active>a:hover{color:#fff;background-color:#080808}.navbar-inverse .navbar-nav .open .dropdown-menu>.disabled>a,.navbar-inverse .navbar-nav .open .dropdown-menu>.disabled>a:focus,.navbar-inverse .navbar-nav .open .dropdown-menu>.disabled>a:hover{color:#444;background-color:transparent}}.navbar-inverse .navbar-link{color:#9d9d9d}.navbar-inverse .navbar-link:hover{color:#fff}.navbar-inverse .btn-link{color:#9d9d9d}.navbar-inverse .btn-link:focus,.navbar-inverse .btn-link:hover{color:#fff}.navbar-inverse .btn-link[disabled]:focus,.navbar-inverse .btn-link[disabled]:hover,fieldset[disabled] .navbar-inverse .btn-link:focus,fieldset[disabled] .navbar-inverse .btn-link:hover{color:#444}.breadcrumb{padding:8px 15px;margin-bottom:20px;list-style:none;background-color:#f5f5f5;border-radius:4px}.breadcrumb>li{display:inline-block}.breadcrumb>li+li:before{padding:0 5px;color:#ccc;content:"/\00a0"}.breadcrumb>.active{color:#777}.pagination{display:inline-block;padding-left:0;margin:20px 0;border-radius:4px}.pagination>li{display:inline}.pagination>li>a,.pagination>li>span{position:relative;float:left;padding:6px 12px;margin-left:-1px;line-height:1.42857143;color:#337ab7;text-decoration:none;background-color:#fff;border:1px solid #ddd}.pagination>li:first-child>a,.pagination>li:first-child>span{margin-left:0;border-top-left-radius:4px;border-bottom-left-radius:4px}.pagination>li:last-child>a,.pagination>li:last-child>span{border-top-right-radius:4px;border-bottom-right-radius:4px}.pagination>li>a:focus,.pagination>li>a:hover,.pagination>li>span:focus,.pagination>li>span:hover{z-index:3;color:#23527c;background-color:#eee;border-color:#ddd}.pagination>.active>a,.pagination>.active>a:focus,.pagination>.active>a:hover,.pagination>.active>span,.pagination>.active>span:focus,.pagination>.active>span:hover{z-index:2;color:#fff;cursor:default;background-color:#337ab7;border-color:#337ab7}.pagination>.disabled>a,.pagination>.disabled>a:focus,.pagination>.disabled>a:hover,.pagination>.disabled>span,.pagination>.disabled>span:focus,.pagination>.disabled>span:hover{color:#777;cursor:not-allowed;background-color:#fff;border-color:#ddd}.pagination-lg>li>a,.pagination-lg>li>span{padding:10px 16px;font-size:18px;line-height:1.3333333}.pagination-lg>li:first-child>a,.pagination-lg>li:first-child>span{border-top-left-radius:6px;border-bottom-left-radius:6px}.pagination-lg>li:last-child>a,.pagination-lg>li:last-child>span{border-top-right-radius:6px;border-bottom-right-radius:6px}.pagination-sm>li>a,.pagination-sm>li>span{padding:5px 10px;font-size:12px;line-height:1.5}.pagination-sm>li:first-child>a,.pagination-sm>li:first-child>span{border-top-left-radius:3px;border-bottom-left-radius:3px}.pagination-sm>li:last-child>a,.pagination-sm>li:last-child>span{border-top-right-radius:3px;border-bottom-right-radius:3px}.pager{padding-left:0;margin:20px 0;text-align:center;list-style:none}.pager li{display:inline}.pager li>a,.pager li>span{display:inline-block;padding:5px 14px;background-color:#fff;border:1px solid #ddd;border-radius:15px}.pager li>a:focus,.pager li>a:hover{text-decoration:none;background-color:#eee}.pager .next>a,.pager .next>span{float:right}.pager .previous>a,.pager .previous>span{float:left}.pager .disabled>a,.pager .disabled>a:focus,.pager .disabled>a:hover,.pager .disabled>span{color:#777;cursor:not-allowed;background-color:#fff}.label{display:inline;padding:.2em .6em .3em;font-size:75%;font-weight:700;line-height:1;color:#fff;text-align:center;white-space:nowrap;vertical-align:baseline;border-radius:.25em}a.label:focus,a.label:hover{color:#fff;text-decoration:none;cursor:pointer}.label:empty{display:none}.btn .label{position:relative;top:-1px}.label-default{background-color:#777}.label-default[href]:focus,.label-default[href]:hover{background-color:#5e5e5e}.label-primary{background-color:#337ab7}.label-primary[href]:focus,.label-primary[href]:hover{background-color:#286090}.label-success{background-color:#5cb85c}.label-success[href]:focus,.label-success[href]:hover{background-color:#449d44}.label-info{background-color:#5bc0de}.label-info[href]:focus,.label-info[href]:hover{background-color:#31b0d5}.label-warning{background-color:#f0ad4e}.label-warning[href]:focus,.label-warning[href]:hover{background-color:#ec971f}.label-danger{background-color:#d9534f}.label-danger[href]:focus,.label-danger[href]:hover{background-color:#c9302c}.badge{display:inline-block;min-width:10px;padding:3px 7px;font-size:12px;font-weight:700;line-height:1;color:#fff;text-align:center;white-space:nowrap;vertical-align:middle;background-color:#777;border-radius:10px}.badge:empty{display:none}.btn .badge{position:relative;top:-1px}.btn-group-xs>.btn .badge,.btn-xs .badge{top:0;padding:1px 5px}a.badge:focus,a.badge:hover{color:#fff;text-decoration:none;cursor:pointer}.list-group-item.active>.badge,.nav-pills>.active>a>.badge{color:#337ab7;background-color:#fff}.list-group-item>.badge{float:right}.list-group-item>.badge+.badge{margin-right:5px}.nav-pills>li>a>.badge{margin-left:3px}.jumbotron{padding-top:30px;padding-bottom:30px;margin-bottom:30px;color:inherit;background-color:#eee}.jumbotron .h1,.jumbotron h1{color:inherit}.jumbotron p{margin-bottom:15px;font-size:21px;font-weight:200}.jumbotron>hr{border-top-color:#d5d5d5}.container .jumbotron,.container-fluid .jumbotron{border-radius:6px}.jumbotron .container{max-width:100%}@media screen and (min-width:768px){.jumbotron{padding-top:48px;padding-bottom:48px}.container .jumbotron,.container-fluid .jumbotron{padding-right:60px;padding-left:60px}.jumbotron .h1,.jumbotron h1{font-size:63px}}.thumbnail{display:block;padding:4px;margin-bottom:20px;line-height:1.42857143;background-color:#fff;border:1px solid #ddd;border-radius:4px;-webkit-transition:border .2s ease-in-out;-o-transition:border .2s ease-in-out;transition:border .2s ease-in-out}.thumbnail a>img,.thumbnail>img{margin-right:auto;margin-left:auto}a.thumbnail.active,a.thumbnail:focus,a.thumbnail:hover{border-color:#337ab7}.thumbnail .caption{padding:9px;color:#333}.alert{padding:15px;margin-bottom:20px;border:1px solid transparent;border-radius:4px}.alert h4{margin-top:0;color:inherit}.alert .alert-link{font-weight:700}.alert>p,.alert>ul{margin-bottom:0}.alert>p+p{margin-top:5px}.alert-dismissable,.alert-dismissible{padding-right:35px}.alert-dismissable .close,.alert-dismissible .close{position:relative;top:-2px;right:-21px;color:inherit}.alert-success{color:#3c763d;background-color:#dff0d8;border-color:#d6e9c6}.alert-success hr{border-top-color:#c9e2b3}.alert-success .alert-link{color:#2b542c}.alert-info{color:#31708f;background-color:#d9edf7;border-color:#bce8f1}.alert-info hr{border-top-color:#a6e1ec}.alert-info .alert-link{color:#245269}.alert-warning{color:#8a6d3b;background-color:#fcf8e3;border-color:#faebcc}.alert-warning hr{border-top-color:#f7e1b5}.alert-warning .alert-link{color:#66512c}.alert-danger{color:#a94442;background-color:#f2dede;border-color:#ebccd1}.alert-danger hr{border-top-color:#e4b9c0}.alert-danger .alert-link{color:#843534}@-webkit-keyframes progress-bar-stripes{from{background-position:40px 0}to{background-position:0 0}}@-o-keyframes progress-bar-stripes{from{background-position:40px 0}to{background-position:0 0}}@keyframes progress-bar-stripes{from{background-position:40px 0}to{background-position:0 0}}.progress{height:20px;margin-bottom:20px;overflow:hidden;background-color:#f5f5f5;border-radius:4px;-webkit-box-shadow:inset 0 1px 2px rgba(0,0,0,.1);box-shadow:inset 0 1px 2px rgba(0,0,0,.1)}.progress-bar{float:left;width:0;height:100%;font-size:12px;line-height:20px;color:#fff;text-align:center;background-color:#337ab7;-webkit-box-shadow:inset 0 -1px 0 rgba(0,0,0,.15);box-shadow:inset 0 -1px 0 rgba(0,0,0,.15);-webkit-transition:width .6s ease;-o-transition:width .6s ease;transition:width .6s ease}.progress-bar-striped,.progress-striped .progress-bar{background-image:-webkit-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:-o-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);-webkit-background-size:40px 40px;background-size:40px 40px}.progress-bar.active,.progress.active .progress-bar{-webkit-animation:progress-bar-stripes 2s linear infinite;-o-animation:progress-bar-stripes 2s linear infinite;animation:progress-bar-stripes 2s linear infinite}.progress-bar-success{background-color:#5cb85c}.progress-striped .progress-bar-success{background-image:-webkit-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:-o-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent)}.progress-bar-info{background-color:#5bc0de}.progress-striped .progress-bar-info{background-image:-webkit-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:-o-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent)}.progress-bar-warning{background-color:#f0ad4e}.progress-striped .progress-bar-warning{background-image:-webkit-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:-o-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent)}.progress-bar-danger{background-color:#d9534f}.progress-striped .progress-bar-danger{background-image:-webkit-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:-o-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent)}.media{margin-top:15px}.media:first-child{margin-top:0}.media,.media-body{overflow:hidden;zoom:1}.media-body{width:10000px}.media-object{display:block}.media-object.img-thumbnail{max-width:none}.media-right,.media>.pull-right{padding-left:10px}.media-left,.media>.pull-left{padding-right:10px}.media-body,.media-left,.media-right{display:table-cell;vertical-align:top}.media-middle{vertical-align:middle}.media-bottom{vertical-align:bottom}.media-heading{margin-top:0;margin-bottom:5px}.media-list{padding-left:0;list-style:none}.list-group{padding-left:0;margin-bottom:20px}.list-group-item{position:relative;display:block;padding:10px 15px;margin-bottom:-1px;background-color:#fff;border:1px solid #ddd}.list-group-item:first-child{border-top-left-radius:4px;border-top-right-radius:4px}.list-group-item:last-child{margin-bottom:0;border-bottom-right-radius:4px;border-bottom-left-radius:4px}a.list-group-item,button.list-group-item{color:#555}a.list-group-item .list-group-item-heading,button.list-group-item .list-group-item-heading{color:#333}a.list-group-item:focus,a.list-group-item:hover,button.list-group-item:focus,button.list-group-item:hover{color:#555;text-decoration:none;background-color:#f5f5f5}button.list-group-item{width:100%;text-align:left}.list-group-item.disabled,.list-group-item.disabled:focus,.list-group-item.disabled:hover{color:#777;cursor:not-allowed;background-color:#eee}.list-group-item.disabled .list-group-item-heading,.list-group-item.disabled:focus .list-group-item-heading,.list-group-item.disabled:hover .list-group-item-heading{color:inherit}.list-group-item.disabled .list-group-item-text,.list-group-item.disabled:focus .list-group-item-text,.list-group-item.disabled:hover .list-group-item-text{color:#777}.list-group-item.active,.list-group-item.active:focus,.list-group-item.active:hover{z-index:2;color:#fff;background-color:#337ab7;border-color:#337ab7}.list-group-item.active .list-group-item-heading,.list-group-item.active .list-group-item-heading>.small,.list-group-item.active .list-group-item-heading>small,.list-group-item.active:focus .list-group-item-heading,.list-group-item.active:focus .list-group-item-heading>.small,.list-group-item.active:focus .list-group-item-heading>small,.list-group-item.active:hover .list-group-item-heading,.list-group-item.active:hover .list-group-item-heading>.small,.list-group-item.active:hover .list-group-item-heading>small{color:inherit}.list-group-item.active .list-group-item-text,.list-group-item.active:focus .list-group-item-text,.list-group-item.active:hover .list-group-item-text{color:#c7ddef}.list-group-item-success{color:#3c763d;background-color:#dff0d8}a.list-group-item-success,button.list-group-item-success{color:#3c763d}a.list-group-item-success .list-group-item-heading,button.list-group-item-success .list-group-item-heading{color:inherit}a.list-group-item-success:focus,a.list-group-item-success:hover,button.list-group-item-success:focus,button.list-group-item-success:hover{color:#3c763d;background-color:#d0e9c6}a.list-group-item-success.active,a.list-group-item-success.active:focus,a.list-group-item-success.active:hover,button.list-group-item-success.active,button.list-group-item-success.active:focus,button.list-group-item-success.active:hover{color:#fff;background-color:#3c763d;border-color:#3c763d}.list-group-item-info{color:#31708f;background-color:#d9edf7}a.list-group-item-info,button.list-group-item-info{color:#31708f}a.list-group-item-info .list-group-item-heading,button.list-group-item-info .list-group-item-heading{color:inherit}a.list-group-item-info:focus,a.list-group-item-info:hover,button.list-group-item-info:focus,button.list-group-item-info:hover{color:#31708f;background-color:#c4e3f3}a.list-group-item-info.active,a.list-group-item-info.active:focus,a.list-group-item-info.active:hover,button.list-group-item-info.active,button.list-group-item-info.active:focus,button.list-group-item-info.active:hover{color:#fff;background-color:#31708f;border-color:#31708f}.list-group-item-warning{color:#8a6d3b;background-color:#fcf8e3}a.list-group-item-warning,button.list-group-item-warning{color:#8a6d3b}a.list-group-item-warning .list-group-item-heading,button.list-group-item-warning .list-group-item-heading{color:inherit}a.list-group-item-warning:focus,a.list-group-item-warning:hover,button.list-group-item-warning:focus,button.list-group-item-warning:hover{color:#8a6d3b;background-color:#faf2cc}a.list-group-item-warning.active,a.list-group-item-warning.active:focus,a.list-group-item-warning.active:hover,button.list-group-item-warning.active,button.list-group-item-warning.active:focus,button.list-group-item-warning.active:hover{color:#fff;background-color:#8a6d3b;border-color:#8a6d3b}.list-group-item-danger{color:#a94442;background-color:#f2dede}a.list-group-item-danger,button.list-group-item-danger{color:#a94442}a.list-group-item-danger .list-group-item-heading,button.list-group-item-danger .list-group-item-heading{color:inherit}a.list-group-item-danger:focus,a.list-group-item-danger:hover,button.list-group-item-danger:focus,button.list-group-item-danger:hover{color:#a94442;background-color:#ebcccc}a.list-group-item-danger.active,a.list-group-item-danger.active:focus,a.list-group-item-danger.active:hover,button.list-group-item-danger.active,button.list-group-item-danger.active:focus,button.list-group-item-danger.active:hover{color:#fff;background-color:#a94442;border-color:#a94442}.list-group-item-heading{margin-top:0;margin-bottom:5px}.list-group-item-text{margin-bottom:0;line-height:1.3}.panel{margin-bottom:20px;background-color:#fff;border:1px solid transparent;border-radius:4px;-webkit-box-shadow:0 1px 1px rgba(0,0,0,.05);box-shadow:0 1px 1px rgba(0,0,0,.05)}.panel-body{padding:15px}.panel-heading{padding:10px 15px;border-bottom:1px solid transparent;border-top-left-radius:3px;border-top-right-radius:3px}.panel-heading>.dropdown .dropdown-toggle{color:inherit}.panel-title{margin-top:0;margin-bottom:0;font-size:16px;color:inherit}.panel-title>.small,.panel-title>.small>a,.panel-title>a,.panel-title>small,.panel-title>small>a{color:inherit}.panel-footer{padding:10px 15px;background-color:#f5f5f5;border-top:1px solid #ddd;border-bottom-right-radius:3px;border-bottom-left-radius:3px}.panel>.list-group,.panel>.panel-collapse>.list-group{margin-bottom:0}.panel>.list-group .list-group-item,.panel>.panel-collapse>.list-group .list-group-item{border-width:1px 0;border-radius:0}.panel>.list-group:first-child .list-group-item:first-child,.panel>.panel-collapse>.list-group:first-child .list-group-item:first-child{border-top:0;border-top-left-radius:3px;border-top-right-radius:3px}.panel>.list-group:last-child .list-group-item:last-child,.panel>.panel-collapse>.list-group:last-child .list-group-item:last-child{border-bottom:0;border-bottom-right-radius:3px;border-bottom-left-radius:3px}.panel>.panel-heading+.panel-collapse>.list-group .list-group-item:first-child{border-top-left-radius:0;border-top-right-radius:0}.panel-heading+.list-group .list-group-item:first-child{border-top-width:0}.list-group+.panel-footer{border-top-width:0}.panel>.panel-collapse>.table,.panel>.table,.panel>.table-responsive>.table{margin-bottom:0}.panel>.panel-collapse>.table caption,.panel>.table caption,.panel>.table-responsive>.table caption{padding-right:15px;padding-left:15px}.panel>.table-responsive:first-child>.table:first-child,.panel>.table:first-child{border-top-left-radius:3px;border-top-right-radius:3px}.panel>.table-responsive:first-child>.table:first-child>tbody:first-child>tr:first-child,.panel>.table-responsive:first-child>.table:first-child>thead:first-child>tr:first-child,.panel>.table:first-child>tbody:first-child>tr:first-child,.panel>.table:first-child>thead:first-child>tr:first-child{border-top-left-radius:3px;border-top-right-radius:3px}.panel>.table-responsive:first-child>.table:first-child>tbody:first-child>tr:first-child td:first-child,.panel>.table-responsive:first-child>.table:first-child>tbody:first-child>tr:first-child th:first-child,.panel>.table-responsive:first-child>.table:first-child>thead:first-child>tr:first-child td:first-child,.panel>.table-responsive:first-child>.table:first-child>thead:first-child>tr:first-child th:first-child,.panel>.table:first-child>tbody:first-child>tr:first-child td:first-child,.panel>.table:first-child>tbody:first-child>tr:first-child th:first-child,.panel>.table:first-child>thead:first-child>tr:first-child td:first-child,.panel>.table:first-child>thead:first-child>tr:first-child th:first-child{border-top-left-radius:3px}.panel>.table-responsive:first-child>.table:first-child>tbody:first-child>tr:first-child td:last-child,.panel>.table-responsive:first-child>.table:first-child>tbody:first-child>tr:first-child th:last-child,.panel>.table-responsive:first-child>.table:first-child>thead:first-child>tr:first-child td:last-child,.panel>.table-responsive:first-child>.table:first-child>thead:first-child>tr:first-child th:last-child,.panel>.table:first-child>tbody:first-child>tr:first-child td:last-child,.panel>.table:first-child>tbody:first-child>tr:first-child th:last-child,.panel>.table:first-child>thead:first-child>tr:first-child td:last-child,.panel>.table:first-child>thead:first-child>tr:first-child th:last-child{border-top-right-radius:3px}.panel>.table-responsive:last-child>.table:last-child,.panel>.table:last-child{border-bottom-right-radius:3px;border-bottom-left-radius:3px}.panel>.table-responsive:last-child>.table:last-child>tbody:last-child>tr:last-child,.panel>.table-responsive:last-child>.table:last-child>tfoot:last-child>tr:last-child,.panel>.table:last-child>tbody:last-child>tr:last-child,.panel>.table:last-child>tfoot:last-child>tr:last-child{border-bottom-right-radius:3px;border-bottom-left-radius:3px}.panel>.table-responsive:last-child>.table:last-child>tbody:last-child>tr:last-child td:first-child,.panel>.table-responsive:last-child>.table:last-child>tbody:last-child>tr:last-child th:first-child,.panel>.table-responsive:last-child>.table:last-child>tfoot:last-child>tr:last-child td:first-child,.panel>.table-responsive:last-child>.table:last-child>tfoot:last-child>tr:last-child th:first-child,.panel>.table:last-child>tbody:last-child>tr:last-child td:first-child,.panel>.table:last-child>tbody:last-child>tr:last-child th:first-child,.panel>.table:last-child>tfoot:last-child>tr:last-child td:first-child,.panel>.table:last-child>tfoot:last-child>tr:last-child th:first-child{border-bottom-left-radius:3px}.panel>.table-responsive:last-child>.table:last-child>tbody:last-child>tr:last-child td:last-child,.panel>.table-responsive:last-child>.table:last-child>tbody:last-child>tr:last-child th:last-child,.panel>.table-responsive:last-child>.table:last-child>tfoot:last-child>tr:last-child td:last-child,.panel>.table-responsive:last-child>.table:last-child>tfoot:last-child>tr:last-child th:last-child,.panel>.table:last-child>tbody:last-child>tr:last-child td:last-child,.panel>.table:last-child>tbody:last-child>tr:last-child th:last-child,.panel>.table:last-child>tfoot:last-child>tr:last-child td:last-child,.panel>.table:last-child>tfoot:last-child>tr:last-child th:last-child{border-bottom-right-radius:3px}.panel>.panel-body+.table,.panel>.panel-body+.table-responsive,.panel>.table+.panel-body,.panel>.table-responsive+.panel-body{border-top:1px solid #ddd}.panel>.table>tbody:first-child>tr:first-child td,.panel>.table>tbody:first-child>tr:first-child th{border-top:0}.panel>.table-bordered,.panel>.table-responsive>.table-bordered{border:0}.panel>.table-bordered>tbody>tr>td:first-child,.panel>.table-bordered>tbody>tr>th:first-child,.panel>.table-bordered>tfoot>tr>td:first-child,.panel>.table-bordered>tfoot>tr>th:first-child,.panel>.table-bordered>thead>tr>td:first-child,.panel>.table-bordered>thead>tr>th:first-child,.panel>.table-responsive>.table-bordered>tbody>tr>td:first-child,.panel>.table-responsive>.table-bordered>tbody>tr>th:first-child,.panel>.table-responsive>.table-bordered>tfoot>tr>td:first-child,.panel>.table-responsive>.table-bordered>tfoot>tr>th:first-child,.panel>.table-responsive>.table-bordered>thead>tr>td:first-child,.panel>.table-responsive>.table-bordered>thead>tr>th:first-child{border-left:0}.panel>.table-bordered>tbody>tr>td:last-child,.panel>.table-bordered>tbody>tr>th:last-child,.panel>.table-bordered>tfoot>tr>td:last-child,.panel>.table-bordered>tfoot>tr>th:last-child,.panel>.table-bordered>thead>tr>td:last-child,.panel>.table-bordered>thead>tr>th:last-child,.panel>.table-responsive>.table-bordered>tbody>tr>td:last-child,.panel>.table-responsive>.table-bordered>tbody>tr>th:last-child,.panel>.table-responsive>.table-bordered>tfoot>tr>td:last-child,.panel>.table-responsive>.table-bordered>tfoot>tr>th:last-child,.panel>.table-responsive>.table-bordered>thead>tr>td:last-child,.panel>.table-responsive>.table-bordered>thead>tr>th:last-child{border-right:0}.panel>.table-bordered>tbody>tr:first-child>td,.panel>.table-bordered>tbody>tr:first-child>th,.panel>.table-bordered>thead>tr:first-child>td,.panel>.table-bordered>thead>tr:first-child>th,.panel>.table-responsive>.table-bordered>tbody>tr:first-child>td,.panel>.table-responsive>.table-bordered>tbody>tr:first-child>th,.panel>.table-responsive>.table-bordered>thead>tr:first-child>td,.panel>.table-responsive>.table-bordered>thead>tr:first-child>th{border-bottom:0}.panel>.table-bordered>tbody>tr:last-child>td,.panel>.table-bordered>tbody>tr:last-child>th,.panel>.table-bordered>tfoot>tr:last-child>td,.panel>.table-bordered>tfoot>tr:last-child>th,.panel>.table-responsive>.table-bordered>tbody>tr:last-child>td,.panel>.table-responsive>.table-bordered>tbody>tr:last-child>th,.panel>.table-responsive>.table-bordered>tfoot>tr:last-child>td,.panel>.table-responsive>.table-bordered>tfoot>tr:last-child>th{border-bottom:0}.panel>.table-responsive{margin-bottom:0;border:0}.panel-group{margin-bottom:20px}.panel-group .panel{margin-bottom:0;border-radius:4px}.panel-group .panel+.panel{margin-top:5px}.panel-group .panel-heading{border-bottom:0}.panel-group .panel-heading+.panel-collapse>.list-group,.panel-group .panel-heading+.panel-collapse>.panel-body{border-top:1px solid #ddd}.panel-group .panel-footer{border-top:0}.panel-group .panel-footer+.panel-collapse .panel-body{border-bottom:1px solid #ddd}.panel-default{border-color:#ddd}.panel-default>.panel-heading{color:#333;background-color:#f5f5f5;border-color:#ddd}.panel-default>.panel-heading+.panel-collapse>.panel-body{border-top-color:#ddd}.panel-default>.panel-heading .badge{color:#f5f5f5;background-color:#333}.panel-default>.panel-footer+.panel-collapse>.panel-body{border-bottom-color:#ddd}.panel-primary{border-color:#337ab7}.panel-primary>.panel-heading{color:#fff;background-color:#337ab7;border-color:#337ab7}.panel-primary>.panel-heading+.panel-collapse>.panel-body{border-top-color:#337ab7}.panel-primary>.panel-heading .badge{color:#337ab7;background-color:#fff}.panel-primary>.panel-footer+.panel-collapse>.panel-body{border-bottom-color:#337ab7}.panel-success{border-color:#d6e9c6}.panel-success>.panel-heading{color:#3c763d;background-color:#dff0d8;border-color:#d6e9c6}.panel-success>.panel-heading+.panel-collapse>.panel-body{border-top-color:#d6e9c6}.panel-success>.panel-heading .badge{color:#dff0d8;background-color:#3c763d}.panel-success>.panel-footer+.panel-collapse>.panel-body{border-bottom-color:#d6e9c6}.panel-info{border-color:#bce8f1}.panel-info>.panel-heading{color:#31708f;background-color:#d9edf7;border-color:#bce8f1}.panel-info>.panel-heading+.panel-collapse>.panel-body{border-top-color:#bce8f1}.panel-info>.panel-heading .badge{color:#d9edf7;background-color:#31708f}.panel-info>.panel-footer+.panel-collapse>.panel-body{border-bottom-color:#bce8f1}.panel-warning{border-color:#faebcc}.panel-warning>.panel-heading{color:#8a6d3b;background-color:#fcf8e3;border-color:#faebcc}.panel-warning>.panel-heading+.panel-collapse>.panel-body{border-top-color:#faebcc}.panel-warning>.panel-heading .badge{color:#fcf8e3;background-color:#8a6d3b}.panel-warning>.panel-footer+.panel-collapse>.panel-body{border-bottom-color:#faebcc}.panel-danger{border-color:#ebccd1}.panel-danger>.panel-heading{color:#a94442;background-color:#f2dede;border-color:#ebccd1}.panel-danger>.panel-heading+.panel-collapse>.panel-body{border-top-color:#ebccd1}.panel-danger>.panel-heading .badge{color:#f2dede;background-color:#a94442}.panel-danger>.panel-footer+.panel-collapse>.panel-body{border-bottom-color:#ebccd1}.embed-responsive{position:relative;display:block;height:0;padding:0;overflow:hidden}.embed-responsive .embed-responsive-item,.embed-responsive embed,.embed-responsive iframe,.embed-responsive object,.embed-responsive video{position:absolute;top:0;bottom:0;left:0;width:100%;height:100%;border:0}.embed-responsive-16by9{padding-bottom:56.25%}.embed-responsive-4by3{padding-bottom:75%}.well{min-height:20px;padding:19px;margin-bottom:20px;background-color:#f5f5f5;border:1px solid #e3e3e3;border-radius:4px;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.05);box-shadow:inset 0 1px 1px rgba(0,0,0,.05)}.well blockquote{border-color:#ddd;border-color:rgba(0,0,0,.15)}.well-lg{padding:24px;border-radius:6px}.well-sm{padding:9px;border-radius:3px}.close{float:right;font-size:21px;font-weight:700;line-height:1;color:#000;text-shadow:0 1px 0 #fff;filter:alpha(opacity=20);opacity:.2}.close:focus,.close:hover{color:#000;text-decoration:none;cursor:pointer;filter:alpha(opacity=50);opacity:.5}button.close{-webkit-appearance:none;padding:0;cursor:pointer;background:0 0;border:0}.modal-open{overflow:hidden}.modal{position:fixed;top:0;right:0;bottom:0;left:0;z-index:1050;display:none;overflow:hidden;-webkit-overflow-scrolling:touch;outline:0}.modal.fade .modal-dialog{-webkit-transition:-webkit-transform .3s ease-out;-o-transition:-o-transform .3s ease-out;transition:transform .3s ease-out;-webkit-transform:translate(0,-25%);-ms-transform:translate(0,-25%);-o-transform:translate(0,-25%);transform:translate(0,-25%)}.modal.in .modal-dialog{-webkit-transform:translate(0,0);-ms-transform:translate(0,0);-o-transform:translate(0,0);transform:translate(0,0)}.modal-open .modal{overflow-x:hidden;overflow-y:auto}.modal-dialog{position:relative;width:auto;margin:10px}.modal-content{position:relative;background-color:#fff;-webkit-background-clip:padding-box;background-clip:padding-box;border:1px solid #999;border:1px solid rgba(0,0,0,.2);border-radius:6px;outline:0;-webkit-box-shadow:0 3px 9px rgba(0,0,0,.5);box-shadow:0 3px 9px rgba(0,0,0,.5)}.modal-backdrop{position:fixed;top:0;right:0;bottom:0;left:0;z-index:1040;background-color:#000}.modal-backdrop.fade{filter:alpha(opacity=0);opacity:0}.modal-backdrop.in{filter:alpha(opacity=50);opacity:.5}.modal-header{min-height:16.43px;padding:15px;border-bottom:1px solid #e5e5e5}.modal-header .close{margin-top:-2px}.modal-title{margin:0;line-height:1.42857143}.modal-body{position:relative;padding:15px}.modal-footer{padding:15px;text-align:right;border-top:1px solid #e5e5e5}.modal-footer .btn+.btn{margin-bottom:0;margin-left:5px}.modal-footer .btn-group .btn+.btn{margin-left:-1px}.modal-footer .btn-block+.btn-block{margin-left:0}.modal-scrollbar-measure{position:absolute;top:-9999px;width:50px;height:50px;overflow:scroll}@media (min-width:768px){.modal-dialog{width:600px;margin:30px auto}.modal-content{-webkit-box-shadow:0 5px 15px rgba(0,0,0,.5);box-shadow:0 5px 15px rgba(0,0,0,.5)}.modal-sm{width:300px}}@media (min-width:992px){.modal-lg{width:900px}}.tooltip{position:absolute;z-index:9999;display:block;font-family:"Helvetica Neue",Helvetica,Arial,sans-serif;font-size:12px;font-style:normal;font-weight:400;line-height:1.42857143;text-align:left;text-align:start;text-decoration:none;text-shadow:none;text-transform:none;letter-spacing:normal;word-break:normal;word-spacing:normal;word-wrap:normal;white-space:normal;filter:alpha(opacity=0);opacity:0;line-break:auto}.tooltip.in{filter:alpha(opacity=90);opacity:.9}.tooltip.top{padding:5px 0;margin-top:-3px}.tooltip.right{padding:0 5px;margin-left:3px}.tooltip.bottom{padding:5px 0;margin-top:3px}.tooltip.left{padding:0 5px;margin-left:-3px}.tooltip-inner{max-width:200px;padding:3px 8px;color:#fff;text-align:center;background-color:#000;border-radius:4px}.tooltip-arrow{position:absolute;width:0;height:0;border-color:transparent;border-style:solid}.tooltip.top .tooltip-arrow{bottom:0;left:50%;margin-left:-5px;border-width:5px 5px 0;border-top-color:#000}.tooltip.top-left .tooltip-arrow{right:5px;bottom:0;margin-bottom:-5px;border-width:5px 5px 0;border-top-color:#000}.tooltip.top-right .tooltip-arrow{bottom:0;left:5px;margin-bottom:-5px;border-width:5px 5px 0;border-top-color:#000}.tooltip.right .tooltip-arrow{top:50%;left:0;margin-top:-5px;border-width:5px 5px 5px 0;border-right-color:#000}.tooltip.left .tooltip-arrow{top:50%;right:0;margin-top:-5px;border-width:5px 0 5px 5px;border-left-color:#000}.tooltip.bottom .tooltip-arrow{top:0;left:50%;margin-left:-5px;border-width:0 5px 5px;border-bottom-color:#000}.tooltip.bottom-left .tooltip-arrow{top:0;right:5px;margin-top:-5px;border-width:0 5px 5px;border-bottom-color:#000}.tooltip.bottom-right .tooltip-arrow{top:0;left:5px;margin-top:-5px;border-width:0 5px 5px;border-bottom-color:#000}.popover{position:absolute;top:0;left:0;z-index:1060;display:none;max-width:276px;padding:1px;font-family:"Helvetica Neue",Helvetica,Arial,sans-serif;font-size:14px;font-style:normal;font-weight:400;line-height:1.42857143;text-align:left;text-align:start;text-decoration:none;text-shadow:none;text-transform:none;letter-spacing:normal;word-break:normal;word-spacing:normal;word-wrap:normal;white-space:normal;background-color:#fff;-webkit-background-clip:padding-box;background-clip:padding-box;border:1px solid #ccc;border:1px solid rgba(0,0,0,.2);border-radius:6px;-webkit-box-shadow:0 5px 10px rgba(0,0,0,.2);box-shadow:0 5px 10px rgba(0,0,0,.2);line-break:auto}.popover.top{margin-top:-10px}.popover.right{margin-left:10px}.popover.bottom{margin-top:10px}.popover.left{margin-left:-10px}.popover-title{padding:8px 14px;margin:0;font-size:14px;background-color:#f7f7f7;border-bottom:1px solid #ebebeb;border-radius:5px 5px 0 0}.popover-content{padding:9px 14px}.popover>.arrow,.popover>.arrow:after{position:absolute;display:block;width:0;height:0;border-color:transparent;border-style:solid}.popover>.arrow{border-width:11px}.popover>.arrow:after{content:"";border-width:10px}.popover.top>.arrow{bottom:-11px;left:50%;margin-left:-11px;border-top-color:#999;border-top-color:rgba(0,0,0,.25);border-bottom-width:0}.popover.top>.arrow:after{bottom:1px;margin-left:-10px;content:" ";border-top-color:#fff;border-bottom-width:0}.popover.right>.arrow{top:50%;left:-11px;margin-top:-11px;border-right-color:#999;border-right-color:rgba(0,0,0,.25);border-left-width:0}.popover.right>.arrow:after{bottom:-10px;left:1px;content:" ";border-right-color:#fff;border-left-width:0}.popover.bottom>.arrow{top:-11px;left:50%;margin-left:-11px;border-top-width:0;border-bottom-color:#999;border-bottom-color:rgba(0,0,0,.25)}.popover.bottom>.arrow:after{top:1px;margin-left:-10px;content:" ";border-top-width:0;border-bottom-color:#fff}.popover.left>.arrow{top:50%;right:-11px;margin-top:-11px;border-right-width:0;border-left-color:#999;border-left-color:rgba(0,0,0,.25)}.popover.left>.arrow:after{right:1px;bottom:-10px;content:" ";border-right-width:0;border-left-color:#fff}.carousel{position:relative}.carousel-inner{position:relative;width:100%;overflow:hidden}.carousel-inner>.item{position:relative;display:none;-webkit-transition:.6s ease-in-out left;-o-transition:.6s ease-in-out left;transition:.6s ease-in-out left}.carousel-inner>.item>a>img,.carousel-inner>.item>img{line-height:1}@media all and (transform-3d),(-webkit-transform-3d){.carousel-inner>.item{-webkit-transition:-webkit-transform .6s ease-in-out;-o-transition:-o-transform .6s ease-in-out;transition:transform .6s ease-in-out;-webkit-backface-visibility:hidden;backface-visibility:hidden;-webkit-perspective:1000px;perspective:1000px}.carousel-inner>.item.active.right,.carousel-inner>.item.next{left:0;-webkit-transform:translate3d(100%,0,0);transform:translate3d(100%,0,0)}.carousel-inner>.item.active.left,.carousel-inner>.item.prev{left:0;-webkit-transform:translate3d(-100%,0,0);transform:translate3d(-100%,0,0)}.carousel-inner>.item.active,.carousel-inner>.item.next.left,.carousel-inner>.item.prev.right{left:0;-webkit-transform:translate3d(0,0,0);transform:translate3d(0,0,0)}}.carousel-inner>.active,.carousel-inner>.next,.carousel-inner>.prev{display:block}.carousel-inner>.active{left:0}.carousel-inner>.next,.carousel-inner>.prev{position:absolute;top:0;width:100%}.carousel-inner>.next{left:100%}.carousel-inner>.prev{left:-100%}.carousel-inner>.next.left,.carousel-inner>.prev.right{left:0}.carousel-inner>.active.left{left:-100%}.carousel-inner>.active.right{left:100%}.carousel-control{position:absolute;top:0;bottom:0;left:0;width:15%;font-size:20px;color:#fff;text-align:center;text-shadow:0 1px 2px rgba(0,0,0,.6);filter:alpha(opacity=50);opacity:.5}.carousel-control.left{background-image:-webkit-linear-gradient(left,rgba(0,0,0,.5) 0,rgba(0,0,0,.0001) 100%);background-image:-o-linear-gradient(left,rgba(0,0,0,.5) 0,rgba(0,0,0,.0001) 100%);background-image:-webkit-gradient(linear,left top,right top,from(rgba(0,0,0,.5)),to(rgba(0,0,0,.0001)));background-image:linear-gradient(to right,rgba(0,0,0,.5) 0,rgba(0,0,0,.0001) 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#80000000', endColorstr='#00000000', GradientType=1);background-repeat:repeat-x}.carousel-control.right{right:0;left:auto;background-image:-webkit-linear-gradient(left,rgba(0,0,0,.0001) 0,rgba(0,0,0,.5) 100%);background-image:-o-linear-gradient(left,rgba(0,0,0,.0001) 0,rgba(0,0,0,.5) 100%);background-image:-webkit-gradient(linear,left top,right top,from(rgba(0,0,0,.0001)),to(rgba(0,0,0,.5)));background-image:linear-gradient(to right,rgba(0,0,0,.0001) 0,rgba(0,0,0,.5) 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#00000000', endColorstr='#80000000', GradientType=1);background-repeat:repeat-x}.carousel-control:focus,.carousel-control:hover{color:#fff;text-decoration:none;filter:alpha(opacity=90);outline:0;opacity:.9}.carousel-control .glyphicon-chevron-left,.carousel-control .glyphicon-chevron-right,.carousel-control .icon-next,.carousel-control .icon-prev{position:absolute;top:50%;z-index:5;display:inline-block;margin-top:-10px}.carousel-control .glyphicon-chevron-left,.carousel-control .icon-prev{left:50%;margin-left:-10px}.carousel-control .glyphicon-chevron-right,.carousel-control .icon-next{right:50%;margin-right:-10px}.carousel-control .icon-next,.carousel-control .icon-prev{width:20px;height:20px;font-family:serif;line-height:1}.carousel-control .icon-prev:before{content:'\2039'}.carousel-control .icon-next:before{content:'\203a'}.carousel-indicators{position:absolute;bottom:10px;left:50%;z-index:15;width:60%;padding-left:0;margin-left:-30%;text-align:center;list-style:none}.carousel-indicators li{display:inline-block;width:10px;height:10px;margin:1px;text-indent:-999px;cursor:pointer;background-color:#000\9;background-color:rgba(0,0,0,0);border:1px solid #fff;border-radius:10px}.carousel-indicators .active{width:12px;height:12px;margin:0;background-color:#fff}.carousel-caption{position:absolute;right:15%;bottom:20px;left:15%;z-index:10;padding-top:20px;padding-bottom:20px;color:#fff;text-align:center;text-shadow:0 1px 2px rgba(0,0,0,.6)}.carousel-caption .btn{text-shadow:none}@media screen and (min-width:768px){.carousel-control .glyphicon-chevron-left,.carousel-control .glyphicon-chevron-right,.carousel-control .icon-next,.carousel-control .icon-prev{width:30px;height:30px;margin-top:-15px;font-size:30px}.carousel-control .glyphicon-chevron-left,.carousel-control .icon-prev{margin-left:-15px}.carousel-control .glyphicon-chevron-right,.carousel-control .icon-next{margin-right:-15px}.carousel-caption{right:20%;left:20%;padding-bottom:30px}.carousel-indicators{bottom:20px}}.btn-group-vertical>.btn-group:after,.btn-group-vertical>.btn-group:before,.btn-toolbar:after,.btn-toolbar:before,.clearfix:after,.clearfix:before,.container-fluid:after,.container-fluid:before,.container:after,.container:before,.dl-horizontal dd:after,.dl-horizontal dd:before,.form-horizontal .form-group:after,.form-horizontal .form-group:before,.modal-footer:after,.modal-footer:before,.nav:after,.nav:before,.navbar-collapse:after,.navbar-collapse:before,.navbar-header:after,.navbar-header:before,.navbar:after,.navbar:before,.pager:after,.pager:before,.panel-body:after,.panel-body:before,.row:after,.row:before{display:table;content:" "}.btn-group-vertical>.btn-group:after,.btn-toolbar:after,.clearfix:after,.container-fluid:after,.container:after,.dl-horizontal dd:after,.form-horizontal .form-group:after,.modal-footer:after,.nav:after,.navbar-collapse:after,.navbar-header:after,.navbar:after,.pager:after,.panel-body:after,.row:after{clear:both}.center-block{display:block;margin-right:auto;margin-left:auto}.pull-right{float:right!important}.pull-left{float:left!important}.hide{display:none!important}.show{display:block!important}.invisible{visibility:hidden}.text-hide{font:0/0 a;color:transparent;text-shadow:none;background-color:transparent;border:0}.hidden{display:none!important}.affix{position:fixed}@-ms-viewport{width:device-width}.visible-lg,.visible-md,.visible-sm,.visible-xs{display:none!important}.visible-lg-block,.visible-lg-inline,.visible-lg-inline-block,.visible-md-block,.visible-md-inline,.visible-md-inline-block,.visible-sm-block,.visible-sm-inline,.visible-sm-inline-block,.visible-xs-block,.visible-xs-inline,.visible-xs-inline-block{display:none!important}@media (max-width:767px){.visible-xs{display:block!important}table.visible-xs{display:table!important}tr.visible-xs{display:table-row!important}td.visible-xs,th.visible-xs{display:table-cell!important}}@media (max-width:767px){.visible-xs-block{display:block!important}}@media (max-width:767px){.visible-xs-inline{display:inline!important}}@media (max-width:767px){.visible-xs-inline-block{display:inline-block!important}}@media (min-width:768px) and (max-width:991px){.visible-sm{display:block!important}table.visible-sm{display:table!important}tr.visible-sm{display:table-row!important}td.visible-sm,th.visible-sm{display:table-cell!important}}@media (min-width:768px) and (max-width:991px){.visible-sm-block{display:block!important}}@media (min-width:768px) and (max-width:991px){.visible-sm-inline{display:inline!important}}@media (min-width:768px) and (max-width:991px){.visible-sm-inline-block{display:inline-block!important}}@media (min-width:992px) and (max-width:1199px){.visible-md{display:block!important}table.visible-md{display:table!important}tr.visible-md{display:table-row!important}td.visible-md,th.visible-md{display:table-cell!important}}@media (min-width:992px) and (max-width:1199px){.visible-md-block{display:block!important}}@media (min-width:992px) and (max-width:1199px){.visible-md-inline{display:inline!important}}@media (min-width:992px) and (max-width:1199px){.visible-md-inline-block{display:inline-block!important}}@media (min-width:1200px){.visible-lg{display:block!important}table.visible-lg{display:table!important}tr.visible-lg{display:table-row!important}td.visible-lg,th.visible-lg{display:table-cell!important}}@media (min-width:1200px){.visible-lg-block{display:block!important}}@media (min-width:1200px){.visible-lg-inline{display:inline!important}}@media (min-width:1200px){.visible-lg-inline-block{display:inline-block!important}}@media (max-width:767px){.hidden-xs{display:none!important}}@media (min-width:768px) and (max-width:991px){.hidden-sm{display:none!important}}@media (min-width:992px) and (max-width:1199px){.hidden-md{display:none!important}}@media (min-width:1200px){.hidden-lg{display:none!important}}.visible-print{display:none!important}@media print{.visible-print{display:block!important}table.visible-print{display:table!important}tr.visible-print{display:table-row!important}td.visible-print,th.visible-print{display:table-cell!important}}.visible-print-block{display:none!important}@media print{.visible-print-block{display:block!important}}.visible-print-inline{display:none!important}@media print{.visible-print-inline{display:inline!important}}.visible-print-inline-block{display:none!important}@media print{.visible-print-inline-block{display:inline-block!important}}@media print{.hidden-print{display:none!important}}
|
7 |
|
8 |
|
9 |
/*
|
121 |
border-top: none;
|
122 |
margin-top: 0 !important;
|
123 |
}
|
124 |
+
.table > tbody > tr > td small,
|
125 |
+
.table > tbody > tr > th small,
|
126 |
+
.table > tfoot > tr > td small,
|
127 |
+
.table > tfoot > tr > th small,
|
128 |
+
.table > thead > tr > td small,
|
129 |
.table > thead > tr > th small{
|
130 |
line-height: 1.2em;
|
131 |
display: block;
|
media/js/aam.js
CHANGED
@@ -120,7 +120,7 @@
|
|
120 |
subject: getAAM().getSubject().type,
|
121 |
subjectId: getAAM().getSubject().id,
|
122 |
ui: getLocal().ui,
|
123 |
-
|
124 |
}
|
125 |
},
|
126 |
columnDefs: [
|
@@ -311,7 +311,7 @@
|
|
311 |
type: 'role',
|
312 |
id: data[0]
|
313 |
},
|
314 |
-
$('#
|
315 |
($(this).hasClass('icon-check-empty') ? 1 : 0),
|
316 |
this
|
317 |
);
|
@@ -319,14 +319,6 @@
|
|
319 |
}
|
320 |
break;
|
321 |
|
322 |
-
case 'no-attach':
|
323 |
-
if (getAAM().isUI('principal')) {
|
324 |
-
$(container).append($('<i/>', {
|
325 |
-
'class': 'aam-row-action icon-check-empty text-muted'
|
326 |
-
}));
|
327 |
-
}
|
328 |
-
break;
|
329 |
-
|
330 |
case 'detach':
|
331 |
if (getAAM().isUI('principal')) {
|
332 |
$(container).append($('<i/>', {
|
@@ -337,7 +329,7 @@
|
|
337 |
type: 'role',
|
338 |
id: data[0]
|
339 |
},
|
340 |
-
$('#
|
341 |
($(this).hasClass('icon-check') ? 0 : 1),
|
342 |
this
|
343 |
);
|
@@ -345,14 +337,6 @@
|
|
345 |
}
|
346 |
break;
|
347 |
|
348 |
-
case 'no-detach':
|
349 |
-
if (getAAM().isUI('principal')) {
|
350 |
-
$(container).append($('<i/>', {
|
351 |
-
'class': 'aam-row-action icon-check text-muted'
|
352 |
-
}));
|
353 |
-
}
|
354 |
-
break;
|
355 |
-
|
356 |
default:
|
357 |
if (getAAM().isUI('main')) {
|
358 |
getAAM().triggerHook('role-action', {
|
@@ -703,7 +687,7 @@
|
|
703 |
params.subject = getAAM().getSubject().type;
|
704 |
params.subjectId = getAAM().getSubject().id;
|
705 |
params.ui = getLocal().ui;
|
706 |
-
params.
|
707 |
|
708 |
return params;
|
709 |
}
|
@@ -937,7 +921,7 @@
|
|
937 |
type: 'user',
|
938 |
id: data[0]
|
939 |
},
|
940 |
-
$('#
|
941 |
1,
|
942 |
this
|
943 |
);
|
@@ -955,7 +939,7 @@
|
|
955 |
type: 'user',
|
956 |
id: data[0]
|
957 |
},
|
958 |
-
$('#
|
959 |
0,
|
960 |
this
|
961 |
);
|
@@ -1160,7 +1144,7 @@
|
|
1160 |
{
|
1161 |
type: 'visitor'
|
1162 |
},
|
1163 |
-
$('#
|
1164 |
effect,
|
1165 |
function (response) {
|
1166 |
if (response.status === 'success') {
|
@@ -1235,7 +1219,7 @@
|
|
1235 |
{
|
1236 |
type: 'default'
|
1237 |
},
|
1238 |
-
$('#
|
1239 |
effect,
|
1240 |
function (response) {
|
1241 |
if (response.status === 'success') {
|
@@ -1515,6 +1499,7 @@
|
|
1515 |
$('#menu-item-name').html($(this).data('name'));
|
1516 |
$('#menu-item-cap').html($(this).data('cap'));
|
1517 |
$('#menu-item-uri').html($(this).data('uri'));
|
|
|
1518 |
});
|
1519 |
});
|
1520 |
|
@@ -1833,6 +1818,7 @@
|
|
1833 |
$(this).bind('click', function () {
|
1834 |
$('#metabox-title').html($(this).data('title'));
|
1835 |
$('#metabox-screen-id').html($(this).data('screen'));
|
|
|
1836 |
});
|
1837 |
});
|
1838 |
|
@@ -1920,6 +1906,7 @@
|
|
1920 |
} else {
|
1921 |
$(btn).attr('class', 'aam-row-action text-success icon-check');
|
1922 |
}
|
|
|
1923 |
}
|
1924 |
},
|
1925 |
error: function () {
|
@@ -2427,6 +2414,50 @@
|
|
2427 |
);
|
2428 |
});
|
2429 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2430 |
// Initialize the "Access Redirect" modal
|
2431 |
$('.post-redirect-type').each(function () {
|
2432 |
$(this).bind('click', function () {
|
@@ -3439,11 +3470,12 @@
|
|
3439 |
uri: uri,
|
3440 |
type: type,
|
3441 |
value: val,
|
3442 |
-
code: code
|
3443 |
-
id: $('#uri-save-btn').attr('data-id')
|
3444 |
},
|
3445 |
beforeSend: function () {
|
3446 |
-
$('#uri-save-btn').text(
|
|
|
|
|
3447 |
},
|
3448 |
success: function (response) {
|
3449 |
if (response.status === 'success') {
|
@@ -3477,7 +3509,7 @@
|
|
3477 |
_ajax_nonce: getLocal().nonce,
|
3478 |
subject: getAAM().getSubject().type,
|
3479 |
subjectId: getAAM().getSubject().id,
|
3480 |
-
|
3481 |
},
|
3482 |
beforeSend: function () {
|
3483 |
$('#uri-delete-btn').text(getAAM().__('Deleting...')).attr('disabled', true);
|
@@ -3526,7 +3558,7 @@
|
|
3526 |
infoFiltered: ''
|
3527 |
},
|
3528 |
columnDefs: [
|
3529 |
-
{ visible: false, targets: [
|
3530 |
],
|
3531 |
initComplete: function () {
|
3532 |
var create = $('<a/>', {
|
@@ -3537,14 +3569,13 @@
|
|
3537 |
$('.form-clearable', '#uri-model').val('');
|
3538 |
$('.aam-uri-access-action').hide();
|
3539 |
$('input[type="radio"]', '#uri-model').prop('checked', false);
|
3540 |
-
$('#uri-save-btn').removeAttr('data-id');
|
3541 |
$('#uri-model').modal('show');
|
3542 |
});
|
3543 |
|
3544 |
$('.dataTables_filter', '#uri-list_wrapper').append(create);
|
3545 |
},
|
3546 |
createdRow: function (row, data) {
|
3547 |
-
var actions = data[
|
3548 |
|
3549 |
var container = $('<div/>', { 'class': 'aam-row-actions' });
|
3550 |
$.each(actions, function (i, action) {
|
@@ -3555,11 +3586,10 @@
|
|
3555 |
}).bind('click', function () {
|
3556 |
$('.form-clearable', '#uri-model').val('');
|
3557 |
$('.aam-uri-access-action').hide();
|
3558 |
-
$('#uri-rule').val(data[
|
3559 |
-
$('input[value="' + data[
|
3560 |
-
$('#uri-access-deny-' + data[
|
3561 |
-
$('#uri-access-deny-redirect-code-value').val(data[
|
3562 |
-
$('#uri-save-btn').attr('data-id', data[0]);
|
3563 |
$('#uri-model').modal('show');
|
3564 |
}).attr({
|
3565 |
'data-toggle': "tooltip",
|
@@ -3571,7 +3601,7 @@
|
|
3571 |
$(container).append($('<i/>', {
|
3572 |
'class': 'aam-row-action icon-trash-empty text-danger'
|
3573 |
}).bind('click', function () {
|
3574 |
-
$('#uri-delete-btn').attr('data-
|
3575 |
$('#uri-delete-model').modal('show');
|
3576 |
}).attr({
|
3577 |
'data-toggle': "tooltip",
|
@@ -3587,7 +3617,7 @@
|
|
3587 |
// Decorate the type of access
|
3588 |
var type = $('<span/>');
|
3589 |
|
3590 |
-
switch(data[
|
3591 |
case 'default':
|
3592 |
case 'message':
|
3593 |
type.html(getAAM().__('Denied'));
|
@@ -3615,8 +3645,6 @@
|
|
3615 |
$('td:eq(2)', row).html(container);
|
3616 |
|
3617 |
$('td:eq(1)', row).html(type);
|
3618 |
-
|
3619 |
-
$('td:eq(0)', row).html(data[1]);
|
3620 |
}
|
3621 |
});
|
3622 |
}
|
@@ -4354,18 +4382,12 @@
|
|
4354 |
AAM.prototype.fetchContent = function (view) {
|
4355 |
var _this = this;
|
4356 |
|
4357 |
-
//referred object ID like post, page or any custom post type
|
4358 |
-
var object = window.location.search.match(/&oid\=([^&]*)/);
|
4359 |
-
var type = window.location.search.match(/&otype\=([^&]*)/);
|
4360 |
-
|
4361 |
var data = {
|
4362 |
action: 'aamc',
|
4363 |
_ajax_nonce: getLocal().nonce,
|
4364 |
partial: view,
|
4365 |
subject: this.getSubject().type,
|
4366 |
-
subjectId: this.getSubject().id
|
4367 |
-
oid: object ? object[1] : null,
|
4368 |
-
otype: type ? type[1] : null
|
4369 |
};
|
4370 |
|
4371 |
$.ajax(getLocal().url.site, {
|
@@ -4522,8 +4544,16 @@
|
|
4522 |
* @returns {undefined}
|
4523 |
*/
|
4524 |
AAM.prototype.initialize = function () {
|
4525 |
-
//
|
4526 |
-
if (
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
4527 |
this.setSubject(
|
4528 |
getLocal().subject.type,
|
4529 |
getLocal().subject.id,
|
120 |
subject: getAAM().getSubject().type,
|
121 |
subjectId: getAAM().getSubject().id,
|
122 |
ui: getLocal().ui,
|
123 |
+
policyId: $('#aam-policy-id').val()
|
124 |
}
|
125 |
},
|
126 |
columnDefs: [
|
311 |
type: 'role',
|
312 |
id: data[0]
|
313 |
},
|
314 |
+
$('#aam-policy-id').val(),
|
315 |
($(this).hasClass('icon-check-empty') ? 1 : 0),
|
316 |
this
|
317 |
);
|
319 |
}
|
320 |
break;
|
321 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
322 |
case 'detach':
|
323 |
if (getAAM().isUI('principal')) {
|
324 |
$(container).append($('<i/>', {
|
329 |
type: 'role',
|
330 |
id: data[0]
|
331 |
},
|
332 |
+
$('#aam-policy-id').val(),
|
333 |
($(this).hasClass('icon-check') ? 0 : 1),
|
334 |
this
|
335 |
);
|
337 |
}
|
338 |
break;
|
339 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
340 |
default:
|
341 |
if (getAAM().isUI('main')) {
|
342 |
getAAM().triggerHook('role-action', {
|
687 |
params.subject = getAAM().getSubject().type;
|
688 |
params.subjectId = getAAM().getSubject().id;
|
689 |
params.ui = getLocal().ui;
|
690 |
+
params.policyId = $('#aam-policy-id').val();
|
691 |
|
692 |
return params;
|
693 |
}
|
921 |
type: 'user',
|
922 |
id: data[0]
|
923 |
},
|
924 |
+
$('#aam-policy-id').val(),
|
925 |
1,
|
926 |
this
|
927 |
);
|
939 |
type: 'user',
|
940 |
id: data[0]
|
941 |
},
|
942 |
+
$('#aam-policy-id').val(),
|
943 |
0,
|
944 |
this
|
945 |
);
|
1144 |
{
|
1145 |
type: 'visitor'
|
1146 |
},
|
1147 |
+
$('#aam-policy-id').val(),
|
1148 |
effect,
|
1149 |
function (response) {
|
1150 |
if (response.status === 'success') {
|
1219 |
{
|
1220 |
type: 'default'
|
1221 |
},
|
1222 |
+
$('#aam-policy-id').val(),
|
1223 |
effect,
|
1224 |
function (response) {
|
1225 |
if (response.status === 'success') {
|
1499 |
$('#menu-item-name').html($(this).data('name'));
|
1500 |
$('#menu-item-cap').html($(this).data('cap'));
|
1501 |
$('#menu-item-uri').html($(this).data('uri'));
|
1502 |
+
$('#menu-item-id').html($(this).data('id'));
|
1503 |
});
|
1504 |
});
|
1505 |
|
1818 |
$(this).bind('click', function () {
|
1819 |
$('#metabox-title').html($(this).data('title'));
|
1820 |
$('#metabox-screen-id').html($(this).data('screen'));
|
1821 |
+
$('#metabox-id').html($(this).data('id'));
|
1822 |
});
|
1823 |
});
|
1824 |
|
1906 |
} else {
|
1907 |
$(btn).attr('class', 'aam-row-action text-success icon-check');
|
1908 |
}
|
1909 |
+
getAAM().notification(getAAM().__('Failed to process request'));
|
1910 |
}
|
1911 |
},
|
1912 |
error: function () {
|
2414 |
);
|
2415 |
});
|
2416 |
|
2417 |
+
// Reset LIMIT counter
|
2418 |
+
$('#reset-limited-btn').bind('click', function() {
|
2419 |
+
getAAM().queueRequest(function () {
|
2420 |
+
$.ajax(getLocal().ajaxurl, {
|
2421 |
+
type: 'POST',
|
2422 |
+
dataType: 'json',
|
2423 |
+
data: {
|
2424 |
+
action: 'aam',
|
2425 |
+
sub_action: 'Main_Post.resetCounter',
|
2426 |
+
_ajax_nonce: getLocal().nonce,
|
2427 |
+
subject: getAAM().getSubject().type,
|
2428 |
+
subjectId: getAAM().getSubject().id,
|
2429 |
+
object: object,
|
2430 |
+
objectId: id
|
2431 |
+
},
|
2432 |
+
beforeSend: function() {
|
2433 |
+
$('#reset-limited-btn').text(
|
2434 |
+
getAAM().__('Resetting...')
|
2435 |
+
).attr('disabled', true);
|
2436 |
+
},
|
2437 |
+
success: function (response) {
|
2438 |
+
if (response.status === 'failure') {
|
2439 |
+
getAAM().notification('danger', response.error);
|
2440 |
+
} else {
|
2441 |
+
getAAM().notification(
|
2442 |
+
'success',
|
2443 |
+
getAAM().__('Counter was reset successfully')
|
2444 |
+
);
|
2445 |
+
$('#modal-limited').modal('hide');
|
2446 |
+
getAAM().loadAccessForm(object, id);
|
2447 |
+
}
|
2448 |
+
},
|
2449 |
+
error: function () {
|
2450 |
+
getAAM().notification('danger');
|
2451 |
+
},
|
2452 |
+
complete: function() {
|
2453 |
+
$('#reset-limited-btn').text(
|
2454 |
+
getAAM().__('Reset')
|
2455 |
+
).attr('disabled', false);
|
2456 |
+
}
|
2457 |
+
});
|
2458 |
+
});
|
2459 |
+
});
|
2460 |
+
|
2461 |
// Initialize the "Access Redirect" modal
|
2462 |
$('.post-redirect-type').each(function () {
|
2463 |
$(this).bind('click', function () {
|
3470 |
uri: uri,
|
3471 |
type: type,
|
3472 |
value: val,
|
3473 |
+
code: code
|
|
|
3474 |
},
|
3475 |
beforeSend: function () {
|
3476 |
+
$('#uri-save-btn').text(
|
3477 |
+
getAAM().__('Saving...')
|
3478 |
+
).attr('disabled', true);
|
3479 |
},
|
3480 |
success: function (response) {
|
3481 |
if (response.status === 'success') {
|
3509 |
_ajax_nonce: getLocal().nonce,
|
3510 |
subject: getAAM().getSubject().type,
|
3511 |
subjectId: getAAM().getSubject().id,
|
3512 |
+
uri: $('#uri-delete-btn').data('uri')
|
3513 |
},
|
3514 |
beforeSend: function () {
|
3515 |
$('#uri-delete-btn').text(getAAM().__('Deleting...')).attr('disabled', true);
|
3558 |
infoFiltered: ''
|
3559 |
},
|
3560 |
columnDefs: [
|
3561 |
+
{ visible: false, targets: [2, 3] }
|
3562 |
],
|
3563 |
initComplete: function () {
|
3564 |
var create = $('<a/>', {
|
3569 |
$('.form-clearable', '#uri-model').val('');
|
3570 |
$('.aam-uri-access-action').hide();
|
3571 |
$('input[type="radio"]', '#uri-model').prop('checked', false);
|
|
|
3572 |
$('#uri-model').modal('show');
|
3573 |
});
|
3574 |
|
3575 |
$('.dataTables_filter', '#uri-list_wrapper').append(create);
|
3576 |
},
|
3577 |
createdRow: function (row, data) {
|
3578 |
+
var actions = data[4].split(',');
|
3579 |
|
3580 |
var container = $('<div/>', { 'class': 'aam-row-actions' });
|
3581 |
$.each(actions, function (i, action) {
|
3586 |
}).bind('click', function () {
|
3587 |
$('.form-clearable', '#uri-model').val('');
|
3588 |
$('.aam-uri-access-action').hide();
|
3589 |
+
$('#uri-rule').val(data[0]);
|
3590 |
+
$('input[value="' + data[1] + '"]', '#uri-model').prop('checked', true).trigger('click');
|
3591 |
+
$('#uri-access-deny-' + data[1] + '-value').val(data[2]);
|
3592 |
+
$('#uri-access-deny-redirect-code-value').val(data[3]);
|
|
|
3593 |
$('#uri-model').modal('show');
|
3594 |
}).attr({
|
3595 |
'data-toggle': "tooltip",
|
3601 |
$(container).append($('<i/>', {
|
3602 |
'class': 'aam-row-action icon-trash-empty text-danger'
|
3603 |
}).bind('click', function () {
|
3604 |
+
$('#uri-delete-btn').attr('data-uri', data[0]);
|
3605 |
$('#uri-delete-model').modal('show');
|
3606 |
}).attr({
|
3607 |
'data-toggle': "tooltip",
|
3617 |
// Decorate the type of access
|
3618 |
var type = $('<span/>');
|
3619 |
|
3620 |
+
switch(data[1]) {
|
3621 |
case 'default':
|
3622 |
case 'message':
|
3623 |
type.html(getAAM().__('Denied'));
|
3645 |
$('td:eq(2)', row).html(container);
|
3646 |
|
3647 |
$('td:eq(1)', row).html(type);
|
|
|
|
|
3648 |
}
|
3649 |
});
|
3650 |
}
|
4382 |
AAM.prototype.fetchContent = function (view) {
|
4383 |
var _this = this;
|
4384 |
|
|
|
|
|
|
|
|
|
4385 |
var data = {
|
4386 |
action: 'aamc',
|
4387 |
_ajax_nonce: getLocal().nonce,
|
4388 |
partial: view,
|
4389 |
subject: this.getSubject().type,
|
4390 |
+
subjectId: this.getSubject().id
|
|
|
|
|
4391 |
};
|
4392 |
|
4393 |
$.ajax(getLocal().url.site, {
|
4544 |
* @returns {undefined}
|
4545 |
*/
|
4546 |
AAM.prototype.initialize = function () {
|
4547 |
+
// Read default subject and set it for AAM object
|
4548 |
+
if ($('#aam-subject-type').length > 0) {
|
4549 |
+
console.log('Here');
|
4550 |
+
this.setSubject(
|
4551 |
+
$('#aam-subject-type').val(),
|
4552 |
+
$('#aam-subject-id').val(),
|
4553 |
+
$('#aam-subject-name').val(),
|
4554 |
+
$('#aam-subject-level').val()
|
4555 |
+
);
|
4556 |
+
} else if (getLocal().subject.type) {
|
4557 |
this.setSubject(
|
4558 |
getLocal().subject.type,
|
4559 |
getLocal().subject.id,
|
tests/Addon/IpCheck/IpCheckTest.php
ADDED
@@ -0,0 +1,343 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
/**
|
4 |
+
* ======================================================================
|
5 |
+
* LICENSE: This file is subject to the terms and conditions defined in *
|
6 |
+
* file 'license.txt', which is part of this source code package. *
|
7 |
+
* ======================================================================
|
8 |
+
*/
|
9 |
+
|
10 |
+
namespace AAM\UnitTest\Addon\IpCheck;
|
11 |
+
|
12 |
+
use AAM,
|
13 |
+
AAM_Service_Content,
|
14 |
+
AAM_Core_Object_Post,
|
15 |
+
PHPUnit\Framework\TestCase,
|
16 |
+
AAM\UnitTest\Libs\ResetTrait,
|
17 |
+
AAM\AddOn\IPCheck\Object\IPCheck as IPCheckObject;
|
18 |
+
|
19 |
+
/**
|
20 |
+
* Test cases for the IP Check addon
|
21 |
+
*
|
22 |
+
* @author Vasyl Martyniuk <vasyl@vasyltech.com>
|
23 |
+
* @version 6.0.0
|
24 |
+
*/
|
25 |
+
class IpCheckTest extends TestCase
|
26 |
+
{
|
27 |
+
use ResetTrait;
|
28 |
+
|
29 |
+
/**
|
30 |
+
* Test that entire website is restricted when IP matched
|
31 |
+
*
|
32 |
+
* @return void
|
33 |
+
*
|
34 |
+
* @access public
|
35 |
+
* @version 6.0.0
|
36 |
+
*/
|
37 |
+
public function testEntireWebsiteRestricted()
|
38 |
+
{
|
39 |
+
// Override the default handlers so we can suppress die exit
|
40 |
+
add_filter('wp_die_handler', function() {
|
41 |
+
return function($message, $title) {
|
42 |
+
_default_wp_die_handler($message, $title, array('exit' => false));
|
43 |
+
};
|
44 |
+
}, PHP_INT_MAX);
|
45 |
+
|
46 |
+
// Fake the IP address
|
47 |
+
$_SERVER['REMOTE_ADDR'] = '127.0.0.1';
|
48 |
+
|
49 |
+
$object = AAM::getUser()->getObject(IPCheckObject::OBJECT_TYPE);
|
50 |
+
$this->assertTrue($object->updateOptionItem('ip|127.0.0.1', true)->save());
|
51 |
+
|
52 |
+
// Capture the WP Die message
|
53 |
+
ob_start();
|
54 |
+
do_action('wp');
|
55 |
+
$content = ob_get_contents();
|
56 |
+
ob_end_clean();
|
57 |
+
|
58 |
+
$this->assertStringContainsString('Access Denied', $content);
|
59 |
+
|
60 |
+
// Reset WP Query
|
61 |
+
remove_all_filters('wp_die_handler', PHP_INT_MAX);
|
62 |
+
unset($_SERVER['REMOTE_ADDR']);
|
63 |
+
}
|
64 |
+
|
65 |
+
/**
|
66 |
+
* Test that access is denied based on user IP address
|
67 |
+
*
|
68 |
+
* @return void
|
69 |
+
*
|
70 |
+
* @access public
|
71 |
+
* @version 6.0.0
|
72 |
+
*/
|
73 |
+
public function testPageRestrictedByIp()
|
74 |
+
{
|
75 |
+
$object = AAM::getUser()->getObject(
|
76 |
+
AAM_Core_Object_Post::OBJECT_TYPE, AAM_UNITTEST_POST_ID
|
77 |
+
);
|
78 |
+
|
79 |
+
// Set restriction
|
80 |
+
$this->assertTrue($object->updateOptionItem('selective', array(
|
81 |
+
'rules' => array(
|
82 |
+
'ip|127.0.0.1' => true,
|
83 |
+
),
|
84 |
+
'enabled' => true
|
85 |
+
))->save());
|
86 |
+
|
87 |
+
// Reset all internal cache
|
88 |
+
$this->_resetSubjects();
|
89 |
+
|
90 |
+
// Verify that access is denied by IP address
|
91 |
+
$_SERVER['REMOTE_ADDR'] = '127.0.0.1';
|
92 |
+
|
93 |
+
$post = AAM::getUser()->getObject(
|
94 |
+
AAM_Core_Object_Post::OBJECT_TYPE, AAM_UNITTEST_POST_ID
|
95 |
+
);
|
96 |
+
|
97 |
+
$result = AAM_Service_Content::getInstance()->isAuthorizedToReadPost($post);
|
98 |
+
$this->assertEquals('WP_Error', get_class($result));
|
99 |
+
$this->assertEquals(
|
100 |
+
'User is unauthorized to access this post. Access Denied.',
|
101 |
+
$result->get_error_message()
|
102 |
+
);
|
103 |
+
|
104 |
+
// Reset original state
|
105 |
+
unset($_SERVER['REMOTE_ADDR']);
|
106 |
+
}
|
107 |
+
|
108 |
+
/**
|
109 |
+
* Test that access is denied for wildcard IP address
|
110 |
+
*
|
111 |
+
* @return void
|
112 |
+
*
|
113 |
+
* @access public
|
114 |
+
* @version 6.0.0
|
115 |
+
*/
|
116 |
+
public function testPageRestrictedByIpWildcard()
|
117 |
+
{
|
118 |
+
$object = AAM::getUser()->getObject(
|
119 |
+
AAM_Core_Object_Post::OBJECT_TYPE, AAM_UNITTEST_POST_ID
|
120 |
+
);
|
121 |
+
|
122 |
+
// Set restriction
|
123 |
+
$this->assertTrue($object->updateOptionItem('selective', array(
|
124 |
+
'rules' => array(
|
125 |
+
'ip|127.0.0.*' => true,
|
126 |
+
),
|
127 |
+
'enabled' => true
|
128 |
+
))->save());
|
129 |
+
|
130 |
+
// Reset all internal cache
|
131 |
+
$this->_resetSubjects();
|
132 |
+
|
133 |
+
// Verify that access is denied by IP address
|
134 |
+
$_SERVER['REMOTE_ADDR'] = '127.0.0.3';
|
135 |
+
|
136 |
+
$post = AAM::getUser()->getObject(
|
137 |
+
AAM_Core_Object_Post::OBJECT_TYPE, AAM_UNITTEST_POST_ID
|
138 |
+
);
|
139 |
+
|
140 |
+
$result = AAM_Service_Content::getInstance()->isAuthorizedToReadPost($post);
|
141 |
+
$this->assertEquals('WP_Error', get_class($result));
|
142 |
+
$this->assertEquals(
|
143 |
+
'User is unauthorized to access this post. Access Denied.',
|
144 |
+
$result->get_error_message()
|
145 |
+
);
|
146 |
+
}
|
147 |
+
|
148 |
+
/**
|
149 |
+
* Test that access is denied for the IP range
|
150 |
+
*
|
151 |
+
* @return void
|
152 |
+
*
|
153 |
+
* @access public
|
154 |
+
* @version 6.0.0
|
155 |
+
*/
|
156 |
+
public function testPageRestrictedByIpRange()
|
157 |
+
{
|
158 |
+
$object = AAM::getUser()->getObject(
|
159 |
+
AAM_Core_Object_Post::OBJECT_TYPE, AAM_UNITTEST_POST_ID
|
160 |
+
);
|
161 |
+
|
162 |
+
// Set restriction
|
163 |
+
$this->assertTrue($object->updateOptionItem('selective', array(
|
164 |
+
'rules' => array(
|
165 |
+
'ip|127.0.0.0-20' => true,
|
166 |
+
),
|
167 |
+
'enabled' => true
|
168 |
+
))->save());
|
169 |
+
|
170 |
+
// Reset all internal cache
|
171 |
+
$this->_resetSubjects();
|
172 |
+
|
173 |
+
// Verify that access is denied by IP address
|
174 |
+
$_SERVER['REMOTE_ADDR'] = '127.0.0.5';
|
175 |
+
|
176 |
+
$post = AAM::getUser()->getObject(
|
177 |
+
AAM_Core_Object_Post::OBJECT_TYPE, AAM_UNITTEST_POST_ID
|
178 |
+
);
|
179 |
+
|
180 |
+
$result = AAM_Service_Content::getInstance()->isAuthorizedToReadPost($post);
|
181 |
+
$this->assertEquals('WP_Error', get_class($result));
|
182 |
+
$this->assertEquals(
|
183 |
+
'User is unauthorized to access this post. Access Denied.',
|
184 |
+
$result->get_error_message()
|
185 |
+
);
|
186 |
+
}
|
187 |
+
|
188 |
+
/**
|
189 |
+
* Test that access is denied by the referred host
|
190 |
+
*
|
191 |
+
* @return void
|
192 |
+
*
|
193 |
+
* @access public
|
194 |
+
* @version 6.0.0
|
195 |
+
*/
|
196 |
+
public function testPageRestrictedByHost()
|
197 |
+
{
|
198 |
+
$object = AAM::getUser()->getObject(
|
199 |
+
AAM_Core_Object_Post::OBJECT_TYPE, AAM_UNITTEST_POST_ID
|
200 |
+
);
|
201 |
+
|
202 |
+
// Set restriction
|
203 |
+
$this->assertTrue($object->updateOptionItem('selective', array(
|
204 |
+
'rules' => array(
|
205 |
+
'host|example.local' => true,
|
206 |
+
),
|
207 |
+
'enabled' => true
|
208 |
+
))->save());
|
209 |
+
|
210 |
+
// Reset all internal cache
|
211 |
+
$this->_resetSubjects();
|
212 |
+
|
213 |
+
// Verify that access is denied by referred host
|
214 |
+
$_SERVER['HTTP_REFERER'] = 'https://example.local';
|
215 |
+
|
216 |
+
$post = AAM::getUser()->getObject(
|
217 |
+
AAM_Core_Object_Post::OBJECT_TYPE, AAM_UNITTEST_POST_ID
|
218 |
+
);
|
219 |
+
|
220 |
+
$result = AAM_Service_Content::getInstance()->isAuthorizedToReadPost($post);
|
221 |
+
$this->assertEquals('WP_Error', get_class($result));
|
222 |
+
$this->assertEquals(
|
223 |
+
'User is unauthorized to access this post. Access Denied.',
|
224 |
+
$result->get_error_message()
|
225 |
+
);
|
226 |
+
}
|
227 |
+
|
228 |
+
/**
|
229 |
+
* Test that access is denied by query param
|
230 |
+
*
|
231 |
+
* @return void
|
232 |
+
*
|
233 |
+
* @access public
|
234 |
+
* @version 6.0.0
|
235 |
+
*/
|
236 |
+
public function testPageRestrictedByRef()
|
237 |
+
{
|
238 |
+
$object = AAM::getUser()->getObject(
|
239 |
+
AAM_Core_Object_Post::OBJECT_TYPE, AAM_UNITTEST_POST_ID
|
240 |
+
);
|
241 |
+
|
242 |
+
// Set restriction
|
243 |
+
$this->assertTrue($object->updateOptionItem('selective', array(
|
244 |
+
'rules' => array(
|
245 |
+
'ref|test' => true,
|
246 |
+
),
|
247 |
+
'enabled' => true
|
248 |
+
))->save());
|
249 |
+
|
250 |
+
// Reset all internal cache
|
251 |
+
$this->_resetSubjects();
|
252 |
+
|
253 |
+
// Verify that access is denied by ref
|
254 |
+
$_GET['ref'] = 'test';
|
255 |
+
|
256 |
+
$post = AAM::getUser()->getObject(
|
257 |
+
AAM_Core_Object_Post::OBJECT_TYPE, AAM_UNITTEST_POST_ID
|
258 |
+
);
|
259 |
+
|
260 |
+
$result = AAM_Service_Content::getInstance()->isAuthorizedToReadPost($post);
|
261 |
+
$this->assertEquals('WP_Error', get_class($result));
|
262 |
+
$this->assertEquals(
|
263 |
+
'User is unauthorized to access this post. Access Denied.',
|
264 |
+
$result->get_error_message()
|
265 |
+
);
|
266 |
+
}
|
267 |
+
|
268 |
+
/**
|
269 |
+
* Test that cookie with JWT is sent when access is granted
|
270 |
+
*
|
271 |
+
* @return void
|
272 |
+
*
|
273 |
+
* @access public
|
274 |
+
* @version 6.0.0
|
275 |
+
*/
|
276 |
+
public function testWebsiteAccessCookieSetup()
|
277 |
+
{
|
278 |
+
// Fake the IP address
|
279 |
+
$_SERVER['REMOTE_ADDR'] = '127.0.0.1';
|
280 |
+
|
281 |
+
$object = AAM::getUser()->getObject(IPCheckObject::OBJECT_TYPE);
|
282 |
+
$this->assertTrue($object->updateOptionItem('ip|127.0.0.1', false)->save());
|
283 |
+
|
284 |
+
// Capture the WP Die message
|
285 |
+
ob_start();
|
286 |
+
do_action('wp');
|
287 |
+
ob_end_clean();
|
288 |
+
|
289 |
+
$this->assertCount(1, array_filter(xdebug_get_headers(), function($m) {
|
290 |
+
return (strpos($m, 'aam_ipcheck_jwt=') !== false);
|
291 |
+
}));
|
292 |
+
|
293 |
+
// Reset WP Query
|
294 |
+
unset($_SERVER['REMOTE_ADDR']);
|
295 |
+
header_remove('Set-Cookie');
|
296 |
+
}
|
297 |
+
|
298 |
+
/**
|
299 |
+
* Test that cookie with JWT is sent when access to page is granted
|
300 |
+
*
|
301 |
+
* @return void
|
302 |
+
*
|
303 |
+
* @access public
|
304 |
+
* @version 6.0.0
|
305 |
+
*/
|
306 |
+
public function testPageAccessCookieSetup()
|
307 |
+
{
|
308 |
+
$object = AAM::getUser()->getObject(
|
309 |
+
AAM_Core_Object_Post::OBJECT_TYPE, AAM_UNITTEST_POST_ID
|
310 |
+
);
|
311 |
+
|
312 |
+
// Set restriction
|
313 |
+
$this->assertTrue($object->updateOptionItem('selective', array(
|
314 |
+
'rules' => array(
|
315 |
+
'ip|127.0.0.0-20' => false,
|
316 |
+
),
|
317 |
+
'enabled' => true
|
318 |
+
))->save());
|
319 |
+
|
320 |
+
// Reset all internal cache
|
321 |
+
$this->_resetSubjects();
|
322 |
+
|
323 |
+
// Verify that access is denied by IP address
|
324 |
+
$_SERVER['REMOTE_ADDR'] = '127.0.0.5';
|
325 |
+
|
326 |
+
$post = AAM::getUser()->getObject(
|
327 |
+
AAM_Core_Object_Post::OBJECT_TYPE, AAM_UNITTEST_POST_ID
|
328 |
+
);
|
329 |
+
|
330 |
+
$this->assertTrue(
|
331 |
+
AAM_Service_Content::getInstance()->isAuthorizedToReadPost($post)
|
332 |
+
);
|
333 |
+
|
334 |
+
// Note! 2 is because there is no way to clear sent headers with xdebug_*
|
335 |
+
$this->assertCount(2, array_filter(xdebug_get_headers(), function($m) {
|
336 |
+
return (strpos($m, 'aam_ipcheck_jwt=') !== false);
|
337 |
+
}));
|
338 |
+
|
339 |
+
// Reset WP Query
|
340 |
+
unset($_SERVER['REMOTE_ADDR']);
|
341 |
+
}
|
342 |
+
|
343 |
+
}
|
tests/Addon/PlusPackage/ContentAccessTest.php
ADDED
@@ -0,0 +1,451 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
/**
|
4 |
+
* ======================================================================
|
5 |
+
* LICENSE: This file is subject to the terms and conditions defined in *
|
6 |
+
* file 'license.txt', which is part of this source code package. *
|
7 |
+
* ======================================================================
|
8 |
+
*/
|
9 |
+
|
10 |
+
namespace AAM\UnitTest\Addon\PlusPackage;
|
11 |
+
|
12 |
+
use AAM,
|
13 |
+
AAM_Core_Object_Post,
|
14 |
+
PHPUnit\Framework\TestCase,
|
15 |
+
AAM\UnitTest\Libs\ResetTrait,
|
16 |
+
AAM\UnitTest\Libs\AuthUserTrait,
|
17 |
+
AAM\AddOn\PlusPackage\Object\Term,
|
18 |
+
AAM\AddOn\PlusPackage\Object\Type,
|
19 |
+
AAM\AddOn\PlusPackage\Object\Taxonomy,
|
20 |
+
AAM\AddOn\PlusPackage\Hooks\ContentHooks;
|
21 |
+
|
22 |
+
/**
|
23 |
+
* Test cases for the Plus Package content access management
|
24 |
+
*
|
25 |
+
* @author Vasyl Martyniuk <vasyl@vasyltech.com>
|
26 |
+
* @version 6.0.0
|
27 |
+
*/
|
28 |
+
class ContentAccessTest extends TestCase
|
29 |
+
{
|
30 |
+
use ResetTrait,
|
31 |
+
AuthUserTrait;
|
32 |
+
|
33 |
+
/**
|
34 |
+
* Test that access settings are inherited from the parent term
|
35 |
+
*
|
36 |
+
* @return void
|
37 |
+
*
|
38 |
+
* @access public
|
39 |
+
* @version 6.0.0
|
40 |
+
*/
|
41 |
+
public function testInheritPostAccessFromParentTerm()
|
42 |
+
{
|
43 |
+
$user = AAM::getUser();
|
44 |
+
$object = $user->getObject(
|
45 |
+
Term::OBJECT_TYPE, AAM_UNITTEST_CATEGORY_ID . '|category'
|
46 |
+
);
|
47 |
+
|
48 |
+
// Check if save returns positive result
|
49 |
+
$this->assertTrue($object->updateOptionItem('post/hidden', true)->save());
|
50 |
+
|
51 |
+
// Reset all internal cache
|
52 |
+
$this->_resetSubjects();
|
53 |
+
ContentHooks::bootstrap()->resetCache();
|
54 |
+
|
55 |
+
$post = $user->getObject(
|
56 |
+
AAM_Core_Object_Post::OBJECT_TYPE, AAM_UNITTEST_POST_ID
|
57 |
+
);
|
58 |
+
|
59 |
+
$this->assertTrue($post->is('hidden'));
|
60 |
+
}
|
61 |
+
|
62 |
+
/**
|
63 |
+
* Test that access settings are inherited from the parent post type
|
64 |
+
*
|
65 |
+
* @return void
|
66 |
+
*
|
67 |
+
* @access public
|
68 |
+
* @version 6.0.0
|
69 |
+
*/
|
70 |
+
public function testInheritPostAccessFromParentType()
|
71 |
+
{
|
72 |
+
$user = AAM::getUser();
|
73 |
+
$object = $user->getObject(Type::OBJECT_TYPE, 'post');
|
74 |
+
|
75 |
+
// Check if save returns positive result
|
76 |
+
$this->assertTrue($object->updateOptionItem('post/hidden', true)->save());
|
77 |
+
|
78 |
+
// Reset all internal cache
|
79 |
+
$this->_resetSubjects();
|
80 |
+
ContentHooks::bootstrap()->resetCache();
|
81 |
+
|
82 |
+
$post = $user->getObject(
|
83 |
+
AAM_Core_Object_Post::OBJECT_TYPE, AAM_UNITTEST_POST_ID
|
84 |
+
);
|
85 |
+
|
86 |
+
$this->assertTrue($post->is('hidden'));
|
87 |
+
}
|
88 |
+
|
89 |
+
/**
|
90 |
+
* Test that access settings are inherited from the parent post
|
91 |
+
*
|
92 |
+
* @return void
|
93 |
+
*
|
94 |
+
* @access public
|
95 |
+
* @version 6.0.0
|
96 |
+
*/
|
97 |
+
public function testInheritFromParentPost()
|
98 |
+
{
|
99 |
+
$user = AAM::getUser();
|
100 |
+
$object = $user->getObject(
|
101 |
+
AAM_Core_Object_Post::OBJECT_TYPE, AAM_UNITTEST_PAGE_LEVEL_1_ID
|
102 |
+
);
|
103 |
+
|
104 |
+
// Check if save returns positive result
|
105 |
+
$this->assertTrue($object->updateOptionItem('hidden', true)->save());
|
106 |
+
|
107 |
+
// Reset all internal cache
|
108 |
+
$this->_resetSubjects();
|
109 |
+
|
110 |
+
$post = $user->getObject(
|
111 |
+
AAM_Core_Object_Post::OBJECT_TYPE, AAM_UNITTEST_PAGE_LEVEL_2_ID
|
112 |
+
);
|
113 |
+
|
114 |
+
$this->assertTrue($post->is('hidden'));
|
115 |
+
}
|
116 |
+
|
117 |
+
/**
|
118 |
+
* Test access settings adjusting based on [ACTION]_OTHERS access option
|
119 |
+
*
|
120 |
+
* @return void
|
121 |
+
*
|
122 |
+
* @access public
|
123 |
+
* @version 6.0.0
|
124 |
+
*/
|
125 |
+
public function testAdjustedPostAccessSettings()
|
126 |
+
{
|
127 |
+
// Make other user as the owner of the post
|
128 |
+
wp_update_post(array(
|
129 |
+
'ID' => AAM_UNITTEST_POST_ID,
|
130 |
+
'post_author' => AAM_UNITTEST_JOHN_ID
|
131 |
+
));
|
132 |
+
|
133 |
+
$user = AAM::getUser();
|
134 |
+
$object = $user->getObject(Type::OBJECT_TYPE, 'post');
|
135 |
+
|
136 |
+
foreach(array('edit', 'hidden', 'delete', 'publish', 'restricted') as $act) {
|
137 |
+
$object->updateOptionItem("post/{$act}_others", true);
|
138 |
+
}
|
139 |
+
|
140 |
+
// Check if save returns positive result
|
141 |
+
$this->assertTrue($object->save());
|
142 |
+
|
143 |
+
// Reset all internal cache
|
144 |
+
$this->_resetSubjects();
|
145 |
+
ContentHooks::bootstrap()->resetCache();
|
146 |
+
|
147 |
+
$post = $user->getObject(
|
148 |
+
AAM_Core_Object_Post::OBJECT_TYPE, AAM_UNITTEST_POST_ID
|
149 |
+
);
|
150 |
+
|
151 |
+
$this->assertTrue($post->is('hidden'));
|
152 |
+
$this->assertTrue($post->is('restricted'));
|
153 |
+
$this->assertFalse($post->isAllowedTo('edit'));
|
154 |
+
$this->assertFalse($post->isAllowedTo('delete'));
|
155 |
+
$this->assertFalse($post->isAllowedTo('publish'));
|
156 |
+
|
157 |
+
// Reset back to the original author
|
158 |
+
wp_update_post(array(
|
159 |
+
'ID' => AAM_UNITTEST_POST_ID,
|
160 |
+
'post_author' => AAM_UNITTEST_AUTH_USER_ID
|
161 |
+
));
|
162 |
+
}
|
163 |
+
|
164 |
+
/**
|
165 |
+
* Test that access is denied to create a new post of a specific post type
|
166 |
+
*
|
167 |
+
* @return void
|
168 |
+
*
|
169 |
+
* @access public
|
170 |
+
* @version 6.0.0
|
171 |
+
*/
|
172 |
+
public function testDenyCreateNewPost()
|
173 |
+
{
|
174 |
+
$user = AAM::getUser();
|
175 |
+
$object = $user->getObject(Type::OBJECT_TYPE, 'aam_test');
|
176 |
+
|
177 |
+
// Check if save returns positive result
|
178 |
+
$this->assertTrue($object->updateOptionItem('post/create', true)->save());
|
179 |
+
|
180 |
+
// Reset all internal cache
|
181 |
+
$this->_resetSubjects();
|
182 |
+
ContentHooks::bootstrap()->resetCache();
|
183 |
+
|
184 |
+
register_post_type('aam_test', array(
|
185 |
+
'label' => __('AAM Test', AAM_KEY),
|
186 |
+
'description' => __('Just for testing purposes', AAM_KEY)
|
187 |
+
));
|
188 |
+
|
189 |
+
$this->assertEquals(
|
190 |
+
get_post_type_object('aam_test')->cap->create_posts, 'do_not_allow'
|
191 |
+
);
|
192 |
+
}
|
193 |
+
|
194 |
+
/**
|
195 |
+
* Test that access is denied to edit or create a new term of a specific taxonomy
|
196 |
+
*
|
197 |
+
* @return void
|
198 |
+
*
|
199 |
+
* @access public
|
200 |
+
* @version 6.0.0
|
201 |
+
*/
|
202 |
+
public function testDenyCreateOrEditTaxonomy()
|
203 |
+
{
|
204 |
+
$user = AAM::getUser();
|
205 |
+
$object = $user->getObject(Taxonomy::OBJECT_TYPE, 'aam_test');
|
206 |
+
|
207 |
+
// Check if save returns positive result
|
208 |
+
$this->assertTrue($object->updateOptionItem('term/edit', true)->save());
|
209 |
+
|
210 |
+
// Reset all internal cache
|
211 |
+
$this->_resetSubjects();
|
212 |
+
ContentHooks::bootstrap()->resetCache();
|
213 |
+
|
214 |
+
register_taxonomy('aam_test', 'post', array('hierarchical' => true));
|
215 |
+
|
216 |
+
$this->assertEquals(
|
217 |
+
get_taxonomy('aam_test')->cap->edit_terms, 'do_not_allow'
|
218 |
+
);
|
219 |
+
}
|
220 |
+
|
221 |
+
/**
|
222 |
+
* Test the ability to edit term
|
223 |
+
*
|
224 |
+
* @return void
|
225 |
+
*
|
226 |
+
* @access public
|
227 |
+
* @version 6.0.0
|
228 |
+
*/
|
229 |
+
public function testEditTermAccessOption()
|
230 |
+
{
|
231 |
+
$user = AAM::getUser();
|
232 |
+
$role = $user->getParent(); // Administrator role
|
233 |
+
|
234 |
+
$object = $role->getObject(
|
235 |
+
Term::OBJECT_TYPE, AAM_UNITTEST_CATEGORY_ID . '|category'
|
236 |
+
);
|
237 |
+
|
238 |
+
$this->assertTrue($object->updateOptionItem('term/edit', true)->save());
|
239 |
+
|
240 |
+
// Reset all internal cache
|
241 |
+
$this->_resetSubjects();
|
242 |
+
ContentHooks::bootstrap()->resetCache();
|
243 |
+
|
244 |
+
$this->assertFalse(current_user_can('edit_term', AAM_UNITTEST_CATEGORY_ID));
|
245 |
+
}
|
246 |
+
|
247 |
+
/**
|
248 |
+
* Test the ability to delete term
|
249 |
+
*
|
250 |
+
* @return void
|
251 |
+
*
|
252 |
+
* @access public
|
253 |
+
* @version 6.0.0
|
254 |
+
*/
|
255 |
+
public function testDeleteTermAccessOption()
|
256 |
+
{
|
257 |
+
$user = AAM::getUser();
|
258 |
+
$role = $user->getParent(); // Administrator role
|
259 |
+
|
260 |
+
$object = $role->getObject(
|
261 |
+
Term::OBJECT_TYPE, AAM_UNITTEST_CATEGORY_ID . '|category'
|
262 |
+
);
|
263 |
+
|
264 |
+
$this->assertTrue($object->updateOptionItem('term/delete', true)->save());
|
265 |
+
|
266 |
+
// Reset all internal cache
|
267 |
+
$this->_resetSubjects();
|
268 |
+
ContentHooks::bootstrap()->resetCache();
|
269 |
+
|
270 |
+
$this->assertFalse(current_user_can('delete_term', AAM_UNITTEST_CATEGORY_ID));
|
271 |
+
}
|
272 |
+
|
273 |
+
/**
|
274 |
+
* Test the ability to assign term
|
275 |
+
*
|
276 |
+
* @return void
|
277 |
+
*
|
278 |
+
* @access public
|
279 |
+
* @version 6.0.0
|
280 |
+
*/
|
281 |
+
public function testAssignTermAccessOption()
|
282 |
+
{
|
283 |
+
$user = AAM::getUser();
|
284 |
+
$role = $user->getParent(); // Administrator role
|
285 |
+
|
286 |
+
$object = $role->getObject(
|
287 |
+
Term::OBJECT_TYPE, AAM_UNITTEST_CATEGORY_ID . '|category'
|
288 |
+
);
|
289 |
+
|
290 |
+
$this->assertTrue($object->updateOptionItem('term/assign', true)->save());
|
291 |
+
|
292 |
+
// Reset all internal cache
|
293 |
+
$this->_resetSubjects();
|
294 |
+
ContentHooks::bootstrap()->resetCache();
|
295 |
+
|
296 |
+
$this->assertFalse(current_user_can('assign_term', AAM_UNITTEST_CATEGORY_ID));
|
297 |
+
}
|
298 |
+
|
299 |
+
/**
|
300 |
+
* Test that term filter is working as expected
|
301 |
+
*
|
302 |
+
* There are multiple different ways to fetch the list of terms and this is
|
303 |
+
* defined by the $fields argument WP_Term_Query::__construct.
|
304 |
+
*
|
305 |
+
* @return void
|
306 |
+
*
|
307 |
+
* @access public
|
308 |
+
* @version 6.0.0
|
309 |
+
*/
|
310 |
+
public function testFilterTerms()
|
311 |
+
{
|
312 |
+
$user = AAM::getUser();
|
313 |
+
$role = $user->getParent(); // Administrator role
|
314 |
+
|
315 |
+
$object = $role->getObject(
|
316 |
+
Term::OBJECT_TYPE, AAM_UNITTEST_CATEGORY_ID . '|category'
|
317 |
+
);
|
318 |
+
|
319 |
+
$this->assertTrue($object->updateOptionItem('term/hidden', true)->save());
|
320 |
+
|
321 |
+
// Reset all internal cache
|
322 |
+
$this->_resetSubjects();
|
323 |
+
ContentHooks::bootstrap()->resetCache();
|
324 |
+
|
325 |
+
$terms = get_terms(array(
|
326 |
+
'number' => 0,
|
327 |
+
'fields' => 'ids',
|
328 |
+
'taxonomy' => 'category',
|
329 |
+
'hide_empty' => false
|
330 |
+
));
|
331 |
+
|
332 |
+
$this->assertFalse(in_array(AAM_UNITTEST_CATEGORY_ID, $terms));
|
333 |
+
|
334 |
+
$terms = get_terms(array(
|
335 |
+
'number' => 0,
|
336 |
+
'fields' => 'id=>slug',
|
337 |
+
'taxonomy' => 'category',
|
338 |
+
'hide_empty' => false
|
339 |
+
));
|
340 |
+
|
341 |
+
$this->assertFalse(array_key_exists(AAM_UNITTEST_CATEGORY_ID, $terms));
|
342 |
+
|
343 |
+
$terms = get_terms(array(
|
344 |
+
'number' => 0,
|
345 |
+
'fields' => 'id=>name',
|
346 |
+
'taxonomy' => 'category',
|
347 |
+
'hide_empty' => false
|
348 |
+
));
|
349 |
+
|
350 |
+
$this->assertFalse(array_key_exists(AAM_UNITTEST_CATEGORY_ID, $terms));
|
351 |
+
|
352 |
+
$terms = get_terms(array(
|
353 |
+
'number' => 0,
|
354 |
+
'fields' => 'id=>parent',
|
355 |
+
'taxonomy' => 'category',
|
356 |
+
'hide_empty' => false
|
357 |
+
));
|
358 |
+
|
359 |
+
$this->assertFalse(array_key_exists(AAM_UNITTEST_CATEGORY_ID, $terms));
|
360 |
+
|
361 |
+
$terms = get_terms(array(
|
362 |
+
'number' => 0,
|
363 |
+
'fields' => 'all',
|
364 |
+
'taxonomy' => 'category',
|
365 |
+
'hide_empty' => false
|
366 |
+
));
|
367 |
+
|
368 |
+
$this->assertCount(0, array_filter($terms, function($term) {
|
369 |
+
return $term->term_id === AAM_UNITTEST_CATEGORY_ID;
|
370 |
+
}));
|
371 |
+
}
|
372 |
+
|
373 |
+
/**
|
374 |
+
* Test that navigation menu is filtered as expected
|
375 |
+
*
|
376 |
+
* @return void
|
377 |
+
*
|
378 |
+
* @access public
|
379 |
+
* @version 5.0.0
|
380 |
+
*/
|
381 |
+
public function testFilterNavMenu()
|
382 |
+
{
|
383 |
+
$user = AAM::getUser();
|
384 |
+
$role = $user->getParent(); // Administrator role
|
385 |
+
|
386 |
+
$object = $role->getObject(
|
387 |
+
Term::OBJECT_TYPE, AAM_UNITTEST_CATEGORY_ID . '|category'
|
388 |
+
);
|
389 |
+
|
390 |
+
$this->assertTrue($object->updateOptionItem('term/hidden', true)->save());
|
391 |
+
|
392 |
+
// Reset all internal cache
|
393 |
+
$this->_resetSubjects();
|
394 |
+
ContentHooks::bootstrap()->resetCache();
|
395 |
+
|
396 |
+
$menu = wp_get_nav_menu_items(AAM_UNITTEST_NAV_MENU_NAME);
|
397 |
+
|
398 |
+
$this->assertCount(0, array_filter($menu, function($item) {
|
399 |
+
return $item->object_id === AAM_UNITTEST_CATEGORY_ID && $item->object === 'category';
|
400 |
+
}));
|
401 |
+
}
|
402 |
+
|
403 |
+
/**
|
404 |
+
* Test that access is denied to browse the category
|
405 |
+
*
|
406 |
+
* @return void
|
407 |
+
*
|
408 |
+
* @access public
|
409 |
+
* @version 6.0.0
|
410 |
+
*/
|
411 |
+
public function testTermBrowseAccessOption()
|
412 |
+
{
|
413 |
+
global $wp_query;
|
414 |
+
|
415 |
+
$user = AAM::getUser();
|
416 |
+
$role = $user->getParent(); // Administrator role
|
417 |
+
|
418 |
+
$object = $role->getObject(
|
419 |
+
Term::OBJECT_TYPE, AAM_UNITTEST_CATEGORY_ID . '|category'
|
420 |
+
);
|
421 |
+
|
422 |
+
$this->assertTrue($object->updateOptionItem('term/browse', true)->save());
|
423 |
+
|
424 |
+
$wp_query->is_category = true;
|
425 |
+
$wp_query->queried_object = get_term(AAM_UNITTEST_CATEGORY_ID, 'category');
|
426 |
+
|
427 |
+
// Override the default handlers so we can suppress die exit
|
428 |
+
add_filter('wp_die_handler', function() {
|
429 |
+
return function($message, $title) {
|
430 |
+
_default_wp_die_handler($message, $title, array('exit' => false));
|
431 |
+
};
|
432 |
+
}, PHP_INT_MAX);
|
433 |
+
|
434 |
+
// Capture the WP Die message
|
435 |
+
ob_start();
|
436 |
+
do_action('wp');
|
437 |
+
$content = ob_get_contents();
|
438 |
+
ob_end_clean();
|
439 |
+
|
440 |
+
$this->assertStringContainsString(
|
441 |
+
'Access denied to browse this category', $content
|
442 |
+
);
|
443 |
+
|
444 |
+
// Reset WP Query
|
445 |
+
remove_all_filters('wp_die_handler', PHP_INT_MAX);
|
446 |
+
|
447 |
+
unset($wp_query->is_category);
|
448 |
+
unset($wp_query->queried_object);
|
449 |
+
}
|
450 |
+
|
451 |
+
}
|
tests/Addon/PlusPackage/ContentVisibilityTest.php
ADDED
@@ -0,0 +1,204 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
/**
|
4 |
+
* ======================================================================
|
5 |
+
* LICENSE: This file is subject to the terms and conditions defined in *
|
6 |
+
* file 'license.txt', which is part of this source code package. *
|
7 |
+
* ======================================================================
|
8 |
+
*/
|
9 |
+
|
10 |
+
namespace AAM\UnitTest\Addon\PlusPackage;
|
11 |
+
|
12 |
+
use AAM,
|
13 |
+
AAM_Core_Object_Post,
|
14 |
+
PHPUnit\Framework\TestCase,
|
15 |
+
AAM\UnitTest\Libs\ResetTrait,
|
16 |
+
AAM\UnitTest\Libs\AuthUserTrait,
|
17 |
+
AAM\AddOn\PlusPackage\Object\Term,
|
18 |
+
AAM\AddOn\PlusPackage\Object\Type,
|
19 |
+
AAM\AddOn\PlusPackage\Hooks\ContentHooks;
|
20 |
+
|
21 |
+
/**
|
22 |
+
* Test cases for the Plus Package content visibility management
|
23 |
+
*
|
24 |
+
* @author Vasyl Martyniuk <vasyl@vasyltech.com>
|
25 |
+
* @version 6.0.0
|
26 |
+
*/
|
27 |
+
class ContentVisibilityTest extends TestCase
|
28 |
+
{
|
29 |
+
use ResetTrait,
|
30 |
+
AuthUserTrait;
|
31 |
+
|
32 |
+
/**
|
33 |
+
* Test that page is hidden when parent page is hidden to
|
34 |
+
*
|
35 |
+
* @return void
|
36 |
+
*
|
37 |
+
* @access public
|
38 |
+
* @version 6.0.0
|
39 |
+
*/
|
40 |
+
public function testInheritanceFromParentPost()
|
41 |
+
{
|
42 |
+
$user = AAM::getUser();
|
43 |
+
$object = $user->getObject(
|
44 |
+
AAM_Core_Object_Post::OBJECT_TYPE, AAM_UNITTEST_PAGE_LEVEL_1_ID
|
45 |
+
);
|
46 |
+
|
47 |
+
// Check if save returns positive result
|
48 |
+
$this->assertTrue($object->updateOptionItem('hidden', true)->save());
|
49 |
+
|
50 |
+
// Reset all internal cache
|
51 |
+
$this->_resetSubjects();
|
52 |
+
ContentHooks::bootstrap()->resetCache();
|
53 |
+
|
54 |
+
$posts = get_posts(array(
|
55 |
+
'post_type' => 'page',
|
56 |
+
'fields' => 'ids',
|
57 |
+
'numberposts' => -1,
|
58 |
+
'suppress_filters' => false
|
59 |
+
));
|
60 |
+
|
61 |
+
$this->assertFalse(in_array(AAM_UNITTEST_PAGE_LEVEL_2_ID, $posts));
|
62 |
+
}
|
63 |
+
|
64 |
+
/**
|
65 |
+
* Test that post is hidden when parent term states so
|
66 |
+
*
|
67 |
+
* @return void
|
68 |
+
*
|
69 |
+
* @access public
|
70 |
+
* @version 6.0.0
|
71 |
+
*/
|
72 |
+
public function testInheritanceFromParentTerm()
|
73 |
+
{
|
74 |
+
$user = AAM::getUser();
|
75 |
+
$object = $user->getObject(
|
76 |
+
Term::OBJECT_TYPE, AAM_UNITTEST_CATEGORY_ID . '|category'
|
77 |
+
);
|
78 |
+
|
79 |
+
// Check if save returns positive result
|
80 |
+
$this->assertTrue($object->updateOptionItem('post/hidden', true)->save());
|
81 |
+
|
82 |
+
// Reset all internal cache
|
83 |
+
$this->_resetSubjects();
|
84 |
+
ContentHooks::bootstrap()->resetCache();
|
85 |
+
|
86 |
+
$posts = get_posts(array(
|
87 |
+
'post_type' => 'post',
|
88 |
+
'fields' => 'ids',
|
89 |
+
'numberposts' => -1,
|
90 |
+
'suppress_filters' => false
|
91 |
+
));
|
92 |
+
|
93 |
+
$this->assertFalse(in_array(AAM_UNITTEST_POST_ID, $posts));
|
94 |
+
}
|
95 |
+
|
96 |
+
/**
|
97 |
+
* Test that posts are hidden when the entire post type states so
|
98 |
+
*
|
99 |
+
* @return void
|
100 |
+
*
|
101 |
+
* @access public
|
102 |
+
* @version 6.0.0
|
103 |
+
*/
|
104 |
+
public function testInheritanceFromParentType()
|
105 |
+
{
|
106 |
+
$user = AAM::getUser();
|
107 |
+
$object = $user->getObject(
|
108 |
+
Type::OBJECT_TYPE, 'post'
|
109 |
+
);
|
110 |
+
|
111 |
+
// Check if save returns positive result
|
112 |
+
$this->assertTrue($object->updateOptionItem('post/hidden', true)->save());
|
113 |
+
|
114 |
+
// Reset all internal cache
|
115 |
+
$this->_resetSubjects();
|
116 |
+
ContentHooks::bootstrap()->resetCache();
|
117 |
+
|
118 |
+
$posts = get_posts(array(
|
119 |
+
'post_type' => 'post',
|
120 |
+
'fields' => 'ids',
|
121 |
+
'numberposts' => -1,
|
122 |
+
'suppress_filters' => false
|
123 |
+
));
|
124 |
+
|
125 |
+
$this->assertCount(0, $posts);
|
126 |
+
}
|
127 |
+
|
128 |
+
/**
|
129 |
+
* Test that post if visible if explicitly defined so
|
130 |
+
*
|
131 |
+
* @return void
|
132 |
+
*
|
133 |
+
* @access public
|
134 |
+
* @version 6.0.0
|
135 |
+
*/
|
136 |
+
public function testInheritanceFromParentTermButOverwritten()
|
137 |
+
{
|
138 |
+
$user = AAM::getUser();
|
139 |
+
$object = $user->getObject(
|
140 |
+
Term::OBJECT_TYPE, AAM_UNITTEST_CATEGORY_ID . '|category'
|
141 |
+
);
|
142 |
+
|
143 |
+
// Check if save returns positive result
|
144 |
+
$this->assertTrue($object->updateOptionItem('post/hidden', true)->save());
|
145 |
+
|
146 |
+
$post = $user->getObject(
|
147 |
+
AAM_Core_Object_Post::OBJECT_TYPE, AAM_UNITTEST_POST_ID
|
148 |
+
);
|
149 |
+
|
150 |
+
// Check if save returns positive result
|
151 |
+
$this->assertTrue($post->updateOptionItem('hidden', false)->save());
|
152 |
+
|
153 |
+
// Reset all internal cache
|
154 |
+
$this->_resetSubjects();
|
155 |
+
ContentHooks::bootstrap()->resetCache();
|
156 |
+
|
157 |
+
$posts = get_posts(array(
|
158 |
+
'post_type' => 'post',
|
159 |
+
'fields' => 'ids',
|
160 |
+
'numberposts' => -1,
|
161 |
+
'suppress_filters' => false
|
162 |
+
));
|
163 |
+
|
164 |
+
$this->assertContains(AAM_UNITTEST_POST_ID, $posts);
|
165 |
+
}
|
166 |
+
|
167 |
+
/**
|
168 |
+
* Test that post if visible if explicitly defined so
|
169 |
+
*
|
170 |
+
* @return void
|
171 |
+
*
|
172 |
+
* @access public
|
173 |
+
* @version 6.0.0
|
174 |
+
*/
|
175 |
+
public function testInheritanceFromParentTypeButOverwritten()
|
176 |
+
{
|
177 |
+
$user = AAM::getUser();
|
178 |
+
$type = $user->getObject(Type::OBJECT_TYPE, 'post');
|
179 |
+
|
180 |
+
// Check if save returns positive result
|
181 |
+
$this->assertTrue($type->updateOptionItem('post/hidden', true)->save());
|
182 |
+
|
183 |
+
$term = $user->getObject(
|
184 |
+
Term::OBJECT_TYPE, AAM_UNITTEST_CATEGORY_ID . '|category'
|
185 |
+
);
|
186 |
+
|
187 |
+
// Check if save returns positive result
|
188 |
+
$this->assertTrue($term->updateOptionItem('post/hidden', false)->save());
|
189 |
+
|
190 |
+
// Reset all internal cache
|
191 |
+
$this->_resetSubjects();
|
192 |
+
ContentHooks::bootstrap()->resetCache();
|
193 |
+
|
194 |
+
$posts = get_posts(array(
|
195 |
+
'post_type' => 'post',
|
196 |
+
'fields' => 'ids',
|
197 |
+
'numberposts' => -1,
|
198 |
+
'suppress_filters' => false
|
199 |
+
));
|
200 |
+
|
201 |
+
$this->assertContains(AAM_UNITTEST_POST_ID, $posts);
|
202 |
+
}
|
203 |
+
|
204 |
+
}
|
tests/Addon/PlusPackage/DefaultCategoryTest.php
ADDED
@@ -0,0 +1,226 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
/**
|
4 |
+
* ======================================================================
|
5 |
+
* LICENSE: This file is subject to the terms and conditions defined in *
|
6 |
+
* file 'license.txt', which is part of this source code package. *
|
7 |
+
* ======================================================================
|
8 |
+
*/
|
9 |
+
|
10 |
+
namespace AAM\UnitTest\Addon\PlusPackage;
|
11 |
+
|
12 |
+
use AAM,
|
13 |
+
AAM_Core_Config,
|
14 |
+
AAM\AddOn\PlusPackage\Main,
|
15 |
+
PHPUnit\Framework\TestCase,
|
16 |
+
AAM\UnitTest\Libs\ResetTrait,
|
17 |
+
AAM\UnitTest\Libs\AuthUserTrait,
|
18 |
+
AAM\AddOn\PlusPackage\Object\System;
|
19 |
+
|
20 |
+
/**
|
21 |
+
* Test default category assignment to a post
|
22 |
+
*
|
23 |
+
* @author Vasyl Martyniuk <vasyl@vasyltech.com>
|
24 |
+
* @version 6.0.0
|
25 |
+
*/
|
26 |
+
class DefaultCategoryTest extends TestCase
|
27 |
+
{
|
28 |
+
use ResetTrait,
|
29 |
+
AuthUserTrait;
|
30 |
+
|
31 |
+
/**
|
32 |
+
* Test the new default category is assigned to post that has no categories
|
33 |
+
* attached
|
34 |
+
*
|
35 |
+
* @return void
|
36 |
+
*
|
37 |
+
* @access public
|
38 |
+
* @version 6.0.0
|
39 |
+
*/
|
40 |
+
public function testPostSaveCategoryAssignment()
|
41 |
+
{
|
42 |
+
// Get original post terms
|
43 |
+
$terms = wp_get_object_terms(AAM_UNITTEST_POST_ID, 'category', array(
|
44 |
+
'fields' => 'ids'
|
45 |
+
));
|
46 |
+
|
47 |
+
// Remove all the terms from the post(
|
48 |
+
wp_remove_object_terms(AAM_UNITTEST_POST_ID, $terms, 'category');
|
49 |
+
|
50 |
+
// Set the default category
|
51 |
+
$system = AAM::getUser()->getObject(System::OBJECT_TYPE);
|
52 |
+
$this->assertTrue(
|
53 |
+
$system->updateOptionItem(
|
54 |
+
'defaultTerm.post.category', AAM_UNITTEST_CATEGORY_LEVEL_1_ID
|
55 |
+
)->save()
|
56 |
+
);
|
57 |
+
|
58 |
+
// Reset all internal cache
|
59 |
+
$this->_resetSubjects();
|
60 |
+
|
61 |
+
wp_update_post(array(
|
62 |
+
'ID' => AAM_UNITTEST_POST_ID
|
63 |
+
));
|
64 |
+
|
65 |
+
$new_terms = wp_get_object_terms(AAM_UNITTEST_POST_ID, 'category', array(
|
66 |
+
'fields' => 'ids'
|
67 |
+
));
|
68 |
+
|
69 |
+
$this->assertContains(AAM_UNITTEST_CATEGORY_LEVEL_1_ID, $new_terms);
|
70 |
+
|
71 |
+
// Restore original categories
|
72 |
+
wp_set_object_terms(AAM_UNITTEST_POST_ID, $terms, 'category');
|
73 |
+
}
|
74 |
+
|
75 |
+
/**
|
76 |
+
* Test the new default category is not assigned to post that has already
|
77 |
+
* category(s) attached
|
78 |
+
*
|
79 |
+
* @return void
|
80 |
+
*
|
81 |
+
* @access public
|
82 |
+
* @version 6.0.0
|
83 |
+
*/
|
84 |
+
public function testPostSaveCategoryPreserved()
|
85 |
+
{
|
86 |
+
// Get original post terms
|
87 |
+
$terms = wp_get_object_terms(AAM_UNITTEST_POST_ID, 'category', array(
|
88 |
+
'fields' => 'ids'
|
89 |
+
));
|
90 |
+
|
91 |
+
// Make sure that we have at least one category attached
|
92 |
+
$this->assertGreaterThanOrEqual(1, count($terms));
|
93 |
+
|
94 |
+
// Set the default category
|
95 |
+
$system = AAM::getUser()->getObject(System::OBJECT_TYPE);
|
96 |
+
$this->assertTrue(
|
97 |
+
$system->updateOptionItem(
|
98 |
+
'defaultTerm.post.category', AAM_UNITTEST_CATEGORY_LEVEL_1_ID
|
99 |
+
)->save()
|
100 |
+
);
|
101 |
+
|
102 |
+
// Reset all internal cache
|
103 |
+
$this->_resetSubjects();
|
104 |
+
|
105 |
+
wp_update_post(array(
|
106 |
+
'ID' => AAM_UNITTEST_POST_ID
|
107 |
+
));
|
108 |
+
|
109 |
+
$new_terms = wp_get_object_terms(AAM_UNITTEST_POST_ID, 'category', array(
|
110 |
+
'fields' => 'ids'
|
111 |
+
));
|
112 |
+
|
113 |
+
$this->assertEquals($terms, $new_terms);
|
114 |
+
}
|
115 |
+
|
116 |
+
/**
|
117 |
+
* Test assigning default category to attachment when none is specified
|
118 |
+
*
|
119 |
+
* @return void
|
120 |
+
*
|
121 |
+
* @access public
|
122 |
+
* @version 6.0.0
|
123 |
+
*/
|
124 |
+
public function testAttachmentUpdateCategoryAssignment()
|
125 |
+
{
|
126 |
+
// Enable media category
|
127 |
+
$this->assertTrue(AAM_Core_Config::set('core.settings.mediaCategory', true));
|
128 |
+
Main::bootstrap()->registerTaxonomies();
|
129 |
+
|
130 |
+
// Get original post terms
|
131 |
+
$terms = wp_get_object_terms(AAM_UNITTEST_ATTACHMENT_ID, 'media_category', array(
|
132 |
+
'fields' => 'ids'
|
133 |
+
));
|
134 |
+
|
135 |
+
// Remove all the terms from the post(
|
136 |
+
wp_remove_object_terms(AAM_UNITTEST_ATTACHMENT_ID, $terms, 'media_category');
|
137 |
+
|
138 |
+
// Set the default category
|
139 |
+
$system = AAM::getUser()->getObject(System::OBJECT_TYPE);
|
140 |
+
$this->assertTrue(
|
141 |
+
$system->updateOptionItem(
|
142 |
+
'defaultTerm.attachment.media_category', AAM_UNITTEST_MEDIA_CATEGORY_ID
|
143 |
+
)->save()
|
144 |
+
);
|
145 |
+
|
146 |
+
// Reset all internal cache
|
147 |
+
$this->_resetSubjects();
|
148 |
+
|
149 |
+
wp_update_post(array(
|
150 |
+
'ID' => AAM_UNITTEST_ATTACHMENT_ID
|
151 |
+
));
|
152 |
+
|
153 |
+
$new_terms = wp_get_object_terms(AAM_UNITTEST_ATTACHMENT_ID, 'media_category', array(
|
154 |
+
'fields' => 'ids'
|
155 |
+
));
|
156 |
+
|
157 |
+
$this->assertContains(AAM_UNITTEST_MEDIA_CATEGORY_ID, $new_terms);
|
158 |
+
|
159 |
+
// Restore original categories
|
160 |
+
wp_set_object_terms(AAM_UNITTEST_ATTACHMENT_ID, $terms, 'media_category');
|
161 |
+
}
|
162 |
+
|
163 |
+
/**
|
164 |
+
* Test assigning default category to new attachment
|
165 |
+
*
|
166 |
+
* @return void
|
167 |
+
*
|
168 |
+
* @access public
|
169 |
+
* @version 6.0.0
|
170 |
+
*/
|
171 |
+
public function testAttachmentAddCategoryAssignment()
|
172 |
+
{
|
173 |
+
// Enable media category
|
174 |
+
$this->assertTrue(AAM_Core_Config::set('core.settings.mediaCategory', true));
|
175 |
+
Main::bootstrap()->registerTaxonomies();
|
176 |
+
|
177 |
+
// Set the default category
|
178 |
+
$system = AAM::getUser()->getObject(System::OBJECT_TYPE);
|
179 |
+
$this->assertTrue(
|
180 |
+
$system->updateOptionItem(
|
181 |
+
'defaultTerm.attachment.media_category', AAM_UNITTEST_MEDIA_CATEGORY_ID
|
182 |
+
)->save()
|
183 |
+
);
|
184 |
+
|
185 |
+
// Reset all internal cache
|
186 |
+
$this->_resetSubjects();
|
187 |
+
|
188 |
+
$id = wp_insert_post(array(
|
189 |
+
'post_type' => 'attachment',
|
190 |
+
'post_title' => 'Dummy Attachment'
|
191 |
+
));
|
192 |
+
|
193 |
+
$new_terms = wp_get_object_terms($id, 'media_category', array(
|
194 |
+
'fields' => 'ids'
|
195 |
+
));
|
196 |
+
|
197 |
+
$this->assertContains(AAM_UNITTEST_MEDIA_CATEGORY_ID, $new_terms);
|
198 |
+
|
199 |
+
// Restore original categories
|
200 |
+
wp_delete_post($id, true);
|
201 |
+
}
|
202 |
+
|
203 |
+
/**
|
204 |
+
* Test that default_category option is adjusted to a new value
|
205 |
+
*
|
206 |
+
* @return void
|
207 |
+
*
|
208 |
+
* @access public
|
209 |
+
* @version 6.0.0
|
210 |
+
*/
|
211 |
+
public function testGetDefaultCategoryOption()
|
212 |
+
{
|
213 |
+
// Set the default category
|
214 |
+
$system = AAM::getUser()->getObject(System::OBJECT_TYPE);
|
215 |
+
$this->assertTrue(
|
216 |
+
$system->updateOptionItem(
|
217 |
+
'defaultTerm.post.category', AAM_UNITTEST_CATEGORY_LEVEL_2_ID
|
218 |
+
)->save()
|
219 |
+
);
|
220 |
+
|
221 |
+
$this->assertEquals(
|
222 |
+
AAM_UNITTEST_CATEGORY_LEVEL_2_ID, get_option('default_category')
|
223 |
+
);
|
224 |
+
}
|
225 |
+
|
226 |
+
}
|
tests/Addon/PlusPackage/TermRESTfulAccessTest.php
ADDED
@@ -0,0 +1,221 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
/**
|
4 |
+
* ======================================================================
|
5 |
+
* LICENSE: This file is subject to the terms and conditions defined in *
|
6 |
+
* file 'license.txt', which is part of this source code package. *
|
7 |
+
* ======================================================================
|
8 |
+
*/
|
9 |
+
|
10 |
+
namespace AAM\UnitTest\Addon\PlusPackage;
|
11 |
+
|
12 |
+
use AAM,
|
13 |
+
WP_REST_Request,
|
14 |
+
PHPUnit\Framework\TestCase,
|
15 |
+
AAM\UnitTest\Libs\ResetTrait,
|
16 |
+
AAM\UnitTest\Libs\AuthUserTrait,
|
17 |
+
AAM\AddOn\PlusPackage\Object\Term,
|
18 |
+
AAM\AddOn\PlusPackage\Object\Taxonomy;
|
19 |
+
|
20 |
+
/**
|
21 |
+
* Test cases for the Plus Package term access management
|
22 |
+
*
|
23 |
+
* @author Vasyl Martyniuk <vasyl@vasyltech.com>
|
24 |
+
* @version 6.0.0
|
25 |
+
*/
|
26 |
+
class TermRESTfulAccessTest extends TestCase
|
27 |
+
{
|
28 |
+
use ResetTrait,
|
29 |
+
AuthUserTrait;
|
30 |
+
|
31 |
+
/**
|
32 |
+
* Test that term is hidden while going through RESTful API endpoint
|
33 |
+
*
|
34 |
+
* @return void
|
35 |
+
*
|
36 |
+
* @access public
|
37 |
+
* @version 6.0.0
|
38 |
+
*/
|
39 |
+
public function testVisibilityTermDirectly()
|
40 |
+
{
|
41 |
+
$user = AAM::getUser();
|
42 |
+
$object = $user->getObject(
|
43 |
+
Term::OBJECT_TYPE, AAM_UNITTEST_CATEGORY_ID . '|category'
|
44 |
+
);
|
45 |
+
|
46 |
+
// Check if save returns positive result
|
47 |
+
$this->assertTrue($object->updateOptionItem('term/hidden', true)->save());
|
48 |
+
|
49 |
+
$server = rest_get_server();
|
50 |
+
|
51 |
+
// Verify that term is no longer in the list of terms
|
52 |
+
$request = new WP_REST_Request('GET', '/wp/v2/categories');
|
53 |
+
$request->set_param('context', 'view');
|
54 |
+
|
55 |
+
$data = $server->dispatch($request)->get_data();
|
56 |
+
|
57 |
+
// First, confirm that post is in the array of posts
|
58 |
+
$this->assertCount(0, array_filter($data, function($term) {
|
59 |
+
return $term['id'] === AAM_UNITTEST_CATEGORY_ID;
|
60 |
+
}));
|
61 |
+
}
|
62 |
+
|
63 |
+
/**
|
64 |
+
* Test that term is restricted while going through RESTful API endpoint
|
65 |
+
*
|
66 |
+
* @return void
|
67 |
+
*
|
68 |
+
* @access public
|
69 |
+
* @version 6.0.0
|
70 |
+
*/
|
71 |
+
public function testRestrictedTermDirectly()
|
72 |
+
{
|
73 |
+
$user = AAM::getUser();
|
74 |
+
$object = $user->getObject(
|
75 |
+
Term::OBJECT_TYPE, AAM_UNITTEST_CATEGORY_ID . '|category'
|
76 |
+
);
|
77 |
+
|
78 |
+
// Check if save returns positive result
|
79 |
+
$this->assertTrue($object->updateOptionItem('term/restricted', true)->save());
|
80 |
+
|
81 |
+
$server = rest_get_server();
|
82 |
+
|
83 |
+
// Verify that term is no longer in the list of terms
|
84 |
+
$request = new WP_REST_Request('GET', '/wp/v2/categories/' . AAM_UNITTEST_CATEGORY_ID);
|
85 |
+
$request->set_param('context', 'view');
|
86 |
+
|
87 |
+
$response = $server->dispatch($request);
|
88 |
+
|
89 |
+
$this->assertEquals(403, $response->get_status());
|
90 |
+
$this->assertEquals('term_access_restricted', $response->get_data()['code']);
|
91 |
+
}
|
92 |
+
|
93 |
+
/**
|
94 |
+
* Test that term is not editable while going through RESTful API endpoint
|
95 |
+
*
|
96 |
+
* @return void
|
97 |
+
*
|
98 |
+
* @access public
|
99 |
+
* @version 6.0.0
|
100 |
+
*/
|
101 |
+
public function testEditableTermDirectly()
|
102 |
+
{
|
103 |
+
$user = AAM::getUser();
|
104 |
+
$object = $user->getObject(
|
105 |
+
Term::OBJECT_TYPE, AAM_UNITTEST_CATEGORY_ID . '|category'
|
106 |
+
);
|
107 |
+
|
108 |
+
// Check if save returns positive result
|
109 |
+
$this->assertTrue($object->updateOptionItem('term/edit', true)->save());
|
110 |
+
|
111 |
+
$server = rest_get_server();
|
112 |
+
|
113 |
+
// Verify that term is no longer in the list of terms
|
114 |
+
$request = new WP_REST_Request('POST', '/wp/v2/categories/' . AAM_UNITTEST_CATEGORY_ID);
|
115 |
+
$request->set_param('description', 'Test');
|
116 |
+
|
117 |
+
$response = $server->dispatch($request);
|
118 |
+
|
119 |
+
$this->assertEquals(403, $response->get_status());
|
120 |
+
$this->assertEquals('rest_cannot_update', $response->get_data()['code']);
|
121 |
+
}
|
122 |
+
|
123 |
+
/**
|
124 |
+
* Test that access is restricted to create a new ter
|
125 |
+
*
|
126 |
+
* @return void
|
127 |
+
*
|
128 |
+
* @access public
|
129 |
+
* @version 6.0.0
|
130 |
+
*/
|
131 |
+
public function testCreationTermDirectly()
|
132 |
+
{
|
133 |
+
global $wp_taxonomies;
|
134 |
+
|
135 |
+
$user = AAM::getUser();
|
136 |
+
$object = $user->getObject(Taxonomy::OBJECT_TYPE, 'category');
|
137 |
+
|
138 |
+
// Check if save returns positive result
|
139 |
+
$this->assertTrue($object->updateOptionItem('term/edit', true)->save());
|
140 |
+
|
141 |
+
// Emulate new taxonomy registration
|
142 |
+
do_action('registered_taxonomy', 'category', 'post');
|
143 |
+
|
144 |
+
$server = rest_get_server();
|
145 |
+
|
146 |
+
// Verify that term is no longer in the list of terms
|
147 |
+
$request = new WP_REST_Request('POST', '/wp/v2/categories');
|
148 |
+
$request->set_param('name', 'Test');
|
149 |
+
$request->set_param('description', 'Test');
|
150 |
+
|
151 |
+
$response = $server->dispatch($request);
|
152 |
+
|
153 |
+
$this->assertEquals(403, $response->get_status());
|
154 |
+
$this->assertEquals('rest_cannot_create', $response->get_data()['code']);
|
155 |
+
|
156 |
+
// Restore original
|
157 |
+
$wp_taxonomies['category']->cap->edit_terms = 'edit_categories';
|
158 |
+
}
|
159 |
+
|
160 |
+
/**
|
161 |
+
* Test that term cannot be deleted while going through RESTful API endpoint
|
162 |
+
*
|
163 |
+
* @return void
|
164 |
+
*
|
165 |
+
* @access public
|
166 |
+
* @version 6.0.0
|
167 |
+
*/
|
168 |
+
public function testDeleteTermDirectly()
|
169 |
+
{
|
170 |
+
$user = AAM::getUser();
|
171 |
+
$object = $user->getObject(
|
172 |
+
Term::OBJECT_TYPE, AAM_UNITTEST_CATEGORY_ID . '|category'
|
173 |
+
);
|
174 |
+
|
175 |
+
// Check if save returns positive result
|
176 |
+
$this->assertTrue($object->updateOptionItem('term/delete', true)->save());
|
177 |
+
|
178 |
+
$server = rest_get_server();
|
179 |
+
|
180 |
+
// Verify that term is no longer in the list of terms
|
181 |
+
$request = new WP_REST_Request('DELETE', '/wp/v2/categories/' . AAM_UNITTEST_CATEGORY_ID);
|
182 |
+
|
183 |
+
$response = $server->dispatch($request);
|
184 |
+
|
185 |
+
$this->assertEquals(403, $response->get_status());
|
186 |
+
$this->assertEquals('rest_cannot_delete', $response->get_data()['code']);
|
187 |
+
}
|
188 |
+
|
189 |
+
/**
|
190 |
+
* Test that term cannot be assigned to a post while going through RESTful
|
191 |
+
* API endpoint
|
192 |
+
*
|
193 |
+
* @return void
|
194 |
+
*
|
195 |
+
* @access public
|
196 |
+
* @version 6.0.0
|
197 |
+
*/
|
198 |
+
public function testAssignTermDirectly()
|
199 |
+
{
|
200 |
+
$user = AAM::getUser();
|
201 |
+
$object = $user->getObject(
|
202 |
+
Term::OBJECT_TYPE, AAM_UNITTEST_CATEGORY_ID . '|category'
|
203 |
+
);
|
204 |
+
|
205 |
+
// Check if save returns positive result
|
206 |
+
$this->assertTrue($object->updateOptionItem('term/assign', true)->save());
|
207 |
+
|
208 |
+
$server = rest_get_server();
|
209 |
+
|
210 |
+
// Verify that term is no longer in the list of terms
|
211 |
+
$request = new WP_REST_Request('POST', '/wp/v2/posts/' . AAM_UNITTEST_POST_ID);
|
212 |
+
$request->set_param('context', 'edit');
|
213 |
+
$request->set_param('categories', array(AAM_UNITTEST_CATEGORY_ID));
|
214 |
+
|
215 |
+
$response = $server->dispatch($request);
|
216 |
+
|
217 |
+
$this->assertEquals(403, $response->get_status());
|
218 |
+
$this->assertEquals('rest_cannot_assign_term', $response->get_data()['code']);
|
219 |
+
}
|
220 |
+
|
221 |
+
}
|
tests/Addon/PlusPackage/UriAccessTest.php
ADDED
@@ -0,0 +1,101 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
/**
|
4 |
+
* ======================================================================
|
5 |
+
* LICENSE: This file is subject to the terms and conditions defined in *
|
6 |
+
* file 'license.txt', which is part of this source code package. *
|
7 |
+
* ======================================================================
|
8 |
+
*/
|
9 |
+
|
10 |
+
namespace AAM\UnitTest\Addon\PlusPackage;
|
11 |
+
|
12 |
+
use AAM,
|
13 |
+
AAM_Service_Uri,
|
14 |
+
AAM_Core_Object_Uri,
|
15 |
+
PHPUnit\Framework\TestCase,
|
16 |
+
AAM\UnitTest\Libs\ResetTrait;
|
17 |
+
|
18 |
+
/**
|
19 |
+
* Test URI access enhancement
|
20 |
+
*
|
21 |
+
* @author Vasyl Martyniuk <vasyl@vasyltech.com>
|
22 |
+
* @version 6.0.0
|
23 |
+
*/
|
24 |
+
class UriAccessTest extends TestCase
|
25 |
+
{
|
26 |
+
use ResetTrait;
|
27 |
+
|
28 |
+
/**
|
29 |
+
* Test the wild card URI access rule
|
30 |
+
*
|
31 |
+
* @return void
|
32 |
+
*
|
33 |
+
* @access public
|
34 |
+
* @version 6.0.0
|
35 |
+
*/
|
36 |
+
public function testWildCardMatch()
|
37 |
+
{
|
38 |
+
$object = AAM::getUser()->getObject(AAM_Core_Object_Uri::OBJECT_TYPE);
|
39 |
+
$result = $object->updateOptionItem('*', array(
|
40 |
+
'type' => 'default',
|
41 |
+
'action' => null
|
42 |
+
))->save();
|
43 |
+
|
44 |
+
$this->assertTrue($result);
|
45 |
+
|
46 |
+
// Override the default handlers so we can suppress die exit
|
47 |
+
add_filter('wp_die_handler', function() {
|
48 |
+
return function($message, $title) {
|
49 |
+
_default_wp_die_handler($message, $title, array('exit' => false));
|
50 |
+
};
|
51 |
+
}, PHP_INT_MAX);
|
52 |
+
$_SERVER['REQUEST_URI'] = '/';
|
53 |
+
|
54 |
+
// Reset all internal cache
|
55 |
+
$this->_resetSubjects();
|
56 |
+
|
57 |
+
ob_start();
|
58 |
+
AAM_Service_Uri::getInstance()->authorizeUri();
|
59 |
+
$content = ob_get_contents();
|
60 |
+
ob_end_clean();
|
61 |
+
|
62 |
+
$this->assertStringContainsString('Access Denied', $content);
|
63 |
+
}
|
64 |
+
|
65 |
+
/**
|
66 |
+
* Test the wild card override rule
|
67 |
+
*
|
68 |
+
* The entire website is denied but only one specific URI is allowed
|
69 |
+
*
|
70 |
+
* @return void
|
71 |
+
*
|
72 |
+
* @access public
|
73 |
+
* @version 6.0.0
|
74 |
+
*/
|
75 |
+
public function testWildCardOverride()
|
76 |
+
{
|
77 |
+
$object = AAM::getUser()->getObject(AAM_Core_Object_Uri::OBJECT_TYPE);
|
78 |
+
|
79 |
+
// Deny access ot the entire site
|
80 |
+
$this->assertTrue($object->updateOptionItem('*', array(
|
81 |
+
'type' => 'default',
|
82 |
+
'action' => null
|
83 |
+
))->save());
|
84 |
+
|
85 |
+
// Allow to only one specific URI
|
86 |
+
$this->assertTrue($object->updateOptionItem('/hello-world', array(
|
87 |
+
'type' => 'allow',
|
88 |
+
'action' => null
|
89 |
+
))->save());
|
90 |
+
|
91 |
+
// Reset all internal cache
|
92 |
+
$this->_resetSubjects();
|
93 |
+
|
94 |
+
$match = AAM::getUser()->getObject(AAM_Core_Object_Uri::OBJECT_TYPE)->findMatch(
|
95 |
+
'/hello-world'
|
96 |
+
);
|
97 |
+
|
98 |
+
$this->assertEquals($match['type'], 'allow');
|
99 |
+
}
|
100 |
+
|
101 |
+
}
|
tests/Addon/RoleHierarchy/RoleHierarchyTest.php
ADDED
@@ -0,0 +1,58 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
/**
|
4 |
+
* ======================================================================
|
5 |
+
* LICENSE: This file is subject to the terms and conditions defined in *
|
6 |
+
* file 'license.txt', which is part of this source code package. *
|
7 |
+
* ======================================================================
|
8 |
+
*/
|
9 |
+
|
10 |
+
namespace AAM\UnitTest\Addon\RoleHierarchy;
|
11 |
+
|
12 |
+
use AAM,
|
13 |
+
AAM_Core_Object_Menu,
|
14 |
+
PHPUnit\Framework\TestCase,
|
15 |
+
AAM\UnitTest\Libs\ResetTrait,
|
16 |
+
AAM\UnitTest\Libs\AuthUserTrait;
|
17 |
+
|
18 |
+
/**
|
19 |
+
* Test cases for the Role Hierarchy addon
|
20 |
+
*
|
21 |
+
* @author Vasyl Martyniuk <vasyl@vasyltech.com>
|
22 |
+
* @version 6.0.0
|
23 |
+
*/
|
24 |
+
class RoleHierarchyTest extends TestCase
|
25 |
+
{
|
26 |
+
use ResetTrait,
|
27 |
+
AuthUserTrait;
|
28 |
+
|
29 |
+
/**
|
30 |
+
* Test that role can have a parent role and settings are propagated properly
|
31 |
+
*
|
32 |
+
* @return void
|
33 |
+
*
|
34 |
+
* @access public
|
35 |
+
* @version 6.0.0
|
36 |
+
*/
|
37 |
+
public function testRoleInheritance()
|
38 |
+
{
|
39 |
+
$contributor = AAM::api()->getRole('contributor');
|
40 |
+
$object = $contributor->getObject(AAM_Core_Object_Menu::OBJECT_TYPE);
|
41 |
+
|
42 |
+
// Set fake settings for the Contributor
|
43 |
+
$this->assertTrue($object->updateOptionItem('index.php', true)->save());
|
44 |
+
|
45 |
+
// Fake the fact that Subscriber has a parent role Contributor
|
46 |
+
AAM::api()->updateConfig('system.role.subscriber.parent', 'contributor');
|
47 |
+
|
48 |
+
// Reset all internal cache
|
49 |
+
$this->_resetSubjects();
|
50 |
+
|
51 |
+
$subscriber = AAM::api()->getRole('subscriber');
|
52 |
+
$object = $subscriber->getObject(AAM_Core_Object_Menu::OBJECT_TYPE);
|
53 |
+
|
54 |
+
$this->assertEquals('contributor', $subscriber->getParent()->getId());
|
55 |
+
$this->assertTrue($object->isRestricted('index.php'));
|
56 |
+
}
|
57 |
+
|
58 |
+
}
|
tests/Core/GatewayTest.php
ADDED
@@ -0,0 +1,90 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
/**
|
4 |
+
* ======================================================================
|
5 |
+
* LICENSE: This file is subject to the terms and conditions defined in *
|
6 |
+
* file 'license.txt', which is part of this source code package. *
|
7 |
+
* ======================================================================
|
8 |
+
*/
|
9 |
+
|
10 |
+
namespace AAM\UnitTest\Core;
|
11 |
+
|
12 |
+
use AAM_Core_Gateway,
|
13 |
+
PHPUnit\Framework\TestCase;
|
14 |
+
|
15 |
+
/**
|
16 |
+
* Test AAM core Gateway
|
17 |
+
*
|
18 |
+
* @package AAM\UnitTest
|
19 |
+
* @version 6.0.0
|
20 |
+
*/
|
21 |
+
class GatewayTest extends TestCase
|
22 |
+
{
|
23 |
+
/**
|
24 |
+
* Test all possible merging permutations with preference
|
25 |
+
*
|
26 |
+
* @return void
|
27 |
+
*
|
28 |
+
* @access public
|
29 |
+
* @dataProvider mergingPreferenceData
|
30 |
+
* @version 6.0.0
|
31 |
+
*/
|
32 |
+
public function testAccessOptionsMerging($set1, $set2, $preference, $expected)
|
33 |
+
{
|
34 |
+
$gateway = AAM_Core_Gateway::getInstance();
|
35 |
+
|
36 |
+
$this->assertSame(
|
37 |
+
$gateway->mergeSettings($set1, $set2, null, $preference), $expected
|
38 |
+
);
|
39 |
+
}
|
40 |
+
|
41 |
+
/**
|
42 |
+
* Return the array of possible access option combinations
|
43 |
+
*
|
44 |
+
* @return array
|
45 |
+
*
|
46 |
+
* @access public
|
47 |
+
* @version 6.0.0
|
48 |
+
*/
|
49 |
+
public function mergingPreferenceData()
|
50 |
+
{
|
51 |
+
return array(
|
52 |
+
array(array('hidden' => true), array('hidden' => true), 'deny', array('hidden' => true)),
|
53 |
+
array(array('hidden' => true), array('hidden' => false), 'deny', array('hidden' => true)),
|
54 |
+
array(array('hidden' => false), array('hidden' => true), 'deny', array('hidden' => true)),
|
55 |
+
array(array('hidden' => false), array('hidden' => false), 'deny', array('hidden' => false)),
|
56 |
+
array(array('hidden' => true), array('hidden' => true), 'allow', array('hidden' => true)),
|
57 |
+
array(array('hidden' => true), array('hidden' => false), 'allow', array('hidden' => false)),
|
58 |
+
array(array('hidden' => false), array('hidden' => true), 'allow', array('hidden' => false)),
|
59 |
+
array(array('hidden' => false), array('hidden' => false), 'allow', array('hidden' => false)),
|
60 |
+
// One of the options is not defined
|
61 |
+
array(array('hidden' => true), array(), 'deny', array('hidden' => true)),
|
62 |
+
array(array('hidden' => false), array(), 'deny', array('hidden' => false)),
|
63 |
+
array(array(), array('hidden' => true), 'deny', array('hidden' => true)),
|
64 |
+
array(array(), array('hidden' => false), 'deny', array('hidden' => false)),
|
65 |
+
array(array('hidden' => true), array(), 'allow', array('hidden' => false)),
|
66 |
+
array(array('hidden' => false), array(), 'allow', array('hidden' => false)),
|
67 |
+
array(array(), array('hidden' => true), 'allow', array('hidden' => false)),
|
68 |
+
array(array(), array('hidden' => false), 'allow', array('hidden' => false)),
|
69 |
+
// Complex access options that are defined as array
|
70 |
+
array(array('limited' => array('enabled' => true, 'threshold' => 1)), array('limited' => array('enabled' => true, 'threshold' => 2)), 'deny', array('limited' => array('enabled' => true, 'threshold' => 2))),
|
71 |
+
array(array('limited' => array('enabled' => true, 'threshold' => 1)), array('limited' => array('enabled' => false, 'threshold' => 2)), 'deny', array('limited' => array('enabled' => true, 'threshold' => 1))),
|
72 |
+
array(array('limited' => array('enabled' => false, 'threshold' => 1)), array('limited' => array('enabled' => true, 'threshold' => 2)), 'deny', array('limited' => array('enabled' => true, 'threshold' => 2))),
|
73 |
+
array(array('limited' => array('enabled' => false, 'threshold' => 1)), array('limited' => array('enabled' => false, 'threshold' => 2)), 'deny', array('limited' => array('enabled' => false, 'threshold' => 2))),
|
74 |
+
array(array('limited' => array('enabled' => true, 'threshold' => 1)), array('limited' => array('enabled' => true, 'threshold' => 2)), 'allow', array('limited' => array('enabled' => true, 'threshold' => 2))),
|
75 |
+
array(array('limited' => array('enabled' => true, 'threshold' => 1)), array('limited' => array('enabled' => false, 'threshold' => 2)), 'allow', array('limited' => array('enabled' => false, 'threshold' => 2))),
|
76 |
+
array(array('limited' => array('enabled' => false, 'threshold' => 1)), array('limited' => array('enabled' => true, 'threshold' => 2)), 'allow', array('limited' => array('enabled' => false, 'threshold' => 1))),
|
77 |
+
array(array('limited' => array('enabled' => false, 'threshold' => 1)), array('limited' => array('enabled' => false, 'threshold' => 2)), 'allow', array('limited' => array('enabled' => false, 'threshold' => 2))),
|
78 |
+
// One of the options is not defined
|
79 |
+
array(array('limited' => array('enabled' => true, 'threshold' => 1)), array(), 'deny', array('limited' => array('enabled' => true, 'threshold' => 1))),
|
80 |
+
array(array(), array('limited' => array('enabled' => true, 'threshold' => 2)), 'deny', array('limited' => array('enabled' => true, 'threshold' => 2))),
|
81 |
+
array(array('limited' => array('enabled' => false, 'threshold' => 1)), array(), 'deny', array('limited' => array('enabled' => false, 'threshold' => 1))),
|
82 |
+
array(array(), array('limited' => array('enabled' => false, 'threshold' => 2)), 'deny', array('limited' => array('enabled' => false, 'threshold' => 2))),
|
83 |
+
array(array('limited' => array('enabled' => true, 'threshold' => 1)), array(), 'allow', array('limited' => array('enabled' => false, 'threshold' => 1))),
|
84 |
+
array(array('limited' => array('enabled' => false, 'threshold' => 1)), array(), 'allow', array('limited' => array('enabled' => false, 'threshold' => 1))),
|
85 |
+
array(array(), array('limited' => array('enabled' => true, 'threshold' => 2)), 'allow', array('limited' => array('enabled' => false, 'threshold' => 2))),
|
86 |
+
array(array(), array('limited' => array('enabled' => false, 'threshold' => 2)), 'allow', array('limited' => array('enabled' => false, 'threshold' => 2))),
|
87 |
+
);
|
88 |
+
}
|
89 |
+
|
90 |
+
}
|
tests/Core/SubjectLoadTest.php
ADDED
@@ -0,0 +1,32 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
/**
|
4 |
+
* ======================================================================
|
5 |
+
* LICENSE: This file is subject to the terms and conditions defined in *
|
6 |
+
* file 'license.txt', which is part of this source code package. *
|
7 |
+
* ======================================================================
|
8 |
+
*/
|
9 |
+
|
10 |
+
use PHPUnit\Framework\TestCase;
|
11 |
+
|
12 |
+
/**
|
13 |
+
* Test if proper subject is picked correctly
|
14 |
+
*
|
15 |
+
* @author Vasyl Martyniuk <vasyl@vasyltech.com>
|
16 |
+
* @version 6.0.0
|
17 |
+
*/
|
18 |
+
class SubjectLoadTest extends TestCase
|
19 |
+
{
|
20 |
+
|
21 |
+
/**
|
22 |
+
* Test that AAM loaded Visitor subject
|
23 |
+
*
|
24 |
+
* AAM has to load Visitor subject when there is no indicators or authentication
|
25 |
+
*/
|
26 |
+
public function testLoadedVisitorType()
|
27 |
+
{
|
28 |
+
$subject = AAM::getUser();
|
29 |
+
|
30 |
+
$this->assertSame('AAM_Core_Subject_Visitor', get_class($subject));
|
31 |
+
}
|
32 |
+
}
|
tests/Libs/AuthManagerUserTrait.php
ADDED
@@ -0,0 +1,36 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
/**
|
4 |
+
* ======================================================================
|
5 |
+
* LICENSE: This file is subject to the terms and conditions defined in *
|
6 |
+
* file 'license.txt', which is part of this source code package. *
|
7 |
+
* ======================================================================
|
8 |
+
*/
|
9 |
+
|
10 |
+
namespace AAM\UnitTest\Libs;
|
11 |
+
|
12 |
+
/**
|
13 |
+
*
|
14 |
+
* @version 6.0.0
|
15 |
+
*/
|
16 |
+
trait AuthManagerUserTrait
|
17 |
+
{
|
18 |
+
/**
|
19 |
+
* @inheritdoc
|
20 |
+
*/
|
21 |
+
public static function setUpBeforeClass()
|
22 |
+
{
|
23 |
+
// Set current User. Emulate that this is admin login
|
24 |
+
wp_set_current_user(AAM_UNITTEST_AUTH_SUBADMIN_USER_ID);
|
25 |
+
}
|
26 |
+
|
27 |
+
/**
|
28 |
+
* @inheritdoc
|
29 |
+
*/
|
30 |
+
public static function tearDownAfterClass()
|
31 |
+
{
|
32 |
+
// Unset the forced user
|
33 |
+
wp_set_current_user(0);
|
34 |
+
}
|
35 |
+
|
36 |
+
}
|
tests/Libs/AuthMultiRoleUserTrait.php
ADDED
@@ -0,0 +1,57 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
/**
|
4 |
+
* ======================================================================
|
5 |
+
* LICENSE: This file is subject to the terms and conditions defined in *
|
6 |
+
* file 'license.txt', which is part of this source code package. *
|
7 |
+
* ======================================================================
|
8 |
+
*/
|
9 |
+
|
10 |
+
namespace AAM\UnitTest\Libs;
|
11 |
+
|
12 |
+
use AAM,
|
13 |
+
AAM_Core_Config,
|
14 |
+
AAM_Core_Subject_User;
|
15 |
+
|
16 |
+
/**
|
17 |
+
* Trait that setup multi-role support
|
18 |
+
*
|
19 |
+
* The `AAM_UNITTEST_AUTH_MULTIROLE_USER_ID` constant that is defined in the main
|
20 |
+
* phpunit.xml.dist config, has to point to the existing WP user that has more than
|
21 |
+
* one role assigned
|
22 |
+
*
|
23 |
+
* @package AAM\UnitTest
|
24 |
+
* @version 6.0.0
|
25 |
+
*/
|
26 |
+
trait AuthMultiRoleUserTrait
|
27 |
+
{
|
28 |
+
|
29 |
+
/**
|
30 |
+
* @inheritdoc
|
31 |
+
*/
|
32 |
+
public static function setUpBeforeClass()
|
33 |
+
{
|
34 |
+
if (is_subclass_of(self::class, 'AAM\UnitTest\Libs\MultiRoleOptionInterface')) {
|
35 |
+
// Enable Multiple Role Support
|
36 |
+
AAM_Core_Config::set('core.settings.multiSubject', true);
|
37 |
+
}
|
38 |
+
|
39 |
+
// Set current User. Emulate that this is admin login
|
40 |
+
wp_set_current_user(AAM_UNITTEST_AUTH_MULTIROLE_USER_ID);
|
41 |
+
|
42 |
+
// Override AAM current user
|
43 |
+
AAM::getInstance()->setUser(
|
44 |
+
new AAM_Core_Subject_User(AAM_UNITTEST_AUTH_MULTIROLE_USER_ID)
|
45 |
+
);
|
46 |
+
}
|
47 |
+
|
48 |
+
/**
|
49 |
+
* @inheritdoc
|
50 |
+
*/
|
51 |
+
public static function tearDownAfterClass()
|
52 |
+
{
|
53 |
+
// Unset the forced user
|
54 |
+
wp_set_current_user(0);
|
55 |
+
}
|
56 |
+
|
57 |
+
}
|
tests/Libs/AuthUserTrait.php
ADDED
@@ -0,0 +1,37 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
/**
|
4 |
+
* ======================================================================
|
5 |
+
* LICENSE: This file is subject to the terms and conditions defined in *
|
6 |
+
* file 'license.txt', which is part of this source code package. *
|
7 |
+
* ======================================================================
|
8 |
+
*/
|
9 |
+
|
10 |
+
namespace AAM\UnitTest\Libs;
|
11 |
+
|
12 |
+
/**
|
13 |
+
* Test access policy integration with core AAM objects
|
14 |
+
*
|
15 |
+
* @version 6.0.0
|
16 |
+
*/
|
17 |
+
trait AuthUserTrait
|
18 |
+
{
|
19 |
+
/**
|
20 |
+
* @inheritdoc
|
21 |
+
*/
|
22 |
+
public static function setUpBeforeClass()
|
23 |
+
{
|
24 |
+
// Set current User. Emulate that this is admin login
|
25 |
+
wp_set_current_user(AAM_UNITTEST_AUTH_USER_ID);
|
26 |
+
}
|
27 |
+
|
28 |
+
/**
|
29 |
+
* @inheritdoc
|
30 |
+
*/
|
31 |
+
public static function tearDownAfterClass()
|
32 |
+
{
|
33 |
+
// Unset the forced user
|
34 |
+
wp_set_current_user(0);
|
35 |
+
}
|
36 |
+
|
37 |
+
}
|
tests/Libs/MultiRoleOptionInterface.php
ADDED
@@ -0,0 +1,17 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
/**
|
4 |
+
* ======================================================================
|
5 |
+
* LICENSE: This file is subject to the terms and conditions defined in *
|
6 |
+
* file 'license.txt', which is part of this source code package. *
|
7 |
+
* ======================================================================
|
8 |
+
*/
|
9 |
+
|
10 |
+
namespace AAM\UnitTest\Libs;
|
11 |
+
|
12 |
+
/**
|
13 |
+
*
|
14 |
+
* @version 6.0.0
|
15 |
+
*/
|
16 |
+
interface MultiRoleOptionInterface
|
17 |
+
{ }
|
tests/Libs/ResetTrait.php
ADDED
@@ -0,0 +1,92 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
/**
|
4 |
+
* ======================================================================
|
5 |
+
* LICENSE: This file is subject to the terms and conditions defined in *
|
6 |
+
* file 'license.txt', which is part of this source code package. *
|
7 |
+
* ======================================================================
|
8 |
+
*/
|
9 |
+
|
10 |
+
namespace AAM\UnitTest\Libs;
|
11 |
+
|
12 |
+
use AAM,
|
13 |
+
AAM_Core_API,
|
14 |
+
AAM_Core_Config,
|
15 |
+
AAM_Core_AccessSettings,
|
16 |
+
AAM_Core_Policy_Factory;
|
17 |
+
|
18 |
+
/**
|
19 |
+
* Reset access settings after each test
|
20 |
+
*
|
21 |
+
* @package AAM\UnitTest
|
22 |
+
* @version 6.0.0
|
23 |
+
*/
|
24 |
+
trait ResetTrait
|
25 |
+
{
|
26 |
+
|
27 |
+
/**
|
28 |
+
* Reset all AAM settings to the default
|
29 |
+
*
|
30 |
+
* @return void
|
31 |
+
*
|
32 |
+
* @access protected
|
33 |
+
* @version 6.0.0
|
34 |
+
*/
|
35 |
+
protected function tearDown()
|
36 |
+
{
|
37 |
+
// Clear all AAM settings
|
38 |
+
AAM_Core_API::clearSettings();
|
39 |
+
|
40 |
+
// Reset Access Settings repository
|
41 |
+
AAM_Core_AccessSettings::getInstance()->reset();
|
42 |
+
|
43 |
+
// Also clear all the internal caching
|
44 |
+
$this->_resetSubjects();
|
45 |
+
|
46 |
+
if (is_subclass_of(self::class, 'AAM\UnitTest\Libs\MultiRoleOptionInterface')) {
|
47 |
+
// Enable Multiple Role Support
|
48 |
+
AAM_Core_Config::set('core.settings.multiSubject', true);
|
49 |
+
}
|
50 |
+
|
51 |
+
// Clear WP core cache
|
52 |
+
wp_cache_flush();
|
53 |
+
|
54 |
+
// Reset internal AAM config cache
|
55 |
+
AAM_Core_Config::bootstrap();
|
56 |
+
|
57 |
+
// Reset Access Policy Factory cache
|
58 |
+
AAM_Core_Policy_Factory::reset();
|
59 |
+
}
|
60 |
+
|
61 |
+
/**
|
62 |
+
* Reset all subjects
|
63 |
+
*
|
64 |
+
* AAM Subject has internal cache that stored already initiated objects for
|
65 |
+
* performance reasons. Reset the cache to allow inheritance mechanism to go
|
66 |
+
* through.
|
67 |
+
*
|
68 |
+
* @return void
|
69 |
+
*
|
70 |
+
* @access private
|
71 |
+
* @see AAM_Core_Subject::getObject
|
72 |
+
* @link https://aamplugin.com/reference/plugin#multiple-roles-support
|
73 |
+
* @version 6.0.0
|
74 |
+
*/
|
75 |
+
private function _resetSubjects()
|
76 |
+
{
|
77 |
+
$subject = AAM::getUser();
|
78 |
+
|
79 |
+
do {
|
80 |
+
// Take in consideration that a subject can have multiple parent subjects
|
81 |
+
// when "Multiple Roles Support" is enabled
|
82 |
+
$subject->flushCache();
|
83 |
+
if ($subject->hasSiblings()) {
|
84 |
+
$siblings = $subject->getSiblings();
|
85 |
+
array_walk($siblings, function($sibling) {
|
86 |
+
$sibling->flushCache();
|
87 |
+
});
|
88 |
+
}
|
89 |
+
} while ($subject = $subject->getParent());
|
90 |
+
}
|
91 |
+
|
92 |
+
}
|
tests/Service/AccessPolicy/PolicyConditionTest.php
ADDED
@@ -0,0 +1,543 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
/**
|
4 |
+
* ======================================================================
|
5 |
+
* LICENSE: This file is subject to the terms and conditions defined in *
|
6 |
+
* file 'license.txt', which is part of this source code package. *
|
7 |
+
* ======================================================================
|
8 |
+
*/
|
9 |
+
|
10 |
+
namespace AAM\UnitTest\Service\AccessPolicy;
|
11 |
+
|
12 |
+
use AAM_Core_Policy_Condition,
|
13 |
+
PHPUnit\Framework\TestCase;
|
14 |
+
|
15 |
+
/**
|
16 |
+
* Test policy condition evaluator
|
17 |
+
*
|
18 |
+
* @author Vasyl Martyniuk <vasyl@vasyltech.com>
|
19 |
+
* @version 6.0.0
|
20 |
+
*/
|
21 |
+
class PolicyConditionTest extends TestCase
|
22 |
+
{
|
23 |
+
/**
|
24 |
+
* Validate Between condition evaluator
|
25 |
+
*
|
26 |
+
* @param array $condition
|
27 |
+
* @param boolean $expectedResult
|
28 |
+
*
|
29 |
+
* @return void
|
30 |
+
*
|
31 |
+
* @access public
|
32 |
+
* @dataProvider betweenDataProvider
|
33 |
+
* @version 6.0.0
|
34 |
+
*/
|
35 |
+
public function testBetweenCondition($condition, $expectedResult)
|
36 |
+
{
|
37 |
+
$manager = AAM_Core_Policy_Condition::getInstance();
|
38 |
+
|
39 |
+
$this->assertEquals($expectedResult, $manager->evaluate($condition));
|
40 |
+
}
|
41 |
+
|
42 |
+
/**
|
43 |
+
* Between condition data provider
|
44 |
+
*
|
45 |
+
* @return void
|
46 |
+
*
|
47 |
+
* @access public
|
48 |
+
* @version 6.0.0
|
49 |
+
*/
|
50 |
+
public function betweenDataProvider()
|
51 |
+
{
|
52 |
+
return array(
|
53 |
+
array(array('Between' => array(10 => array(5, 15))), true),
|
54 |
+
array(array('Between' => array(10 => array(array(1, 3), array(5, 12)))), true),
|
55 |
+
array(array('Between' => array(21 => array(array(1, 3), array(5, 12), array(20, 21)))), true),
|
56 |
+
array(array('Between' => array(1 => array(5, 15))), false)
|
57 |
+
);
|
58 |
+
}
|
59 |
+
|
60 |
+
/**
|
61 |
+
* Validate Equals condition evaluator
|
62 |
+
*
|
63 |
+
* @param array $condition
|
64 |
+
* @param boolean $expectedResult
|
65 |
+
*
|
66 |
+
* @return void
|
67 |
+
*
|
68 |
+
* @access public
|
69 |
+
* @dataProvider equalsDataProvider
|
70 |
+
* @version 6.0.0
|
71 |
+
*/
|
72 |
+
public function testEqualsCondition($condition, $expectedResult)
|
73 |
+
{
|
74 |
+
$manager = AAM_Core_Policy_Condition::getInstance();
|
75 |
+
|
76 |
+
$this->assertEquals($expectedResult, $manager->evaluate($condition));
|
77 |
+
}
|
78 |
+
|
79 |
+
/**
|
80 |
+
* Equals condition data provider
|
81 |
+
*
|
82 |
+
* @return void
|
83 |
+
*
|
84 |
+
* @access public
|
85 |
+
* @version 6.0.0
|
86 |
+
*/
|
87 |
+
public function equalsDataProvider()
|
88 |
+
{
|
89 |
+
// Note! Left side of the condition should never be boolean
|
90 |
+
return array(
|
91 |
+
array(array('Equals' => array(0 => null)), false),
|
92 |
+
array(array('Equals' => array(5 => 4)), false),
|
93 |
+
array(array('Equals' => array(1 => 1)), true),
|
94 |
+
array(array('Equals' => array(1 => '1')), false),
|
95 |
+
array(array('Equals' => array('hello' => 'hello')), true),
|
96 |
+
array(array('Equals' => array('hello' => 'hello1')), false),
|
97 |
+
);
|
98 |
+
}
|
99 |
+
|
100 |
+
/**
|
101 |
+
* Validate NotEquals condition evaluator
|
102 |
+
*
|
103 |
+
* @param array $condition
|
104 |
+
* @param boolean $expectedResult
|
105 |
+
*
|
106 |
+
* @return void
|
107 |
+
*
|
108 |
+
* @access public
|
109 |
+
* @dataProvider notEqualsDataProvider
|
110 |
+
* @version 6.0.0
|
111 |
+
*/
|
112 |
+
public function testNotEqualsCondition($condition, $expectedResult)
|
113 |
+
{
|
114 |
+
$manager = AAM_Core_Policy_Condition::getInstance();
|
115 |
+
|
116 |
+
$this->assertEquals($expectedResult, $manager->evaluate($condition));
|
117 |
+
}
|
118 |
+
|
119 |
+
/**
|
120 |
+
* NotEquals condition data provider
|
121 |
+
*
|
122 |
+
* @return void
|
123 |
+
*
|
124 |
+
* @access public
|
125 |
+
* @version 6.0.0
|
126 |
+
*/
|
127 |
+
public function notEqualsDataProvider()
|
128 |
+
{
|
129 |
+
// Note! Left side of the condition should never be boolean
|
130 |
+
return array(
|
131 |
+
array(array('NotEquals' => array(0 => null)), true),
|
132 |
+
array(array('NotEquals' => array(5 => 4)), true),
|
133 |
+
array(array('NotEquals' => array(1 => 1)), false),
|
134 |
+
array(array('NotEquals' => array(1 => '1')), true),
|
135 |
+
array(array('NotEquals' => array('2a' => 2)), true),
|
136 |
+
array(array('NotEquals' => array('hello' => 'hello')), false),
|
137 |
+
array(array('NotEquals' => array('hello' => 'hello1')), true),
|
138 |
+
);
|
139 |
+
}
|
140 |
+
|
141 |
+
/**
|
142 |
+
* Validate Greater condition evaluator
|
143 |
+
*
|
144 |
+
* @param array $condition
|
145 |
+
* @param boolean $expectedResult
|
146 |
+
*
|
147 |
+
* @return void
|
148 |
+
*
|
149 |
+
* @access public
|
150 |
+
* @dataProvider greaterDataProvider
|
151 |
+
* @version 6.0.0
|
152 |
+
*/
|
153 |
+
public function testGreaterCondition($condition, $expectedResult)
|
154 |
+
{
|
155 |
+
$manager = AAM_Core_Policy_Condition::getInstance();
|
156 |
+
|
157 |
+
$this->assertEquals($expectedResult, $manager->evaluate($condition));
|
158 |
+
}
|
159 |
+
|
160 |
+
/**
|
161 |
+
* Greater condition data provider
|
162 |
+
*
|
163 |
+
* @return void
|
164 |
+
*
|
165 |
+
* @access public
|
166 |
+
* @version 6.0.0
|
167 |
+
*/
|
168 |
+
public function greaterDataProvider()
|
169 |
+
{
|
170 |
+
return array(
|
171 |
+
array(array('Greater' => array(5 => 1)), true),
|
172 |
+
array(array('Greater' => array(15 => 15)), false),
|
173 |
+
array(array('Greater' => array(3 => 5)), false)
|
174 |
+
);
|
175 |
+
}
|
176 |
+
|
177 |
+
/**
|
178 |
+
* Validate Less condition evaluator
|
179 |
+
*
|
180 |
+
* @param array $condition
|
181 |
+
* @param boolean $expectedResult
|
182 |
+
*
|
183 |
+
* @return void
|
184 |
+
*
|
185 |
+
* @access public
|
186 |
+
* @dataProvider lessDataProvider
|
187 |
+
* @version 6.0.0
|
188 |
+
*/
|
189 |
+
public function testLessCondition($condition, $expectedResult)
|
190 |
+
{
|
191 |
+
$manager = AAM_Core_Policy_Condition::getInstance();
|
192 |
+
|
193 |
+
$this->assertEquals($expectedResult, $manager->evaluate($condition));
|
194 |
+
}
|
195 |
+
|
196 |
+
/**
|
197 |
+
* Less condition data provider
|
198 |
+
*
|
199 |
+
* @return void
|
200 |
+
*
|
201 |
+
* @access public
|
202 |
+
* @version 6.0.0
|
203 |
+
*/
|
204 |
+
public function lessDataProvider()
|
205 |
+
{
|
206 |
+
return array(
|
207 |
+
array(array('Less' => array(5 => 10)), true),
|
208 |
+
array(array('Less' => array(15 => 15)), false),
|
209 |
+
array(array('Less' => array(13 => 5)), false)
|
210 |
+
);
|
211 |
+
}
|
212 |
+
|
213 |
+
/**
|
214 |
+
* Validate greater or equals condition evaluator
|
215 |
+
*
|
216 |
+
* @param array $condition
|
217 |
+
* @param boolean $expectedResult
|
218 |
+
*
|
219 |
+
* @return void
|
220 |
+
*
|
221 |
+
* @access public
|
222 |
+
* @dataProvider greaterOrEqualsDataProvider
|
223 |
+
* @version 6.0.0
|
224 |
+
*/
|
225 |
+
public function testGreaterOrEqualsCondition($condition, $expectedResult)
|
226 |
+
{
|
227 |
+
$manager = AAM_Core_Policy_Condition::getInstance();
|
228 |
+
|
229 |
+
$this->assertEquals($expectedResult, $manager->evaluate($condition));
|
230 |
+
}
|
231 |
+
|
232 |
+
/**
|
233 |
+
* Greater or equals condition data provider
|
234 |
+
*
|
235 |
+
* @return void
|
236 |
+
*
|
237 |
+
* @access public
|
238 |
+
* @version 6.0.0
|
239 |
+
*/
|
240 |
+
public function greaterOrEqualsDataProvider()
|
241 |
+
{
|
242 |
+
return array(
|
243 |
+
array(array('GreaterOrEquals' => array(5 => 1)), true),
|
244 |
+
array(array('GreaterOrEquals' => array(15 => 15)), true),
|
245 |
+
array(array('GreaterOrEquals' => array(3 => 5)), false)
|
246 |
+
);
|
247 |
+
}
|
248 |
+
|
249 |
+
/**
|
250 |
+
* Validate Less or equals condition evaluator
|
251 |
+
*
|
252 |
+
* @param array $condition
|
253 |
+
* @param boolean $expectedResult
|
254 |
+
*
|
255 |
+
* @return void
|
256 |
+
*
|
257 |
+
* @access public
|
258 |
+
* @dataProvider lessOrEqualsDataProvider
|
259 |
+
* @version 6.0.0
|
260 |
+
*/
|
261 |
+
public function testLessOrEqualsCondition($condition, $expectedResult)
|
262 |
+
{
|
263 |
+
$manager = AAM_Core_Policy_Condition::getInstance();
|
264 |
+
|
265 |
+
$this->assertEquals($expectedResult, $manager->evaluate($condition));
|
266 |
+
}
|
267 |
+
|
268 |
+
/**
|
269 |
+
* Less or equals condition data provider
|
270 |
+
*
|
271 |
+
* @return void
|
272 |
+
*
|
273 |
+
* @access public
|
274 |
+
* @version 6.0.0
|
275 |
+
*/
|
276 |
+
public function lessOrEqualsDataProvider()
|
277 |
+
{
|
278 |
+
return array(
|
279 |
+
array(array('LessOrEquals' => array(5 => 10)), true),
|
280 |
+
array(array('LessOrEquals' => array(15 => 15)), true),
|
281 |
+
array(array('LessOrEquals' => array(13 => 5)), false)
|
282 |
+
);
|
283 |
+
}
|
284 |
+
|
285 |
+
/**
|
286 |
+
* Validate In condition evaluator
|
287 |
+
*
|
288 |
+
* @param array $condition
|
289 |
+
* @param boolean $expectedResult
|
290 |
+
*
|
291 |
+
* @return void
|
292 |
+
*
|
293 |
+
* @access public
|
294 |
+
* @dataProvider inDataProvider
|
295 |
+
* @version 6.0.0
|
296 |
+
*/
|
297 |
+
public function testInCondition($condition, $expectedResult)
|
298 |
+
{
|
299 |
+
$manager = AAM_Core_Policy_Condition::getInstance();
|
300 |
+
|
301 |
+
$this->assertEquals($expectedResult, $manager->evaluate($condition));
|
302 |
+
}
|
303 |
+
|
304 |
+
/**
|
305 |
+
* In condition data provider
|
306 |
+
*
|
307 |
+
* @return void
|
308 |
+
*
|
309 |
+
* @access public
|
310 |
+
* @version 6.0.0
|
311 |
+
*/
|
312 |
+
public function inDataProvider()
|
313 |
+
{
|
314 |
+
return array(
|
315 |
+
array(array('In' => array('test' => array('test', 'test1'))), true),
|
316 |
+
array(array('In' => array(2 => array(2, 5, 7))), true),
|
317 |
+
array(array('In' => array('no' => array('yes', 'maybe'))), false)
|
318 |
+
);
|
319 |
+
}
|
320 |
+
|
321 |
+
/**
|
322 |
+
* Validate NotIn condition evaluator
|
323 |
+
*
|
324 |
+
* @param array $condition
|
325 |
+
* @param boolean $expectedResult
|
326 |
+
*
|
327 |
+
* @return void
|
328 |
+
*
|
329 |
+
* @access public
|
330 |
+
* @dataProvider notInDataProvider
|
331 |
+
* @version 6.0.0
|
332 |
+
*/
|
333 |
+
public function testNotInCondition($condition, $expectedResult)
|
334 |
+
{
|
335 |
+
$manager = AAM_Core_Policy_Condition::getInstance();
|
336 |
+
|
337 |
+
$this->assertEquals($expectedResult, $manager->evaluate($condition));
|
338 |
+
}
|
339 |
+
|
340 |
+
/**
|
341 |
+
* NotIn condition data provider
|
342 |
+
*
|
343 |
+
* @return void
|
344 |
+
*
|
345 |
+
* @access public
|
346 |
+
* @version 6.0.0
|
347 |
+
*/
|
348 |
+
public function notInDataProvider()
|
349 |
+
{
|
350 |
+
return array(
|
351 |
+
array(array('NotIn' => array('test' => array('test', 'test1'))), false),
|
352 |
+
array(array('NotIn' => array(2 => array(2, 5, 7))), false),
|
353 |
+
array(array('NotIn' => array('no' => array('yes', 'maybe'))), true)
|
354 |
+
);
|
355 |
+
}
|
356 |
+
|
357 |
+
/**
|
358 |
+
* Validate Like condition evaluator
|
359 |
+
*
|
360 |
+
* @param array $condition
|
361 |
+
* @param boolean $expectedResult
|
362 |
+
*
|
363 |
+
* @return void
|
364 |
+
*
|
365 |
+
* @access public
|
366 |
+
* @dataProvider likeDataProvider
|
367 |
+
* @version 6.0.0
|
368 |
+
*/
|
369 |
+
public function testLikeCondition($condition, $expectedResult)
|
370 |
+
{
|
371 |
+
$manager = AAM_Core_Policy_Condition::getInstance();
|
372 |
+
|
373 |
+
$this->assertEquals($expectedResult, $manager->evaluate($condition));
|
374 |
+
}
|
375 |
+
|
376 |
+
/**
|
377 |
+
* Like condition data provider
|
378 |
+
*
|
379 |
+
* @return void
|
380 |
+
*
|
381 |
+
* @access public
|
382 |
+
* @version 6.0.0
|
383 |
+
*/
|
384 |
+
public function likeDataProvider()
|
385 |
+
{
|
386 |
+
return array(
|
387 |
+
array(array('Like' => array('Lucy van Pelt' => 'Lucy*')), true),
|
388 |
+
array(array('Like' => array('Lucy van Pelt' => '*Pelt')), true),
|
389 |
+
array(array('Like' => array('Lucy van Pelt' => 'Lucy*Pelt')), true),
|
390 |
+
array(array('Like' => array('Lucy van Pelt' => 'Johny*Pelt')), false)
|
391 |
+
);
|
392 |
+
}
|
393 |
+
|
394 |
+
/**
|
395 |
+
* Validate NotLike condition evaluator
|
396 |
+
*
|
397 |
+
* @param array $condition
|
398 |
+
* @param boolean $expectedResult
|
399 |
+
*
|
400 |
+
* @return void
|
401 |
+
*
|
402 |
+
* @access public
|
403 |
+
* @dataProvider notLikeDataProvider
|
404 |
+
* @version 6.0.0
|
405 |
+
*/
|
406 |
+
public function testNotLikeCondition($condition, $expectedResult)
|
407 |
+
{
|
408 |
+
$manager = AAM_Core_Policy_Condition::getInstance();
|
409 |
+
|
410 |
+
$this->assertEquals($expectedResult, $manager->evaluate($condition));
|
411 |
+
}
|
412 |
+
|
413 |
+
/**
|
414 |
+
* NotLike condition data provider
|
415 |
+
*
|
416 |
+
* @return void
|
417 |
+
*
|
418 |
+
* @access public
|
419 |
+
* @version 6.0.0
|
420 |
+
*/
|
421 |
+
public function notLikeDataProvider()
|
422 |
+
{
|
423 |
+
return array(
|
424 |
+
array(array('NotLike' => array('Lucy van Pelt' => 'Lucy*')), false),
|
425 |
+
array(array('NotLike' => array('Lucy van Pelt' => '*Pelt')), false),
|
426 |
+
array(array('NotLike' => array('Lucy van Pelt' => 'Lucy*Pelt')), false),
|
427 |
+
array(array('NotLike' => array('Lucy van Pelt' => 'Johny*Pelt')), true)
|
428 |
+
);
|
429 |
+
}
|
430 |
+
|
431 |
+
/**
|
432 |
+
* Validate RegEx condition evaluator
|
433 |
+
*
|
434 |
+
* @param array $condition
|
435 |
+
* @param boolean $expectedResult
|
436 |
+
*
|
437 |
+
* @return void
|
438 |
+
*
|
439 |
+
* @access public
|
440 |
+
* @dataProvider regExDataProvider
|
441 |
+
* @version 6.0.0
|
442 |
+
*/
|
443 |
+
public function testRegExCondition($condition, $expectedResult)
|
444 |
+
{
|
445 |
+
$manager = AAM_Core_Policy_Condition::getInstance();
|
446 |
+
|
447 |
+
$this->assertEquals($expectedResult, $manager->evaluate($condition));
|
448 |
+
}
|
449 |
+
|
450 |
+
/**
|
451 |
+
* RegEx condition data provider
|
452 |
+
*
|
453 |
+
* @return void
|
454 |
+
*
|
455 |
+
* @access public
|
456 |
+
* @version 6.0.0
|
457 |
+
*/
|
458 |
+
public function regExDataProvider()
|
459 |
+
{
|
460 |
+
return array(
|
461 |
+
array(array('RegEx' => array('Hello World' => '/^[\w\s]+$/i')), true),
|
462 |
+
array(array('RegEx' => array('Hello World!' => '/^[\w]+$/')), false)
|
463 |
+
);
|
464 |
+
}
|
465 |
+
|
466 |
+
/**
|
467 |
+
* Validate condition type casting
|
468 |
+
*
|
469 |
+
* @param array $condition
|
470 |
+
* @param boolean $expectedResult
|
471 |
+
*
|
472 |
+
* @return void
|
473 |
+
*
|
474 |
+
* @access public
|
475 |
+
* @dataProvider typeCastingDataProvider
|
476 |
+
* @version 6.0.0
|
477 |
+
*/
|
478 |
+
public function testTypeCasting($condition, $expectedResult)
|
479 |
+
{
|
480 |
+
$manager = AAM_Core_Policy_Condition::getInstance();
|
481 |
+
|
482 |
+
$this->assertEquals($expectedResult, $manager->evaluate($condition));
|
483 |
+
}
|
484 |
+
|
485 |
+
/**
|
486 |
+
* Type casting data provider
|
487 |
+
*
|
488 |
+
* @return void
|
489 |
+
*
|
490 |
+
* @access public
|
491 |
+
* @version 6.0.0
|
492 |
+
*/
|
493 |
+
public function typeCastingDataProvider()
|
494 |
+
{
|
495 |
+
return array(
|
496 |
+
array(array('Equals' => array('(*int)1' => 1)), true),
|
497 |
+
array(array('Equals' => array('(*bool)false' => false)), true),
|
498 |
+
array(array('Equals' => array('(*boolean)true' => true)), true),
|
499 |
+
array(array('Equals' => array('(*string)1' => '1')), true),
|
500 |
+
array(array('Equals' => array('(*null)' => null)), true),
|
501 |
+
array(array('Equals' => array('(*array)[2,3]' => array(2,3))), true),
|
502 |
+
array(array('Equals' => array('(*ip)192.168.1.1' => inet_pton('192.168.1.1'))), true)
|
503 |
+
);
|
504 |
+
}
|
505 |
+
|
506 |
+
/**
|
507 |
+
* Validate complex condition
|
508 |
+
*
|
509 |
+
* @param array $condition
|
510 |
+
* @param boolean $expectedResult
|
511 |
+
*
|
512 |
+
* @return void
|
513 |
+
*
|
514 |
+
* @access public
|
515 |
+
* @dataProvider complexDataProvider
|
516 |
+
* @version 6.0.0
|
517 |
+
*/
|
518 |
+
public function testComplexCondition($condition, $expectedResult)
|
519 |
+
{
|
520 |
+
$manager = AAM_Core_Policy_Condition::getInstance();
|
521 |
+
|
522 |
+
$this->assertEquals($expectedResult, $manager->evaluate($condition));
|
523 |
+
}
|
524 |
+
|
525 |
+
/**
|
526 |
+
* Complex condition data provider
|
527 |
+
*
|
528 |
+
* @return void
|
529 |
+
*
|
530 |
+
* @access public
|
531 |
+
* @version 6.0.0
|
532 |
+
*/
|
533 |
+
public function complexDataProvider()
|
534 |
+
{
|
535 |
+
return array(
|
536 |
+
array(array(
|
537 |
+
'Equals' => array('(*int)1' => 1),
|
538 |
+
'NotEquals' => array('2a' => 2)
|
539 |
+
), true)
|
540 |
+
);
|
541 |
+
}
|
542 |
+
|
543 |
+
}
|
tests/Service/AccessPolicy/PolicyManagerTest.php
ADDED
@@ -0,0 +1,170 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
/**
|
4 |
+
* ======================================================================
|
5 |
+
* LICENSE: This file is subject to the terms and conditions defined in *
|
6 |
+
* file 'license.txt', which is part of this source code package. *
|
7 |
+
* ======================================================================
|
8 |
+
*/
|
9 |
+
|
10 |
+
namespace AAM\UnitTest\Service\AccessPolicy;
|
11 |
+
|
12 |
+
use AAM,
|
13 |
+
AAM_Core_Object_Policy,
|
14 |
+
AAM_Core_Policy_Manager,
|
15 |
+
PHPUnit\Framework\TestCase,
|
16 |
+
AAM\UnitTest\Libs\ResetTrait,
|
17 |
+
AAM\UnitTest\Libs\AuthUserTrait;
|
18 |
+
|
19 |
+
/**
|
20 |
+
* Test policy manager
|
21 |
+
*
|
22 |
+
* Make sure that access policies are parsed properly
|
23 |
+
*
|
24 |
+
* @author Vasyl Martyniuk <vasyl@vasyltech.com>
|
25 |
+
* @version 6.0.0
|
26 |
+
*/
|
27 |
+
class PolicyManagerTest extends TestCase
|
28 |
+
{
|
29 |
+
use ResetTrait,
|
30 |
+
AuthUserTrait;
|
31 |
+
|
32 |
+
/**
|
33 |
+
* Test simple policy load
|
34 |
+
*
|
35 |
+
* @return void
|
36 |
+
*
|
37 |
+
* @access public
|
38 |
+
* @version 6.0.0
|
39 |
+
*/
|
40 |
+
public function testSimplePolicy()
|
41 |
+
{
|
42 |
+
$stub = $this->prepareManagerStub('simple-policy');
|
43 |
+
|
44 |
+
$this->assertEquals($stub->getTree(), array(
|
45 |
+
'Statement' => array(
|
46 |
+
'backendmenu:edit.php' => array(
|
47 |
+
'Effect' => 'deny'
|
48 |
+
)
|
49 |
+
),
|
50 |
+
'Param' => array()
|
51 |
+
));
|
52 |
+
}
|
53 |
+
|
54 |
+
/**
|
55 |
+
* Test simple policy load
|
56 |
+
*
|
57 |
+
* @return void
|
58 |
+
*
|
59 |
+
* @access public
|
60 |
+
* @version 6.0.0
|
61 |
+
*/
|
62 |
+
public function testSimplePolicyWithAction()
|
63 |
+
{
|
64 |
+
$stub = $this->prepareManagerStub('simple-policy-with-action');
|
65 |
+
|
66 |
+
$this->assertEquals($stub->getTree(), array(
|
67 |
+
'Statement' => array(
|
68 |
+
'capability:switch_themes:aam:toggle' => array(
|
69 |
+
'Effect' => 'deny'
|
70 |
+
)
|
71 |
+
),
|
72 |
+
'Param' => array()
|
73 |
+
));
|
74 |
+
}
|
75 |
+
|
76 |
+
/**
|
77 |
+
* Test that site options are overwritten by policy
|
78 |
+
*
|
79 |
+
* @return void
|
80 |
+
*
|
81 |
+
* @access public
|
82 |
+
* @version 6.0.0
|
83 |
+
*/
|
84 |
+
public function testOptionOverridePolicy()
|
85 |
+
{
|
86 |
+
$stub = $this->prepareManagerStub('option-override-policy');
|
87 |
+
|
88 |
+
$this->assertEquals($stub->getTree(), array(
|
89 |
+
'Statement' => array(),
|
90 |
+
'Param' => array(
|
91 |
+
'option:unittest' => array(
|
92 |
+
'Key' => 'option:unittest',
|
93 |
+
'Value' => 'unititest.me'
|
94 |
+
)
|
95 |
+
)
|
96 |
+
));
|
97 |
+
|
98 |
+
$this->assertEquals('unititest.me', get_option('unittest'));
|
99 |
+
$this->assertEquals('unititest.me', get_site_option('unittest'));
|
100 |
+
}
|
101 |
+
|
102 |
+
/**
|
103 |
+
* Test that dynamic markers are replaced with actual value
|
104 |
+
*
|
105 |
+
* @return void
|
106 |
+
*
|
107 |
+
* @access public
|
108 |
+
* @version 6.0.0
|
109 |
+
*/
|
110 |
+
public function testDynamicResourcePolicy()
|
111 |
+
{
|
112 |
+
$stub = $this->prepareManagerStub('dynamic-resource');
|
113 |
+
|
114 |
+
$this->assertArrayHasKey('post:post:1:read', $stub->getTree()['Statement']);
|
115 |
+
}
|
116 |
+
|
117 |
+
/**
|
118 |
+
* Test that dynamic markers are replaced with actual value
|
119 |
+
*
|
120 |
+
* @return void
|
121 |
+
*
|
122 |
+
* @access public
|
123 |
+
* @version 6.0.0
|
124 |
+
*/
|
125 |
+
public function testDynamicParamPolicy()
|
126 |
+
{
|
127 |
+
$stub = $this->prepareManagerStub('dynamic-param');
|
128 |
+
|
129 |
+
$this->assertArrayHasKey('hello-world-admin', $stub->getTree()['Param']);
|
130 |
+
}
|
131 |
+
|
132 |
+
/**
|
133 |
+
* Prepare proper policy manager stub
|
134 |
+
*
|
135 |
+
* @param string $policy_file
|
136 |
+
*
|
137 |
+
* @return object
|
138 |
+
*
|
139 |
+
* @access protected
|
140 |
+
* @version 6.0.0
|
141 |
+
*/
|
142 |
+
protected function prepareManagerStub($policy_file)
|
143 |
+
{
|
144 |
+
// Fake the assigned policy to the user
|
145 |
+
$object = AAM::getUser()->getObject(AAM_Core_Object_Policy::OBJECT_TYPE);
|
146 |
+
$object->updateOptionItem(1, true)->save();
|
147 |
+
|
148 |
+
// Create a stub for the SomeClass class.
|
149 |
+
$stub = $this->getMockBuilder(AAM_Core_Policy_Manager::class)
|
150 |
+
->setConstructorArgs(array(AAM::getUser()))
|
151 |
+
->setMethods(array('fetchPolicies'))
|
152 |
+
->getMock();
|
153 |
+
|
154 |
+
// Configure the stub
|
155 |
+
$stub->method('fetchPolicies')->willReturn(array(
|
156 |
+
(object) array(
|
157 |
+
'ID' => 1,
|
158 |
+
'post_content' => file_get_contents(
|
159 |
+
__DIR__ . '/policies/' . $policy_file . '.json'
|
160 |
+
)
|
161 |
+
)
|
162 |
+
));
|
163 |
+
|
164 |
+
// Initialize the policy tree
|
165 |
+
$stub->initialize();
|
166 |
+
|
167 |
+
return $stub;
|
168 |
+
}
|
169 |
+
|
170 |
+
}
|
tests/Service/AccessPolicy/PolicyServiceIntegrationTest.php
ADDED
@@ -0,0 +1,413 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
/**
|
4 |
+
* ======================================================================
|
5 |
+
* LICENSE: This file is subject to the terms and conditions defined in *
|
6 |
+
* file 'license.txt', which is part of this source code package. *
|
7 |
+
* ======================================================================
|
8 |
+
*/
|
9 |
+
|
10 |
+
namespace AAM\UnitTest\Service\AccessPolicy;
|
11 |
+
|
12 |
+
use AAM,
|
13 |
+
AAM_Core_Object_Uri,
|
14 |
+
AAM_Core_Object_Post,
|
15 |
+
AAM_Core_Object_Menu,
|
16 |
+
AAM_Core_Object_Policy,
|
17 |
+
AAM_Core_Policy_Factory,
|
18 |
+
AAM_Core_Object_Toolbar,
|
19 |
+
AAM_Core_Object_Metabox,
|
20 |
+
PHPUnit\Framework\TestCase,
|
21 |
+
AAM\UnitTest\Libs\ResetTrait,
|
22 |
+
AAM\UnitTest\Libs\AuthUserTrait;
|
23 |
+
|
24 |
+
/**
|
25 |
+
* Test access policy integration with core AAM services
|
26 |
+
*
|
27 |
+
* @author Vasyl Martyniuk <vasyl@vasyltech.com>
|
28 |
+
* @version 6.0.0
|
29 |
+
*/
|
30 |
+
class PolicyServiceIntegrationTest extends TestCase
|
31 |
+
{
|
32 |
+
use ResetTrait,
|
33 |
+
AuthUserTrait;
|
34 |
+
|
35 |
+
/**
|
36 |
+
* Test that Access Policy integrates with Admin Menu service
|
37 |
+
*
|
38 |
+
* @return void
|
39 |
+
*
|
40 |
+
* @access public
|
41 |
+
* @version 6.0.0
|
42 |
+
*/
|
43 |
+
public function testAdminMenuIntegration()
|
44 |
+
{
|
45 |
+
$this->preparePlayground('admin-menu');
|
46 |
+
|
47 |
+
$object = AAM::getUser()->getObject(AAM_Core_Object_Menu::OBJECT_TYPE);
|
48 |
+
|
49 |
+
$this->assertTrue($object->isRestricted('edit.php'));
|
50 |
+
}
|
51 |
+
|
52 |
+
/**
|
53 |
+
* Test that Access Policy integrates with Toolbar service
|
54 |
+
*
|
55 |
+
* @return void
|
56 |
+
*
|
57 |
+
* @access public
|
58 |
+
* @version 6.0.0
|
59 |
+
*/
|
60 |
+
public function testToolbarIntegration()
|
61 |
+
{
|
62 |
+
$this->preparePlayground('toolbar');
|
63 |
+
|
64 |
+
$object = AAM::getUser()->getObject(AAM_Core_Object_Toolbar::OBJECT_TYPE);
|
65 |
+
|
66 |
+
$this->assertTrue($object->isHidden('about'));
|
67 |
+
}
|
68 |
+
|
69 |
+
/**
|
70 |
+
* Test that Access Policy integrates with Metaboxes & Widgets service
|
71 |
+
*
|
72 |
+
* @return void
|
73 |
+
*
|
74 |
+
* @access public
|
75 |
+
* @version 6.0.0
|
76 |
+
*/
|
77 |
+
public function testMetaboxIntegration()
|
78 |
+
{
|
79 |
+
$this->preparePlayground('metabox');
|
80 |
+
|
81 |
+
$object = AAM::getUser()->getObject(AAM_Core_Object_Metabox::OBJECT_TYPE);
|
82 |
+
|
83 |
+
$this->assertTrue($object->isHidden('widgets', 'WP_Widget_Pages'));
|
84 |
+
$this->assertTrue($object->isHidden('aam_policy', 'revisionsdiv'));
|
85 |
+
}
|
86 |
+
|
87 |
+
/**
|
88 |
+
* Test that Access Policy integrates with Content service for simple actions
|
89 |
+
*
|
90 |
+
* @return void
|
91 |
+
*
|
92 |
+
* @access public
|
93 |
+
* @version 6.0.0
|
94 |
+
*/
|
95 |
+
public function testContentSimpleActionsIntegration()
|
96 |
+
{
|
97 |
+
$this->preparePlayground('post-simple-actions');
|
98 |
+
|
99 |
+
$object = AAM::getUser()->getObject(AAM_Core_Object_Post::OBJECT_TYPE, 1);
|
100 |
+
|
101 |
+
$this->assertFalse($object->isAllowedTo('edit'));
|
102 |
+
$this->assertFalse($object->isAllowedTo('delete'));
|
103 |
+
$this->assertFalse($object->isAllowedTo('publish'));
|
104 |
+
$this->assertFalse($object->isAllowedTo('comment'));
|
105 |
+
}
|
106 |
+
|
107 |
+
/**
|
108 |
+
* Test that Access Policy integrates with Content service for Restricted action
|
109 |
+
*
|
110 |
+
* @return void
|
111 |
+
*
|
112 |
+
* @access public
|
113 |
+
* @version 6.0.0
|
114 |
+
*/
|
115 |
+
public function testContentRestrictedIntegration()
|
116 |
+
{
|
117 |
+
$this->preparePlayground('post-restricted');
|
118 |
+
|
119 |
+
$object = AAM::getUser()->getObject(AAM_Core_Object_Post::OBJECT_TYPE, 1);
|
120 |
+
|
121 |
+
$this->assertTrue($object->is('restricted'));
|
122 |
+
}
|
123 |
+
|
124 |
+
/**
|
125 |
+
* Test that Access Policy integrates with Content service for Hidden action
|
126 |
+
*
|
127 |
+
* @return void
|
128 |
+
*
|
129 |
+
* @access public
|
130 |
+
* @version 6.0.0
|
131 |
+
*/
|
132 |
+
public function testContentHiddenIntegration()
|
133 |
+
{
|
134 |
+
$this->preparePlayground('post-hidden');
|
135 |
+
|
136 |
+
$object = AAM::getUser()->getObject(AAM_Core_Object_Post::OBJECT_TYPE, 1);
|
137 |
+
|
138 |
+
$this->assertTrue($object->is('hidden'));
|
139 |
+
|
140 |
+
// Verify that post is no longer in the list of posts
|
141 |
+
$posts = get_posts(array(
|
142 |
+
'post_type' => 'post',
|
143 |
+
'fields' => 'ids',
|
144 |
+
'suppress_filters' => false
|
145 |
+
));
|
146 |
+
|
147 |
+
// First, confirm that post is in the array of posts
|
148 |
+
$this->assertFalse(in_array(1, $posts));
|
149 |
+
}
|
150 |
+
|
151 |
+
/**
|
152 |
+
* Test that Access Policy integrates with Content service for Password protected
|
153 |
+
* action
|
154 |
+
*
|
155 |
+
* @return void
|
156 |
+
*
|
157 |
+
* @access public
|
158 |
+
* @version 6.0.0
|
159 |
+
*/
|
160 |
+
public function testContentComplexActionsIntegration()
|
161 |
+
{
|
162 |
+
$this->preparePlayground('post-complex-actions');
|
163 |
+
|
164 |
+
$object = AAM::getUser()->getObject(AAM_Core_Object_Post::OBJECT_TYPE, 1);
|
165 |
+
|
166 |
+
$this->assertTrue($object->is('protected'));
|
167 |
+
$this->assertEquals(array(
|
168 |
+
'enabled' => true,
|
169 |
+
'password' => '123456'
|
170 |
+
), $object->get('protected'));
|
171 |
+
|
172 |
+
$this->assertTrue($object->has('teaser'));
|
173 |
+
$this->assertEquals(array(
|
174 |
+
'enabled' => true,
|
175 |
+
'message' => 'This is just a teaser message'
|
176 |
+
), $object->get('teaser'));
|
177 |
+
}
|
178 |
+
|
179 |
+
/**
|
180 |
+
* Test that Access Policy integrates with Content service for Redirected action
|
181 |
+
* where page ID is specified
|
182 |
+
*
|
183 |
+
* @return void
|
184 |
+
*
|
185 |
+
* @access public
|
186 |
+
* @version 6.0.0
|
187 |
+
*/
|
188 |
+
public function testContentRedirectPageIdIntegration()
|
189 |
+
{
|
190 |
+
$this->preparePlayground('post-redirect-page-id');
|
191 |
+
|
192 |
+
$object = AAM::getUser()->getObject(AAM_Core_Object_Post::OBJECT_TYPE, 1);
|
193 |
+
|
194 |
+
$this->assertTrue($object->is('redirected'));
|
195 |
+
$this->assertEquals(array(
|
196 |
+
'enabled' => true,
|
197 |
+
'type' => 'page',
|
198 |
+
'httpCode' => 301,
|
199 |
+
'destination' => 2
|
200 |
+
), $object->get('redirected'));
|
201 |
+
}
|
202 |
+
|
203 |
+
/**
|
204 |
+
* Test that Access Policy integrates with Content service for Redirected action
|
205 |
+
* where page slug is specified
|
206 |
+
*
|
207 |
+
* @return void
|
208 |
+
*
|
209 |
+
* @access public
|
210 |
+
* @version 6.0.0
|
211 |
+
*/
|
212 |
+
public function testContentRedirectPageSlugIntegration()
|
213 |
+
{
|
214 |
+
$this->preparePlayground('post-redirect-page-slug');
|
215 |
+
|
216 |
+
$object = AAM::getUser()->getObject(AAM_Core_Object_Post::OBJECT_TYPE, 1);
|
217 |
+
|
218 |
+
$this->assertTrue($object->is('redirected'));
|
219 |
+
$this->assertEquals(array(
|
220 |
+
'enabled' => true,
|
221 |
+
'type' => 'page',
|
222 |
+
'httpCode' => 301,
|
223 |
+
'destination' => get_page_by_path('sample-page', OBJECT)->ID
|
224 |
+
), $object->get('redirected'));
|
225 |
+
}
|
226 |
+
|
227 |
+
/**
|
228 |
+
* Test that Access Policy integrates with Content service for Redirected action
|
229 |
+
* where URL is specified
|
230 |
+
*
|
231 |
+
* @return void
|
232 |
+
*
|
233 |
+
* @access public
|
234 |
+
* @version 6.0.0
|
235 |
+
*/
|
236 |
+
public function testContentRedirectUrlIntegration()
|
237 |
+
{
|
238 |
+
$this->preparePlayground('post-redirect-url');
|
239 |
+
|
240 |
+
$object = AAM::getUser()->getObject(AAM_Core_Object_Post::OBJECT_TYPE, 1);
|
241 |
+
|
242 |
+
$this->assertTrue($object->is('redirected'));
|
243 |
+
$this->assertEquals(array(
|
244 |
+
'enabled' => true,
|
245 |
+
'type' => 'url',
|
246 |
+
'httpCode' => 307,
|
247 |
+
'destination' => 'https://aamplugin.com'
|
248 |
+
), $object->get('redirected'));
|
249 |
+
}
|
250 |
+
|
251 |
+
/**
|
252 |
+
* Test that Access Policy integrates with Content service for Redirected action
|
253 |
+
* where callback is specified
|
254 |
+
*
|
255 |
+
* @return void
|
256 |
+
*
|
257 |
+
* @access public
|
258 |
+
* @version 6.0.0
|
259 |
+
*/
|
260 |
+
public function testContentRedirectCallbackIntegration()
|
261 |
+
{
|
262 |
+
$this->preparePlayground('post-redirect-callback');
|
263 |
+
|
264 |
+
$object = AAM::getUser()->getObject(AAM_Core_Object_Post::OBJECT_TYPE, 1);
|
265 |
+
|
266 |
+
$this->assertTrue($object->is('redirected'));
|
267 |
+
$this->assertEquals(array(
|
268 |
+
'enabled' => true,
|
269 |
+
'type' => 'callback',
|
270 |
+
'httpCode' => 307,
|
271 |
+
'destination' => 'AAM\Callback\Main::helloWorld'
|
272 |
+
), $object->get('redirected'));
|
273 |
+
}
|
274 |
+
|
275 |
+
/**
|
276 |
+
* Test that Access Policy integrates with URI service for all possible permutation
|
277 |
+
* of actions
|
278 |
+
*
|
279 |
+
* @return void
|
280 |
+
*
|
281 |
+
* @access public
|
282 |
+
* @version 6.0.0
|
283 |
+
*/
|
284 |
+
public function testUriIntegration()
|
285 |
+
{
|
286 |
+
$this->preparePlayground('uri');
|
287 |
+
|
288 |
+
$object = AAM::getUser()->getObject(AAM_Core_Object_Uri::OBJECT_TYPE);
|
289 |
+
|
290 |
+
$this->assertEquals(array(
|
291 |
+
'type' => 'default',
|
292 |
+
), $object->findMatch('/hello-world-1/'));
|
293 |
+
|
294 |
+
$this->assertEquals(array(
|
295 |
+
'type' => 'message',
|
296 |
+
'action' => 'Access Is Denied',
|
297 |
+
'code' => 307
|
298 |
+
), $object->findMatch('/hello-world-2/'));
|
299 |
+
|
300 |
+
$this->assertEquals(array(
|
301 |
+
'type' => 'page',
|
302 |
+
'action' => 2,
|
303 |
+
'code' => 307
|
304 |
+
), $object->findMatch('/hello-world-3/'));
|
305 |
+
|
306 |
+
$this->assertEquals(array(
|
307 |
+
'type' => 'page',
|
308 |
+
'action' => get_page_by_path('sample-page', OBJECT, 'page')->ID,
|
309 |
+
'code' => 307
|
310 |
+
), $object->findMatch('/hello-world-4/'));
|
311 |
+
|
312 |
+
$this->assertEquals(array(
|
313 |
+
'type' => 'url',
|
314 |
+
'action' => '/another-location',
|
315 |
+
'code' => 303
|
316 |
+
), $object->findMatch('/hello-world-5/'));
|
317 |
+
|
318 |
+
$this->assertEquals(array(
|
319 |
+
'type' => 'callback',
|
320 |
+
'action' => 'AAM\\Callback\\Main::helloWorld',
|
321 |
+
'code' => 307
|
322 |
+
), $object->findMatch('/hello-world-6/'));
|
323 |
+
|
324 |
+
$this->assertEquals(array(
|
325 |
+
'type' => 'login',
|
326 |
+
'action' => null,
|
327 |
+
'code' => 401
|
328 |
+
), $object->findMatch('/hello-world-7/'));
|
329 |
+
}
|
330 |
+
|
331 |
+
/**
|
332 |
+
* Test ability to toggle the ability activate/deactivate individual plugin with
|
333 |
+
* Access Policy
|
334 |
+
*
|
335 |
+
* @return void
|
336 |
+
*
|
337 |
+
* @access public
|
338 |
+
* @version 6.0.0
|
339 |
+
*/
|
340 |
+
public function testSinglePluginIntegration()
|
341 |
+
{
|
342 |
+
// Making sure that current user can activate/deactivate plugin
|
343 |
+
$this->assertTrue(current_user_can('activate_plugin', 'advanced-access-manager'));
|
344 |
+
$this->assertTrue(current_user_can('deactivate_plugin', 'advanced-access-manager'));
|
345 |
+
|
346 |
+
$this->preparePlayground('single-plugin');
|
347 |
+
|
348 |
+
// Making sure that current user no longer has these privileges
|
349 |
+
$this->assertFalse(current_user_can('activate_plugin', 'advanced-access-manager'));
|
350 |
+
$this->assertFalse(current_user_can('deactivate_plugin', 'advanced-access-manager'));
|
351 |
+
}
|
352 |
+
|
353 |
+
/**
|
354 |
+
* Test ability to toggle the ability activate/deactivate individual plugin with
|
355 |
+
* Access Policy
|
356 |
+
*
|
357 |
+
* @return void
|
358 |
+
*
|
359 |
+
* @access public
|
360 |
+
* @version 6.0.0
|
361 |
+
*/
|
362 |
+
public function testAllPluginsIntegration()
|
363 |
+
{
|
364 |
+
// Making sure that current user can perform all 4 basic actions
|
365 |
+
$this->assertTrue(current_user_can('install_plugins'));
|
366 |
+
$this->assertTrue(current_user_can('update_plugins'));
|
367 |
+
$this->assertTrue(current_user_can('edit_plugins'));
|
368 |
+
$this->assertTrue(current_user_can('delete_plugins'));
|
369 |
+
|
370 |
+
$this->preparePlayground('plugins');
|
371 |
+
|
372 |
+
// Making sure that current user no longer has these privileges
|
373 |
+
$this->assertFalse(current_user_can('install_plugins'));
|
374 |
+
$this->assertFalse(current_user_can('update_plugins'));
|
375 |
+
$this->assertFalse(current_user_can('edit_plugins'));
|
376 |
+
$this->assertFalse(current_user_can('delete_plugins'));
|
377 |
+
}
|
378 |
+
|
379 |
+
/**
|
380 |
+
* Prepare the environment
|
381 |
+
*
|
382 |
+
* Update Unit Test access policy with proper policy
|
383 |
+
*
|
384 |
+
* @param string $policy_file
|
385 |
+
*
|
386 |
+
* @return void
|
387 |
+
*
|
388 |
+
* @access protected
|
389 |
+
* @version 6.0.0
|
390 |
+
*/
|
391 |
+
protected function preparePlayground($policy_file)
|
392 |
+
{
|
393 |
+
// Update existing Access Policy with new policy
|
394 |
+
wp_update_post(array(
|
395 |
+
'ID' => AAM_UNITTEST_ACCESS_POLICY_ID,
|
396 |
+
'post_content' => file_get_contents(
|
397 |
+
__DIR__ . '/policies/' . $policy_file . '.json'
|
398 |
+
)
|
399 |
+
));
|
400 |
+
|
401 |
+
$object = AAM::getUser()->getObject(AAM_Core_Object_Policy::OBJECT_TYPE);
|
402 |
+
$this->assertTrue(
|
403 |
+
$object->updateOptionItem(AAM_UNITTEST_ACCESS_POLICY_ID, true)->save()
|
404 |
+
);
|
405 |
+
|
406 |
+
// Reset all internal cache
|
407 |
+
$this->_resetSubjects();
|
408 |
+
|
409 |
+
// Reset Access Policy Factory cache
|
410 |
+
AAM_Core_Policy_Factory::reset();
|
411 |
+
}
|
412 |
+
|
413 |
+
}
|
tests/Service/AccessPolicy/PolicyTokenTest.php
ADDED
@@ -0,0 +1,236 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
/**
|
4 |
+
* ======================================================================
|
5 |
+
* LICENSE: This file is subject to the terms and conditions defined in *
|
6 |
+
* file 'license.txt', which is part of this source code package. *
|
7 |
+
* ======================================================================
|
8 |
+
*/
|
9 |
+
|
10 |
+
namespace AAM\UnitTest\Service\AccessPolicy;
|
11 |
+
|
12 |
+
use AAM,
|
13 |
+
AAM_Core_Jwt_Issuer,
|
14 |
+
AAM_Core_Policy_Token,
|
15 |
+
PHPUnit\Framework\TestCase,
|
16 |
+
AAM\UnitTest\Libs\ResetTrait;
|
17 |
+
|
18 |
+
/**
|
19 |
+
* Test policy token evaluator
|
20 |
+
*
|
21 |
+
* @author Vasyl Martyniuk <vasyl@vasyltech.com>
|
22 |
+
* @version 6.0.0
|
23 |
+
*/
|
24 |
+
class PolicyTokenTest extends TestCase
|
25 |
+
{
|
26 |
+
|
27 |
+
use ResetTrait;
|
28 |
+
|
29 |
+
/**
|
30 |
+
* Validate correct USER token evaluation
|
31 |
+
*
|
32 |
+
* @return void
|
33 |
+
*
|
34 |
+
* @access public
|
35 |
+
* @version 6.0.0
|
36 |
+
*/
|
37 |
+
public function testUserTokenEvaluation()
|
38 |
+
{
|
39 |
+
$_SERVER['REMOTE_ADDR'] = '127.0.0.1';
|
40 |
+
|
41 |
+
// Set current User. Emulate that this is admin login
|
42 |
+
wp_set_current_user(AAM_UNITTEST_AUTH_USER_ID);
|
43 |
+
|
44 |
+
$caps = array();
|
45 |
+
foreach ((array) AAM::getUser()->allcaps as $cap => $effect) {
|
46 |
+
if (!empty($effect)) {
|
47 |
+
$caps[] = $cap;
|
48 |
+
}
|
49 |
+
}
|
50 |
+
|
51 |
+
$cases = array(
|
52 |
+
array('${USER.ID}', 1),
|
53 |
+
array('${USER.ip}', '127.0.0.1'),
|
54 |
+
array('${USER.ipAddress}', '127.0.0.1'),
|
55 |
+
array('${USER.authenticated}', true),
|
56 |
+
array('${USER.isAuthenticated}', true),
|
57 |
+
array('${USER.capabilities}', json_encode($caps)),
|
58 |
+
array('${USER.caps}', json_encode($caps)),
|
59 |
+
);
|
60 |
+
|
61 |
+
foreach($cases as $case) {
|
62 |
+
$this->assertEquals(
|
63 |
+
$case[1], AAM_Core_Policy_Token::evaluate($case[0], array($case[0]))
|
64 |
+
);
|
65 |
+
}
|
66 |
+
|
67 |
+
// Reset user
|
68 |
+
wp_set_current_user(0);
|
69 |
+
unset($_SERVER['REMOTE_ADDR']);
|
70 |
+
}
|
71 |
+
|
72 |
+
/**
|
73 |
+
* Validate correct USER_META token evaluation
|
74 |
+
*
|
75 |
+
* @return void
|
76 |
+
*
|
77 |
+
* @access public
|
78 |
+
* @version 6.0.0
|
79 |
+
*/
|
80 |
+
public function testUserMetaTokenEvaluation()
|
81 |
+
{
|
82 |
+
// Set current User. Emulate that this is admin login
|
83 |
+
wp_set_current_user(AAM_UNITTEST_AUTH_USER_ID);
|
84 |
+
|
85 |
+
add_user_meta(AAM_UNITTEST_AUTH_USER_ID, 'aam_unittest', 'hello');
|
86 |
+
|
87 |
+
$this->assertEquals(
|
88 |
+
'hello',
|
89 |
+
AAM_Core_Policy_Token::evaluate(
|
90 |
+
'${USER_META.aam_unittest}', array('${USER_META.aam_unittest}')
|
91 |
+
)
|
92 |
+
);
|
93 |
+
|
94 |
+
// Reset user
|
95 |
+
wp_set_current_user(0);
|
96 |
+
unset($_SERVER['REMOTE_ADDR']);
|
97 |
+
delete_user_meta(AAM_UNITTEST_AUTH_USER_ID, 'aam_unittest');
|
98 |
+
}
|
99 |
+
|
100 |
+
/**
|
101 |
+
* Test DATETIME token evaluation
|
102 |
+
*
|
103 |
+
* @return void
|
104 |
+
*
|
105 |
+
* @access public
|
106 |
+
* @version 6.0.0
|
107 |
+
*/
|
108 |
+
public function testDateTimeTokenEvaluation()
|
109 |
+
{
|
110 |
+
$this->assertEquals(
|
111 |
+
date('Y-m-d'),
|
112 |
+
AAM_Core_Policy_Token::evaluate(
|
113 |
+
'${DATETIME.Y-m-d}', array('${DATETIME.Y-m-d}')
|
114 |
+
)
|
115 |
+
);
|
116 |
+
}
|
117 |
+
|
118 |
+
/**
|
119 |
+
* Test HTTP_* and PHP_* tokens evaluation
|
120 |
+
*
|
121 |
+
* @return void
|
122 |
+
*
|
123 |
+
* @access public
|
124 |
+
* @version 6.0.0
|
125 |
+
*/
|
126 |
+
public function testHttpTokensEvaluation()
|
127 |
+
{
|
128 |
+
// Fake data
|
129 |
+
$_GET['aam_test'] = "1a";
|
130 |
+
$_POST['aam_test'] = "1b";
|
131 |
+
$_COOKIE['aam_test'] = "1c";
|
132 |
+
$_SERVER['aam_test'] = "1d";
|
133 |
+
|
134 |
+
$this->assertEquals(
|
135 |
+
'1a', AAM_Core_Policy_Token::evaluate('${HTTP_GET.aam_test}', array('${HTTP_GET.aam_test}'))
|
136 |
+
);
|
137 |
+
|
138 |
+
$this->assertEquals(
|
139 |
+
'1a', AAM_Core_Policy_Token::evaluate('${HTTP_QUERY.aam_test}', array('${HTTP_QUERY.aam_test}'))
|
140 |
+
);
|
141 |
+
|
142 |
+
$this->assertEquals(
|
143 |
+
'1b', AAM_Core_Policy_Token::evaluate('${HTTP_POST.aam_test}', array('${HTTP_POST.aam_test}'))
|
144 |
+
);
|
145 |
+
|
146 |
+
$this->assertEquals(
|
147 |
+
'1c', AAM_Core_Policy_Token::evaluate('${HTTP_COOKIE.aam_test}', array('${HTTP_COOKIE.aam_test}'))
|
148 |
+
);
|
149 |
+
|
150 |
+
$this->assertEquals(
|
151 |
+
'1d', AAM_Core_Policy_Token::evaluate('${PHP_SERVER.aam_test}', array('${PHP_SERVER.aam_test}'))
|
152 |
+
);
|
153 |
+
}
|
154 |
+
|
155 |
+
/**
|
156 |
+
* Test ARGS token evaluation
|
157 |
+
*
|
158 |
+
* @return void
|
159 |
+
*
|
160 |
+
* @access public
|
161 |
+
* @version 6.0.0
|
162 |
+
*/
|
163 |
+
public function testArgTokenEvaluation()
|
164 |
+
{
|
165 |
+
$this->assertEquals(
|
166 |
+
'1a',
|
167 |
+
AAM_Core_Policy_Token::evaluate(
|
168 |
+
'${ARGS.test}', array('${ARGS.test}'), array('test' => '1a')
|
169 |
+
)
|
170 |
+
);
|
171 |
+
}
|
172 |
+
|
173 |
+
/**
|
174 |
+
* Test CONST token evaluation
|
175 |
+
*
|
176 |
+
* @return void
|
177 |
+
*
|
178 |
+
* @access public
|
179 |
+
* @version 6.0.0
|
180 |
+
*/
|
181 |
+
public function testConstTokenEvaluation()
|
182 |
+
{
|
183 |
+
$this->assertEquals(
|
184 |
+
AAM_VERSION,
|
185 |
+
AAM_Core_Policy_Token::evaluate(
|
186 |
+
'${CONST.AAM_VERSION}', array('${CONST.AAM_VERSION}')
|
187 |
+
)
|
188 |
+
);
|
189 |
+
}
|
190 |
+
|
191 |
+
/**
|
192 |
+
* Test WP_OPTION token evaluation
|
193 |
+
*
|
194 |
+
* @return void
|
195 |
+
*
|
196 |
+
* @access public
|
197 |
+
* @version 6.0.0
|
198 |
+
*/
|
199 |
+
public function testWpOptionTokenEvaluation()
|
200 |
+
{
|
201 |
+
$this->assertEquals(
|
202 |
+
get_option('siteurl'),
|
203 |
+
AAM_Core_Policy_Token::evaluate(
|
204 |
+
'${WP_OPTION.siteurl}', array('${WP_OPTION.siteurl}')
|
205 |
+
)
|
206 |
+
);
|
207 |
+
}
|
208 |
+
|
209 |
+
/**
|
210 |
+
* Test JWT token evaluation
|
211 |
+
*
|
212 |
+
* @return void
|
213 |
+
*
|
214 |
+
* @access public
|
215 |
+
* @version 6.0.0
|
216 |
+
*/
|
217 |
+
public function testJwtTokenEvaluation()
|
218 |
+
{
|
219 |
+
// generate token
|
220 |
+
$result = AAM_Core_Jwt_Issuer::getInstance()->issueToken(
|
221 |
+
array('testProp' => 'helloWorld')
|
222 |
+
);
|
223 |
+
|
224 |
+
$_SERVER['HTTP_AUTHENTICATION'] = $result->token;
|
225 |
+
|
226 |
+
$this->assertEquals(
|
227 |
+
'helloWorld',
|
228 |
+
AAM_Core_Policy_Token::evaluate(
|
229 |
+
'${JWT.testProp}', array('${JWT.testProp}')
|
230 |
+
)
|
231 |
+
);
|
232 |
+
|
233 |
+
unset($_SERVER['HTTP_AUTHENTICATION']);
|
234 |
+
}
|
235 |
+
|
236 |
+
}
|
tests/Service/AccessPolicy/PolicyUserRoleIntegrationTest.php
ADDED
@@ -0,0 +1,143 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
/**
|
4 |
+
* ======================================================================
|
5 |
+
* LICENSE: This file is subject to the terms and conditions defined in *
|
6 |
+
* file 'license.txt', which is part of this source code package. *
|
7 |
+
* ======================================================================
|
8 |
+
*/
|
9 |
+
|
10 |
+
namespace AAM\UnitTest\Service\AccessPolicy;
|
11 |
+
|
12 |
+
use AAM,
|
13 |
+
AAM_Core_API,
|
14 |
+
AAM_Core_Config,
|
15 |
+
AAM_Core_Policy_Factory,
|
16 |
+
AAM_Core_AccessSettings,
|
17 |
+
PHPUnit\Framework\TestCase;
|
18 |
+
|
19 |
+
|
20 |
+
/**
|
21 |
+
* Test access policy integration with core user roles system
|
22 |
+
*
|
23 |
+
* @version 6.0.0
|
24 |
+
*/
|
25 |
+
class PolicyUserRoleIntegrationTest extends TestCase
|
26 |
+
{
|
27 |
+
|
28 |
+
/**
|
29 |
+
* Test that policy allows to assign or deprive specific capabilities
|
30 |
+
*
|
31 |
+
* @return void
|
32 |
+
*
|
33 |
+
* @access public
|
34 |
+
* @version 6.0.0
|
35 |
+
*/
|
36 |
+
public function testCapabilityAdded()
|
37 |
+
{
|
38 |
+
$this->preparePlayground('capability-changes');
|
39 |
+
|
40 |
+
// Reset current user to trigger policy changes
|
41 |
+
wp_set_current_user(AAM_UNITTEST_AUTH_USER_ID);
|
42 |
+
|
43 |
+
$this->assertFalse(current_user_can('switch_themes'));
|
44 |
+
$this->assertTrue(current_user_can('hello_world'));
|
45 |
+
}
|
46 |
+
|
47 |
+
/**
|
48 |
+
* Test that policy allows to add new role to user
|
49 |
+
*
|
50 |
+
* @return void
|
51 |
+
*
|
52 |
+
* @access public
|
53 |
+
* @version 6.0.0
|
54 |
+
*/
|
55 |
+
public function testAddedRole()
|
56 |
+
{
|
57 |
+
$this->preparePlayground('role-add');
|
58 |
+
|
59 |
+
// Reset current user to trigger policy changes
|
60 |
+
wp_set_current_user(AAM_UNITTEST_AUTH_USER_ID);
|
61 |
+
|
62 |
+
$this->assertContains('administrator', AAM::getUser()->roles);
|
63 |
+
$this->assertContains('contributor', AAM::getUser()->roles);
|
64 |
+
}
|
65 |
+
|
66 |
+
/**
|
67 |
+
* Test that policy allows to add new role to user
|
68 |
+
*
|
69 |
+
* @return void
|
70 |
+
*
|
71 |
+
* @access public
|
72 |
+
* @version 6.0.0
|
73 |
+
*/
|
74 |
+
public function testRemovedRole()
|
75 |
+
{
|
76 |
+
$this->preparePlayground('role-remove', AAM_UNITTEST_AUTH_MULTIROLE_USER_ID);
|
77 |
+
|
78 |
+
// Reset current user to trigger policy changes
|
79 |
+
wp_set_current_user(AAM_UNITTEST_AUTH_MULTIROLE_USER_ID);
|
80 |
+
|
81 |
+
$this->assertFalse(in_array('editor', AAM::getUser()->roles, true));
|
82 |
+
$this->assertContains('subscriber', AAM::getUser()->roles);
|
83 |
+
}
|
84 |
+
|
85 |
+
/**
|
86 |
+
* Prepare the environment
|
87 |
+
*
|
88 |
+
* Update Unit Test access policy with proper policy
|
89 |
+
*
|
90 |
+
* @param string $policy_file
|
91 |
+
* @param int $user
|
92 |
+
*
|
93 |
+
* @return void
|
94 |
+
*
|
95 |
+
* @access protected
|
96 |
+
* @version 6.0.0
|
97 |
+
*/
|
98 |
+
protected function preparePlayground($policy_file, $user = AAM_UNITTEST_AUTH_USER_ID)
|
99 |
+
{
|
100 |
+
// Update existing Access Policy with new policy
|
101 |
+
wp_update_post(array(
|
102 |
+
'ID' => AAM_UNITTEST_ACCESS_POLICY_ID,
|
103 |
+
'post_content' => file_get_contents(
|
104 |
+
__DIR__ . '/policies/' . $policy_file . '.json'
|
105 |
+
)
|
106 |
+
));
|
107 |
+
|
108 |
+
$settings = AAM_Core_AccessSettings::getInstance();
|
109 |
+
$settings->set(sprintf(
|
110 |
+
'user.%d.policy.%d', $user, AAM_UNITTEST_ACCESS_POLICY_ID
|
111 |
+
), true);
|
112 |
+
}
|
113 |
+
|
114 |
+
/**
|
115 |
+
* Reset all AAM settings to the default
|
116 |
+
*
|
117 |
+
* @return void
|
118 |
+
*
|
119 |
+
* @access protected
|
120 |
+
* @version 6.0.0
|
121 |
+
*/
|
122 |
+
protected function tearDown()
|
123 |
+
{
|
124 |
+
// Clear all AAM settings
|
125 |
+
AAM_Core_API::clearSettings();
|
126 |
+
|
127 |
+
// Reset Access Settings repository
|
128 |
+
AAM_Core_AccessSettings::getInstance()->reset();
|
129 |
+
|
130 |
+
// Unset the forced user
|
131 |
+
wp_set_current_user(0);
|
132 |
+
|
133 |
+
// Clear WP core cache
|
134 |
+
wp_cache_flush();
|
135 |
+
|
136 |
+
// Reset internal AAM config cache
|
137 |
+
AAM_Core_Config::bootstrap();
|
138 |
+
|
139 |
+
// Reset Access Policy Factory cache
|
140 |
+
AAM_Core_Policy_Factory::reset();
|
141 |
+
}
|
142 |
+
|
143 |
+
}
|
tests/Service/AccessPolicy/PolicyValidationTest.php
ADDED
@@ -0,0 +1,125 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
/**
|
4 |
+
* ======================================================================
|
5 |
+
* LICENSE: This file is subject to the terms and conditions defined in *
|
6 |
+
* file 'license.txt', which is part of this source code package. *
|
7 |
+
* ======================================================================
|
8 |
+
*/
|
9 |
+
|
10 |
+
namespace AAM\UnitTest\Service\AccessPolicy;
|
11 |
+
|
12 |
+
use AAM_Backend_View_Helper,
|
13 |
+
AAM_Core_Policy_Validator,
|
14 |
+
PHPUnit\Framework\TestCase;
|
15 |
+
|
16 |
+
/**
|
17 |
+
* Test policy validator
|
18 |
+
*
|
19 |
+
* @author Vasyl Martyniuk <vasyl@vasyltech.com>
|
20 |
+
* @version 6.0.0
|
21 |
+
*/
|
22 |
+
class PolicyValidationTest extends TestCase
|
23 |
+
{
|
24 |
+
/**
|
25 |
+
* Test that error is triggered when policy is empty
|
26 |
+
*
|
27 |
+
* @return void
|
28 |
+
*
|
29 |
+
* @access public
|
30 |
+
* @version 6.0.0
|
31 |
+
*/
|
32 |
+
public function testEmptyPolicy()
|
33 |
+
{
|
34 |
+
$validator = new AAM_Core_Policy_Validator('[]');
|
35 |
+
|
36 |
+
$this->assertEquals(array(
|
37 |
+
__('The policy document is empty', AAM_KEY)
|
38 |
+
), $validator->validate());
|
39 |
+
}
|
40 |
+
|
41 |
+
/**
|
42 |
+
* Test that error is triggered when policy contains invalid JSON
|
43 |
+
*
|
44 |
+
* @return void
|
45 |
+
*
|
46 |
+
* @access public
|
47 |
+
* @version 6.0.0
|
48 |
+
*/
|
49 |
+
public function testInvalidJsonPolicy()
|
50 |
+
{
|
51 |
+
$validator = new AAM_Core_Policy_Validator('--');
|
52 |
+
|
53 |
+
$this->assertEquals(array(
|
54 |
+
__('The policy is not valid JSON object', AAM_KEY)
|
55 |
+
), $validator->validate());
|
56 |
+
}
|
57 |
+
|
58 |
+
/**
|
59 |
+
* Test that error is triggered when missing dependency
|
60 |
+
*
|
61 |
+
* @return void
|
62 |
+
*
|
63 |
+
* @access public
|
64 |
+
* @version 6.0.0
|
65 |
+
*/
|
66 |
+
public function testMissingDependencyPolicy()
|
67 |
+
{
|
68 |
+
$validator = new AAM_Core_Policy_Validator('{
|
69 |
+
"Dependency": {
|
70 |
+
"advanced-access-manager-x": "^1.0.0"
|
71 |
+
}
|
72 |
+
}');
|
73 |
+
|
74 |
+
$this->assertEquals(array(
|
75 |
+
AAM_Backend_View_Helper::preparePhrase(
|
76 |
+
"The plugin [advanced-access-manager-x] is required by the policy",
|
77 |
+
'b'
|
78 |
+
)
|
79 |
+
), $validator->validate());
|
80 |
+
}
|
81 |
+
|
82 |
+
/**
|
83 |
+
* Test that error is triggered when dependency version is not satisfied
|
84 |
+
*
|
85 |
+
* @return void
|
86 |
+
*
|
87 |
+
* @access public
|
88 |
+
* @version 6.0.0
|
89 |
+
*/
|
90 |
+
public function testLowDependencyPolicy()
|
91 |
+
{
|
92 |
+
$validator = new AAM_Core_Policy_Validator('{
|
93 |
+
"Dependency": {
|
94 |
+
"advanced-access-manager": "<6.0.0"
|
95 |
+
}
|
96 |
+
}');
|
97 |
+
|
98 |
+
$this->assertEquals(array(
|
99 |
+
AAM_Backend_View_Helper::preparePhrase(
|
100 |
+
"The dependency [advanced-access-manager] does not satisfy version requirement by the policy",
|
101 |
+
'b'
|
102 |
+
)
|
103 |
+
), $validator->validate());
|
104 |
+
}
|
105 |
+
|
106 |
+
/**
|
107 |
+
* Test that there is no error when everything is ok
|
108 |
+
*
|
109 |
+
* @return void
|
110 |
+
*
|
111 |
+
* @access public
|
112 |
+
* @version 6.0.0
|
113 |
+
*/
|
114 |
+
public function testValidDependencyPolicy()
|
115 |
+
{
|
116 |
+
$validator = new AAM_Core_Policy_Validator('{
|
117 |
+
"Dependency": {
|
118 |
+
"advanced-access-manager": ">=' . AAM_VERSION . '"
|
119 |
+
}
|
120 |
+
}');
|
121 |
+
|
122 |
+
$this->assertEquals(0, count($validator->validate()));
|
123 |
+
}
|
124 |
+
|
125 |
+
}
|
tests/Service/AccessPolicy/policies/admin-menu.json
ADDED
@@ -0,0 +1,11 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
{
|
2 |
+
"Version": "1.0.0",
|
3 |
+
"Statement": [
|
4 |
+
{
|
5 |
+
"Effect": "deny",
|
6 |
+
"Resource": [
|
7 |
+
"BackendMenu:edit.php"
|
8 |
+
]
|
9 |
+
}
|
10 |
+
]
|
11 |
+
}
|
tests/Service/AccessPolicy/policies/capability-changes.json
ADDED
@@ -0,0 +1,17 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
{
|
2 |
+
"Version": "1.0.0",
|
3 |
+
"Statement": [
|
4 |
+
{
|
5 |
+
"Effect": "deny",
|
6 |
+
"Resource": [
|
7 |
+
"Capability:switch_themes"
|
8 |
+
]
|
9 |
+
},
|
10 |
+
{
|
11 |
+
"Effect": "allow",
|
12 |
+
"Resource": [
|
13 |
+
"Capability:hello_world"
|
14 |
+
]
|
15 |
+
}
|
16 |
+
]
|
17 |
+
}
|
tests/Service/AccessPolicy/policies/dynamic-param.json
ADDED
@@ -0,0 +1,9 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
{
|
2 |
+
"Version": "1.0.0",
|
3 |
+
"Param": [
|
4 |
+
{
|
5 |
+
"Key": "hello-world-${USER.user_nicename}",
|
6 |
+
"Value": "hello"
|
7 |
+
}
|
8 |
+
]
|
9 |
+
}
|
tests/Service/AccessPolicy/policies/dynamic-resource.json
ADDED
@@ -0,0 +1,12 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
{
|
2 |
+
"Version": "1.0.0",
|
3 |
+
"Statement": [
|
4 |
+
{
|
5 |
+
"Effect": "deny",
|
6 |
+
"Resource": [
|
7 |
+
"Post:post:${USER.ID}"
|
8 |
+
],
|
9 |
+
"Action": ["Read"]
|
10 |
+
}
|
11 |
+
]
|
12 |
+
}
|
tests/Service/AccessPolicy/policies/metabox.json
ADDED
@@ -0,0 +1,12 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
{
|
2 |
+
"Version": "1.0.0",
|
3 |
+
"Statement": [
|
4 |
+
{
|
5 |
+
"Effect": "deny",
|
6 |
+
"Resource": [
|
7 |
+
"Widget:widgets|wp_widget_pages",
|
8 |
+
"Metabox:aam_policy|revisionsdiv"
|
9 |
+
]
|
10 |
+
}
|
11 |
+
]
|
12 |
+
}
|
tests/Service/AccessPolicy/policies/option-override-policy.json
ADDED
@@ -0,0 +1,9 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
{
|
2 |
+
"Version": "1.0.0",
|
3 |
+
"Param": [
|
4 |
+
{
|
5 |
+
"Key": "option:unittest",
|
6 |
+
"Value": "unititest.me"
|
7 |
+
}
|
8 |
+
]
|
9 |
+
}
|
tests/Service/AccessPolicy/policies/plugins.json
ADDED
@@ -0,0 +1,8 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
{
|
2 |
+
"Version": "1.0.0",
|
3 |
+
"Statement": {
|
4 |
+
"Effect": "deny",
|
5 |
+
"Resource": "Plugin",
|
6 |
+
"Action": ["WP:install", "WP:edit", "WP:update", "WP:delete"]
|
7 |
+
}
|
8 |
+
}
|
tests/Service/AccessPolicy/policies/post-complex-actions.json
ADDED
@@ -0,0 +1,18 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
{
|
2 |
+
"Version": "1.0.0",
|
3 |
+
"Statement": [
|
4 |
+
{
|
5 |
+
"Effect": "deny",
|
6 |
+
"Resource": "Post:post:1",
|
7 |
+
"Action": "Read",
|
8 |
+
"Metadata": {
|
9 |
+
"Password": {
|
10 |
+
"Value": "123456"
|
11 |
+
},
|
12 |
+
"Teaser": {
|
13 |
+
"Value": "This is just a teaser message"
|
14 |
+
}
|
15 |
+
}
|
16 |
+
}
|
17 |
+
]
|
18 |
+
}
|
tests/Service/AccessPolicy/policies/post-hidden.json
ADDED
@@ -0,0 +1,10 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
{
|
2 |
+
"Version": "1.0.0",
|
3 |
+
"Statement": [
|
4 |
+
{
|
5 |
+
"Effect": "deny",
|
6 |
+
"Resource": "Post:post:1",
|
7 |
+
"Action": ["List"]
|
8 |
+
}
|
9 |
+
]
|
10 |
+
}
|
tests/Service/AccessPolicy/policies/post-redirect-callback.json
ADDED
@@ -0,0 +1,16 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
{
|
2 |
+
"Version": "1.0.0",
|
3 |
+
"Statement": [
|
4 |
+
{
|
5 |
+
"Effect": "deny",
|
6 |
+
"Resource": "Post:post:1",
|
7 |
+
"Action": "Read",
|
8 |
+
"Metadata": {
|
9 |
+
"Redirect": {
|
10 |
+
"Type": "callback",
|
11 |
+
"Callback": "AAM\\\\Callback\\\\Main::helloWorld"
|
12 |
+
}
|
13 |
+
}
|
14 |
+
}
|
15 |
+
]
|
16 |
+
}
|
tests/Service/AccessPolicy/policies/post-redirect-page-id.json
ADDED
@@ -0,0 +1,17 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
{
|
2 |
+
"Version": "1.0.0",
|
3 |
+
"Statement": [
|
4 |
+
{
|
5 |
+
"Effect": "deny",
|
6 |
+
"Resource": "Post:post:1",
|
7 |
+
"Action": "Read",
|
8 |
+
"Metadata": {
|
9 |
+
"Redirect": {
|
10 |
+
"Type": "page",
|
11 |
+
"Id": 2,
|
12 |
+
"Code": 301
|
13 |
+
}
|
14 |
+
}
|
15 |
+
}
|
16 |
+
]
|
17 |
+
}
|
tests/Service/AccessPolicy/policies/post-redirect-page-slug.json
ADDED
@@ -0,0 +1,17 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
{
|
2 |
+
"Version": "1.0.0",
|
3 |
+
"Statement": [
|
4 |
+
{
|
5 |
+
"Effect": "deny",
|
6 |
+
"Resource": "Post:post:1",
|
7 |
+
"Action": "Read",
|
8 |
+
"Metadata": {
|
9 |
+
"Redirect": {
|
10 |
+
"Type": "page",
|
11 |
+
"Slug": "sample-page",
|
12 |
+
"Code": 301
|
13 |
+
}
|
14 |
+
}
|
15 |
+
}
|
16 |
+
]
|
17 |
+
}
|
tests/Service/AccessPolicy/policies/post-redirect-url.json
ADDED
@@ -0,0 +1,14 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
{
|
2 |
+
"Version": "1.0.0",
|
3 |
+
"Statement": {
|
4 |
+
"Effect": "deny",
|
5 |
+
"Resource": "Post:post:1",
|
6 |
+
"Action": "Read",
|
7 |
+
"Metadata": {
|
8 |
+
"Redirect": {
|
9 |
+
"Type": "url",
|
10 |
+
"URL": "https://aamplugin.com"
|
11 |
+
}
|
12 |
+
}
|
13 |
+
}
|
14 |
+
}
|
tests/Service/AccessPolicy/policies/post-restricted.json
ADDED
@@ -0,0 +1,10 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
{
|
2 |
+
"Version": "1.0.0",
|
3 |
+
"Statement": [
|
4 |
+
{
|
5 |
+
"Effect": "deny",
|
6 |
+
"Resource": "Post:post:1",
|
7 |
+
"Action": ["Read"]
|
8 |
+
}
|
9 |
+
]
|
10 |
+
}
|
tests/Service/AccessPolicy/policies/post-simple-actions.json
ADDED
@@ -0,0 +1,10 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
{
|
2 |
+
"Version": "1.0.0",
|
3 |
+
"Statement": [
|
4 |
+
{
|
5 |
+
"Effect": "deny",
|
6 |
+
"Resource": "Post:post:1",
|
7 |
+
"Action": ["Edit", "Delete", "Publish", "Comment"]
|
8 |
+
}
|
9 |
+
]
|
10 |
+
}
|
tests/Service/AccessPolicy/policies/role-add.json
ADDED
@@ -0,0 +1,11 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
{
|
2 |
+
"Version": "1.0.0",
|
3 |
+
"Statement": [
|
4 |
+
{
|
5 |
+
"Effect": "allow",
|
6 |
+
"Resource": [
|
7 |
+
"Role:contributor"
|
8 |
+
]
|
9 |
+
}
|
10 |
+
]
|
11 |
+
}
|
tests/Service/AccessPolicy/policies/role-remove.json
ADDED
@@ -0,0 +1,11 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
{
|
2 |
+
"Version": "1.0.0",
|
3 |
+
"Statement": [
|
4 |
+
{
|
5 |
+
"Effect": "deny",
|
6 |
+
"Resource": [
|
7 |
+
"Role:editor"
|
8 |
+
]
|
9 |
+
}
|
10 |
+
]
|
11 |
+
}
|
tests/Service/AccessPolicy/policies/simple-policy-with-action.json
ADDED
@@ -0,0 +1,12 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
{
|
2 |
+
"Version": "1.0.0",
|
3 |
+
"Statement": [
|
4 |
+
{
|
5 |
+
"Effect": "deny",
|
6 |
+
"Resource": [
|
7 |
+
"Capability:switch_themes"
|
8 |
+
],
|
9 |
+
"Action": "AAM:toggle"
|
10 |
+
}
|
11 |
+
]
|
12 |
+
}
|
tests/Service/AccessPolicy/policies/simple-policy.json
ADDED
@@ -0,0 +1,9 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
{
|
2 |
+
"Version": "1.0.0",
|
3 |
+
"Statement": {
|
4 |
+
"Effect": "deny",
|
5 |
+
"Resource": [
|
6 |
+
"BackendMenu:edit.php"
|
7 |
+
]
|
8 |
+
}
|
9 |
+
}
|
tests/Service/AccessPolicy/policies/single-plugin.json
ADDED
@@ -0,0 +1,10 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
{
|
2 |
+
"Version": "1.0.0",
|
3 |
+
"Statement": {
|
4 |
+
"Effect": "deny",
|
5 |
+
"Resource": [
|
6 |
+
"Plugin:advanced-access-manager"
|
7 |
+
],
|
8 |
+
"Action": ["WP:deactivate", "WP:activate"]
|
9 |
+
}
|
10 |
+
}
|
tests/Service/AccessPolicy/policies/toolbar.json
ADDED
@@ -0,0 +1,11 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
{
|
2 |
+
"Version": "1.0.0",
|
3 |
+
"Statement": [
|
4 |
+
{
|
5 |
+
"Effect": "deny",
|
6 |
+
"Resource": [
|
7 |
+
"Toolbar:about"
|
8 |
+
]
|
9 |
+
}
|
10 |
+
]
|
11 |
+
}
|
tests/Service/AccessPolicy/policies/uri.json
ADDED
@@ -0,0 +1,57 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
{
|
2 |
+
"Version": "1.0.0",
|
3 |
+
"Statement": [
|
4 |
+
{
|
5 |
+
"Effect": "deny",
|
6 |
+
"Resource": "URI:/hello-world-1"
|
7 |
+
},
|
8 |
+
{
|
9 |
+
"Effect": "deny",
|
10 |
+
"Resource": "URI:/hello-world-2",
|
11 |
+
"Metadata": {
|
12 |
+
"Type": "message",
|
13 |
+
"Message": "Access Is Denied"
|
14 |
+
}
|
15 |
+
},
|
16 |
+
{
|
17 |
+
"Effect": "deny",
|
18 |
+
"Resource": "URI:/hello-world-3",
|
19 |
+
"Metadata": {
|
20 |
+
"Type": "page",
|
21 |
+
"Id": 2
|
22 |
+
}
|
23 |
+
},
|
24 |
+
{
|
25 |
+
"Effect": "deny",
|
26 |
+
"Resource": "URI:/hello-world-4",
|
27 |
+
"Metadata": {
|
28 |
+
"Type": "page",
|
29 |
+
"Slug": "sample-page"
|
30 |
+
}
|
31 |
+
},
|
32 |
+
{
|
33 |
+
"Effect": "deny",
|
34 |
+
"Resource": "URI:/hello-world-5",
|
35 |
+
"Metadata": {
|
36 |
+
"Type": "url",
|
37 |
+
"URL": "/another-location",
|
38 |
+
"Code": 303
|
39 |
+
}
|
40 |
+
},
|
41 |
+
{
|
42 |
+
"Effect": "deny",
|
43 |
+
"Resource": "URI:/hello-world-6",
|
44 |
+
"Metadata": {
|
45 |
+
"Type": "callback",
|
46 |
+
"Callback": "AAM\\\\Callback\\\\Main::helloWorld"
|
47 |
+
}
|
48 |
+
},
|
49 |
+
{
|
50 |
+
"Effect": "deny",
|
51 |
+
"Resource": "URI:/hello-world-7",
|
52 |
+
"Metadata": {
|
53 |
+
"Type": "login"
|
54 |
+
}
|
55 |
+
}
|
56 |
+
]
|
57 |
+
}
|
tests/Service/AdminMenu/MultipleRoleInheritanceTest.php
ADDED
@@ -0,0 +1,182 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
/**
|
4 |
+
* ======================================================================
|
5 |
+
* LICENSE: This file is subject to the terms and conditions defined in *
|
6 |
+
* file 'license.txt', which is part of this source code package. *
|
7 |
+
* ======================================================================
|
8 |
+
*/
|
9 |
+
|
10 |
+
namespace AAM\UnitTest\Service\AdminMenu;
|
11 |
+
|
12 |
+
use AAM,
|
13 |
+
AAM_Core_Config,
|
14 |
+
AAM_Core_Object_Menu,
|
15 |
+
PHPUnit\Framework\TestCase,
|
16 |
+
AAM\UnitTest\Libs\ResetTrait,
|
17 |
+
AAM\UnitTest\Libs\AuthMultiRoleUserTrait,
|
18 |
+
AAM\UnitTest\Libs\MultiRoleOptionInterface;
|
19 |
+
|
20 |
+
/**
|
21 |
+
* Test AAM access settings inheritance mechanism for multiple roles per user for
|
22 |
+
* the Admin Menu service
|
23 |
+
*
|
24 |
+
* Admin Menu is available only for authenticated users so no Visitors are tested
|
25 |
+
*
|
26 |
+
* @package AAM\UnitTest
|
27 |
+
* @version 6.0.0
|
28 |
+
*/
|
29 |
+
class MultipleRoleInheritanceTest extends TestCase implements MultiRoleOptionInterface
|
30 |
+
{
|
31 |
+
use ResetTrait,
|
32 |
+
AuthMultiRoleUserTrait;
|
33 |
+
|
34 |
+
/**
|
35 |
+
* Test that access settings are inherited from multiple parent roles
|
36 |
+
*
|
37 |
+
* This test is designed to verify that access settings are propagated property
|
38 |
+
* when there access settings defined for multiple parent roles.
|
39 |
+
*
|
40 |
+
* A. Test that settings can be stored for the parent roles;
|
41 |
+
* B. Test that access settings are propagated property to the User level
|
42 |
+
*
|
43 |
+
* @return void
|
44 |
+
*
|
45 |
+
* @access public
|
46 |
+
* @version 6.0.0
|
47 |
+
*/
|
48 |
+
public function testInheritanceMergeFromMultipleRoles()
|
49 |
+
{
|
50 |
+
$user = AAM::getUser();
|
51 |
+
$role = $user->getParent();
|
52 |
+
|
53 |
+
// Make sure that we have parent roles defined properly
|
54 |
+
$this->assertEquals('AAM_Core_Subject_Role', get_class($role));
|
55 |
+
|
56 |
+
// Save access settings for the base role and iterate over each sibling and
|
57 |
+
// add additional settings
|
58 |
+
$object = $role->getObject(AAM_Core_Object_Menu::OBJECT_TYPE, null, true);
|
59 |
+
$this->assertTrue($object->updateOptionItem('index.php?id=0', true)->save());
|
60 |
+
|
61 |
+
foreach($role->getSiblings() as $i => $sibling) {
|
62 |
+
// Save access settings for each role and make sure they are saved property
|
63 |
+
// Check if save returns positive result
|
64 |
+
$this->assertTrue(
|
65 |
+
$sibling->getObject(AAM_Core_Object_Menu::OBJECT_TYPE, null, true)->updateOptionItem(
|
66 |
+
'index.php?id=' . ($i + 1), ($i % 2 ? true : false)
|
67 |
+
)->save()
|
68 |
+
);
|
69 |
+
}
|
70 |
+
|
71 |
+
// Reset internal AAM cache
|
72 |
+
$this->_resetSubjects();
|
73 |
+
|
74 |
+
// Assert that we have both roles merged result is as following
|
75 |
+
// Array (
|
76 |
+
// index.php?id=0 => true,
|
77 |
+
// index.php?id=1 => false
|
78 |
+
// )
|
79 |
+
$option = $user->getObject(AAM_Core_Object_Menu::OBJECT_TYPE)->getOption();
|
80 |
+
$this->assertSame(
|
81 |
+
array('index.php?id=0' => true, 'index.php?id=1' => false), $option
|
82 |
+
);
|
83 |
+
}
|
84 |
+
|
85 |
+
/**
|
86 |
+
* Test that access settings are merged with default "deny" precedence correctly
|
87 |
+
*
|
88 |
+
* @return void
|
89 |
+
*
|
90 |
+
* @access public
|
91 |
+
* @version 6.0.0
|
92 |
+
*/
|
93 |
+
public function testInheritanceDenyPrecedenceFromMultipleRoles()
|
94 |
+
{
|
95 |
+
$user = AAM::getUser();
|
96 |
+
$role = $user->getParent();
|
97 |
+
|
98 |
+
// Make sure that we have parent roles defined properly
|
99 |
+
$this->assertEquals('AAM_Core_Subject_Role', get_class($role));
|
100 |
+
|
101 |
+
// Save access settings for the base role and iterate over each sibling and
|
102 |
+
// add additional settings
|
103 |
+
$this->assertTrue(
|
104 |
+
$role->getObject(AAM_Core_Object_Menu::OBJECT_TYPE, null, true)->updateOptionItem(
|
105 |
+
'index.php', true
|
106 |
+
)->save()
|
107 |
+
);
|
108 |
+
|
109 |
+
foreach($role->getSiblings() as $sibling) {
|
110 |
+
// Save access settings for each role and make sure they are saved property
|
111 |
+
// Check if save returns positive result
|
112 |
+
$this->assertTrue(
|
113 |
+
$sibling->getObject(AAM_Core_Object_Menu::OBJECT_TYPE, null, true)->updateOptionItem(
|
114 |
+
'index.php', false
|
115 |
+
)->save()
|
116 |
+
);
|
117 |
+
}
|
118 |
+
|
119 |
+
// Reset internal AAM cache
|
120 |
+
$this->_resetSubjects();
|
121 |
+
|
122 |
+
// Assert that we have both roles merged result is as following
|
123 |
+
// Array (
|
124 |
+
// index.php => true
|
125 |
+
// )
|
126 |
+
$option = $user->getObject(AAM_Core_Object_Menu::OBJECT_TYPE)->getOption();
|
127 |
+
$this->assertSame(
|
128 |
+
array('index.php' => true), $option
|
129 |
+
);
|
130 |
+
}
|
131 |
+
|
132 |
+
/**
|
133 |
+
* Test that access settings are merged correctly with "allowed" precedence
|
134 |
+
* correctly
|
135 |
+
*
|
136 |
+
* @return void
|
137 |
+
* @version 6.0.0
|
138 |
+
*/
|
139 |
+
public function testInheritanceAllowPrecedenceFromMultipleRoles()
|
140 |
+
{
|
141 |
+
$user = AAM::getUser();
|
142 |
+
$role = $user->getParent();
|
143 |
+
|
144 |
+
// Make sure that we have parent roles defined properly
|
145 |
+
$this->assertEquals('AAM_Core_Subject_Role', get_class($role));
|
146 |
+
|
147 |
+
// Save access settings for the base role and iterate over each sibling and
|
148 |
+
// add additional settings
|
149 |
+
$this->assertTrue(
|
150 |
+
$role->getObject(AAM_Core_Object_Menu::OBJECT_TYPE, null, true)->updateOptionItem(
|
151 |
+
'index.php', true
|
152 |
+
)->save()
|
153 |
+
);
|
154 |
+
|
155 |
+
foreach($role->getSiblings() as $sibling) {
|
156 |
+
// Save access settings for each role and make sure they are saved property
|
157 |
+
// Check if save returns positive result
|
158 |
+
$this->assertTrue(
|
159 |
+
$sibling->getObject(AAM_Core_Object_Menu::OBJECT_TYPE, null, true)->updateOptionItem(
|
160 |
+
'index.php', false
|
161 |
+
)->save()
|
162 |
+
);
|
163 |
+
}
|
164 |
+
|
165 |
+
// Override the default "deny" precedence
|
166 |
+
AAM_Core_Config::set(
|
167 |
+
sprintf('core.settings.%s.merge.preference', AAM_Core_Object_Menu::OBJECT_TYPE),
|
168 |
+
'allow'
|
169 |
+
);
|
170 |
+
|
171 |
+
// Reset internal AAM cache
|
172 |
+
$this->_resetSubjects();
|
173 |
+
|
174 |
+
// Assert that we have both roles merged result is as following
|
175 |
+
// Array (
|
176 |
+
// index.php => false
|
177 |
+
// )
|
178 |
+
$option = $user->getObject(AAM_Core_Object_Menu::OBJECT_TYPE)->getOption();
|
179 |
+
$this->assertSame(array('index.php' => false), $option);
|
180 |
+
}
|
181 |
+
|
182 |
+
}
|
tests/Service/AdminMenu/SingleRoleInheritanceTest.php
ADDED
@@ -0,0 +1,226 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
/**
|
4 |
+
* ======================================================================
|
5 |
+
* LICENSE: This file is subject to the terms and conditions defined in *
|
6 |
+
* file 'license.txt', which is part of this source code package. *
|
7 |
+
* ======================================================================
|
8 |
+
*/
|
9 |
+
|
10 |
+
namespace AAM\UnitTest\Service\AdminMenu;
|
11 |
+
|
12 |
+
use AAM,
|
13 |
+
AAM_Core_Object_Menu,
|
14 |
+
PHPUnit\Framework\TestCase,
|
15 |
+
AAM\UnitTest\Libs\ResetTrait,
|
16 |
+
AAM\UnitTest\Libs\AuthUserTrait;
|
17 |
+
|
18 |
+
/**
|
19 |
+
* Test AAM access settings inheritance mechanism for the Admin Menu service
|
20 |
+
*
|
21 |
+
* Admin Menu is available only for authenticated users so no Visitors are tested
|
22 |
+
*
|
23 |
+
* @author Vasyl Martyniuk <vasyl@vasyltech.com>
|
24 |
+
* @version 6.0.0
|
25 |
+
*/
|
26 |
+
class SingleRoleInheritanceTest extends TestCase
|
27 |
+
{
|
28 |
+
use ResetTrait,
|
29 |
+
AuthUserTrait;
|
30 |
+
|
31 |
+
/**
|
32 |
+
* Test to insure that access settings are stored property on the User level
|
33 |
+
*
|
34 |
+
* A. Test that "index.php" is stored to the database with "true" flag and true
|
35 |
+
* is returned by AAM_Core_Subject_User::updateOption method;
|
36 |
+
* B. Test that information is actually stored property in the database and can
|
37 |
+
* be retrieved successfully.
|
38 |
+
*
|
39 |
+
* @return void
|
40 |
+
*
|
41 |
+
* @access public
|
42 |
+
* @see AAM_Core_Subject_User::updateOption
|
43 |
+
* @version 6.0.0
|
44 |
+
*/
|
45 |
+
public function testSaveAdminMenuOption()
|
46 |
+
{
|
47 |
+
$user = AAM::getUser();
|
48 |
+
$object = $user->getObject(AAM_Core_Object_Menu::OBJECT_TYPE);
|
49 |
+
|
50 |
+
// Check if save returns positive result
|
51 |
+
$this->assertTrue($object->updateOptionItem('index.php', true)->save());
|
52 |
+
|
53 |
+
// Read from the database saved values and assert that we have
|
54 |
+
// Array (
|
55 |
+
// index.php => true
|
56 |
+
// )
|
57 |
+
$option = $user->readOption('menu');
|
58 |
+
$this->assertSame(array('index.php' => true), $option);
|
59 |
+
}
|
60 |
+
|
61 |
+
/**
|
62 |
+
* Test that access settings are inherited from the parent role property
|
63 |
+
*
|
64 |
+
* This test is designed to verify that access settings are propagated property
|
65 |
+
* when there is only one role assigned to a user.
|
66 |
+
*
|
67 |
+
* A. Test that settings can be stored for the parent role;
|
68 |
+
* B. Test that access settings are propagated property to the User level
|
69 |
+
*
|
70 |
+
* @return void
|
71 |
+
*
|
72 |
+
* @access public
|
73 |
+
* @version 6.0.0
|
74 |
+
*/
|
75 |
+
public function testInheritanceFromSingleRole()
|
76 |
+
{
|
77 |
+
$user = AAM::getUser();
|
78 |
+
$parent = $user->getParent();
|
79 |
+
$object = $parent->getObject(AAM_Core_Object_Menu::OBJECT_TYPE);
|
80 |
+
|
81 |
+
// Make sure that we have parent role defined
|
82 |
+
$this->assertEquals('AAM_Core_Subject_Role', get_class($parent));
|
83 |
+
|
84 |
+
// Save access settings for the role and make sure they are saved property
|
85 |
+
// Check if save returns positive result
|
86 |
+
$this->assertTrue($object->updateOptionItem('index.php', true)->save());
|
87 |
+
|
88 |
+
// Read from the database saved values and assert that we have
|
89 |
+
// Array (
|
90 |
+
// index.php => true
|
91 |
+
// )
|
92 |
+
$option = $parent->readOption('menu');
|
93 |
+
$this->assertSame(array('index.php' => true), $option);
|
94 |
+
|
95 |
+
// Finally verify that access settings are propagated property to the User
|
96 |
+
// Level
|
97 |
+
$menu = $user->getObject(AAM_Core_Object_Menu::OBJECT_TYPE);
|
98 |
+
$this->assertSame(array('index.php' => true), $menu->getOption());
|
99 |
+
}
|
100 |
+
|
101 |
+
/**
|
102 |
+
* Test that access settings are propagated and merged properly
|
103 |
+
*
|
104 |
+
* The test is designed to verify that access settings are propagated properly
|
105 |
+
* from the parent role and merged well with explicitly defined access settings on
|
106 |
+
* the User level.
|
107 |
+
*
|
108 |
+
* The expected result is to have combined array of access settings from the parent
|
109 |
+
* role and specific user.
|
110 |
+
*
|
111 |
+
* A. Test that access settings are stored for the parent role;
|
112 |
+
* B. Test that access settings are stored for the user;
|
113 |
+
* C. Test that access settings are propagated and merged properly;
|
114 |
+
*
|
115 |
+
* @return void
|
116 |
+
*
|
117 |
+
* @access public
|
118 |
+
* @version 6.0.0
|
119 |
+
*/
|
120 |
+
public function testInheritanceMergeFromSingleRole()
|
121 |
+
{
|
122 |
+
$user = AAM::getUser();
|
123 |
+
$parent = $user->getParent();
|
124 |
+
|
125 |
+
$object = $parent->getObject(AAM_Core_Object_Menu::OBJECT_TYPE);
|
126 |
+
|
127 |
+
// Save access settings for the role and make sure they are saved property
|
128 |
+
// Check if save returns positive result
|
129 |
+
$this->assertTrue($object->updateOptionItem('update.php', true)->save());
|
130 |
+
|
131 |
+
// Save access setting for the user and make sure they are saved property
|
132 |
+
$menu = $user->getObject(AAM_Core_Object_Menu::OBJECT_TYPE, null, true);
|
133 |
+
$this->assertTrue($menu->updateOptionItem('post.php?post_type=page', false)->save());
|
134 |
+
|
135 |
+
// Reset cache and try to kick-in the inheritance mechanism
|
136 |
+
$this->_resetSubjects();
|
137 |
+
|
138 |
+
$menu = $user->getObject(AAM_Core_Object_Menu::OBJECT_TYPE);
|
139 |
+
$this->assertSame(
|
140 |
+
array('update.php' => true, 'post.php?post_type=page' => false),
|
141 |
+
$menu->getOption()
|
142 |
+
);
|
143 |
+
}
|
144 |
+
|
145 |
+
/**
|
146 |
+
* Test that the full inheritance mechanism is working as expected
|
147 |
+
*
|
148 |
+
* Make sure that access settings are propagated and merged properly from the top
|
149 |
+
* (Default Level)to the bottom (User Level).
|
150 |
+
*
|
151 |
+
* A. Assert that access settings are stored properly for each Access Level;
|
152 |
+
* B. Assert that access settings are merged properly and assigned to User Level;
|
153 |
+
*
|
154 |
+
* @return void
|
155 |
+
*
|
156 |
+
* @access public
|
157 |
+
* @version 6.0.0
|
158 |
+
*/
|
159 |
+
public function testFullInheritanceChainSingeRole()
|
160 |
+
{
|
161 |
+
$user = AAM::getUser();
|
162 |
+
$role = $user->getParent();
|
163 |
+
$default = $role->getParent();
|
164 |
+
|
165 |
+
$userMenu = $user->getObject(AAM_Core_Object_Menu::OBJECT_TYPE, null, true);
|
166 |
+
$roleMenu = $role->getObject(AAM_Core_Object_Menu::OBJECT_TYPE, null, true);
|
167 |
+
$defaultMenu = $default->getObject(AAM_Core_Object_Menu::OBJECT_TYPE, null, true);
|
168 |
+
|
169 |
+
// Save access settings for all subjects
|
170 |
+
$this->assertTrue($userMenu->updateOptionItem('update.php', true)->save());
|
171 |
+
$this->assertTrue($roleMenu->updateOptionItem('post.php?post_type=page', true)->save());
|
172 |
+
$this->assertTrue($defaultMenu->updateOptionItem('customize.php', true)->save());
|
173 |
+
|
174 |
+
// Reset cache and try to kick-in the inheritance mechanism
|
175 |
+
$this->_resetSubjects();
|
176 |
+
|
177 |
+
// All settings has to be merged into one array
|
178 |
+
$menu = $user->getObject(AAM_Core_Object_Menu::OBJECT_TYPE);
|
179 |
+
$this->assertSame(
|
180 |
+
array(
|
181 |
+
'customize.php' => true,
|
182 |
+
'post.php?post_type=page' => true,
|
183 |
+
'update.php' => true
|
184 |
+
),
|
185 |
+
$menu->getOption()
|
186 |
+
);
|
187 |
+
}
|
188 |
+
|
189 |
+
/**
|
190 |
+
* Test that access settings overwrite works as expected
|
191 |
+
*
|
192 |
+
* The expected result is lower Access Level overwrite access settings from the
|
193 |
+
* higher Access Level.
|
194 |
+
*
|
195 |
+
* A. Assert that access settings are stored properly for the parent role;
|
196 |
+
* B. Assert that access settings are stored properly for the specific user;
|
197 |
+
* C. Assert that access settings are overwritten properly on the User Level;
|
198 |
+
*
|
199 |
+
* @return void
|
200 |
+
*
|
201 |
+
* @access public
|
202 |
+
* @version 6.0.0
|
203 |
+
*/
|
204 |
+
public function testInheritanceOverrideForSingleRole()
|
205 |
+
{
|
206 |
+
$user = AAM::getUser();
|
207 |
+
$parent = $user->getParent();
|
208 |
+
|
209 |
+
$object = $parent->getObject(AAM_Core_Object_Menu::OBJECT_TYPE);
|
210 |
+
|
211 |
+
// Save access settings for the role and make sure they are saved property
|
212 |
+
// Check if save returns positive result
|
213 |
+
$this->assertTrue($object->updateOptionItem('update.php', true)->save());
|
214 |
+
|
215 |
+
// Save access setting for the user and make sure they are saved property
|
216 |
+
$menu = $user->getObject(AAM_Core_Object_Menu::OBJECT_TYPE, null, true);
|
217 |
+
$this->assertTrue($menu->updateOptionItem('update.php', false)->save());
|
218 |
+
|
219 |
+
// Reset cache and try to kick-in the inheritance mechanism
|
220 |
+
$this->_resetSubjects();
|
221 |
+
|
222 |
+
$menu = $user->getObject(AAM_Core_Object_Menu::OBJECT_TYPE);
|
223 |
+
$this->assertSame(array('update.php' => false), $menu->getOption());
|
224 |
+
}
|
225 |
+
|
226 |
+
}
|
tests/Service/Capabilities/CapabilityManagerTest.php
ADDED
@@ -0,0 +1,345 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
/**
|
4 |
+
* ======================================================================
|
5 |
+
* LICENSE: This file is subject to the terms and conditions defined in *
|
6 |
+
* file 'license.txt', which is part of this source code package. *
|
7 |
+
* ======================================================================
|
8 |
+
*/
|
9 |
+
|
10 |
+
namespace AAM\UnitTest\Service\Capability;
|
11 |
+
|
12 |
+
use AAM,
|
13 |
+
AAM_Core_Subject_Role,
|
14 |
+
PHPUnit\Framework\TestCase,
|
15 |
+
AAM\UnitTest\Libs\AuthUserTrait,
|
16 |
+
AAM_Backend_Feature_Main_Capability;
|
17 |
+
|
18 |
+
/**
|
19 |
+
* Test Capability manager features
|
20 |
+
*
|
21 |
+
* @version 6.0.0
|
22 |
+
*/
|
23 |
+
class CapabilityManagerTest extends TestCase
|
24 |
+
{
|
25 |
+
|
26 |
+
use AuthUserTrait;
|
27 |
+
|
28 |
+
/**
|
29 |
+
* Test if capabilities can be added properly for defined role
|
30 |
+
*
|
31 |
+
* @return void
|
32 |
+
*
|
33 |
+
* @access public
|
34 |
+
* @version 6.0.0
|
35 |
+
*/
|
36 |
+
public function testAssignCapabilityToRole()
|
37 |
+
{
|
38 |
+
global $wpdb;
|
39 |
+
|
40 |
+
$stub = $this->prepareRoleStub(
|
41 |
+
// Create a map of arguments to return values
|
42 |
+
array(
|
43 |
+
array('capability', FILTER_DEFAULT, null, 'aam_test_cap_a'),
|
44 |
+
array('effect', FILTER_VALIDATE_BOOLEAN, null, true),
|
45 |
+
),
|
46 |
+
// Subject callback
|
47 |
+
function() {
|
48 |
+
return new AAM_Core_Subject_Role('subscriber');
|
49 |
+
}
|
50 |
+
);
|
51 |
+
|
52 |
+
// Check if save returns positive result
|
53 |
+
$this->assertEquals(
|
54 |
+
$stub->save(), wp_json_encode(array('status' => 'success'))
|
55 |
+
);
|
56 |
+
|
57 |
+
// Verify that created capability actually is inside the user_roles option
|
58 |
+
$option = get_option(sprintf('%suser_roles', $wpdb->prefix));
|
59 |
+
|
60 |
+
$this->assertTrue(
|
61 |
+
array_key_exists('aam_test_cap_a', $option['subscriber']['capabilities'])
|
62 |
+
);
|
63 |
+
|
64 |
+
$this->assertTrue($option['subscriber']['capabilities']['aam_test_cap_a']);
|
65 |
+
}
|
66 |
+
|
67 |
+
/**
|
68 |
+
* Test if capabilities can be added properly for the defined role and also
|
69 |
+
* current user
|
70 |
+
*
|
71 |
+
* @return void
|
72 |
+
*
|
73 |
+
* @access public
|
74 |
+
* @version 6.0.0
|
75 |
+
*/
|
76 |
+
public function testAssignCapabilityToRoleAndCurrentUser()
|
77 |
+
{
|
78 |
+
global $wpdb;
|
79 |
+
|
80 |
+
$stub = $this->prepareRoleStub(
|
81 |
+
// Create a map of arguments to return values
|
82 |
+
array(
|
83 |
+
array('capability', FILTER_DEFAULT, null, 'aam_test_cap_c'),
|
84 |
+
array('effect', FILTER_VALIDATE_BOOLEAN, null, true),
|
85 |
+
array('assignToMe', FILTER_VALIDATE_BOOLEAN, null, true)
|
86 |
+
),
|
87 |
+
// Subject callback
|
88 |
+
function() {
|
89 |
+
return new AAM_Core_Subject_Role('subscriber');
|
90 |
+
}
|
91 |
+
);
|
92 |
+
|
93 |
+
// Check if save returns positive result
|
94 |
+
$this->assertEquals(
|
95 |
+
$stub->save(), wp_json_encode(array('status' => 'success'))
|
96 |
+
);
|
97 |
+
|
98 |
+
// Verify that created capability actually is inside the user_roles option
|
99 |
+
$option = get_option(sprintf('%suser_roles', $wpdb->prefix));
|
100 |
+
|
101 |
+
$this->assertTrue(
|
102 |
+
array_key_exists('aam_test_cap_c', $option['subscriber']['capabilities'])
|
103 |
+
);
|
104 |
+
|
105 |
+
$this->assertTrue($option['subscriber']['capabilities']['aam_test_cap_c']);
|
106 |
+
|
107 |
+
$this->assertTrue(AAM::getUser()->hasCapability('aam_test_cap_c'));
|
108 |
+
|
109 |
+
// Clean-up after execution
|
110 |
+
AAM::getUser()->removeCapability('aam_test_cap_c');
|
111 |
+
$stub->delete();
|
112 |
+
}
|
113 |
+
|
114 |
+
/**
|
115 |
+
* Test if capabilities can be deprived properly for defined role
|
116 |
+
*
|
117 |
+
* @return void
|
118 |
+
*
|
119 |
+
* @access public
|
120 |
+
* @version 6.0.0
|
121 |
+
*/
|
122 |
+
public function testDepriveCapabilityToRole()
|
123 |
+
{
|
124 |
+
global $wpdb;
|
125 |
+
|
126 |
+
$stub = $this->prepareRoleStub(
|
127 |
+
// Create a map of arguments to return values
|
128 |
+
array(
|
129 |
+
array('capability', FILTER_DEFAULT, null, 'aam_test_cap_a'),
|
130 |
+
array('effect', FILTER_VALIDATE_BOOLEAN, null, false),
|
131 |
+
),
|
132 |
+
// Subject callback
|
133 |
+
function() {
|
134 |
+
return new AAM_Core_Subject_Role('subscriber');
|
135 |
+
}
|
136 |
+
);
|
137 |
+
|
138 |
+
// Check if save returns positive result
|
139 |
+
$this->assertEquals(
|
140 |
+
$stub->save(), wp_json_encode(array('status' => 'success'))
|
141 |
+
);
|
142 |
+
|
143 |
+
// Verify that created capability actually is inside the user_roles option
|
144 |
+
$option = get_option(sprintf('%suser_roles', $wpdb->prefix));
|
145 |
+
|
146 |
+
$this->assertTrue(
|
147 |
+
array_key_exists('aam_test_cap_a', $option['subscriber']['capabilities'])
|
148 |
+
);
|
149 |
+
|
150 |
+
$this->assertFalse($option['subscriber']['capabilities']['aam_test_cap_a']);
|
151 |
+
}
|
152 |
+
|
153 |
+
/**
|
154 |
+
* Test if capabilities can be deleted from the very specific role
|
155 |
+
*
|
156 |
+
* @return void
|
157 |
+
*
|
158 |
+
* @access public
|
159 |
+
* @version 6.0.0
|
160 |
+
*/
|
161 |
+
public function testCapabilityDeletionFromRole()
|
162 |
+
{
|
163 |
+
global $wpdb;
|
164 |
+
|
165 |
+
$stub = $this->prepareRoleStub(
|
166 |
+
// Create a map of arguments to return values
|
167 |
+
array(
|
168 |
+
array('capability', FILTER_DEFAULT, null, 'aam_test_cap_a'),
|
169 |
+
array('effect', FILTER_VALIDATE_BOOLEAN, null, true),
|
170 |
+
array('subjectOnly', FILTER_VALIDATE_BOOLEAN, null, true)
|
171 |
+
),
|
172 |
+
// Subject callback
|
173 |
+
function() {
|
174 |
+
return new AAM_Core_Subject_Role('subscriber');
|
175 |
+
}
|
176 |
+
);
|
177 |
+
|
178 |
+
// Insert the test capability before it'll be deleted
|
179 |
+
$stub->save();
|
180 |
+
|
181 |
+
// Delete the test capability from the subject
|
182 |
+
$this->assertEquals(
|
183 |
+
$stub->delete(), wp_json_encode(array('status' => 'success'))
|
184 |
+
);
|
185 |
+
|
186 |
+
// Confirm that deleted capability is no longer in the subscriber role
|
187 |
+
$option = get_option(sprintf('%suser_roles', $wpdb->prefix));
|
188 |
+
|
189 |
+
$this->assertFalse(
|
190 |
+
array_key_exists('aam_test_cap_a', $option['subscriber']['capabilities'])
|
191 |
+
);
|
192 |
+
}
|
193 |
+
|
194 |
+
/**
|
195 |
+
* Test if capabilities can be deleted from all roles
|
196 |
+
*
|
197 |
+
* @return void
|
198 |
+
*
|
199 |
+
* @access public
|
200 |
+
* @version 6.0.0
|
201 |
+
*/
|
202 |
+
public function testCapabilityDeletionFromAllRoles()
|
203 |
+
{
|
204 |
+
global $wpdb;
|
205 |
+
|
206 |
+
// Prepare and insert test capability for the "subscriber" editor
|
207 |
+
$stubA = $this->prepareRoleStub(
|
208 |
+
// Create a map of arguments to return values
|
209 |
+
array(
|
210 |
+
array('capability', FILTER_DEFAULT, null, 'aam_test_cap_a'),
|
211 |
+
array('effect', FILTER_VALIDATE_BOOLEAN, null, true),
|
212 |
+
array('subjectOnly', FILTER_VALIDATE_BOOLEAN, null, false)
|
213 |
+
),
|
214 |
+
// Subject callback
|
215 |
+
function() {
|
216 |
+
return new AAM_Core_Subject_Role('subscriber');
|
217 |
+
}
|
218 |
+
);
|
219 |
+
// Insert the test capability before it'll be deleted
|
220 |
+
$this->assertEquals(
|
221 |
+
$stubA->save(), wp_json_encode(array('status' => 'success'))
|
222 |
+
);
|
223 |
+
|
224 |
+
// Prepare and insert test capability for the "editor" role
|
225 |
+
$stubB = $this->prepareRoleStub(
|
226 |
+
// Create a map of arguments to return values
|
227 |
+
array(
|
228 |
+
array('capability', FILTER_DEFAULT, null, 'aam_test_cap_a'),
|
229 |
+
array('effect', FILTER_VALIDATE_BOOLEAN, null, true)
|
230 |
+
),
|
231 |
+
// Subject callback
|
232 |
+
function() {
|
233 |
+
return new AAM_Core_Subject_Role('editor');
|
234 |
+
}
|
235 |
+
);
|
236 |
+
// Insert the test capability before it'll be deleted
|
237 |
+
$this->assertEquals(
|
238 |
+
$stubB->save(), wp_json_encode(array('status' => 'success'))
|
239 |
+
);
|
240 |
+
|
241 |
+
// Delete the test capability from all roles
|
242 |
+
$this->assertEquals(
|
243 |
+
$stubA->delete(), wp_json_encode(array('status' => 'success'))
|
244 |
+
);
|
245 |
+
|
246 |
+
// Confirm that deleted capability is no longer in the subscriber & editor
|
247 |
+
// roles
|
248 |
+
$option = get_option(sprintf('%suser_roles', $wpdb->prefix));
|
249 |
+
|
250 |
+
$this->assertFalse(
|
251 |
+
array_key_exists('aam_test_cap_a', $option['subscriber']['capabilities'])
|
252 |
+
);
|
253 |
+
|
254 |
+
$this->assertFalse(
|
255 |
+
array_key_exists('aam_test_cap_a', $option['editor']['capabilities'])
|
256 |
+
);
|
257 |
+
}
|
258 |
+
|
259 |
+
/**
|
260 |
+
* Test if capabilities can be updated properly for the defined subject
|
261 |
+
*
|
262 |
+
* @return void
|
263 |
+
*
|
264 |
+
* @access public
|
265 |
+
* @version 6.0.0
|
266 |
+
*/
|
267 |
+
public function testUpdateCapability()
|
268 |
+
{
|
269 |
+
global $wpdb;
|
270 |
+
|
271 |
+
$stubA = $this->prepareRoleStub(
|
272 |
+
// Create a map of arguments to return values
|
273 |
+
array(
|
274 |
+
array('capability', FILTER_DEFAULT, null, 'aam_test_cap_a'),
|
275 |
+
array('effect', FILTER_VALIDATE_BOOLEAN, null, false),
|
276 |
+
),
|
277 |
+
// Subject callback
|
278 |
+
function() {
|
279 |
+
return new AAM_Core_Subject_Role('subscriber');
|
280 |
+
}
|
281 |
+
);
|
282 |
+
|
283 |
+
// Check if save returns positive result
|
284 |
+
$this->assertEquals(
|
285 |
+
$stubA->save(), wp_json_encode(array('status' => 'success'))
|
286 |
+
);
|
287 |
+
|
288 |
+
// Create a new stub that will update the test capability
|
289 |
+
$stubB = $this->prepareRoleStub(
|
290 |
+
// Create a map of arguments to return values
|
291 |
+
array(
|
292 |
+
array('capability', FILTER_DEFAULT, null, 'aam_test_cap_a'),
|
293 |
+
array('updated', FILTER_DEFAULT, null, 'aam_test_cap_b')
|
294 |
+
),
|
295 |
+
// Subject callback
|
296 |
+
function() {
|
297 |
+
return new AAM_Core_Subject_Role('subscriber');
|
298 |
+
}
|
299 |
+
);
|
300 |
+
|
301 |
+
// Check if save returns positive result
|
302 |
+
$this->assertEquals(
|
303 |
+
$stubB->update(), wp_json_encode(array('status' => 'success'))
|
304 |
+
);
|
305 |
+
|
306 |
+
// Verify that capability actually is updated the user_roles option
|
307 |
+
$option = get_option(sprintf('%suser_roles', $wpdb->prefix));
|
308 |
+
|
309 |
+
$this->assertFalse(
|
310 |
+
array_key_exists('aam_test_cap_a', $option['subscriber']['capabilities'])
|
311 |
+
);
|
312 |
+
|
313 |
+
$this->assertTrue(
|
314 |
+
array_key_exists('aam_test_cap_b', $option['subscriber']['capabilities'])
|
315 |
+
);
|
316 |
+
|
317 |
+
$this->assertFalse($option['subscriber']['capabilities']['aam_test_cap_b']);
|
318 |
+
}
|
319 |
+
|
320 |
+
/**
|
321 |
+
* Prepare proper subject stub
|
322 |
+
*
|
323 |
+
* @param array $paramMap
|
324 |
+
* @param callback $callback
|
325 |
+
*
|
326 |
+
* @return object
|
327 |
+
*
|
328 |
+
* @access protected
|
329 |
+
* @version 6.0.0
|
330 |
+
*/
|
331 |
+
protected function prepareRoleStub($paramMap, $callback)
|
332 |
+
{
|
333 |
+
// Create a stub for the SomeClass class.
|
334 |
+
$stub = $this->getMockBuilder(AAM_Backend_Feature_Main_Capability::class)
|
335 |
+
->setMethods(array('getFromPost', 'getSubject'))
|
336 |
+
->getMock();
|
337 |
+
|
338 |
+
// Configure the stub
|
339 |
+
$stub->method('getFromPost')->will($this->returnValueMap($paramMap));
|
340 |
+
$stub->method('getSubject')->will($this->returnCallback($callback));
|
341 |
+
|
342 |
+
return $stub;
|
343 |
+
}
|
344 |
+
|
345 |
+
}
|
tests/Service/Content/Callback.php
ADDED
@@ -0,0 +1,13 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
namespace AAM\UnitTest\Service\Content;
|
4 |
+
|
5 |
+
class Callback
|
6 |
+
{
|
7 |
+
const REDIRECT_URL = 'https://aamplugin.com/redirect';
|
8 |
+
|
9 |
+
public static function redirectCallback()
|
10 |
+
{
|
11 |
+
return self::REDIRECT_URL;
|
12 |
+
}
|
13 |
+
}
|
tests/Service/Content/MultipleRoleInheritanceTest.php
ADDED
@@ -0,0 +1,190 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
/**
|
4 |
+
* ======================================================================
|
5 |
+
* LICENSE: This file is subject to the terms and conditions defined in *
|
6 |
+
* file 'license.txt', which is part of this source code package. *
|
7 |
+
* ======================================================================
|
8 |
+
*/
|
9 |
+
|
10 |
+
namespace AAM\UnitTest\Service\Content;
|
11 |
+
|
12 |
+
use AAM,
|
13 |
+
AAM_Core_Config,
|
14 |
+
AAM_Core_Object_Post,
|
15 |
+
PHPUnit\Framework\TestCase,
|
16 |
+
AAM\UnitTest\Libs\ResetTrait,
|
17 |
+
AAM\UnitTest\Libs\AuthMultiRoleUserTrait,
|
18 |
+
AAM\UnitTest\Libs\MultiRoleOptionInterface;
|
19 |
+
|
20 |
+
/**
|
21 |
+
* Test AAM access settings inheritance mechanism for multiple roles per user for
|
22 |
+
* the Content service
|
23 |
+
*
|
24 |
+
* @package AAM\UnitTest
|
25 |
+
* @version 6.0.0
|
26 |
+
*/
|
27 |
+
class MultipleRoleInheritanceTest extends TestCase implements MultiRoleOptionInterface
|
28 |
+
{
|
29 |
+
use ResetTrait,
|
30 |
+
AuthMultiRoleUserTrait;
|
31 |
+
|
32 |
+
/**
|
33 |
+
* Test that access settings are inherited from multiple parent roles
|
34 |
+
*
|
35 |
+
* This test is designed to verify that access settings are propagated property
|
36 |
+
* when there access settings defined for multiple parent roles.
|
37 |
+
*
|
38 |
+
* A. Test that settings can be stored for the parent roles;
|
39 |
+
* B. Test that access settings are propagated property to the User level
|
40 |
+
*
|
41 |
+
* @return void
|
42 |
+
*
|
43 |
+
* @access public
|
44 |
+
* @version 6.0.0
|
45 |
+
*/
|
46 |
+
public function testInheritanceMergeFromMultipleRoles()
|
47 |
+
{
|
48 |
+
$user = AAM::getUser();
|
49 |
+
$role = $user->getParent();
|
50 |
+
|
51 |
+
// Make sure that we have parent roles defined properly
|
52 |
+
$this->assertEquals('AAM_Core_Subject_Role', get_class($role));
|
53 |
+
|
54 |
+
// Save access settings for the base role and iterate over each sibling and
|
55 |
+
// add additional settings
|
56 |
+
$this->assertTrue(
|
57 |
+
$role->getObject(AAM_Core_Object_Post::OBJECT_TYPE, AAM_UNITTEST_POST_ID, true)->updateOptionItem(
|
58 |
+
'limited',
|
59 |
+
array(
|
60 |
+
'enabled' => true,
|
61 |
+
'threshold' => 1
|
62 |
+
)
|
63 |
+
)->save()
|
64 |
+
);
|
65 |
+
|
66 |
+
// Set the access settings for the next Sibling
|
67 |
+
$sibling = $role->getSiblings()[0];
|
68 |
+
|
69 |
+
$sibling->getObject(AAM_Core_Object_Post::OBJECT_TYPE, AAM_UNITTEST_POST_ID, true)->updateOptionItem(
|
70 |
+
'hidden',
|
71 |
+
false
|
72 |
+
)->save();
|
73 |
+
|
74 |
+
// Reset internal AAM cache
|
75 |
+
$this->_resetSubjects();
|
76 |
+
|
77 |
+
// Assert that we have both roles merged result is as following
|
78 |
+
// Array (
|
79 |
+
// limited => Array (
|
80 |
+
// enabled => true,
|
81 |
+
// threshold => 1
|
82 |
+
// ),
|
83 |
+
// hidden => false
|
84 |
+
// )
|
85 |
+
$object = $user->getObject(AAM_Core_Object_Post::OBJECT_TYPE, AAM_UNITTEST_POST_ID);
|
86 |
+
|
87 |
+
$this->assertSame(
|
88 |
+
array(
|
89 |
+
'limited' => array(
|
90 |
+
'enabled' => true,
|
91 |
+
'threshold' => 1
|
92 |
+
),
|
93 |
+
'hidden' => false
|
94 |
+
),
|
95 |
+
$object->getOption()
|
96 |
+
);
|
97 |
+
}
|
98 |
+
|
99 |
+
/**
|
100 |
+
* Test that access settings are merged with default "deny" preference correctly
|
101 |
+
*
|
102 |
+
* @return void
|
103 |
+
*
|
104 |
+
* @access public
|
105 |
+
* @version 6.0.0
|
106 |
+
*/
|
107 |
+
public function testInheritanceDenyPreferenceFromMultipleRoles()
|
108 |
+
{
|
109 |
+
$user = AAM::getUser();
|
110 |
+
$role = $user->getParent();
|
111 |
+
|
112 |
+
// Make sure that we have parent roles defined properly
|
113 |
+
$this->assertEquals('AAM_Core_Subject_Role', get_class($role));
|
114 |
+
|
115 |
+
// Save access settings for the base role and iterate over each sibling and
|
116 |
+
// add additional settings
|
117 |
+
$this->assertTrue(
|
118 |
+
$role->getObject(AAM_Core_Object_Post::OBJECT_TYPE, AAM_UNITTEST_POST_ID, true)->updateOptionItem(
|
119 |
+
'hidden', true
|
120 |
+
)->save()
|
121 |
+
);
|
122 |
+
|
123 |
+
// Set the access settings for the next Sibling
|
124 |
+
$sibling = $role->getSiblings()[0];
|
125 |
+
|
126 |
+
$sibling->getObject(AAM_Core_Object_Post::OBJECT_TYPE, AAM_UNITTEST_POST_ID, true)->updateOptionItem(
|
127 |
+
'hidden',
|
128 |
+
false
|
129 |
+
)->save();
|
130 |
+
|
131 |
+
// Reset internal AAM cache
|
132 |
+
$this->_resetSubjects();
|
133 |
+
|
134 |
+
// Assert that we have both roles merged result is as following
|
135 |
+
// Array (
|
136 |
+
// hidden => true
|
137 |
+
// )
|
138 |
+
$option = $user->getObject(AAM_Core_Object_Post::OBJECT_TYPE, AAM_UNITTEST_POST_ID)->getOption();
|
139 |
+
$this->assertSame(array('hidden' => true), $option);
|
140 |
+
}
|
141 |
+
|
142 |
+
/**
|
143 |
+
* Test that access settings are merged with default "deny" preference correctly
|
144 |
+
*
|
145 |
+
* In this test, the first role will have explicitly defined access settings that
|
146 |
+
* deny access, while the second role has no settings defined. This way the
|
147 |
+
* expected outcome should be access allowed.
|
148 |
+
*
|
149 |
+
* @return void
|
150 |
+
*
|
151 |
+
* @access public
|
152 |
+
* @version 6.0.0
|
153 |
+
*/
|
154 |
+
public function testInheritanceAllowPreferenceFromMultipleRoles()
|
155 |
+
{
|
156 |
+
$user = AAM::getUser();
|
157 |
+
$role = $user->getParent();
|
158 |
+
|
159 |
+
// Make sure that we have parent roles defined properly
|
160 |
+
$this->assertEquals('AAM_Core_Subject_Role', get_class($role));
|
161 |
+
|
162 |
+
// Save access settings for the base role and iterate over each sibling and
|
163 |
+
// add additional settings
|
164 |
+
$this->assertTrue(
|
165 |
+
$role->getObject(AAM_Core_Object_Post::OBJECT_TYPE, AAM_UNITTEST_POST_ID, true)->updateOptionItem(
|
166 |
+
'limited', array('enabled' => true, 'threshold' => 10)
|
167 |
+
)->save()
|
168 |
+
);
|
169 |
+
|
170 |
+
// Override the default "deny" precedence
|
171 |
+
AAM_Core_Config::set(
|
172 |
+
sprintf('core.settings.%s.merge.preference', AAM_Core_Object_Post::OBJECT_TYPE),
|
173 |
+
'allow'
|
174 |
+
);
|
175 |
+
|
176 |
+
// Reset internal AAM cache
|
177 |
+
$this->_resetSubjects();
|
178 |
+
|
179 |
+
// Assert that we have both roles merged result is as following
|
180 |
+
// Array (
|
181 |
+
// limited => Array (
|
182 |
+
// enabled => false,
|
183 |
+
// threshold => 10
|
184 |
+
// )
|
185 |
+
// )
|
186 |
+
$option = $user->getObject(AAM_Core_Object_Post::OBJECT_TYPE, AAM_UNITTEST_POST_ID)->getOption();
|
187 |
+
$this->assertSame(array('limited' => array('enabled' => false, 'threshold' => 10)), $option);
|
188 |
+
}
|
189 |
+
|
190 |
+
}
|
tests/Service/Content/RESTfulSingleRoleAccessControlTest.php
ADDED
@@ -0,0 +1,579 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
/**
|
4 |
+
* ======================================================================
|
5 |
+
* LICENSE: This file is subject to the terms and conditions defined in *
|
6 |
+
* file 'license.txt', which is part of this source code package. *
|
7 |
+
* ======================================================================
|
8 |
+
*/
|
9 |
+
|
10 |
+
namespace AAM\UnitTest\Service\Content;
|
11 |
+
|
12 |
+
use AAM,
|
13 |
+
WP_REST_Request,
|
14 |
+
AAM_Service_Content,
|
15 |
+
AAM_Core_Object_Post,
|
16 |
+
PHPUnit\Framework\TestCase,
|
17 |
+
AAM\UnitTest\Libs\ResetTrait,
|
18 |
+
AAM\UnitTest\Libs\AuthUserTrait;
|
19 |
+
|
20 |
+
/**
|
21 |
+
* Test that content access settings through the WP RESTful API
|
22 |
+
*
|
23 |
+
* @author Vasyl Martyniuk <vasyl@vasyltech.com>
|
24 |
+
* @version 6.0.0
|
25 |
+
*/
|
26 |
+
class RESTfulSingleRoleAccessControlTest extends TestCase
|
27 |
+
{
|
28 |
+
use ResetTrait,
|
29 |
+
AuthUserTrait;
|
30 |
+
|
31 |
+
/**
|
32 |
+
* Test that user is not allowed to access the post when access settings are set
|
33 |
+
* so on the User Level
|
34 |
+
*
|
35 |
+
* @return void
|
36 |
+
*
|
37 |
+
* @access public
|
38 |
+
* @version 6.0.0
|
39 |
+
*/
|
40 |
+
public function testRestrictedOption()
|
41 |
+
{
|
42 |
+
$user = AAM::getUser();
|
43 |
+
$object = $user->getObject(
|
44 |
+
AAM_Core_Object_Post::OBJECT_TYPE, AAM_UNITTEST_POST_ID
|
45 |
+
);
|
46 |
+
|
47 |
+
// Check if save returns positive result
|
48 |
+
$this->assertTrue($object->updateOptionItem('restricted', true)->save());
|
49 |
+
|
50 |
+
// Reset all internal cache
|
51 |
+
$this->_resetSubjects();
|
52 |
+
|
53 |
+
$server = rest_get_server();
|
54 |
+
|
55 |
+
$request = new WP_REST_Request('GET', '/wp/v2/posts/' . AAM_UNITTEST_POST_ID);
|
56 |
+
$request->set_param('context', 'view');
|
57 |
+
|
58 |
+
$data = $server->dispatch($request)->get_data();
|
59 |
+
|
60 |
+
$this->assertEquals('post_access_restricted', $data['code']);
|
61 |
+
}
|
62 |
+
|
63 |
+
/**
|
64 |
+
* Test that user does not have the ability to see hidden post
|
65 |
+
*
|
66 |
+
* @return void
|
67 |
+
*
|
68 |
+
* @access public
|
69 |
+
* @version 6.0.0
|
70 |
+
*/
|
71 |
+
public function testHiddenOption()
|
72 |
+
{
|
73 |
+
$server = rest_get_server();
|
74 |
+
|
75 |
+
// Hide the post
|
76 |
+
$user = AAM::getUser();
|
77 |
+
$object = $user->getObject(
|
78 |
+
AAM_Core_Object_Post::OBJECT_TYPE, AAM_UNITTEST_POST_ID
|
79 |
+
);
|
80 |
+
|
81 |
+
// Check if save returns positive result
|
82 |
+
$this->assertTrue($object->updateOptionItem('hidden', true)->save());
|
83 |
+
|
84 |
+
// Reset all internal cache
|
85 |
+
$this->_resetSubjects();
|
86 |
+
|
87 |
+
// Verify that post is no longer in the list of posts
|
88 |
+
$request = new WP_REST_Request('GET', '/wp/v2/posts');
|
89 |
+
$request->set_param('context', 'view');
|
90 |
+
|
91 |
+
$data = $server->dispatch($request)->get_data();
|
92 |
+
|
93 |
+
// First, confirm that post is in the array of posts
|
94 |
+
$this->assertCount(0, array_filter($data, function($post) {
|
95 |
+
return $post['id'] === AAM_UNITTEST_POST_ID;
|
96 |
+
}));
|
97 |
+
}
|
98 |
+
|
99 |
+
/**
|
100 |
+
* Test that content is limited with the Teaser message and enabled excerpt
|
101 |
+
* shortcode
|
102 |
+
*
|
103 |
+
* @return void
|
104 |
+
*
|
105 |
+
* @access public
|
106 |
+
* @version 6.0.0
|
107 |
+
*/
|
108 |
+
public function testTeaserMessageOption()
|
109 |
+
{
|
110 |
+
$user = AAM::getUser();
|
111 |
+
$object = $user->getObject(
|
112 |
+
AAM_Core_Object_Post::OBJECT_TYPE, AAM_UNITTEST_POST_ID
|
113 |
+
);
|
114 |
+
|
115 |
+
// Check if save returns positive result
|
116 |
+
$this->assertTrue($object->updateOptionItem('teaser', array(
|
117 |
+
'enabled' => true,
|
118 |
+
'message' => 'Test teaser with [excerpt]'
|
119 |
+
))->save());
|
120 |
+
|
121 |
+
// Reset all internal cache
|
122 |
+
$this->_resetSubjects();
|
123 |
+
|
124 |
+
// Confirm that teaser message is returned instead of actual content
|
125 |
+
$server = rest_get_server();
|
126 |
+
$request = new WP_REST_Request('GET', '/wp/v2/posts/' . AAM_UNITTEST_POST_ID);
|
127 |
+
$request->set_param('context', 'view');
|
128 |
+
|
129 |
+
$data = $server->dispatch($request)->get_data();
|
130 |
+
|
131 |
+
$this->assertSame(
|
132 |
+
$data['content']['rendered'], 'Test teaser with ' . $object->post_excerpt
|
133 |
+
);
|
134 |
+
}
|
135 |
+
|
136 |
+
/**
|
137 |
+
* Test the LIMITED option
|
138 |
+
*
|
139 |
+
* @return void
|
140 |
+
*
|
141 |
+
* @access public
|
142 |
+
* @version 6.0.0
|
143 |
+
*/
|
144 |
+
public function testLimitedOption()
|
145 |
+
{
|
146 |
+
// Limit the post
|
147 |
+
$user = AAM::getUser();
|
148 |
+
$object = $user->getObject(
|
149 |
+
AAM_Core_Object_Post::OBJECT_TYPE, AAM_UNITTEST_POST_ID
|
150 |
+
);
|
151 |
+
|
152 |
+
// Check if save returns positive result
|
153 |
+
$this->assertTrue($object->updateOptionItem('limited', array(
|
154 |
+
'enabled' => true,
|
155 |
+
'threshold' => 1
|
156 |
+
))->save());
|
157 |
+
|
158 |
+
// Faking the fact that user already seen this post once
|
159 |
+
update_user_meta(
|
160 |
+
AAM_UNITTEST_AUTH_USER_ID,
|
161 |
+
sprintf(AAM_Service_Content::POST_COUNTER_DB_OPTION, AAM_UNITTEST_POST_ID),
|
162 |
+
1
|
163 |
+
);
|
164 |
+
|
165 |
+
// Reset all internal cache
|
166 |
+
$this->_resetSubjects();
|
167 |
+
|
168 |
+
$server = rest_get_server();
|
169 |
+
|
170 |
+
$request = new WP_REST_Request('GET', '/wp/v2/posts/' . AAM_UNITTEST_POST_ID);
|
171 |
+
$request->set_param('context', 'view');
|
172 |
+
|
173 |
+
$data = $server->dispatch($request)->get_data();
|
174 |
+
|
175 |
+
$this->assertEquals('post_access_exceeded_limit', $data['code']);
|
176 |
+
}
|
177 |
+
|
178 |
+
/**
|
179 |
+
* Test that view counter is incremented after each view
|
180 |
+
*
|
181 |
+
* @return void
|
182 |
+
*
|
183 |
+
* @access public
|
184 |
+
* @version 6.0.0
|
185 |
+
*/
|
186 |
+
public function testLimitedIncrementedCounterOption()
|
187 |
+
{
|
188 |
+
// Limit the post
|
189 |
+
$user = AAM::getUser();
|
190 |
+
$object = $user->getObject(
|
191 |
+
AAM_Core_Object_Post::OBJECT_TYPE, AAM_UNITTEST_POST_ID
|
192 |
+
);
|
193 |
+
|
194 |
+
// Check if save returns positive result
|
195 |
+
$this->assertTrue($object->updateOptionItem('limited', array(
|
196 |
+
'enabled' => true,
|
197 |
+
'threshold' => 10
|
198 |
+
))->save());
|
199 |
+
|
200 |
+
// Tracking key
|
201 |
+
$key = sprintf(AAM_Service_Content::POST_COUNTER_DB_OPTION, AAM_UNITTEST_POST_ID);
|
202 |
+
|
203 |
+
// Faking the fact that user already seen this post once
|
204 |
+
update_user_meta(AAM_UNITTEST_AUTH_USER_ID, $key, 1);
|
205 |
+
|
206 |
+
// Reset all internal cache
|
207 |
+
$this->_resetSubjects();
|
208 |
+
|
209 |
+
$server = rest_get_server();
|
210 |
+
|
211 |
+
$request = new WP_REST_Request('GET', '/wp/v2/posts/' . AAM_UNITTEST_POST_ID);
|
212 |
+
$request->set_param('context', 'view');
|
213 |
+
|
214 |
+
$status = $server->dispatch($request)->get_status();
|
215 |
+
|
216 |
+
$this->assertEquals(200, $status);
|
217 |
+
$this->assertEquals(2, get_user_meta(AAM_UNITTEST_AUTH_USER_ID, $key, true));
|
218 |
+
}
|
219 |
+
|
220 |
+
/**
|
221 |
+
* Test that user does not have the ability to comment on a post
|
222 |
+
*
|
223 |
+
* @return void
|
224 |
+
*
|
225 |
+
* @access public
|
226 |
+
* @version 6.0.0
|
227 |
+
*/
|
228 |
+
public function testCommentingOption()
|
229 |
+
{
|
230 |
+
$user = AAM::getUser();
|
231 |
+
$object = $user->getObject(
|
232 |
+
AAM_Core_Object_Post::OBJECT_TYPE, AAM_UNITTEST_POST_ID
|
233 |
+
);
|
234 |
+
|
235 |
+
// Verify that commenting for this feature is set as open
|
236 |
+
$this->assertEquals($object->comment_status, 'open');
|
237 |
+
|
238 |
+
// Check if save returns positive result
|
239 |
+
$this->assertTrue($object->updateOptionItem('comment', true)->save());
|
240 |
+
|
241 |
+
// Reset all internal cache
|
242 |
+
$this->_resetSubjects();
|
243 |
+
|
244 |
+
$server = rest_get_server();
|
245 |
+
|
246 |
+
$request = new WP_REST_Request('POST', '/wp/v2/comments');
|
247 |
+
$request->set_param('post', AAM_UNITTEST_POST_ID);
|
248 |
+
$request->set_param('content', 'Test comment');
|
249 |
+
|
250 |
+
$data = $server->dispatch($request)->get_data();
|
251 |
+
|
252 |
+
$this->assertEquals('rest_comment_closed', $data['code']);
|
253 |
+
}
|
254 |
+
|
255 |
+
/**
|
256 |
+
* Test that REDIRECTED to Existing Page option is working as expected
|
257 |
+
*
|
258 |
+
* @return void
|
259 |
+
*
|
260 |
+
* @access public
|
261 |
+
* @version 6.0.0
|
262 |
+
*/
|
263 |
+
public function testRedirectPageOption()
|
264 |
+
{
|
265 |
+
$user = AAM::getUser();
|
266 |
+
$object = $user->getObject(
|
267 |
+
AAM_Core_Object_Post::OBJECT_TYPE, AAM_UNITTEST_POST_ID
|
268 |
+
);
|
269 |
+
|
270 |
+
// Check if save returns positive result
|
271 |
+
$this->assertTrue($object->updateOptionItem('redirected', array(
|
272 |
+
'enabled' => true,
|
273 |
+
'type' => 'page',
|
274 |
+
'destination' => AAM_UNITTEST_PAGE_ID,
|
275 |
+
'httpCode' => 301
|
276 |
+
))->save());
|
277 |
+
|
278 |
+
// Reset all internal cache
|
279 |
+
$this->_resetSubjects();
|
280 |
+
|
281 |
+
$server = rest_get_server();
|
282 |
+
|
283 |
+
$request = new WP_REST_Request('GET', '/wp/v2/posts/' . AAM_UNITTEST_POST_ID);
|
284 |
+
$request->set_param('context', 'view');
|
285 |
+
|
286 |
+
$data = $server->dispatch($request)->get_data();
|
287 |
+
|
288 |
+
$this->assertEquals('post_access_redirected', $data['code']);
|
289 |
+
$this->assertEquals(get_page_link(AAM_UNITTEST_PAGE_ID), $data['location']);
|
290 |
+
}
|
291 |
+
|
292 |
+
/**
|
293 |
+
* Test that REDIRECTED to URL option is working as expected
|
294 |
+
*
|
295 |
+
* @return void
|
296 |
+
*
|
297 |
+
* @access public
|
298 |
+
* @version 6.0.0
|
299 |
+
*/
|
300 |
+
public function testRedirectURLOption()
|
301 |
+
{
|
302 |
+
$user = AAM::getUser();
|
303 |
+
$object = $user->getObject(
|
304 |
+
AAM_Core_Object_Post::OBJECT_TYPE, AAM_UNITTEST_POST_ID
|
305 |
+
);
|
306 |
+
|
307 |
+
// Check if save returns positive result
|
308 |
+
$this->assertTrue($object->updateOptionItem('redirected', array(
|
309 |
+
'enabled' => true,
|
310 |
+
'type' => 'url',
|
311 |
+
'destination' => 'https://aamplugin.com',
|
312 |
+
'httpCode' => 307
|
313 |
+
))->save());
|
314 |
+
|
315 |
+
// Reset all internal cache
|
316 |
+
$this->_resetSubjects();
|
317 |
+
|
318 |
+
$server = rest_get_server();
|
319 |
+
|
320 |
+
$request = new WP_REST_Request('GET', '/wp/v2/posts/' . AAM_UNITTEST_POST_ID);
|
321 |
+
$request->set_param('context', 'view');
|
322 |
+
|
323 |
+
$data = $server->dispatch($request)->get_data();
|
324 |
+
|
325 |
+
$this->assertEquals('post_access_redirected', $data['code']);
|
326 |
+
$this->assertEquals('https://aamplugin.com', $data['location']);
|
327 |
+
}
|
328 |
+
|
329 |
+
/**
|
330 |
+
* Test that REDIRECTED to PHP Callback option is working as expected
|
331 |
+
*
|
332 |
+
* @return void
|
333 |
+
*
|
334 |
+
* @access public
|
335 |
+
* @version 6.0.0
|
336 |
+
*/
|
337 |
+
public function testRedirectCallbackOption()
|
338 |
+
{
|
339 |
+
$user = AAM::getUser();
|
340 |
+
$object = $user->getObject(
|
341 |
+
AAM_Core_Object_Post::OBJECT_TYPE, AAM_UNITTEST_POST_ID
|
342 |
+
);
|
343 |
+
|
344 |
+
// Check if save returns positive result
|
345 |
+
$this->assertTrue($object->updateOptionItem('redirected', array(
|
346 |
+
'enabled' => true,
|
347 |
+
'type' => 'callback',
|
348 |
+
// WordPress core strips slashes, so we have to double slash all this
|
349 |
+
'destination' => 'AAM\\UnitTest\\Service\\Content\\Callback::redirectCallback',
|
350 |
+
'httpCode' => 310
|
351 |
+
))->save());
|
352 |
+
|
353 |
+
// Reset all internal cache
|
354 |
+
$this->_resetSubjects();
|
355 |
+
|
356 |
+
$server = rest_get_server();
|
357 |
+
|
358 |
+
$request = new WP_REST_Request('GET', '/wp/v2/posts/' . AAM_UNITTEST_POST_ID);
|
359 |
+
$request->set_param('context', 'view');
|
360 |
+
|
361 |
+
$data = $server->dispatch($request)->get_data();
|
362 |
+
|
363 |
+
$this->assertEquals('post_access_redirected', $data['code']);
|
364 |
+
$this->assertEquals(Callback::REDIRECT_URL, $data['location']);
|
365 |
+
}
|
366 |
+
|
367 |
+
/**
|
368 |
+
* Test PASSWORD PROTECTED option when password is enforced by AAM and is valid
|
369 |
+
*
|
370 |
+
* @return void
|
371 |
+
*
|
372 |
+
* @access public
|
373 |
+
* @version 6.0.0
|
374 |
+
*/
|
375 |
+
public function testAAMEnforcedPasswordValidOption()
|
376 |
+
{
|
377 |
+
$user = AAM::getUser();
|
378 |
+
$object = $user->getObject(
|
379 |
+
AAM_Core_Object_Post::OBJECT_TYPE, AAM_UNITTEST_POST_ID
|
380 |
+
);
|
381 |
+
|
382 |
+
// Check if save returns positive result
|
383 |
+
$this->assertTrue($object->updateOptionItem('protected', array(
|
384 |
+
'enabled' => true,
|
385 |
+
'password' => '123456'
|
386 |
+
))->save());
|
387 |
+
|
388 |
+
// Reset all internal cache
|
389 |
+
$this->_resetSubjects();
|
390 |
+
|
391 |
+
$server = rest_get_server();
|
392 |
+
|
393 |
+
$request = new WP_REST_Request('GET', '/wp/v2/posts/' . AAM_UNITTEST_POST_ID);
|
394 |
+
$request->set_param('context', 'view');
|
395 |
+
$request->set_param('password', '123456');
|
396 |
+
|
397 |
+
$this->assertEquals(200, $server->dispatch($request)->get_status());
|
398 |
+
}
|
399 |
+
|
400 |
+
/**
|
401 |
+
* Test PASSWORD PROTECTED option when password is enforced by AAM and is invalid
|
402 |
+
*
|
403 |
+
* @return void
|
404 |
+
*
|
405 |
+
* @access public
|
406 |
+
* @version 6.0.0
|
407 |
+
*/
|
408 |
+
public function testAAMEnforcedPasswordInvalidOption()
|
409 |
+
{
|
410 |
+
$user = AAM::getUser();
|
411 |
+
$object = $user->getObject(
|
412 |
+
AAM_Core_Object_Post::OBJECT_TYPE, AAM_UNITTEST_POST_ID
|
413 |
+
);
|
414 |
+
|
415 |
+
// Check if save returns positive result
|
416 |
+
$this->assertTrue($object->updateOptionItem('protected', array(
|
417 |
+
'enabled' => true,
|
418 |
+
'password' => '123456'
|
419 |
+
))->save());
|
420 |
+
|
421 |
+
// Reset all internal cache
|
422 |
+
$this->_resetSubjects();
|
423 |
+
|
424 |
+
$server = rest_get_server();
|
425 |
+
|
426 |
+
$request = new WP_REST_Request('GET', '/wp/v2/posts/' . AAM_UNITTEST_POST_ID);
|
427 |
+
$request->set_param('context', 'view');
|
428 |
+
$request->set_param('password', 'abs');
|
429 |
+
|
430 |
+
$response = $server->dispatch($request);
|
431 |
+
|
432 |
+
$this->assertEquals(401, $response->get_status());
|
433 |
+
$this->assertEquals('post_access_protected', $response->get_data()['code']);
|
434 |
+
}
|
435 |
+
|
436 |
+
/**
|
437 |
+
* Test CEASED option
|
438 |
+
*
|
439 |
+
* @return void
|
440 |
+
*
|
441 |
+
* @access public
|
442 |
+
* @version 6.0.0
|
443 |
+
*/
|
444 |
+
public function testCeasedOption()
|
445 |
+
{
|
446 |
+
// Hide the post
|
447 |
+
$user = AAM::getUser();
|
448 |
+
$object = $user->getObject(
|
449 |
+
AAM_Core_Object_Post::OBJECT_TYPE, AAM_UNITTEST_POST_ID
|
450 |
+
);
|
451 |
+
|
452 |
+
// Check if save returns positive result
|
453 |
+
$this->assertTrue($object->updateOptionItem('ceased', array(
|
454 |
+
'enabled' => true,
|
455 |
+
'after' => '08/01/2019, 4:37 pm'
|
456 |
+
))->save());
|
457 |
+
|
458 |
+
// Reset all internal cache
|
459 |
+
$this->_resetSubjects();
|
460 |
+
|
461 |
+
$server = rest_get_server();
|
462 |
+
|
463 |
+
$request = new WP_REST_Request('GET', '/wp/v2/posts/' . AAM_UNITTEST_POST_ID);
|
464 |
+
$request->set_param('context', 'view');
|
465 |
+
|
466 |
+
$response = $server->dispatch($request);
|
467 |
+
|
468 |
+
$this->assertEquals(401, $response->get_status());
|
469 |
+
$this->assertEquals('post_access_expired', $response->get_data()['code']);
|
470 |
+
}
|
471 |
+
|
472 |
+
/**
|
473 |
+
* Test that user does not have the ability to edit a post
|
474 |
+
*
|
475 |
+
* @return void
|
476 |
+
*
|
477 |
+
* @access public
|
478 |
+
* @version 6.0.0
|
479 |
+
*/
|
480 |
+
public function testEditOption()
|
481 |
+
{
|
482 |
+
$user = AAM::getUser();
|
483 |
+
$object = $user->getObject(
|
484 |
+
AAM_Core_Object_Post::OBJECT_TYPE, AAM_UNITTEST_POST_ID
|
485 |
+
);
|
486 |
+
|
487 |
+
// Verify that editing is allowed for a specific post
|
488 |
+
$this->assertTrue(current_user_can('edit_post', AAM_UNITTEST_POST_ID));
|
489 |
+
|
490 |
+
// Check if save returns positive result
|
491 |
+
$this->assertTrue($object->updateOptionItem('edit', true)->save());
|
492 |
+
|
493 |
+
// Reset all internal cache
|
494 |
+
$this->_resetSubjects();
|
495 |
+
|
496 |
+
$server = rest_get_server();
|
497 |
+
|
498 |
+
$request = new WP_REST_Request('POST', '/wp/v2/posts/' . AAM_UNITTEST_POST_ID);
|
499 |
+
$request->set_param('content', 'Test');
|
500 |
+
|
501 |
+
$response = $server->dispatch($request);
|
502 |
+
|
503 |
+
$this->assertEquals(403, $response->get_status());
|
504 |
+
$this->assertEquals('rest_cannot_edit', $response->get_data()['code']);
|
505 |
+
}
|
506 |
+
|
507 |
+
/**
|
508 |
+
* Test that user does not have the ability to delete a post
|
509 |
+
*
|
510 |
+
* @return void
|
511 |
+
*
|
512 |
+
* @access public
|
513 |
+
* @version 6.0.0
|
514 |
+
*/
|
515 |
+
public function testDeleteOption()
|
516 |
+
{
|
517 |
+
$user = AAM::getUser();
|
518 |
+
$object = $user->getObject(
|
519 |
+
AAM_Core_Object_Post::OBJECT_TYPE, AAM_UNITTEST_POST_ID
|
520 |
+
);
|
521 |
+
|
522 |
+
// Verify that deletion is allowed for a specific post
|
523 |
+
$this->assertTrue(current_user_can('delete_post', AAM_UNITTEST_POST_ID));
|
524 |
+
|
525 |
+
// Check if save returns positive result
|
526 |
+
$this->assertTrue($object->updateOptionItem('delete', true)->save());
|
527 |
+
|
528 |
+
// Reset all internal cache
|
529 |
+
$this->_resetSubjects();
|
530 |
+
|
531 |
+
$server = rest_get_server();
|
532 |
+
|
533 |
+
$request = new WP_REST_Request('DELETE', '/wp/v2/posts/' . AAM_UNITTEST_POST_ID);
|
534 |
+
$response = $server->dispatch($request);
|
535 |
+
|
536 |
+
$this->assertEquals(403, $response->get_status());
|
537 |
+
$this->assertEquals('rest_cannot_delete', $response->get_data()['code']);
|
538 |
+
}
|
539 |
+
|
540 |
+
/**
|
541 |
+
* Test that user does not have the ability to publish a post
|
542 |
+
*
|
543 |
+
* @return void
|
544 |
+
*
|
545 |
+
* @access public
|
546 |
+
* @version 6.0.0
|
547 |
+
*/
|
548 |
+
public function testPublishOption()
|
549 |
+
{
|
550 |
+
global $post;
|
551 |
+
|
552 |
+
$user = AAM::getUser();
|
553 |
+
$object = $user->getObject(
|
554 |
+
AAM_Core_Object_Post::OBJECT_TYPE, AAM_UNITTEST_POST_ID
|
555 |
+
);
|
556 |
+
|
557 |
+
// Force global post
|
558 |
+
$post = get_post(AAM_UNITTEST_POST_ID);
|
559 |
+
|
560 |
+
// Verify that publishing is allowed for a specific post
|
561 |
+
$this->assertTrue(current_user_can('publish_post', AAM_UNITTEST_POST_ID));
|
562 |
+
|
563 |
+
// Check if save returns positive result
|
564 |
+
$this->assertTrue($object->updateOptionItem('publish', true)->save());
|
565 |
+
|
566 |
+
// Reset all internal cache
|
567 |
+
$this->_resetSubjects();
|
568 |
+
|
569 |
+
$server = rest_get_server();
|
570 |
+
|
571 |
+
$request = new WP_REST_Request('POST', '/wp/v2/posts/' . AAM_UNITTEST_POST_ID);
|
572 |
+
$request->set_param('status', 'publish');
|
573 |
+
$response = $server->dispatch($request);
|
574 |
+
|
575 |
+
$this->assertEquals(403, $response->get_status());
|
576 |
+
$this->assertEquals('rest_cannot_publish', $response->get_data()['code']);
|
577 |
+
}
|
578 |
+
|
579 |
+
}
|
tests/Service/Content/SingleRoleAccessControlTest.php
ADDED
@@ -0,0 +1,602 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
/**
|
4 |
+
* ======================================================================
|
5 |
+
* LICENSE: This file is subject to the terms and conditions defined in *
|
6 |
+
* file 'license.txt', which is part of this source code package. *
|
7 |
+
* ======================================================================
|
8 |
+
*/
|
9 |
+
|
10 |
+
namespace AAM\UnitTest\Service\Content;
|
11 |
+
|
12 |
+
use AAM,
|
13 |
+
AAM_Core_API,
|
14 |
+
AAM_Service_Content,
|
15 |
+
AAM_Core_Object_Post,
|
16 |
+
PHPUnit\Framework\TestCase,
|
17 |
+
AAM\UnitTest\Libs\ResetTrait,
|
18 |
+
AAM\UnitTest\Libs\AuthUserTrait;
|
19 |
+
|
20 |
+
/**
|
21 |
+
* Test that content access settings are applied and used properly with WordPress core
|
22 |
+
*
|
23 |
+
* @author Vasyl Martyniuk <vasyl@vasyltech.com>
|
24 |
+
* @version 6.0.0
|
25 |
+
*/
|
26 |
+
class SingleRoleAccessControlTest extends TestCase
|
27 |
+
{
|
28 |
+
use ResetTrait,
|
29 |
+
AuthUserTrait;
|
30 |
+
|
31 |
+
/**
|
32 |
+
* Test that user is not allowed to access the post when access settings are set
|
33 |
+
* so on the User Level
|
34 |
+
*
|
35 |
+
* @return void
|
36 |
+
*
|
37 |
+
* @access public
|
38 |
+
* @version 6.0.0
|
39 |
+
*/
|
40 |
+
public function testRestrictedOption()
|
41 |
+
{
|
42 |
+
$user = AAM::getUser();
|
43 |
+
$object = $user->getObject(
|
44 |
+
AAM_Core_Object_Post::OBJECT_TYPE, AAM_UNITTEST_POST_ID
|
45 |
+
);
|
46 |
+
|
47 |
+
// Check if save returns positive result
|
48 |
+
$this->assertTrue($object->updateOptionItem('restricted', true)->save());
|
49 |
+
|
50 |
+
// Reset all internal cache
|
51 |
+
$this->_resetSubjects();
|
52 |
+
|
53 |
+
$post = $user->getObject(
|
54 |
+
AAM_Core_Object_Post::OBJECT_TYPE, AAM_UNITTEST_POST_ID
|
55 |
+
);
|
56 |
+
|
57 |
+
// Make sure that AAM API returns correct result
|
58 |
+
$this->assertTrue($post->is('restricted'));
|
59 |
+
|
60 |
+
// Check that current user is not allowed to read_post
|
61 |
+
$this->assertFalse(current_user_can('read_post', AAM_UNITTEST_POST_ID));
|
62 |
+
}
|
63 |
+
|
64 |
+
/**
|
65 |
+
* Test that user does not have the ability to see hidden post
|
66 |
+
*
|
67 |
+
* @return void
|
68 |
+
*
|
69 |
+
* @access public
|
70 |
+
* @version 6.0.0
|
71 |
+
*/
|
72 |
+
public function testHiddenOption()
|
73 |
+
{
|
74 |
+
$posts = get_posts(array(
|
75 |
+
'post_type' => 'post',
|
76 |
+
'fields' => 'ids',
|
77 |
+
'suppress_filters' => false
|
78 |
+
));
|
79 |
+
|
80 |
+
// First, confirm that post is in the array of posts
|
81 |
+
$this->assertTrue(in_array(AAM_UNITTEST_POST_ID, $posts));
|
82 |
+
|
83 |
+
// Hide the post
|
84 |
+
$user = AAM::getUser();
|
85 |
+
$object = $user->getObject(
|
86 |
+
AAM_Core_Object_Post::OBJECT_TYPE, AAM_UNITTEST_POST_ID
|
87 |
+
);
|
88 |
+
|
89 |
+
// Check if save returns positive result
|
90 |
+
$this->assertTrue($object->updateOptionItem('hidden', true)->save());
|
91 |
+
|
92 |
+
// Reset all internal cache
|
93 |
+
$this->_resetSubjects();
|
94 |
+
|
95 |
+
// Verify that post is no longer in the list of posts
|
96 |
+
$posts = get_posts(array(
|
97 |
+
'post_type' => 'post',
|
98 |
+
'fields' => 'ids',
|
99 |
+
'suppress_filters' => false
|
100 |
+
));
|
101 |
+
|
102 |
+
// First, confirm that post is in the array of posts
|
103 |
+
$this->assertFalse(in_array(AAM_UNITTEST_POST_ID, $posts));
|
104 |
+
}
|
105 |
+
|
106 |
+
/**
|
107 |
+
* Test that content is limited with the Teaser message and enabled excerpt
|
108 |
+
* shortcode
|
109 |
+
*
|
110 |
+
* @return void
|
111 |
+
*
|
112 |
+
* @access public
|
113 |
+
* @version 6.0.0
|
114 |
+
*/
|
115 |
+
public function testTeaserMessageOption()
|
116 |
+
{
|
117 |
+
$user = AAM::getUser();
|
118 |
+
$object = $user->getObject(
|
119 |
+
AAM_Core_Object_Post::OBJECT_TYPE, AAM_UNITTEST_POST_ID
|
120 |
+
);
|
121 |
+
|
122 |
+
// Check if save returns positive result
|
123 |
+
$this->assertTrue($object->updateOptionItem('teaser', array(
|
124 |
+
'enabled' => true,
|
125 |
+
'message' => 'Test teaser with [excerpt]'
|
126 |
+
))->save());
|
127 |
+
|
128 |
+
// Reset all internal cache
|
129 |
+
$this->_resetSubjects();
|
130 |
+
|
131 |
+
// Confirm that teaser message is returned instead of actual content
|
132 |
+
$GLOBALS['post'] = AAM_UNITTEST_POST_ID;
|
133 |
+
ob_start();
|
134 |
+
the_content();
|
135 |
+
$this->assertSame(
|
136 |
+
ob_get_contents(), 'Test teaser with ' . $object->post_excerpt
|
137 |
+
);
|
138 |
+
ob_end_clean();
|
139 |
+
}
|
140 |
+
|
141 |
+
/**
|
142 |
+
* Test the LIMITED option
|
143 |
+
*
|
144 |
+
* Forcing $wp_query to trigger AAM_Service_Content::wp
|
145 |
+
*
|
146 |
+
* @return void
|
147 |
+
*
|
148 |
+
* @access public
|
149 |
+
* @see AAM_Service_Content::wp
|
150 |
+
* @version 6.0.0
|
151 |
+
*/
|
152 |
+
public function testLimitedOption()
|
153 |
+
{
|
154 |
+
global $wp_query;
|
155 |
+
|
156 |
+
// Limit the post
|
157 |
+
$user = AAM::getUser();
|
158 |
+
$object = $user->getObject(
|
159 |
+
AAM_Core_Object_Post::OBJECT_TYPE, AAM_UNITTEST_POST_ID
|
160 |
+
);
|
161 |
+
|
162 |
+
// Check if save returns positive result
|
163 |
+
$this->assertTrue($object->updateOptionItem('limited', array(
|
164 |
+
'enabled' => true,
|
165 |
+
'threshold' => 1
|
166 |
+
))->save());
|
167 |
+
|
168 |
+
// Faking the fact that user already seen this post once
|
169 |
+
update_user_meta(
|
170 |
+
AAM_UNITTEST_AUTH_USER_ID,
|
171 |
+
sprintf(AAM_Service_Content::POST_COUNTER_DB_OPTION, AAM_UNITTEST_POST_ID),
|
172 |
+
1
|
173 |
+
);
|
174 |
+
|
175 |
+
// Reset all internal cache
|
176 |
+
$this->_resetSubjects();
|
177 |
+
|
178 |
+
// Forcing WP_Query to the right path
|
179 |
+
$wp_query->is_single = true;
|
180 |
+
$GLOBALS['post'] = get_post(AAM_UNITTEST_POST_ID);
|
181 |
+
|
182 |
+
// Override the default handlers so we can suppress die exit
|
183 |
+
add_filter('wp_die_handler', function() {
|
184 |
+
return function($message, $title) {
|
185 |
+
_default_wp_die_handler($message, $title, array('exit' => false));
|
186 |
+
};
|
187 |
+
}, PHP_INT_MAX);
|
188 |
+
|
189 |
+
// Capture the WP Die message
|
190 |
+
ob_start();
|
191 |
+
do_action('wp');
|
192 |
+
$content = ob_get_contents();
|
193 |
+
ob_end_clean();
|
194 |
+
|
195 |
+
$this->assertStringContainsString(
|
196 |
+
'User exceeded allowed access number. Access denied.', $content
|
197 |
+
);
|
198 |
+
|
199 |
+
// Reset WP Query
|
200 |
+
remove_all_filters('wp_die_handler', PHP_INT_MAX);
|
201 |
+
|
202 |
+
$wp_query->is_single = null;
|
203 |
+
unset($GLOBALS['post']);
|
204 |
+
}
|
205 |
+
|
206 |
+
/**
|
207 |
+
* Test that user does not have the ability to comment on a post
|
208 |
+
*
|
209 |
+
* @return void
|
210 |
+
*
|
211 |
+
* @access public
|
212 |
+
* @version 6.0.0
|
213 |
+
*/
|
214 |
+
public function testCommentingOption()
|
215 |
+
{
|
216 |
+
$user = AAM::getUser();
|
217 |
+
$object = $user->getObject(
|
218 |
+
AAM_Core_Object_Post::OBJECT_TYPE, AAM_UNITTEST_POST_ID
|
219 |
+
);
|
220 |
+
|
221 |
+
// Verify that commenting for this feature is set as open
|
222 |
+
$this->assertEquals($object->comment_status, 'open');
|
223 |
+
|
224 |
+
// Check if save returns positive result
|
225 |
+
$this->assertTrue($object->updateOptionItem('comment', true)->save());
|
226 |
+
|
227 |
+
// Reset all internal cache
|
228 |
+
$this->_resetSubjects();
|
229 |
+
|
230 |
+
// First, confirm that post is in the array of posts
|
231 |
+
$this->assertFalse(comments_open(AAM_UNITTEST_POST_ID));
|
232 |
+
}
|
233 |
+
|
234 |
+
/**
|
235 |
+
* Test that REDIRECTED to Existing Page option is working as expected
|
236 |
+
*
|
237 |
+
* @return void
|
238 |
+
*
|
239 |
+
* @access public
|
240 |
+
* @version 6.0.0
|
241 |
+
*/
|
242 |
+
public function testRedirectPageOption()
|
243 |
+
{
|
244 |
+
$user = AAM::getUser();
|
245 |
+
$object = $user->getObject(
|
246 |
+
AAM_Core_Object_Post::OBJECT_TYPE, AAM_UNITTEST_POST_ID
|
247 |
+
);
|
248 |
+
|
249 |
+
// Check if save returns positive result
|
250 |
+
$this->assertTrue($object->updateOptionItem('redirected', array(
|
251 |
+
'enabled' => true,
|
252 |
+
'type' => 'page',
|
253 |
+
'destination' => AAM_UNITTEST_PAGE_ID,
|
254 |
+
'httpCode' => 301
|
255 |
+
))->save());
|
256 |
+
|
257 |
+
// Reset all internal cache
|
258 |
+
$this->_resetSubjects();
|
259 |
+
|
260 |
+
$service = AAM_Service_Content::getInstance();
|
261 |
+
$response = $service->isAuthorizedToReadPost($user->getObject(
|
262 |
+
AAM_Core_Object_Post::OBJECT_TYPE, AAM_UNITTEST_POST_ID
|
263 |
+
));
|
264 |
+
|
265 |
+
// Make sure that we have WP Error
|
266 |
+
$this->assertEquals(
|
267 |
+
$response->get_error_message(),
|
268 |
+
'Direct access is not allowed. Follow the provided redirect rule.'
|
269 |
+
);
|
270 |
+
|
271 |
+
$this->assertEquals(array(
|
272 |
+
'location' => get_page_link(AAM_UNITTEST_PAGE_ID),
|
273 |
+
'status' => 301
|
274 |
+
), $response->get_error_data());
|
275 |
+
}
|
276 |
+
|
277 |
+
/**
|
278 |
+
* Test that REDIRECTED to URL option is working as expected
|
279 |
+
*
|
280 |
+
* @return void
|
281 |
+
*
|
282 |
+
* @access public
|
283 |
+
* @version 6.0.0
|
284 |
+
*/
|
285 |
+
public function testRedirectURLOption()
|
286 |
+
{
|
287 |
+
$user = AAM::getUser();
|
288 |
+
$object = $user->getObject(
|
289 |
+
AAM_Core_Object_Post::OBJECT_TYPE, AAM_UNITTEST_POST_ID
|
290 |
+
);
|
291 |
+
|
292 |
+
// Check if save returns positive result
|
293 |
+
$this->assertTrue($object->updateOptionItem('redirected', array(
|
294 |
+
'enabled' => true,
|
295 |
+
'type' => 'url',
|
296 |
+
'destination' => 'https://aamplugin.com',
|
297 |
+
'httpCode' => 307
|
298 |
+
))->save());
|
299 |
+
|
300 |
+
// Reset all internal cache
|
301 |
+
$this->_resetSubjects();
|
302 |
+
|
303 |
+
$service = AAM_Service_Content::getInstance();
|
304 |
+
$response = $service->isAuthorizedToReadPost($user->getObject(
|
305 |
+
AAM_Core_Object_Post::OBJECT_TYPE, AAM_UNITTEST_POST_ID
|
306 |
+
));
|
307 |
+
|
308 |
+
// Make sure that we have WP Error
|
309 |
+
$this->assertEquals(
|
310 |
+
$response->get_error_message(),
|
311 |
+
'Direct access is not allowed. Follow the provided redirect rule.'
|
312 |
+
);
|
313 |
+
|
314 |
+
$this->assertEquals(array(
|
315 |
+
'location' => 'https://aamplugin.com',
|
316 |
+
'status' => 307
|
317 |
+
), $response->get_error_data());
|
318 |
+
}
|
319 |
+
|
320 |
+
/**
|
321 |
+
* Test that REDIRECTED to PHP Callback option is working as expected
|
322 |
+
*
|
323 |
+
* @return void
|
324 |
+
*
|
325 |
+
* @access public
|
326 |
+
* @version 6.0.0
|
327 |
+
*/
|
328 |
+
public function testRedirectCallbackOption()
|
329 |
+
{
|
330 |
+
$user = AAM::getUser();
|
331 |
+
$object = $user->getObject(
|
332 |
+
AAM_Core_Object_Post::OBJECT_TYPE, AAM_UNITTEST_POST_ID
|
333 |
+
);
|
334 |
+
|
335 |
+
// Check if save returns positive result
|
336 |
+
$this->assertTrue($object->updateOptionItem('redirected', array(
|
337 |
+
'enabled' => true,
|
338 |
+
'type' => 'callback',
|
339 |
+
// WordPress core strips slashes, so we have to double slash all this
|
340 |
+
'destination' => 'AAM\\UnitTest\\Service\\Content\\Callback::redirectCallback',
|
341 |
+
'httpCode' => 310
|
342 |
+
))->save());
|
343 |
+
|
344 |
+
// Reset all internal cache
|
345 |
+
$this->_resetSubjects();
|
346 |
+
|
347 |
+
$service = AAM_Service_Content::getInstance();
|
348 |
+
$response = $service->isAuthorizedToReadPost($user->getObject(
|
349 |
+
AAM_Core_Object_Post::OBJECT_TYPE, AAM_UNITTEST_POST_ID
|
350 |
+
));
|
351 |
+
|
352 |
+
// Make sure that we have WP Error
|
353 |
+
$this->assertEquals(
|
354 |
+
$response->get_error_message(),
|
355 |
+
'Direct access is not allowed. Follow the provided redirect rule.'
|
356 |
+
);
|
357 |
+
|
358 |
+
$this->assertEquals(array(
|
359 |
+
'location' => Callback::REDIRECT_URL,
|
360 |
+
'status' => 310
|
361 |
+
), $response->get_error_data());
|
362 |
+
}
|
363 |
+
|
364 |
+
/**
|
365 |
+
* Test PASSWORD PROTECTED option
|
366 |
+
*
|
367 |
+
* @return void
|
368 |
+
*
|
369 |
+
* @access public
|
370 |
+
* @version 6.0.0
|
371 |
+
*/
|
372 |
+
public function testProtectedOption()
|
373 |
+
{
|
374 |
+
$user = AAM::getUser();
|
375 |
+
$object = $user->getObject(
|
376 |
+
AAM_Core_Object_Post::OBJECT_TYPE, AAM_UNITTEST_POST_ID
|
377 |
+
);
|
378 |
+
|
379 |
+
// Check if save returns positive result
|
380 |
+
$this->assertTrue($object->updateOptionItem('protected', array(
|
381 |
+
'enabled' => true,
|
382 |
+
'password' => '123456'
|
383 |
+
))->save());
|
384 |
+
|
385 |
+
// Reset all internal cache
|
386 |
+
$this->_resetSubjects();
|
387 |
+
|
388 |
+
// Get post
|
389 |
+
$post = $user->getObject(
|
390 |
+
AAM_Core_Object_Post::OBJECT_TYPE, AAM_UNITTEST_POST_ID
|
391 |
+
);
|
392 |
+
|
393 |
+
// Verify that password is required
|
394 |
+
$this->assertTrue(
|
395 |
+
apply_filters('post_password_required', false, get_post(AAM_UNITTEST_POST_ID))
|
396 |
+
);
|
397 |
+
|
398 |
+
// Verify that password is not required when explicitly provided
|
399 |
+
$this->assertTrue(
|
400 |
+
AAM_Service_Content::getInstance()->checkPostPassword($post, '123456')
|
401 |
+
);
|
402 |
+
|
403 |
+
// Test that password is required when incorrect password is provided
|
404 |
+
$this->assertEquals(
|
405 |
+
'WP_Error',
|
406 |
+
get_class(AAM_Service_Content::getInstance()->checkPostPassword($post, '654321'))
|
407 |
+
);
|
408 |
+
}
|
409 |
+
|
410 |
+
/**
|
411 |
+
* Test PASSWORD PROTECTED option with passed cookie
|
412 |
+
*
|
413 |
+
* @return void
|
414 |
+
*
|
415 |
+
* @access public
|
416 |
+
* @version 6.0.0
|
417 |
+
*/
|
418 |
+
public function testProtectedWithCookieOption()
|
419 |
+
{
|
420 |
+
$user = AAM::getUser();
|
421 |
+
$object = $user->getObject(
|
422 |
+
AAM_Core_Object_Post::OBJECT_TYPE, AAM_UNITTEST_POST_ID
|
423 |
+
);
|
424 |
+
|
425 |
+
// Check if save returns positive result
|
426 |
+
$this->assertTrue($object->updateOptionItem('protected', array(
|
427 |
+
'enabled' => true,
|
428 |
+
'password' => '123456'
|
429 |
+
))->save());
|
430 |
+
|
431 |
+
// Reset all internal cache
|
432 |
+
$this->_resetSubjects();
|
433 |
+
|
434 |
+
// Get post
|
435 |
+
$post = $user->getObject(
|
436 |
+
AAM_Core_Object_Post::OBJECT_TYPE, AAM_UNITTEST_POST_ID
|
437 |
+
);
|
438 |
+
|
439 |
+
// Verify that password is required
|
440 |
+
$this->assertTrue(
|
441 |
+
apply_filters('post_password_required', false, get_post(AAM_UNITTEST_POST_ID))
|
442 |
+
);
|
443 |
+
|
444 |
+
// Generate cookie
|
445 |
+
$hasher = AAM_Core_API::prepareHasher();
|
446 |
+
$_COOKIE['wp-postpass_' . COOKIEHASH] = $hasher->HashPassword('123456');
|
447 |
+
|
448 |
+
// Verify that password is not required when explicitly provided
|
449 |
+
$this->assertTrue(
|
450 |
+
AAM_Service_Content::getInstance()->checkPostPassword($post)
|
451 |
+
);
|
452 |
+
|
453 |
+
// Test that password is required when incorrect password is provided
|
454 |
+
$_COOKIE['wp-postpass_' . COOKIEHASH] = $hasher->HashPassword('654321');
|
455 |
+
$this->assertEquals(
|
456 |
+
'WP_Error',
|
457 |
+
get_class(AAM_Service_Content::getInstance()->checkPostPassword($post))
|
458 |
+
);
|
459 |
+
|
460 |
+
// Reset
|
461 |
+
unset($_COOKIE['wp-postpass_' . COOKIEHASH]);
|
462 |
+
}
|
463 |
+
|
464 |
+
/**
|
465 |
+
* Test CEASED option
|
466 |
+
*
|
467 |
+
* @return void
|
468 |
+
*
|
469 |
+
* @access public
|
470 |
+
* @version 6.0.0
|
471 |
+
*/
|
472 |
+
public function testCeasedOption()
|
473 |
+
{
|
474 |
+
// Hide the post
|
475 |
+
$user = AAM::getUser();
|
476 |
+
$object = $user->getObject(
|
477 |
+
AAM_Core_Object_Post::OBJECT_TYPE, AAM_UNITTEST_POST_ID
|
478 |
+
);
|
479 |
+
|
480 |
+
// Check if save returns positive result
|
481 |
+
$this->assertTrue($object->updateOptionItem('ceased', array(
|
482 |
+
'enabled' => true,
|
483 |
+
'after' => '08/01/2019, 4:37 pm'
|
484 |
+
))->save());
|
485 |
+
|
486 |
+
// Reset all internal cache
|
487 |
+
$this->_resetSubjects();
|
488 |
+
|
489 |
+
// Get post
|
490 |
+
$post = $user->getObject(
|
491 |
+
AAM_Core_Object_Post::OBJECT_TYPE, AAM_UNITTEST_POST_ID
|
492 |
+
);
|
493 |
+
|
494 |
+
// Verify that access to the post is expired
|
495 |
+
$error = AAM_Service_Content::getInstance()->checkPostExpiration($post);
|
496 |
+
|
497 |
+
$this->assertEquals('WP_Error', get_class($error));
|
498 |
+
$this->assertEquals(
|
499 |
+
'User is unauthorized to access this post. Access Expired.',
|
500 |
+
$error->get_error_message()
|
501 |
+
);
|
502 |
+
|
503 |
+
// Test that password is required when incorrect password is provided
|
504 |
+
$this->assertEquals(
|
505 |
+
'WP_Error',
|
506 |
+
get_class(AAM_Service_Content::getInstance()->isAuthorizedToReadPost($post))
|
507 |
+
);
|
508 |
+
}
|
509 |
+
|
510 |
+
/**
|
511 |
+
* Test that user does not have the ability to edit a post
|
512 |
+
*
|
513 |
+
* @return void
|
514 |
+
*
|
515 |
+
* @access public
|
516 |
+
* @version 6.0.0
|
517 |
+
*/
|
518 |
+
public function testEditOption()
|
519 |
+
{
|
520 |
+
$user = AAM::getUser();
|
521 |
+
$object = $user->getObject(
|
522 |
+
AAM_Core_Object_Post::OBJECT_TYPE, AAM_UNITTEST_POST_ID
|
523 |
+
);
|
524 |
+
|
525 |
+
// Verify that editing is allowed for a specific post
|
526 |
+
$this->assertTrue(current_user_can('edit_post', AAM_UNITTEST_POST_ID));
|
527 |
+
|
528 |
+
// Check if save returns positive result
|
529 |
+
$this->assertTrue($object->updateOptionItem('edit', true)->save());
|
530 |
+
|
531 |
+
// Reset all internal cache
|
532 |
+
$this->_resetSubjects();
|
533 |
+
|
534 |
+
// Verify that user is no longer allowed to edit a post
|
535 |
+
$this->assertFalse(current_user_can('edit_post', AAM_UNITTEST_POST_ID));
|
536 |
+
}
|
537 |
+
|
538 |
+
/**
|
539 |
+
* Test that user does not have the ability to delete a post
|
540 |
+
*
|
541 |
+
* @return void
|
542 |
+
*
|
543 |
+
* @access public
|
544 |
+
* @version 6.0.0
|
545 |
+
*/
|
546 |
+
public function testDeleteOption()
|
547 |
+
{
|
548 |
+
$user = AAM::getUser();
|
549 |
+
$object = $user->getObject(
|
550 |
+
AAM_Core_Object_Post::OBJECT_TYPE, AAM_UNITTEST_POST_ID
|
551 |
+
);
|
552 |
+
|
553 |
+
// Verify that deletion is allowed for a specific post
|
554 |
+
$this->assertTrue(current_user_can('delete_post', AAM_UNITTEST_POST_ID));
|
555 |
+
|
556 |
+
// Check if save returns positive result
|
557 |
+
$this->assertTrue($object->updateOptionItem('delete', true)->save());
|
558 |
+
|
559 |
+
// Reset all internal cache
|
560 |
+
$this->_resetSubjects();
|
561 |
+
|
562 |
+
// Verify that user is no longer allowed to delete a post
|
563 |
+
$this->assertFalse(current_user_can('delete_post', AAM_UNITTEST_POST_ID));
|
564 |
+
}
|
565 |
+
|
566 |
+
/**
|
567 |
+
* Test that user does not have the ability to publish a post
|
568 |
+
*
|
569 |
+
* @return void
|
570 |
+
*
|
571 |
+
* @access public
|
572 |
+
* @version 6.0.0
|
573 |
+
*/
|
574 |
+
public function testPublishOption()
|
575 |
+
{
|
576 |
+
global $post;
|
577 |
+
|
578 |
+
$user = AAM::getUser();
|
579 |
+
$object = $user->getObject(
|
580 |
+
AAM_Core_Object_Post::OBJECT_TYPE, AAM_UNITTEST_POST_ID
|
581 |
+
);
|
582 |
+
|
583 |
+
// Force global post
|
584 |
+
$post = get_post(AAM_UNITTEST_POST_ID);
|
585 |
+
|
586 |
+
// Verify that publishing is allowed for a specific post
|
587 |
+
$this->assertTrue(current_user_can('publish_post', AAM_UNITTEST_POST_ID));
|
588 |
+
|
589 |
+
// Check if save returns positive result
|
590 |
+
$this->assertTrue($object->updateOptionItem('publish', true)->save());
|
591 |
+
|
592 |
+
// Reset all internal cache
|
593 |
+
$this->_resetSubjects();
|
594 |
+
|
595 |
+
// Verify that user is no longer allowed to publish a post
|
596 |
+
$this->assertFalse(current_user_can('publish_post', AAM_UNITTEST_POST_ID));
|
597 |
+
|
598 |
+
// Reset to default the global state
|
599 |
+
unset($post);
|
600 |
+
}
|
601 |
+
|
602 |
+
}
|
tests/Service/Content/SingleRoleInheritanceTest.php
ADDED
@@ -0,0 +1,221 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
/**
|
4 |
+
* ======================================================================
|
5 |
+
* LICENSE: This file is subject to the terms and conditions defined in *
|
6 |
+
* file 'license.txt', which is part of this source code package. *
|
7 |
+
* ======================================================================
|
8 |
+
*/
|
9 |
+
|
10 |
+
namespace AAM\UnitTest\Service\Content;
|
11 |
+
|
12 |
+
use AAM,
|
13 |
+
AAM_Core_Object_Post,
|
14 |
+
PHPUnit\Framework\TestCase,
|
15 |
+
AAM\UnitTest\Libs\ResetTrait,
|
16 |
+
AAM\UnitTest\Libs\AuthUserTrait;
|
17 |
+
|
18 |
+
/**
|
19 |
+
* Test AAM access settings inheritance mechanism for the Content (Posts & Terms)
|
20 |
+
* service
|
21 |
+
*
|
22 |
+
* @author Vasyl Martyniuk <vasyl@vasyltech.com>
|
23 |
+
* @version 6.0.0
|
24 |
+
*/
|
25 |
+
class SingleRoleInheritanceTest extends TestCase
|
26 |
+
{
|
27 |
+
use ResetTrait,
|
28 |
+
AuthUserTrait;
|
29 |
+
|
30 |
+
/**
|
31 |
+
* Test to insure that access settings are stored property on the User level
|
32 |
+
*
|
33 |
+
* @return void
|
34 |
+
*
|
35 |
+
* @access public
|
36 |
+
* @version 6.0.0
|
37 |
+
*/
|
38 |
+
public function testSaveUserLevelOption()
|
39 |
+
{
|
40 |
+
$user = AAM::getUser();
|
41 |
+
$object = $user->getObject(
|
42 |
+
AAM_Core_Object_Post::OBJECT_TYPE, AAM_UNITTEST_POST_ID
|
43 |
+
);
|
44 |
+
|
45 |
+
// Check if save returns positive result
|
46 |
+
$this->assertTrue($object->updateOptionItem('hidden', true)->save());
|
47 |
+
|
48 |
+
// Read from the database saved values and assert that we have
|
49 |
+
// Array (
|
50 |
+
// hidden => true
|
51 |
+
// )
|
52 |
+
$option = $user->readOption(
|
53 |
+
AAM_Core_Object_Post::OBJECT_TYPE, AAM_UNITTEST_POST_ID . '|post'
|
54 |
+
);
|
55 |
+
|
56 |
+
$this->assertSame(array('hidden' => true), $option);
|
57 |
+
}
|
58 |
+
|
59 |
+
/**
|
60 |
+
* Test that access settings are inherited from the parent role property
|
61 |
+
*
|
62 |
+
* This test is designed to verify that access settings are propagated property
|
63 |
+
* when there is only one role assigned to a user.
|
64 |
+
*
|
65 |
+
* @return void
|
66 |
+
*
|
67 |
+
* @access public
|
68 |
+
* @version 6.0.0
|
69 |
+
*/
|
70 |
+
public function testInheritanceFromSingleRole()
|
71 |
+
{
|
72 |
+
$user = AAM::getUser();
|
73 |
+
$parent = $user->getParent();
|
74 |
+
$object = $parent->getObject(
|
75 |
+
AAM_Core_Object_Post::OBJECT_TYPE, AAM_UNITTEST_POST_ID
|
76 |
+
);
|
77 |
+
|
78 |
+
// Make sure that we have parent role defined
|
79 |
+
$this->assertEquals('AAM_Core_Subject_Role', get_class($parent));
|
80 |
+
|
81 |
+
// Save access settings for the role and make sure they are saved property
|
82 |
+
// Check if save returns positive result
|
83 |
+
$this->assertTrue($object->updateOptionItem('hidden', true)->save());
|
84 |
+
|
85 |
+
// Read from the database saved values and assert that we have
|
86 |
+
// Array (
|
87 |
+
// hidden => true
|
88 |
+
// )
|
89 |
+
$option = $parent->readOption(
|
90 |
+
AAM_Core_Object_Post::OBJECT_TYPE, AAM_UNITTEST_POST_ID . '|post'
|
91 |
+
);
|
92 |
+
$this->assertSame(array('hidden' => true), $option);
|
93 |
+
|
94 |
+
// Finally verify that access settings are propagated property to the User
|
95 |
+
// Level
|
96 |
+
$post = $user->getObject(
|
97 |
+
AAM_Core_Object_Post::OBJECT_TYPE, AAM_UNITTEST_POST_ID
|
98 |
+
);
|
99 |
+
$this->assertSame(array('hidden' => true), $post->getOption());
|
100 |
+
}
|
101 |
+
|
102 |
+
/**
|
103 |
+
* Test that access settings are propagated and merged properly
|
104 |
+
*
|
105 |
+
* The test is designed to verify that access settings are propagated properly
|
106 |
+
* from the parent role and merged well with explicitly defined access settings on
|
107 |
+
* the User level.
|
108 |
+
*
|
109 |
+
* The expected result is to have combined array of access settings from the parent
|
110 |
+
* role and specific user.
|
111 |
+
*
|
112 |
+
* @return void
|
113 |
+
*
|
114 |
+
* @access public
|
115 |
+
* @version 6.0.0
|
116 |
+
*/
|
117 |
+
public function testInheritanceMergeFromSingleRole()
|
118 |
+
{
|
119 |
+
$user = AAM::getUser();
|
120 |
+
$parent = $user->getParent();
|
121 |
+
$object = $parent->getObject(
|
122 |
+
AAM_Core_Object_Post::OBJECT_TYPE, AAM_UNITTEST_POST_ID
|
123 |
+
);
|
124 |
+
|
125 |
+
// Save access settings for the role and make sure they are saved property
|
126 |
+
// Check if save returns positive result
|
127 |
+
$this->assertTrue($object->updateOptionItem('hidden', true)->save());
|
128 |
+
|
129 |
+
// Save access setting for the user and make sure they are saved property
|
130 |
+
$post = $user->getObject(
|
131 |
+
AAM_Core_Object_Post::OBJECT_TYPE, AAM_UNITTEST_POST_ID, true
|
132 |
+
);
|
133 |
+
$this->assertTrue($post->updateOptionItem('comment', false)->save());
|
134 |
+
|
135 |
+
// Reset cache and try to kick-in the inheritance mechanism
|
136 |
+
$this->_resetSubjects();
|
137 |
+
|
138 |
+
$post = $user->getObject(
|
139 |
+
AAM_Core_Object_Post::OBJECT_TYPE, AAM_UNITTEST_POST_ID
|
140 |
+
);
|
141 |
+
$this->assertSame(
|
142 |
+
array('hidden' => true, 'comment' => false),
|
143 |
+
$post->getOption()
|
144 |
+
);
|
145 |
+
}
|
146 |
+
|
147 |
+
/**
|
148 |
+
* Test that the full inheritance mechanism is working as expected
|
149 |
+
*
|
150 |
+
* Make sure that access settings are propagated and merged properly from the top
|
151 |
+
* (Default Level) to the bottom (User Level).
|
152 |
+
*
|
153 |
+
* @return void
|
154 |
+
*
|
155 |
+
* @access public
|
156 |
+
* @version 6.0.0
|
157 |
+
*/
|
158 |
+
public function testFullInheritanceChainSingeRole()
|
159 |
+
{
|
160 |
+
$user = AAM::getUser();
|
161 |
+
$role = $user->getParent();
|
162 |
+
$default = $role->getParent();
|
163 |
+
|
164 |
+
$userPost = $user->getObject(AAM_Core_Object_Post::OBJECT_TYPE, AAM_UNITTEST_POST_ID, true);
|
165 |
+
$rolePost = $role->getObject(AAM_Core_Object_Post::OBJECT_TYPE, AAM_UNITTEST_POST_ID, true);
|
166 |
+
$defaultPost = $default->getObject(AAM_Core_Object_Post::OBJECT_TYPE, AAM_UNITTEST_POST_ID, true);
|
167 |
+
|
168 |
+
// Save access settings for all subjects
|
169 |
+
$this->assertTrue($userPost->updateOptionItem('hidden', true)->save());
|
170 |
+
$this->assertTrue($rolePost->updateOptionItem('comment', true)->save());
|
171 |
+
$this->assertTrue($defaultPost->updateOptionItem('restricted', true)->save());
|
172 |
+
|
173 |
+
// Reset cache and try to kick-in the inheritance mechanism
|
174 |
+
$this->_resetSubjects();
|
175 |
+
|
176 |
+
// All settings has to be merged into one array
|
177 |
+
$post = $user->getObject(AAM_Core_Object_Post::OBJECT_TYPE, AAM_UNITTEST_POST_ID);
|
178 |
+
$this->assertSame(
|
179 |
+
array(
|
180 |
+
'restricted' => true,
|
181 |
+
'comment' => true,
|
182 |
+
'hidden' => true
|
183 |
+
),
|
184 |
+
$post->getOption()
|
185 |
+
);
|
186 |
+
}
|
187 |
+
|
188 |
+
/**
|
189 |
+
* Test that access settings overwrite works as expected
|
190 |
+
*
|
191 |
+
* The expected result is lower Access Level overwrite access settings from the
|
192 |
+
* higher Access Level.
|
193 |
+
*
|
194 |
+
* @return void
|
195 |
+
*
|
196 |
+
* @access public
|
197 |
+
* @version 6.0.0
|
198 |
+
*/
|
199 |
+
public function testInheritanceOverrideForSingleRole()
|
200 |
+
{
|
201 |
+
$user = AAM::getUser();
|
202 |
+
$parent = $user->getParent();
|
203 |
+
|
204 |
+
$object = $parent->getObject(AAM_Core_Object_Post::OBJECT_TYPE, AAM_UNITTEST_POST_ID);
|
205 |
+
|
206 |
+
// Save access settings for the role and make sure they are saved property
|
207 |
+
// Check if save returns positive result
|
208 |
+
$this->assertTrue($object->updateOptionItem('hidden', true)->save());
|
209 |
+
|
210 |
+
// Save access setting for the user and make sure they are saved property
|
211 |
+
$post = $user->getObject(AAM_Core_Object_Post::OBJECT_TYPE, AAM_UNITTEST_POST_ID, true);
|
212 |
+
$this->assertTrue($post->updateOptionItem('hidden', false)->save());
|
213 |
+
|
214 |
+
// Reset cache and try to kick-in the inheritance mechanism
|
215 |
+
$this->_resetSubjects();
|
216 |
+
|
217 |
+
$post = $user->getObject(AAM_Core_Object_Post::OBJECT_TYPE, AAM_UNITTEST_POST_ID);
|
218 |
+
$this->assertSame(array('hidden' => false), $post->getOption());
|
219 |
+
}
|
220 |
+
|
221 |
+
}
|
tests/Service/Content/VisitorAccessControlTest.php
ADDED
@@ -0,0 +1,432 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
/**
|
4 |
+
* ======================================================================
|
5 |
+
* LICENSE: This file is subject to the terms and conditions defined in *
|
6 |
+
* file 'license.txt', which is part of this source code package. *
|
7 |
+
* ======================================================================
|
8 |
+
*/
|
9 |
+
|
10 |
+
namespace AAM\UnitTest\Service\Content;
|
11 |
+
|
12 |
+
use AAM,
|
13 |
+
AAM_Core_API,
|
14 |
+
AAM_Service_Content,
|
15 |
+
AAM_Core_Object_Post,
|
16 |
+
PHPUnit\Framework\TestCase,
|
17 |
+
AAM\UnitTest\Libs\ResetTrait;
|
18 |
+
|
19 |
+
/**
|
20 |
+
* Test that content access settings are applied and used properly with WordPress core
|
21 |
+
* for the unauthorized user
|
22 |
+
*
|
23 |
+
* @author Vasyl Martyniuk <vasyl@vasyltech.com>
|
24 |
+
* @version 6.0.0
|
25 |
+
*/
|
26 |
+
class VisitorAccessControlTest extends TestCase
|
27 |
+
{
|
28 |
+
use ResetTrait;
|
29 |
+
|
30 |
+
/**
|
31 |
+
* Test that visitor is not allowed to access the post when access settings
|
32 |
+
* are set so on the Visitor Level
|
33 |
+
*
|
34 |
+
* @return void
|
35 |
+
*
|
36 |
+
* @access public
|
37 |
+
* @version 6.0.0
|
38 |
+
*/
|
39 |
+
public function testRestrictedOption()
|
40 |
+
{
|
41 |
+
$user = AAM::getUser();
|
42 |
+
$object = $user->getObject(
|
43 |
+
AAM_Core_Object_Post::OBJECT_TYPE, AAM_UNITTEST_POST_ID
|
44 |
+
);
|
45 |
+
|
46 |
+
// Check if save returns positive result
|
47 |
+
$this->assertTrue($object->updateOptionItem('restricted', true)->save());
|
48 |
+
|
49 |
+
// Reset all internal cache
|
50 |
+
$this->_resetSubjects();
|
51 |
+
|
52 |
+
$post = $user->getObject(
|
53 |
+
AAM_Core_Object_Post::OBJECT_TYPE, AAM_UNITTEST_POST_ID
|
54 |
+
);
|
55 |
+
|
56 |
+
// Make sure that AAM API returns correct result
|
57 |
+
$this->assertTrue($post->is('restricted'));
|
58 |
+
|
59 |
+
// Check that current user is not allowed to read_post
|
60 |
+
$this->assertFalse(current_user_can('read_post', AAM_UNITTEST_POST_ID));
|
61 |
+
}
|
62 |
+
|
63 |
+
/**
|
64 |
+
* Test that visitor does not have the ability to see hidden post
|
65 |
+
*
|
66 |
+
* @return void
|
67 |
+
*
|
68 |
+
* @access public
|
69 |
+
* @version 6.0.0
|
70 |
+
*/
|
71 |
+
public function testHiddenOption()
|
72 |
+
{
|
73 |
+
$posts = get_posts(array(
|
74 |
+
'post_type' => 'post',
|
75 |
+
'fields' => 'ids',
|
76 |
+
'suppress_filters' => false
|
77 |
+
));
|
78 |
+
|
79 |
+
// First, confirm that post is in the array of posts
|
80 |
+
$this->assertTrue(in_array(AAM_UNITTEST_POST_ID, $posts));
|
81 |
+
|
82 |
+
// Hide the post
|
83 |
+
$user = AAM::getUser();
|
84 |
+
$object = $user->getObject(
|
85 |
+
AAM_Core_Object_Post::OBJECT_TYPE, AAM_UNITTEST_POST_ID
|
86 |
+
);
|
87 |
+
|
88 |
+
// Check if save returns positive result
|
89 |
+
$this->assertTrue($object->updateOptionItem('hidden', true)->save());
|
90 |
+
|
91 |
+
// Reset all internal cache
|
92 |
+
$this->_resetSubjects();
|
93 |
+
|
94 |
+
// Verify that post is no longer in the list of posts
|
95 |
+
$posts = get_posts(array(
|
96 |
+
'post_type' => 'post',
|
97 |
+
'fields' => 'ids',
|
98 |
+
'suppress_filters' => false
|
99 |
+
));
|
100 |
+
|
101 |
+
// First, confirm that post is in the array of posts
|
102 |
+
$this->assertFalse(in_array(AAM_UNITTEST_POST_ID, $posts));
|
103 |
+
}
|
104 |
+
|
105 |
+
/**
|
106 |
+
* Test that content is limited with the Teaser message and enabled excerpt
|
107 |
+
* shortcode
|
108 |
+
*
|
109 |
+
* @return void
|
110 |
+
*
|
111 |
+
* @access public
|
112 |
+
* @version 6.0.0
|
113 |
+
*/
|
114 |
+
public function testTeaserMessageOption()
|
115 |
+
{
|
116 |
+
$user = AAM::getUser();
|
117 |
+
$object = $user->getObject(
|
118 |
+
AAM_Core_Object_Post::OBJECT_TYPE, AAM_UNITTEST_POST_ID
|
119 |
+
);
|
120 |
+
|
121 |
+
// Check if save returns positive result
|
122 |
+
$this->assertTrue($object->updateOptionItem('teaser', array(
|
123 |
+
'enabled' => true,
|
124 |
+
'message' => 'Test teaser with [excerpt]'
|
125 |
+
))->save());
|
126 |
+
|
127 |
+
// Reset all internal cache
|
128 |
+
$this->_resetSubjects();
|
129 |
+
|
130 |
+
// Confirm that teaser message is returned instead of actual content
|
131 |
+
$GLOBALS['post'] = AAM_UNITTEST_POST_ID;
|
132 |
+
ob_start();
|
133 |
+
the_content();
|
134 |
+
$this->assertSame(
|
135 |
+
ob_get_contents(), 'Test teaser with ' . $object->post_excerpt
|
136 |
+
);
|
137 |
+
ob_end_clean();
|
138 |
+
}
|
139 |
+
|
140 |
+
/**
|
141 |
+
* Test that visitor does not have the ability to comment on a post
|
142 |
+
*
|
143 |
+
* @return void
|
144 |
+
*
|
145 |
+
* @access public
|
146 |
+
* @version 6.0.0
|
147 |
+
*/
|
148 |
+
public function testCommentingOption()
|
149 |
+
{
|
150 |
+
$user = AAM::getUser();
|
151 |
+
$object = $user->getObject(
|
152 |
+
AAM_Core_Object_Post::OBJECT_TYPE, AAM_UNITTEST_POST_ID
|
153 |
+
);
|
154 |
+
|
155 |
+
// Verify that commenting for this feature is set as open
|
156 |
+
$this->assertEquals($object->comment_status, 'open');
|
157 |
+
|
158 |
+
// Check if save returns positive result
|
159 |
+
$this->assertTrue($object->updateOptionItem('comment', true)->save());
|
160 |
+
|
161 |
+
// Reset all internal cache
|
162 |
+
$this->_resetSubjects();
|
163 |
+
|
164 |
+
// First, confirm that post is in the array of posts
|
165 |
+
$this->assertFalse(comments_open(AAM_UNITTEST_POST_ID));
|
166 |
+
}
|
167 |
+
|
168 |
+
/**
|
169 |
+
* Test that REDIRECTED to Existing Page option is working as expected
|
170 |
+
*
|
171 |
+
* @return void
|
172 |
+
*
|
173 |
+
* @access public
|
174 |
+
* @version 6.0.0
|
175 |
+
*/
|
176 |
+
public function testRedirectPageOption()
|
177 |
+
{
|
178 |
+
$user = AAM::getUser();
|
179 |
+
$object = $user->getObject(
|
180 |
+
AAM_Core_Object_Post::OBJECT_TYPE, AAM_UNITTEST_POST_ID
|
181 |
+
);
|
182 |
+
|
183 |
+
// Check if save returns positive result
|
184 |
+
$this->assertTrue($object->updateOptionItem('redirected', array(
|
185 |
+
'enabled' => true,
|
186 |
+
'type' => 'page',
|
187 |
+
'destination' => AAM_UNITTEST_PAGE_ID,
|
188 |
+
'httpCode' => 301
|
189 |
+
))->save());
|
190 |
+
|
191 |
+
// Reset all internal cache
|
192 |
+
$this->_resetSubjects();
|
193 |
+
|
194 |
+
$service = AAM_Service_Content::getInstance();
|
195 |
+
$response = $service->isAuthorizedToReadPost($user->getObject(
|
196 |
+
AAM_Core_Object_Post::OBJECT_TYPE, AAM_UNITTEST_POST_ID
|
197 |
+
));
|
198 |
+
|
199 |
+
// Make sure that we have WP Error
|
200 |
+
$this->assertEquals(
|
201 |
+
$response->get_error_message(),
|
202 |
+
'Direct access is not allowed. Follow the provided redirect rule.'
|
203 |
+
);
|
204 |
+
|
205 |
+
$this->assertEquals(array(
|
206 |
+
'location' => get_page_link(AAM_UNITTEST_PAGE_ID),
|
207 |
+
'status' => 301
|
208 |
+
), $response->get_error_data());
|
209 |
+
}
|
210 |
+
|
211 |
+
/**
|
212 |
+
* Test that REDIRECTED to URL option is working as expected
|
213 |
+
*
|
214 |
+
* @return void
|
215 |
+
*
|
216 |
+
* @access public
|
217 |
+
* @version 6.0.0
|
218 |
+
*/
|
219 |
+
public function testRedirectURLOption()
|
220 |
+
{
|
221 |
+
$user = AAM::getUser();
|
222 |
+
$object = $user->getObject(
|
223 |
+
AAM_Core_Object_Post::OBJECT_TYPE, AAM_UNITTEST_POST_ID
|
224 |
+
);
|
225 |
+
|
226 |
+
// Check if save returns positive result
|
227 |
+
$this->assertTrue($object->updateOptionItem('redirected', array(
|
228 |
+
'enabled' => true,
|
229 |
+
'type' => 'url',
|
230 |
+
'destination' => 'https://aamplugin.com',
|
231 |
+
'httpCode' => 307
|
232 |
+
))->save());
|
233 |
+
|
234 |
+
// Reset all internal cache
|
235 |
+
$this->_resetSubjects();
|
236 |
+
|
237 |
+
$service = AAM_Service_Content::getInstance();
|
238 |
+
$response = $service->isAuthorizedToReadPost($user->getObject(
|
239 |
+
AAM_Core_Object_Post::OBJECT_TYPE, AAM_UNITTEST_POST_ID
|
240 |
+
));
|
241 |
+
|
242 |
+
// Make sure that we have WP Error
|
243 |
+
$this->assertEquals(
|
244 |
+
$response->get_error_message(),
|
245 |
+
'Direct access is not allowed. Follow the provided redirect rule.'
|
246 |
+
);
|
247 |
+
|
248 |
+
$this->assertEquals(array(
|
249 |
+
'location' => 'https://aamplugin.com',
|
250 |
+
'status' => 307
|
251 |
+
), $response->get_error_data());
|
252 |
+
}
|
253 |
+
|
254 |
+
/**
|
255 |
+
* Test that REDIRECTED to PHP Callback option is working as expected
|
256 |
+
*
|
257 |
+
* @return void
|
258 |
+
*
|
259 |
+
* @access public
|
260 |
+
* @version 6.0.0
|
261 |
+
*/
|
262 |
+
public function testRedirectCallbackOption()
|
263 |
+
{
|
264 |
+
$user = AAM::getUser();
|
265 |
+
$object = $user->getObject(
|
266 |
+
AAM_Core_Object_Post::OBJECT_TYPE, AAM_UNITTEST_POST_ID
|
267 |
+
);
|
268 |
+
|
269 |
+
// Check if save returns positive result
|
270 |
+
$this->assertTrue($object->updateOptionItem('redirected', array(
|
271 |
+
'enabled' => true,
|
272 |
+
'type' => 'callback',
|
273 |
+
// WordPress core strips slashes, so we have to double slash all this
|
274 |
+
'destination' => 'AAM\\UnitTest\\Service\\Content\\Callback::redirectCallback',
|
275 |
+
'httpCode' => 310
|
276 |
+
))->save());
|
277 |
+
|
278 |
+
// Reset all internal cache
|
279 |
+
$this->_resetSubjects();
|
280 |
+
|
281 |
+
$service = AAM_Service_Content::getInstance();
|
282 |
+
$response = $service->isAuthorizedToReadPost($user->getObject(
|
283 |
+
AAM_Core_Object_Post::OBJECT_TYPE, AAM_UNITTEST_POST_ID
|
284 |
+
));
|
285 |
+
|
286 |
+
// Make sure that we have WP Error
|
287 |
+
$this->assertEquals(
|
288 |
+
$response->get_error_message(),
|
289 |
+
'Direct access is not allowed. Follow the provided redirect rule.'
|
290 |
+
);
|
291 |
+
|
292 |
+
$this->assertEquals(array(
|
293 |
+
'location' => Callback::REDIRECT_URL,
|
294 |
+
'status' => 310
|
295 |
+
), $response->get_error_data());
|
296 |
+
}
|
297 |
+
|
298 |
+
/**
|
299 |
+
* Test that REDIRECTED to Login Page option is working as expected
|
300 |
+
*
|
301 |
+
* @return void
|
302 |
+
*
|
303 |
+
* @access public
|
304 |
+
* @version 6.0.0
|
305 |
+
*/
|
306 |
+
public function testRedirectLoginOption()
|
307 |
+
{
|
308 |
+
$user = AAM::getUser();
|
309 |
+
$object = $user->getObject(
|
310 |
+
AAM_Core_Object_Post::OBJECT_TYPE, AAM_UNITTEST_POST_ID
|
311 |
+
);
|
312 |
+
|
313 |
+
// Check if save returns positive result
|
314 |
+
$this->assertTrue($object->updateOptionItem('redirected', array(
|
315 |
+
'enabled' => true,
|
316 |
+
'type' => 'login',
|
317 |
+
'httpCode' => 301
|
318 |
+
))->save());
|
319 |
+
|
320 |
+
// Reset all internal cache
|
321 |
+
$this->_resetSubjects();
|
322 |
+
|
323 |
+
$service = AAM_Service_Content::getInstance();
|
324 |
+
$response = $service->isAuthorizedToReadPost($user->getObject(
|
325 |
+
AAM_Core_Object_Post::OBJECT_TYPE, AAM_UNITTEST_POST_ID
|
326 |
+
));
|
327 |
+
|
328 |
+
// Make sure that we have WP Error
|
329 |
+
$this->assertEquals(
|
330 |
+
$response->get_error_message(),
|
331 |
+
'Direct access is not allowed. Follow the provided redirect rule.'
|
332 |
+
);
|
333 |
+
|
334 |
+
$this->assertEquals(array(
|
335 |
+
'location' => wp_login_url() . '?reason=restricted',
|
336 |
+
'status' => 301
|
337 |
+
), $response->get_error_data());
|
338 |
+
}
|
339 |
+
|
340 |
+
/**
|
341 |
+
* Test PASSWORD PROTECTED option
|
342 |
+
*
|
343 |
+
* @return void
|
344 |
+
*
|
345 |
+
* @access public
|
346 |
+
* @version 6.0.0
|
347 |
+
*/
|
348 |
+
public function testProtectedOption()
|
349 |
+
{
|
350 |
+
$user = AAM::getUser();
|
351 |
+
$object = $user->getObject(
|
352 |
+
AAM_Core_Object_Post::OBJECT_TYPE, AAM_UNITTEST_POST_ID
|
353 |
+
);
|
354 |
+
|
355 |
+
// Check if save returns positive result
|
356 |
+
$this->assertTrue($object->updateOptionItem('protected', array(
|
357 |
+
'enabled' => true,
|
358 |
+
'password' => '123456'
|
359 |
+
))->save());
|
360 |
+
|
361 |
+
// Reset all internal cache
|
362 |
+
$this->_resetSubjects();
|
363 |
+
|
364 |
+
// Get post
|
365 |
+
$post = $user->getObject(
|
366 |
+
AAM_Core_Object_Post::OBJECT_TYPE, AAM_UNITTEST_POST_ID
|
367 |
+
);
|
368 |
+
|
369 |
+
// Verify that password is required
|
370 |
+
$this->assertTrue(
|
371 |
+
apply_filters('post_password_required', false, get_post(AAM_UNITTEST_POST_ID))
|
372 |
+
);
|
373 |
+
|
374 |
+
// Verify that password is not required when explicitly provided
|
375 |
+
$this->assertTrue(
|
376 |
+
AAM_Service_Content::getInstance()->checkPostPassword($post, '123456')
|
377 |
+
);
|
378 |
+
|
379 |
+
// Test that password is required when incorrect password is provided
|
380 |
+
$this->assertEquals(
|
381 |
+
'WP_Error',
|
382 |
+
get_class(AAM_Service_Content::getInstance()->checkPostPassword($post, '654321'))
|
383 |
+
);
|
384 |
+
}
|
385 |
+
|
386 |
+
/**
|
387 |
+
* Test CEASED option
|
388 |
+
*
|
389 |
+
* @return void
|
390 |
+
*
|
391 |
+
* @access public
|
392 |
+
* @version 6.0.0
|
393 |
+
*/
|
394 |
+
public function testCeasedOption()
|
395 |
+
{
|
396 |
+
// Hide the post
|
397 |
+
$user = AAM::getUser();
|
398 |
+
$object = $user->getObject(
|
399 |
+
AAM_Core_Object_Post::OBJECT_TYPE, AAM_UNITTEST_POST_ID
|
400 |
+
);
|
401 |
+
|
402 |
+
// Check if save returns positive result
|
403 |
+
$this->assertTrue($object->updateOptionItem('ceased', array(
|
404 |
+
'enabled' => true,
|
405 |
+
'after' => '08/01/2019, 4:37 pm'
|
406 |
+
))->save());
|
407 |
+
|
408 |
+
// Reset all internal cache
|
409 |
+
$this->_resetSubjects();
|
410 |
+
|
411 |
+
// Get post
|
412 |
+
$post = $user->getObject(
|
413 |
+
AAM_Core_Object_Post::OBJECT_TYPE, AAM_UNITTEST_POST_ID
|
414 |
+
);
|
415 |
+
|
416 |
+
// Verify that access to the post is expired
|
417 |
+
$error = AAM_Service_Content::getInstance()->checkPostExpiration($post);
|
418 |
+
|
419 |
+
$this->assertEquals('WP_Error', get_class($error));
|
420 |
+
$this->assertEquals(
|
421 |
+
'User is unauthorized to access this post. Access Expired.',
|
422 |
+
$error->get_error_message()
|
423 |
+
);
|
424 |
+
|
425 |
+
// Test that password is required when incorrect password is provided
|
426 |
+
$this->assertEquals(
|
427 |
+
'WP_Error',
|
428 |
+
get_class(AAM_Service_Content::getInstance()->isAuthorizedToReadPost($post))
|
429 |
+
);
|
430 |
+
}
|
431 |
+
|
432 |
+
}
|
tests/Service/Core/CoreServiceTest.php
ADDED
@@ -0,0 +1,43 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
/**
|
4 |
+
* ======================================================================
|
5 |
+
* LICENSE: This file is subject to the terms and conditions defined in *
|
6 |
+
* file 'license.txt', which is part of this source code package. *
|
7 |
+
* ======================================================================
|
8 |
+
*/
|
9 |
+
|
10 |
+
namespace AAM\UnitTest\Service\Core;
|
11 |
+
|
12 |
+
use AAM,
|
13 |
+
AAM_Core_Object_Menu,
|
14 |
+
PHPUnit\Framework\TestCase,
|
15 |
+
AAM\UnitTest\Libs\ResetTrait,
|
16 |
+
AAM\UnitTest\Libs\AuthUserTrait;
|
17 |
+
|
18 |
+
/**
|
19 |
+
* Test AAM core service functionality
|
20 |
+
*
|
21 |
+
* @author Vasyl Martyniuk <vasyl@vasyltech.com>
|
22 |
+
* @version 6.0.0
|
23 |
+
*/
|
24 |
+
class CoreServiceTest extends TestCase
|
25 |
+
{
|
26 |
+
use ResetTrait,
|
27 |
+
AuthUserTrait;
|
28 |
+
|
29 |
+
/**
|
30 |
+
* Test that all AAM related labels are properly escaped to mitigate XSS
|
31 |
+
*
|
32 |
+
* @return void
|
33 |
+
*
|
34 |
+
* @access public
|
35 |
+
* @version 6.0.0
|
36 |
+
*/
|
37 |
+
public function testEscapeTranslation()
|
38 |
+
{
|
39 |
+
$escaped = __('<script>alert(1);</script>', AAM_KEY);
|
40 |
+
$this->assertEquals($escaped, '<script>alert(1);</script>');
|
41 |
+
}
|
42 |
+
|
43 |
+
}
|
tests/Service/DeniedRedirect/Callback.php
ADDED
@@ -0,0 +1,14 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
namespace AAM\UnitTest\Service\DeniedRedirect;
|
4 |
+
|
5 |
+
class Callback
|
6 |
+
{
|
7 |
+
const OUTPUT = 'Redirect Callback Output';
|
8 |
+
|
9 |
+
public static function printOutput()
|
10 |
+
{
|
11 |
+
echo self::OUTPUT;
|
12 |
+
}
|
13 |
+
|
14 |
+
}
|
tests/Service/DeniedRedirect/DeniedRedirectTest.php
ADDED
@@ -0,0 +1,189 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
/**
|
4 |
+
* ======================================================================
|
5 |
+
* LICENSE: This file is subject to the terms and conditions defined in *
|
6 |
+
* file 'license.txt', which is part of this source code package. *
|
7 |
+
* ======================================================================
|
8 |
+
*/
|
9 |
+
|
10 |
+
namespace AAM\UnitTest\Service\DeniedRedirect;
|
11 |
+
|
12 |
+
use AAM,
|
13 |
+
AAM_Core_Object_Redirect,
|
14 |
+
PHPUnit\Framework\TestCase,
|
15 |
+
AAM\UnitTest\Libs\ResetTrait;
|
16 |
+
|
17 |
+
/**
|
18 |
+
* Access Denied Redirect service
|
19 |
+
*
|
20 |
+
* @package AAM\UnitTest
|
21 |
+
* @version 6.0.0
|
22 |
+
*/
|
23 |
+
class DeniedRedirectTest extends TestCase
|
24 |
+
{
|
25 |
+
use ResetTrait;
|
26 |
+
|
27 |
+
/**
|
28 |
+
* Test default redirect which is "Access Denied" message
|
29 |
+
*
|
30 |
+
* @return void
|
31 |
+
*
|
32 |
+
* @access public
|
33 |
+
* @version 6.0.0
|
34 |
+
*/
|
35 |
+
public function testDefaultRedirect()
|
36 |
+
{
|
37 |
+
// Capture the WP Die message
|
38 |
+
ob_start();
|
39 |
+
wp_die('Restricted Access', 'aam_access_denied', array('exit' => false));
|
40 |
+
$content = ob_get_contents();
|
41 |
+
ob_end_clean();
|
42 |
+
|
43 |
+
$this->assertStringContainsString('Access Denied', $content);
|
44 |
+
}
|
45 |
+
|
46 |
+
/**
|
47 |
+
* Test custom WP Die message content
|
48 |
+
*
|
49 |
+
* @return void
|
50 |
+
*
|
51 |
+
* @access public
|
52 |
+
* @version 6.0.0
|
53 |
+
*/
|
54 |
+
public function testCustomMessageRedirect()
|
55 |
+
{
|
56 |
+
// Define custom access denied message
|
57 |
+
$redirect = AAM::getUser()->getObject(AAM_Core_Object_Redirect::OBJECT_TYPE);
|
58 |
+
$redirect->updateOptionItem('frontend.redirect.type', 'message');
|
59 |
+
$redirect->updateOptionItem('frontend.redirect.message', 'Denied by test');
|
60 |
+
|
61 |
+
$this->assertTrue($redirect->save());
|
62 |
+
|
63 |
+
// Reset all internal cache
|
64 |
+
$this->_resetSubjects();
|
65 |
+
|
66 |
+
// Capture the WP Die message
|
67 |
+
ob_start();
|
68 |
+
wp_die('Test', 'aam_access_denied', array('exit' => false));
|
69 |
+
$content = ob_get_contents();
|
70 |
+
ob_end_clean();
|
71 |
+
|
72 |
+
$this->assertStringContainsString('Denied by test', $content);
|
73 |
+
}
|
74 |
+
|
75 |
+
/**
|
76 |
+
* Test redirect to the existing page
|
77 |
+
*
|
78 |
+
* @return void
|
79 |
+
*
|
80 |
+
* @access public
|
81 |
+
* @version 6.0.0
|
82 |
+
*/
|
83 |
+
public function testExistingPageRedirect()
|
84 |
+
{
|
85 |
+
// Define custom access denied message
|
86 |
+
$redirect = AAM::getUser()->getObject(AAM_Core_Object_Redirect::OBJECT_TYPE);
|
87 |
+
$redirect->updateOptionItem('frontend.redirect.type', 'page');
|
88 |
+
$redirect->updateOptionItem('frontend.redirect.page', AAM_UNITTEST_PAGE_ID);
|
89 |
+
|
90 |
+
$this->assertTrue($redirect->save());
|
91 |
+
|
92 |
+
// Reset all internal cache
|
93 |
+
$this->_resetSubjects();
|
94 |
+
|
95 |
+
// Capture the WP Die message
|
96 |
+
ob_start();
|
97 |
+
wp_die('Access Denied', 'aam_access_denied', array('exit' => false));
|
98 |
+
ob_end_clean();
|
99 |
+
|
100 |
+
$this->assertContains('Location: ' . get_page_link(AAM_UNITTEST_PAGE_ID), xdebug_get_headers());
|
101 |
+
}
|
102 |
+
|
103 |
+
/**
|
104 |
+
* Test redirect to specified URI
|
105 |
+
*
|
106 |
+
* @return void
|
107 |
+
*
|
108 |
+
* @access public
|
109 |
+
* @version 6.0.0
|
110 |
+
*/
|
111 |
+
public function testUrlRedirect()
|
112 |
+
{
|
113 |
+
// Define custom access denied message
|
114 |
+
$redirect = AAM::getUser()->getObject(AAM_Core_Object_Redirect::OBJECT_TYPE);
|
115 |
+
$redirect->updateOptionItem('frontend.redirect.type', 'url');
|
116 |
+
$redirect->updateOptionItem('frontend.redirect.url', '/hello-world');
|
117 |
+
|
118 |
+
$this->assertTrue($redirect->save());
|
119 |
+
|
120 |
+
// Reset all internal cache
|
121 |
+
$this->_resetSubjects();
|
122 |
+
|
123 |
+
// Capture the WP Die message
|
124 |
+
ob_start();
|
125 |
+
wp_die('Access Denied', 'aam_access_denied', array('exit' => false));
|
126 |
+
ob_end_clean();
|
127 |
+
|
128 |
+
$this->assertContains('Location: /hello-world', xdebug_get_headers());
|
129 |
+
}
|
130 |
+
|
131 |
+
/**
|
132 |
+
* Test redirect to the login screen
|
133 |
+
*
|
134 |
+
* @return void
|
135 |
+
*
|
136 |
+
* @access public
|
137 |
+
* @version 6.0.0
|
138 |
+
*/
|
139 |
+
public function testLoginPageRedirect()
|
140 |
+
{
|
141 |
+
// Define custom access denied message
|
142 |
+
$redirect = AAM::getUser()->getObject(AAM_Core_Object_Redirect::OBJECT_TYPE);
|
143 |
+
$redirect->updateOptionItem('frontend.redirect.type', 'login');
|
144 |
+
|
145 |
+
$this->assertTrue($redirect->save());
|
146 |
+
|
147 |
+
// Reset all internal cache
|
148 |
+
$this->_resetSubjects();
|
149 |
+
|
150 |
+
// Capture the WP Die message
|
151 |
+
ob_start();
|
152 |
+
wp_die('Access Denied', 'aam_access_denied', array('exit' => false));
|
153 |
+
ob_end_clean();
|
154 |
+
|
155 |
+
$this->assertContains('Location: ' . add_query_arg(
|
156 |
+
array('reason' => 'restricted'), wp_login_url()
|
157 |
+
), xdebug_get_headers());
|
158 |
+
}
|
159 |
+
|
160 |
+
/**
|
161 |
+
* Test redirect to the PHP callback function
|
162 |
+
*
|
163 |
+
* @return void
|
164 |
+
*
|
165 |
+
* @access public
|
166 |
+
* @version 6.0.0
|
167 |
+
*/
|
168 |
+
public function testCallbackRedirect()
|
169 |
+
{
|
170 |
+
// Define custom access denied message
|
171 |
+
$redirect = AAM::getUser()->getObject(AAM_Core_Object_Redirect::OBJECT_TYPE);
|
172 |
+
$redirect->updateOptionItem('frontend.redirect.type', 'callback');
|
173 |
+
$redirect->updateOptionItem('frontend.redirect.callback', 'AAM\\UnitTest\\Service\\DeniedRedirect\\Callback::printOutput');
|
174 |
+
|
175 |
+
$this->assertTrue($redirect->save());
|
176 |
+
|
177 |
+
// Reset all internal cache
|
178 |
+
$this->_resetSubjects();
|
179 |
+
|
180 |
+
// Capture the WP Die message
|
181 |
+
ob_start();
|
182 |
+
wp_die('Access Denied', 'aam_access_denied', array('exit' => false));
|
183 |
+
$content = ob_get_contents();
|
184 |
+
ob_end_clean();
|
185 |
+
|
186 |
+
$this->assertStringContainsString(Callback::OUTPUT, $content);
|
187 |
+
}
|
188 |
+
|
189 |
+
}
|
tests/Service/Jwt/JwtTest.php
ADDED
@@ -0,0 +1,360 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
/**
|
4 |
+
* ======================================================================
|
5 |
+
* LICENSE: This file is subject to the terms and conditions defined in *
|
6 |
+
* file 'license.txt', which is part of this source code package. *
|
7 |
+
* ======================================================================
|
8 |
+
*/
|
9 |
+
|
10 |
+
namespace AAM\UnitTest\Service\Jwt;
|
11 |
+
|
12 |
+
use DateTime,
|
13 |
+
AAM_Service_Jwt,
|
14 |
+
WP_REST_Request,
|
15 |
+
AAM_Core_Config,
|
16 |
+
AAM_Core_Jwt_Issuer,
|
17 |
+
PHPUnit\Framework\TestCase,
|
18 |
+
AAM\UnitTest\Libs\ResetTrait;
|
19 |
+
|
20 |
+
/**
|
21 |
+
* Jwt service tests
|
22 |
+
*
|
23 |
+
* @package AAM\UnitTest
|
24 |
+
* @version 6.0.0
|
25 |
+
*/
|
26 |
+
class JwtTest extends TestCase
|
27 |
+
{
|
28 |
+
use ResetTrait;
|
29 |
+
|
30 |
+
/**
|
31 |
+
* Assert that jwt token is generated for the authentication request
|
32 |
+
*
|
33 |
+
* @return void
|
34 |
+
*
|
35 |
+
* @access public
|
36 |
+
* @version 6.0.0
|
37 |
+
*/
|
38 |
+
public function testAuthResponseContainsJwt()
|
39 |
+
{
|
40 |
+
$server = rest_get_server();
|
41 |
+
|
42 |
+
// No need to generate Auth cookies
|
43 |
+
add_filter('send_auth_cookies', '__return_false');
|
44 |
+
|
45 |
+
$request = new WP_REST_Request('POST', '/aam/v2/authenticate');
|
46 |
+
$request->set_param('username', AAM_UNITTEST_USERNAME);
|
47 |
+
$request->set_param('password', AAM_UNITTEST_PASSWORD);
|
48 |
+
$request->set_param('issueJWT', true);
|
49 |
+
|
50 |
+
$data = $server->dispatch($request)->get_data();
|
51 |
+
|
52 |
+
$this->assertArrayHasKey('jwt', $data);
|
53 |
+
}
|
54 |
+
|
55 |
+
/**
|
56 |
+
* Validate that issued JWT token is valid when it is marked as none-revokable
|
57 |
+
*
|
58 |
+
* @return void
|
59 |
+
*
|
60 |
+
* @access public
|
61 |
+
* @version 6.0.0
|
62 |
+
*/
|
63 |
+
public function testValidateNotRevocableJwtToken()
|
64 |
+
{
|
65 |
+
$server = rest_get_server();
|
66 |
+
|
67 |
+
// Generate valid JWT token
|
68 |
+
$jwt = AAM_Core_Jwt_Issuer::getInstance()->issueToken(array(
|
69 |
+
'userId' => AAM_UNITTEST_AUTH_USER_ID,
|
70 |
+
'revocable' => false,
|
71 |
+
'refreshable' => false
|
72 |
+
));
|
73 |
+
|
74 |
+
$this->assertObjectHasAttribute('token', $jwt);
|
75 |
+
$this->assertObjectHasAttribute('claims', $jwt);
|
76 |
+
|
77 |
+
$request = new WP_REST_Request('POST', '/aam/v1/validate-jwt');
|
78 |
+
$request->set_param('jwt', $jwt->token);
|
79 |
+
|
80 |
+
$response = $server->dispatch($request);
|
81 |
+
|
82 |
+
$this->assertEquals(200, $response->get_status());
|
83 |
+
}
|
84 |
+
|
85 |
+
/**
|
86 |
+
* Validate that issued JWT is not valid when it is marked as revokable and is
|
87 |
+
* not stored in the JWT store
|
88 |
+
*
|
89 |
+
* @access public
|
90 |
+
* @version 6.0.0
|
91 |
+
*/
|
92 |
+
public function testValidateRevocableJwtToken()
|
93 |
+
{
|
94 |
+
$server = rest_get_server();
|
95 |
+
|
96 |
+
// Generate valid JWT token
|
97 |
+
$jwt = AAM_Core_Jwt_Issuer::getInstance()->issueToken(array(
|
98 |
+
'userId' => AAM_UNITTEST_AUTH_USER_ID,
|
99 |
+
'revocable' => true,
|
100 |
+
'refreshable' => false
|
101 |
+
));
|
102 |
+
|
103 |
+
$this->assertObjectHasAttribute('token', $jwt);
|
104 |
+
$this->assertObjectHasAttribute('claims', $jwt);
|
105 |
+
|
106 |
+
$request = new WP_REST_Request('POST', '/aam/v1/validate-jwt');
|
107 |
+
$request->set_param('jwt', $jwt->token);
|
108 |
+
|
109 |
+
$response = $server->dispatch($request);
|
110 |
+
|
111 |
+
$this->assertEquals(400, $response->get_status());
|
112 |
+
$this->assertEquals('Token has been revoked', $response->get_data()->get_error_message());
|
113 |
+
}
|
114 |
+
|
115 |
+
/**
|
116 |
+
* Validate that JWT token is invalid when it is expired
|
117 |
+
*
|
118 |
+
* @access public
|
119 |
+
* @version 6.0.0
|
120 |
+
*/
|
121 |
+
public function testValidateExpiredJwtToken()
|
122 |
+
{
|
123 |
+
$server = rest_get_server();
|
124 |
+
|
125 |
+
// Generate valid JWT token
|
126 |
+
$jwt = AAM_Core_Jwt_Issuer::getInstance()->issueToken(array(
|
127 |
+
'userId' => AAM_UNITTEST_AUTH_USER_ID,
|
128 |
+
'revocable' => true,
|
129 |
+
'refreshable' => false
|
130 |
+
), DateTime::createFromFormat('m/d/Y', '01/01/2018'));
|
131 |
+
|
132 |
+
$this->assertObjectHasAttribute('token', $jwt);
|
133 |
+
$this->assertObjectHasAttribute('claims', $jwt);
|
134 |
+
|
135 |
+
$request = new WP_REST_Request('POST', '/aam/v1/validate-jwt');
|
136 |
+
$request->set_param('jwt', $jwt->token);
|
137 |
+
|
138 |
+
$response = $server->dispatch($request);
|
139 |
+
|
140 |
+
$this->assertEquals(400, $response->get_status());
|
141 |
+
$this->assertEquals('Expired token', $response->get_data()->get_error_message());
|
142 |
+
}
|
143 |
+
|
144 |
+
/**
|
145 |
+
* Verify that user JWT token registry is populated correctly
|
146 |
+
*
|
147 |
+
* @return void
|
148 |
+
*
|
149 |
+
* @access public
|
150 |
+
* @version 6.0.0
|
151 |
+
*/
|
152 |
+
public function testTokenRegistryPopulated()
|
153 |
+
{
|
154 |
+
$service = AAM_Service_Jwt::getInstance();
|
155 |
+
$tokens = $service->getTokenRegistry(AAM_UNITTEST_JOHN_ID);
|
156 |
+
|
157 |
+
// Assert that the registry is empty
|
158 |
+
$this->assertEquals(0, count($tokens));
|
159 |
+
|
160 |
+
// Issue new token and verify that registry increased by one
|
161 |
+
$res = $service->issueToken(AAM_UNITTEST_JOHN_ID);
|
162 |
+
|
163 |
+
// Reset cache
|
164 |
+
wp_cache_flush();
|
165 |
+
|
166 |
+
$tokens = $service->getTokenRegistry(AAM_UNITTEST_JOHN_ID);
|
167 |
+
|
168 |
+
// Assert that the new token is there
|
169 |
+
$this->assertEquals(1, count($tokens));
|
170 |
+
$this->assertTrue(in_array($res->token, $tokens, true));
|
171 |
+
}
|
172 |
+
|
173 |
+
/**
|
174 |
+
* Verify that registry implement ring-buffer approach and does not allow to
|
175 |
+
* overload the DB
|
176 |
+
*
|
177 |
+
* @return void
|
178 |
+
*
|
179 |
+
* @access public
|
180 |
+
* @version 6.0.0
|
181 |
+
*/
|
182 |
+
public function testTokenRegistryOverflow()
|
183 |
+
{
|
184 |
+
AAM_Core_Config::set('authentication.jwt.registryLimit', 1);
|
185 |
+
|
186 |
+
// Reset cache
|
187 |
+
wp_cache_flush();
|
188 |
+
|
189 |
+
$service = AAM_Service_Jwt::getInstance();
|
190 |
+
$tokens = $service->getTokenRegistry(AAM_UNITTEST_JOHN_ID);
|
191 |
+
|
192 |
+
// Assert that the registry is empty
|
193 |
+
$this->assertEquals(0, count($tokens));
|
194 |
+
|
195 |
+
// Issue new token and verify that registry increased by one
|
196 |
+
$res1 = $service->issueToken(AAM_UNITTEST_JOHN_ID);
|
197 |
+
|
198 |
+
// Reset cache
|
199 |
+
wp_cache_flush();
|
200 |
+
|
201 |
+
$tokens = $service->getTokenRegistry(AAM_UNITTEST_JOHN_ID);
|
202 |
+
|
203 |
+
// Assert that token is in the registry
|
204 |
+
$this->assertEquals(1, count($tokens));
|
205 |
+
|
206 |
+
// Issue a new token and make sure that there is only one token in the
|
207 |
+
// registry
|
208 |
+
$res2 = $service->issueToken(AAM_UNITTEST_JOHN_ID);
|
209 |
+
|
210 |
+
// Reset cache
|
211 |
+
wp_cache_flush();
|
212 |
+
|
213 |
+
$tokens = $service->getTokenRegistry(AAM_UNITTEST_JOHN_ID);
|
214 |
+
|
215 |
+
// Assert that token is in the registry
|
216 |
+
$this->assertEquals(1, count($tokens));
|
217 |
+
|
218 |
+
$this->assertFalse(in_array($res1->token, $tokens, true));
|
219 |
+
$this->assertTrue(in_array($res2->token, $tokens, true));
|
220 |
+
}
|
221 |
+
|
222 |
+
/**
|
223 |
+
* Verify that token can be refreshed successfully
|
224 |
+
*
|
225 |
+
* @return void
|
226 |
+
*
|
227 |
+
* @access public
|
228 |
+
* @version 6.0.0
|
229 |
+
*/
|
230 |
+
public function testTokenRefreshValid()
|
231 |
+
{
|
232 |
+
$server = rest_get_server();
|
233 |
+
$service = AAM_Service_Jwt::getInstance();
|
234 |
+
|
235 |
+
// Issue a token that later we'll refresh
|
236 |
+
$jwt = $service->issueToken(AAM_UNITTEST_JOHN_ID, null, null, true);
|
237 |
+
|
238 |
+
// Verify that token was issued
|
239 |
+
$this->assertObjectHasAttribute('token', $jwt);
|
240 |
+
|
241 |
+
// Refresh token
|
242 |
+
$request = new WP_REST_Request('POST', '/aam/v1/refresh-jwt');
|
243 |
+
$request->set_param('jwt', $jwt->token);
|
244 |
+
|
245 |
+
$response = $server->dispatch($request);
|
246 |
+
|
247 |
+
$this->assertEquals(200, $response->get_status());
|
248 |
+
}
|
249 |
+
|
250 |
+
/**
|
251 |
+
* Verify that token can't be refreshed if it is simply invalid JWT token
|
252 |
+
*
|
253 |
+
* @return void
|
254 |
+
*
|
255 |
+
* @access public
|
256 |
+
* @version 6.0.0
|
257 |
+
*/
|
258 |
+
public function testTokenRefreshNotValid()
|
259 |
+
{
|
260 |
+
$server = rest_get_server();
|
261 |
+
|
262 |
+
// Refresh token
|
263 |
+
$request = new WP_REST_Request('POST', '/aam/v1/refresh-jwt');
|
264 |
+
$request->set_param('jwt', 'invalid-token');
|
265 |
+
|
266 |
+
$response = $server->dispatch($request);
|
267 |
+
|
268 |
+
$this->assertEquals(400, $response->get_status());
|
269 |
+
$this->assertStringContainsString('Invalid JWT token: Malformed UTF-8 characters', $response->get_data()->get_error_message());
|
270 |
+
}
|
271 |
+
|
272 |
+
/**
|
273 |
+
* Verify that new token is not issued for already expired token
|
274 |
+
*
|
275 |
+
* @return void
|
276 |
+
*
|
277 |
+
* @access public
|
278 |
+
* @version 6.0.0
|
279 |
+
*/
|
280 |
+
public function testTokenRefreshExpired()
|
281 |
+
{
|
282 |
+
$server = rest_get_server();
|
283 |
+
|
284 |
+
// Generate valid JWT token
|
285 |
+
$jwt = AAM_Core_Jwt_Issuer::getInstance()->issueToken(array(
|
286 |
+
'userId' => AAM_UNITTEST_AUTH_USER_ID,
|
287 |
+
'revocable' => true,
|
288 |
+
'refreshable' => true
|
289 |
+
), DateTime::createFromFormat('m/d/Y', '01/01/2018'));
|
290 |
+
|
291 |
+
$this->assertObjectHasAttribute('token', $jwt);
|
292 |
+
$this->assertObjectHasAttribute('claims', $jwt);
|
293 |
+
|
294 |
+
$request = new WP_REST_Request('POST', '/aam/v1/refresh-jwt');
|
295 |
+
$request->set_param('jwt', $jwt->token);
|
296 |
+
|
297 |
+
$response = $server->dispatch($request);
|
298 |
+
|
299 |
+
$this->assertEquals(400, $response->get_status());
|
300 |
+
$this->assertEquals('Expired token', $response->get_data()->get_error_message());
|
301 |
+
}
|
302 |
+
|
303 |
+
/**
|
304 |
+
* Verify that new token is not issued for none-refreshable token
|
305 |
+
*
|
306 |
+
* @return void
|
307 |
+
*
|
308 |
+
* @access public
|
309 |
+
* @version 6.0.0
|
310 |
+
*/
|
311 |
+
public function testTokenRefreshNotRefreshable()
|
312 |
+
{
|
313 |
+
$server = rest_get_server();
|
314 |
+
|
315 |
+
// Generate valid JWT token
|
316 |
+
$jwt = AAM_Core_Jwt_Issuer::getInstance()->issueToken(array(
|
317 |
+
'userId' => AAM_UNITTEST_AUTH_USER_ID,
|
318 |
+
'revocable' => false,
|
319 |
+
'refreshable' => false
|
320 |
+
));
|
321 |
+
|
322 |
+
$this->assertObjectHasAttribute('token', $jwt);
|
323 |
+
$this->assertObjectHasAttribute('claims', $jwt);
|
324 |
+
|
325 |
+
$request = new WP_REST_Request('POST', '/aam/v1/refresh-jwt');
|
326 |
+
$request->set_param('jwt', $jwt->token);
|
327 |
+
|
328 |
+
$response = $server->dispatch($request);
|
329 |
+
|
330 |
+
$this->assertEquals(400, $response->get_status());
|
331 |
+
$this->assertEquals('JWT token is not refreshable', $response->get_data()->get_error_message());
|
332 |
+
}
|
333 |
+
|
334 |
+
/**
|
335 |
+
* Verify that token is revoked properly
|
336 |
+
*
|
337 |
+
* @access public
|
338 |
+
* @version 6.0.0
|
339 |
+
*/
|
340 |
+
public function testTokenRevoked()
|
341 |
+
{
|
342 |
+
$service = AAM_Service_Jwt::getInstance();
|
343 |
+
|
344 |
+
// Issue a token that later we'll refresh
|
345 |
+
$jwt = $service->issueToken(AAM_UNITTEST_JOHN_ID, null, null, true);
|
346 |
+
|
347 |
+
// Verify that token was issued
|
348 |
+
$this->assertObjectHasAttribute('token', $jwt);
|
349 |
+
|
350 |
+
$this->assertTrue($service->revokeToken(AAM_UNITTEST_JOHN_ID, $jwt->token));
|
351 |
+
|
352 |
+
// Reset cache
|
353 |
+
wp_cache_flush();
|
354 |
+
|
355 |
+
$tokens = $service->getTokenRegistry(AAM_UNITTEST_JOHN_ID);
|
356 |
+
|
357 |
+
$this->assertFalse(in_array($jwt->token, $tokens, true));
|
358 |
+
}
|
359 |
+
|
360 |
+
}
|
tests/Service/LoginRedirect/Callback.php
ADDED
@@ -0,0 +1,14 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
namespace AAM\UnitTest\Service\LoginRedirect;
|
4 |
+
|
5 |
+
class Callback
|
6 |
+
{
|
7 |
+
const REDIRECT_URL = 'https://aamplugin.com/redirect';
|
8 |
+
|
9 |
+
public static function redirectCallback()
|
10 |
+
{
|
11 |
+
return self::REDIRECT_URL;
|
12 |
+
}
|
13 |
+
|
14 |
+
}
|
tests/Service/LoginRedirect/LoginRedirectTest.php
ADDED
@@ -0,0 +1,215 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
/**
|
4 |
+
* ======================================================================
|
5 |
+
* LICENSE: This file is subject to the terms and conditions defined in *
|
6 |
+
* file 'license.txt', which is part of this source code package. *
|
7 |
+
* ======================================================================
|
8 |
+
*/
|
9 |
+
|
10 |
+
namespace AAM\UnitTest\Service\LoginRedirect;
|
11 |
+
|
12 |
+
use WP_REST_Request,
|
13 |
+
AAM_Core_Subject_User,
|
14 |
+
PHPUnit\Framework\TestCase,
|
15 |
+
AAM\UnitTest\Libs\ResetTrait,
|
16 |
+
AAM_Core_Object_LoginRedirect;
|
17 |
+
|
18 |
+
/**
|
19 |
+
* Login Redirect feature
|
20 |
+
*
|
21 |
+
* @package AAM\UnitTest
|
22 |
+
* @version 6.0.0
|
23 |
+
*/
|
24 |
+
class LoginRedirectTest extends TestCase
|
25 |
+
{
|
26 |
+
use ResetTrait;
|
27 |
+
|
28 |
+
/**
|
29 |
+
* Assert that correct URL login redirect is returns for RESTful auth call
|
30 |
+
*
|
31 |
+
* @return void
|
32 |
+
*
|
33 |
+
* @access public
|
34 |
+
* @version 6.0.0
|
35 |
+
*/
|
36 |
+
public function testRESTfulLoginURLRedirect()
|
37 |
+
{
|
38 |
+
$server = rest_get_server();
|
39 |
+
|
40 |
+
// No need to generate Auth cookies
|
41 |
+
add_filter('send_auth_cookies', '__return_false');
|
42 |
+
|
43 |
+
// Set login redirect
|
44 |
+
$subject = new AAM_Core_Subject_User(AAM_UNITTEST_JOHN_ID);
|
45 |
+
$object = $subject->getObject(AAM_Core_Object_LoginRedirect::OBJECT_TYPE, null, true);
|
46 |
+
$object->setOption(array(
|
47 |
+
'login.redirect.type' => 'url',
|
48 |
+
'login.redirect.url' => 'https://aamplugin.com'
|
49 |
+
));
|
50 |
+
$object->save();
|
51 |
+
|
52 |
+
$request = new WP_REST_Request('POST', '/aam/v2/authenticate');
|
53 |
+
$request->set_param('username', AAM_UNITTEST_USERNAME);
|
54 |
+
$request->set_param('password', AAM_UNITTEST_PASSWORD);
|
55 |
+
|
56 |
+
$data = $server->dispatch($request)->get_data();
|
57 |
+
|
58 |
+
$this->assertEquals('WP_User', get_class($data['user']));
|
59 |
+
$this->assertEquals('https://aamplugin.com', $data['redirect']);
|
60 |
+
}
|
61 |
+
|
62 |
+
/**
|
63 |
+
* Assert that correct Page login redirect is returns for RESTful auth call
|
64 |
+
*
|
65 |
+
* @return void
|
66 |
+
*
|
67 |
+
* @access public
|
68 |
+
* @version 6.0.0
|
69 |
+
*/
|
70 |
+
public function testRESTfulLoginPageRedirect()
|
71 |
+
{
|
72 |
+
$server = rest_get_server();
|
73 |
+
|
74 |
+
// No need to generate Auth cookies
|
75 |
+
add_filter('send_auth_cookies', '__return_false');
|
76 |
+
|
77 |
+
// Set login redirect
|
78 |
+
$subject = new AAM_Core_Subject_User(AAM_UNITTEST_JOHN_ID);
|
79 |
+
$object = $subject->getObject(AAM_Core_Object_LoginRedirect::OBJECT_TYPE, null, true);
|
80 |
+
$object->setOption(array(
|
81 |
+
'login.redirect.type' => 'page',
|
82 |
+
'login.redirect.page' => AAM_UNITTEST_PAGE_ID
|
83 |
+
));
|
84 |
+
$object->save();
|
85 |
+
|
86 |
+
$request = new WP_REST_Request('POST', '/aam/v2/authenticate');
|
87 |
+
$request->set_param('username', AAM_UNITTEST_USERNAME);
|
88 |
+
$request->set_param('password', AAM_UNITTEST_PASSWORD);
|
89 |
+
|
90 |
+
$data = $server->dispatch($request)->get_data();
|
91 |
+
|
92 |
+
$this->assertEquals('WP_User', get_class($data['user']));
|
93 |
+
$this->assertEquals(get_page_link(AAM_UNITTEST_PAGE_ID), $data['redirect']);
|
94 |
+
}
|
95 |
+
|
96 |
+
/**
|
97 |
+
* Assert that correct login redirect is returns for RESTful auth call for
|
98 |
+
* callback type of redirect
|
99 |
+
*
|
100 |
+
* @return void
|
101 |
+
*
|
102 |
+
* @access public
|
103 |
+
* @version 6.0.0
|
104 |
+
*/
|
105 |
+
public function testRESTfulLoginCallbackRedirect()
|
106 |
+
{
|
107 |
+
$server = rest_get_server();
|
108 |
+
|
109 |
+
// No need to generate Auth cookies
|
110 |
+
add_filter('send_auth_cookies', '__return_false');
|
111 |
+
|
112 |
+
// Set login redirect
|
113 |
+
$subject = new AAM_Core_Subject_User(AAM_UNITTEST_JOHN_ID);
|
114 |
+
$object = $subject->getObject(AAM_Core_Object_LoginRedirect::OBJECT_TYPE, null, true);
|
115 |
+
$object->setOption(array(
|
116 |
+
'login.redirect.type' => 'callback',
|
117 |
+
'login.redirect.callback' => 'AAM\\UnitTest\\Service\\LoginRedirect\\Callback::redirectCallback'
|
118 |
+
));
|
119 |
+
$object->save();
|
120 |
+
|
121 |
+
$request = new WP_REST_Request('POST', '/aam/v2/authenticate');
|
122 |
+
$request->set_param('username', AAM_UNITTEST_USERNAME);
|
123 |
+
$request->set_param('password', AAM_UNITTEST_PASSWORD);
|
124 |
+
|
125 |
+
$data = $server->dispatch($request)->get_data();
|
126 |
+
|
127 |
+
$this->assertEquals('WP_User', get_class($data['user']));
|
128 |
+
$this->assertEquals(Callback::REDIRECT_URL, $data['redirect']);
|
129 |
+
}
|
130 |
+
|
131 |
+
/**
|
132 |
+
* Assert that null login redirect is returns for RESTful auth call
|
133 |
+
*
|
134 |
+
* @return void
|
135 |
+
*
|
136 |
+
* @access public
|
137 |
+
* @version 6.0.0
|
138 |
+
*/
|
139 |
+
public function testRESTfulLoginDefaultRedirect()
|
140 |
+
{
|
141 |
+
$server = rest_get_server();
|
142 |
+
|
143 |
+
// No need to generate Auth cookies
|
144 |
+
add_filter('send_auth_cookies', '__return_false');
|
145 |
+
|
146 |
+
$request = new WP_REST_Request('POST', '/aam/v2/authenticate');
|
147 |
+
$request->set_param('username', AAM_UNITTEST_USERNAME);
|
148 |
+
$request->set_param('password', AAM_UNITTEST_PASSWORD);
|
149 |
+
|
150 |
+
$data = $server->dispatch($request)->get_data();
|
151 |
+
|
152 |
+
$this->assertEquals('WP_User', get_class($data['user']));
|
153 |
+
$this->assertNull($data['redirect']);
|
154 |
+
}
|
155 |
+
|
156 |
+
/**
|
157 |
+
* Validate that `login_redirect` filter is triggered with AAM hook
|
158 |
+
*
|
159 |
+
* Make sure that user will be redirected to the existing page
|
160 |
+
*
|
161 |
+
* @return void
|
162 |
+
*
|
163 |
+
* @access public
|
164 |
+
* @version 6.0.0
|
165 |
+
*/
|
166 |
+
public function testLoginRedirectHookTriggerChanges()
|
167 |
+
{
|
168 |
+
// Set login redirect
|
169 |
+
$subject = new AAM_Core_Subject_User(AAM_UNITTEST_JOHN_ID);
|
170 |
+
$object = $subject->getObject(AAM_Core_Object_LoginRedirect::OBJECT_TYPE, null, true);
|
171 |
+
$object->setOption(array(
|
172 |
+
'login.redirect.type' => 'page',
|
173 |
+
'login.redirect.page' => AAM_UNITTEST_PAGE_ID
|
174 |
+
));
|
175 |
+
$object->save();
|
176 |
+
|
177 |
+
$redirect = apply_filters('login_redirect', admin_url(), admin_url(), $subject->getPrincipal());
|
178 |
+
|
179 |
+
$this->assertEquals(get_page_link(AAM_UNITTEST_PAGE_ID), $redirect);
|
180 |
+
}
|
181 |
+
|
182 |
+
/**
|
183 |
+
* Validate that `login_redirect` filter is triggered with AAM hook
|
184 |
+
*
|
185 |
+
* Make sure that user will be redirected to originally defined destination. By
|
186 |
+
* default AAM overwrites only destinations that are different than admin_url()
|
187 |
+
* return.
|
188 |
+
*
|
189 |
+
* @return void
|
190 |
+
*
|
191 |
+
* @access public
|
192 |
+
* @version 6.0.0
|
193 |
+
*/
|
194 |
+
public function testLoginRedirectHookTriggerPersistOriginalRedirect()
|
195 |
+
{
|
196 |
+
// Set login redirect
|
197 |
+
$subject = new AAM_Core_Subject_User(AAM_UNITTEST_JOHN_ID);
|
198 |
+
$object = $subject->getObject(AAM_Core_Object_LoginRedirect::OBJECT_TYPE, null, true);
|
199 |
+
$object->setOption(array(
|
200 |
+
'login.redirect.type' => 'url',
|
201 |
+
'login.redirect.url' => 'https://aamplugin.com'
|
202 |
+
));
|
203 |
+
$object->save();
|
204 |
+
|
205 |
+
$redirect = apply_filters(
|
206 |
+
'login_redirect',
|
207 |
+
get_page_link(AAM_UNITTEST_PAGE_ID),
|
208 |
+
get_page_link(AAM_UNITTEST_PAGE_ID),
|
209 |
+
$subject->getPrincipal()
|
210 |
+
);
|
211 |
+
|
212 |
+
$this->assertEquals(get_page_link(AAM_UNITTEST_PAGE_ID), $redirect);
|
213 |
+
}
|
214 |
+
|
215 |
+
}
|
tests/Service/LogoutRedirect/Callback.php
ADDED
@@ -0,0 +1,14 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
namespace AAM\UnitTest\Service\LogoutRedirect;
|
4 |
+
|
5 |
+
class Callback
|
6 |
+
{
|
7 |
+
const REDIRECT_URL = 'https://aamplugin.com/redirect';
|
8 |
+
|
9 |
+
public static function redirectCallback()
|
10 |
+
{
|
11 |
+
header('Location: ' . self::REDIRECT_URL);
|
12 |
+
}
|
13 |
+
|
14 |
+
}
|
tests/Service/LogoutRedirect/LogoutRedirectTest.php
ADDED
@@ -0,0 +1,115 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
/**
|
4 |
+
* ======================================================================
|
5 |
+
* LICENSE: This file is subject to the terms and conditions defined in *
|
6 |
+
* file 'license.txt', which is part of this source code package. *
|
7 |
+
* ======================================================================
|
8 |
+
*/
|
9 |
+
|
10 |
+
namespace AAM\UnitTest\Service\LogoutRedirect;
|
11 |
+
|
12 |
+
use AAM,
|
13 |
+
PHPUnit\Framework\TestCase,
|
14 |
+
AAM\UnitTest\Libs\ResetTrait,
|
15 |
+
AAM_Core_Object_LogoutRedirect,
|
16 |
+
AAM\UnitTest\Libs\AuthUserTrait;
|
17 |
+
|
18 |
+
/**
|
19 |
+
* Logout Redirect feature
|
20 |
+
*
|
21 |
+
* @package AAM\UnitTest
|
22 |
+
* @version 6.0.0
|
23 |
+
*/
|
24 |
+
class LogoutRedirectTest extends TestCase
|
25 |
+
{
|
26 |
+
use ResetTrait,
|
27 |
+
AuthUserTrait;
|
28 |
+
|
29 |
+
/**
|
30 |
+
* Test the default logout redirect
|
31 |
+
*
|
32 |
+
* AAM should not issue any redirect headers
|
33 |
+
*
|
34 |
+
* @return void
|
35 |
+
*
|
36 |
+
* @access public
|
37 |
+
* @version 6.0.0
|
38 |
+
*/
|
39 |
+
public function testDefaultLogoutRedirect()
|
40 |
+
{
|
41 |
+
// Reset any already sent "Location" headers. This way insure that no other
|
42 |
+
// redirect headers are sent
|
43 |
+
header('Location: empty');
|
44 |
+
do_action('wp_logout');
|
45 |
+
|
46 |
+
$this->assertContains('Location: empty', xdebug_get_headers());
|
47 |
+
}
|
48 |
+
|
49 |
+
/**
|
50 |
+
* Test redirect to the existing page
|
51 |
+
*
|
52 |
+
* @return void
|
53 |
+
*
|
54 |
+
* @access public
|
55 |
+
* @version 6.0.0
|
56 |
+
*/
|
57 |
+
public function testExistingPageLogoutRedirect()
|
58 |
+
{
|
59 |
+
$object = AAM::getUser()->getObject(AAM_Core_Object_LogoutRedirect::OBJECT_TYPE, null, true);
|
60 |
+
$object->setOption(array(
|
61 |
+
'logout.redirect.type' => 'page',
|
62 |
+
'logout.redirect.page' => AAM_UNITTEST_PAGE_ID
|
63 |
+
));
|
64 |
+
$object->save();
|
65 |
+
|
66 |
+
do_action('wp_logout');
|
67 |
+
|
68 |
+
$this->assertContains('Location: ' . get_page_link(AAM_UNITTEST_PAGE_ID), xdebug_get_headers());
|
69 |
+
}
|
70 |
+
|
71 |
+
/**
|
72 |
+
* Test redirect to the defined URL
|
73 |
+
*
|
74 |
+
* @return void
|
75 |
+
*
|
76 |
+
* @access public
|
77 |
+
* @version 6.0.0
|
78 |
+
*/
|
79 |
+
public function testUrlLogoutRedirect()
|
80 |
+
{
|
81 |
+
$object = AAM::getUser()->getObject(AAM_Core_Object_LogoutRedirect::OBJECT_TYPE, null, true);
|
82 |
+
$object->setOption(array(
|
83 |
+
'logout.redirect.type' => 'url',
|
84 |
+
'logout.redirect.url' => '/hello-world'
|
85 |
+
));
|
86 |
+
$object->save();
|
87 |
+
|
88 |
+
do_action('wp_logout');
|
89 |
+
|
90 |
+
$this->assertContains('Location: /hello-world', xdebug_get_headers());
|
91 |
+
}
|
92 |
+
|
93 |
+
/**
|
94 |
+
* Test execution of the callback function as redirect
|
95 |
+
*
|
96 |
+
* @return void
|
97 |
+
*
|
98 |
+
* @access public
|
99 |
+
* @version 6.0.0
|
100 |
+
*/
|
101 |
+
public function testCallbackLogoutRedirect()
|
102 |
+
{
|
103 |
+
$object = AAM::getUser()->getObject(AAM_Core_Object_LogoutRedirect::OBJECT_TYPE, null, true);
|
104 |
+
$object->setOption(array(
|
105 |
+
'logout.redirect.type' => 'callback',
|
106 |
+
'logout.redirect.callback' => 'AAM\\UnitTest\\Service\\LogoutRedirect\\Callback::redirectCallback'
|
107 |
+
));
|
108 |
+
$object->save();
|
109 |
+
|
110 |
+
do_action('wp_logout');
|
111 |
+
|
112 |
+
$this->assertContains('Location: ' . Callback::REDIRECT_URL, xdebug_get_headers());
|
113 |
+
}
|
114 |
+
|
115 |
+
}
|
tests/Service/Metabox/MultipleRoleInheritanceTest.php
ADDED
@@ -0,0 +1,192 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
/**
|
4 |
+
* ======================================================================
|
5 |
+
* LICENSE: This file is subject to the terms and conditions defined in *
|
6 |
+
* file 'license.txt', which is part of this source code package. *
|
7 |
+
* ======================================================================
|
8 |
+
*/
|
9 |
+
|
10 |
+
namespace AAM\UnitTest\Service\Metabox;
|
11 |
+
|
12 |
+
use AAM,
|
13 |
+
AAM_Core_Config,
|
14 |
+
AAM_Core_Object_Metabox,
|
15 |
+
PHPUnit\Framework\TestCase,
|
16 |
+
AAM\UnitTest\Libs\ResetTrait,
|
17 |
+
AAM\UnitTest\Libs\AuthMultiRoleUserTrait,
|
18 |
+
AAM\UnitTest\Libs\MultiRoleOptionInterface;
|
19 |
+
|
20 |
+
/**
|
21 |
+
* Test AAM access settings inheritance mechanism for multiple roles per user for
|
22 |
+
* the Metaboxes & Widgets service
|
23 |
+
*
|
24 |
+
* @package AAM\UnitTest
|
25 |
+
* @version 6.0.0
|
26 |
+
*/
|
27 |
+
class MultipleRoleInheritanceTest extends TestCase implements MultiRoleOptionInterface
|
28 |
+
{
|
29 |
+
use ResetTrait,
|
30 |
+
AuthMultiRoleUserTrait;
|
31 |
+
|
32 |
+
/**
|
33 |
+
* Test that access settings are inherited from multiple parent roles
|
34 |
+
*
|
35 |
+
* This test is designed to verify that access settings are propagated property
|
36 |
+
* when there access settings defined for multiple parent roles.
|
37 |
+
*
|
38 |
+
* A. Test that settings can be stored for the parent roles;
|
39 |
+
* B. Test that access settings are propagated property to the User level
|
40 |
+
*
|
41 |
+
* @return void
|
42 |
+
*
|
43 |
+
* @access public
|
44 |
+
* @version 6.0.0
|
45 |
+
*/
|
46 |
+
public function testInheritanceMergeFromMultipleRoles()
|
47 |
+
{
|
48 |
+
$user = AAM::getUser();
|
49 |
+
$role = $user->getParent();
|
50 |
+
|
51 |
+
// Make sure that we have parent roles defined properly
|
52 |
+
$this->assertEquals('AAM_Core_Subject_Role', get_class($role));
|
53 |
+
|
54 |
+
// Save access settings for the base role and iterate over each sibling and
|
55 |
+
// add additional settings
|
56 |
+
$this->assertTrue(
|
57 |
+
$role->getObject(AAM_Core_Object_Metabox::OBJECT_TYPE, null, true)->updateOptionItem(
|
58 |
+
'dashboard|dashboard_quick_press_0', true
|
59 |
+
)->save()
|
60 |
+
);
|
61 |
+
|
62 |
+
foreach($role->getSiblings() as $i => $sibling) {
|
63 |
+
// Save access settings for each role and make sure they are saved property
|
64 |
+
// Check if save returns positive result
|
65 |
+
$this->assertTrue(
|
66 |
+
$sibling->getObject(AAM_Core_Object_Metabox::OBJECT_TYPE, null, true)->updateOptionItem(
|
67 |
+
'dashboard|dashboard_quick_press_' . ($i + 1), ($i % 2 ? true : false)
|
68 |
+
)->save()
|
69 |
+
);
|
70 |
+
}
|
71 |
+
|
72 |
+
// Reset internal AAM cache
|
73 |
+
$this->_resetSubjects();
|
74 |
+
|
75 |
+
// Assert that we have both roles merged result is as following
|
76 |
+
// Array (
|
77 |
+
// dashboard|dashboard_quick_press_0 => true,
|
78 |
+
// dashboard|dashboard_quick_press_1 => false
|
79 |
+
// )
|
80 |
+
$option = $user->getObject(AAM_Core_Object_Metabox::OBJECT_TYPE)->getOption();
|
81 |
+
$this->assertSame(
|
82 |
+
array(
|
83 |
+
'dashboard|dashboard_quick_press_0' => true,
|
84 |
+
'dashboard|dashboard_quick_press_1' => false
|
85 |
+
),
|
86 |
+
$option
|
87 |
+
);
|
88 |
+
}
|
89 |
+
|
90 |
+
/**
|
91 |
+
* Check that access to resource is denied when two or more roles have the same
|
92 |
+
* resource defined
|
93 |
+
*
|
94 |
+
* @return void
|
95 |
+
*
|
96 |
+
* @access public
|
97 |
+
* @version 6.0.0
|
98 |
+
*/
|
99 |
+
public function testInheritanceDenyPrecedenceFromMultipleRoles()
|
100 |
+
{
|
101 |
+
$user = AAM::getUser();
|
102 |
+
$role = $user->getParent();
|
103 |
+
|
104 |
+
// Make sure that we have parent roles defined properly
|
105 |
+
$this->assertEquals('AAM_Core_Subject_Role', get_class($role));
|
106 |
+
|
107 |
+
// Save access settings for the base role and iterate over each sibling and
|
108 |
+
// add additional settings
|
109 |
+
$this->assertTrue(
|
110 |
+
$role->getObject(AAM_Core_Object_Metabox::OBJECT_TYPE, null, true)->updateOptionItem(
|
111 |
+
'widgets|WP_Widget_Media_Video', true
|
112 |
+
)->save()
|
113 |
+
);
|
114 |
+
|
115 |
+
foreach($role->getSiblings() as $sibling) {
|
116 |
+
// Save access settings for each role and make sure they are saved property
|
117 |
+
// Check if save returns positive result
|
118 |
+
$this->assertTrue(
|
119 |
+
$sibling->getObject(AAM_Core_Object_Metabox::OBJECT_TYPE, null, true)->updateOptionItem(
|
120 |
+
'widgets|WP_Widget_Media_Video', false
|
121 |
+
)->save()
|
122 |
+
);
|
123 |
+
}
|
124 |
+
|
125 |
+
// Reset internal AAM cache
|
126 |
+
$this->_resetSubjects();
|
127 |
+
|
128 |
+
// Assert that we have both roles merged result is as following
|
129 |
+
// Array (
|
130 |
+
// widgets|WP_Widget_Media_Video => true
|
131 |
+
// )
|
132 |
+
$option = $user->getObject(AAM_Core_Object_Metabox::OBJECT_TYPE)->getOption();
|
133 |
+
$this->assertSame(
|
134 |
+
array('widgets|WP_Widget_Media_Video' => true), $option
|
135 |
+
);
|
136 |
+
}
|
137 |
+
|
138 |
+
/**
|
139 |
+
* Check that access is allowed to the resource when two or more roles have the
|
140 |
+
* same resource defined
|
141 |
+
*
|
142 |
+
* @return void
|
143 |
+
*
|
144 |
+
* @access public
|
145 |
+
* @version 6.0.0
|
146 |
+
*/
|
147 |
+
public function testInheritanceAllowPrecedenceFromMultipleRoles()
|
148 |
+
{
|
149 |
+
$user = AAM::getUser();
|
150 |
+
$role = $user->getParent();
|
151 |
+
|
152 |
+
// Make sure that we have parent roles defined properly
|
153 |
+
$this->assertEquals('AAM_Core_Subject_Role', get_class($role));
|
154 |
+
|
155 |
+
// Save access settings for the base role and iterate over each sibling and
|
156 |
+
// add additional settings
|
157 |
+
$this->assertTrue(
|
158 |
+
$role->getObject(AAM_Core_Object_Metabox::OBJECT_TYPE, null, true)->updateOptionItem(
|
159 |
+
'widgets|WP_Widget_Media_Video', true
|
160 |
+
)->save()
|
161 |
+
);
|
162 |
+
|
163 |
+
foreach($role->getSiblings() as $sibling) {
|
164 |
+
// Save access settings for each role and make sure they are saved property
|
165 |
+
// Check if save returns positive result
|
166 |
+
$this->assertTrue(
|
167 |
+
$sibling->getObject(AAM_Core_Object_Metabox::OBJECT_TYPE, null, true)->updateOptionItem(
|
168 |
+
'widgets|WP_Widget_Media_Video', false
|
169 |
+
)->save()
|
170 |
+
);
|
171 |
+
}
|
172 |
+
|
173 |
+
// Override the default "deny" precedence
|
174 |
+
AAM_Core_Config::set(
|
175 |
+
sprintf('core.settings.%s.merge.preference', AAM_Core_Object_Metabox::OBJECT_TYPE),
|
176 |
+
'allow'
|
177 |
+
);
|
178 |
+
|
179 |
+
// Reset internal AAM cache
|
180 |
+
$this->_resetSubjects();
|
181 |
+
|
182 |
+
// Assert that we have both roles merged result is as following
|
183 |
+
// Array (
|
184 |
+
// widgets|WP_Widget_Media_Video => false
|
185 |
+
// )
|
186 |
+
$option = $user->getObject(AAM_Core_Object_Metabox::OBJECT_TYPE)->getOption();
|
187 |
+
$this->assertSame(
|
188 |
+
array('widgets|WP_Widget_Media_Video' => false), $option
|
189 |
+
);
|
190 |
+
}
|
191 |
+
|
192 |
+
}
|
tests/Service/Metabox/SingleRoleInheritanceTest.php
ADDED
@@ -0,0 +1,231 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
/**
|
4 |
+
* ======================================================================
|
5 |
+
* LICENSE: This file is subject to the terms and conditions defined in *
|
6 |
+
* file 'license.txt', which is part of this source code package. *
|
7 |
+
* ======================================================================
|
8 |
+
*/
|
9 |
+
|
10 |
+
namespace AAM\UnitTest\Service\Metabox;
|
11 |
+
|
12 |
+
use AAM,
|
13 |
+
AAM_Core_Object_Metabox,
|
14 |
+
PHPUnit\Framework\TestCase,
|
15 |
+
AAM\UnitTest\Libs\ResetTrait,
|
16 |
+
AAM\UnitTest\Libs\AuthUserTrait;
|
17 |
+
|
18 |
+
/**
|
19 |
+
* Test AAM access settings inheritance mechanism for the Metaboxes & Widgets service
|
20 |
+
*
|
21 |
+
* @author Vasyl Martyniuk <vasyl@vasyltech.com>
|
22 |
+
* @version 6.0.0
|
23 |
+
*/
|
24 |
+
class SingleRoleInheritanceTest extends TestCase
|
25 |
+
{
|
26 |
+
use ResetTrait,
|
27 |
+
AuthUserTrait;
|
28 |
+
|
29 |
+
/**
|
30 |
+
* Test to insure that access settings are stored property on the User level
|
31 |
+
*
|
32 |
+
* A. Test that metabox is stored to the database with "true" flag and true
|
33 |
+
* is returned by AAM_Core_Subject_User::updateOption method;
|
34 |
+
* B. Test that information is actually stored property in the database and can
|
35 |
+
* be retrieved successfully.
|
36 |
+
*
|
37 |
+
* @return void
|
38 |
+
*
|
39 |
+
* @access public
|
40 |
+
* @see AAM_Core_Subject_User::updateOption
|
41 |
+
* @version 6.0.0
|
42 |
+
*/
|
43 |
+
public function testSaveMetaboxOption()
|
44 |
+
{
|
45 |
+
$user = AAM::getUser();
|
46 |
+
$object = $user->getObject(AAM_Core_Object_Metabox::OBJECT_TYPE);
|
47 |
+
|
48 |
+
// Check if save returns positive result
|
49 |
+
$this->assertTrue($object->updateOptionItem('widgets|WP_Widget_Media_Video', true)->save());
|
50 |
+
|
51 |
+
// Read from the database saved values and assert that we have
|
52 |
+
// Array (
|
53 |
+
// widgets|WP_Widget_Media_Video => true
|
54 |
+
// )
|
55 |
+
$option = $user->readOption(AAM_Core_Object_Metabox::OBJECT_TYPE);
|
56 |
+
$this->assertSame(array('widgets|WP_Widget_Media_Video' => true), $option);
|
57 |
+
}
|
58 |
+
|
59 |
+
/**
|
60 |
+
* Test that access settings are inherited from the parent role property
|
61 |
+
*
|
62 |
+
* This test is designed to verify that access settings are propagated property
|
63 |
+
* when there is only one role assigned to a user.
|
64 |
+
*
|
65 |
+
* A. Test that settings can be stored for the parent role;
|
66 |
+
* B. Test that access settings are propagated property to the User level
|
67 |
+
*
|
68 |
+
* @return void
|
69 |
+
*
|
70 |
+
* @access public
|
71 |
+
* @version 6.0.0
|
72 |
+
*/
|
73 |
+
public function testInheritanceFromSingleRole()
|
74 |
+
{
|
75 |
+
$user = AAM::getUser();
|
76 |
+
$parent = $user->getParent();
|
77 |
+
$object = $parent->getObject(AAM_Core_Object_Metabox::OBJECT_TYPE);
|
78 |
+
|
79 |
+
// Make sure that we have parent role defined
|
80 |
+
$this->assertEquals('AAM_Core_Subject_Role', get_class($parent));
|
81 |
+
|
82 |
+
// Save access settings for the role and make sure they are saved property
|
83 |
+
// Check if save returns positive result
|
84 |
+
$this->assertTrue($object->updateOptionItem('dashboard|dashboard_quick_press', true)->save());
|
85 |
+
|
86 |
+
// Read from the database saved values and assert that we have
|
87 |
+
// Array (
|
88 |
+
// dashboard|dashboard_quick_press => true
|
89 |
+
// )
|
90 |
+
$option = $parent->readOption(AAM_Core_Object_Metabox::OBJECT_TYPE);
|
91 |
+
$this->assertSame(array('dashboard|dashboard_quick_press' => true), $option);
|
92 |
+
|
93 |
+
// Finally verify that access settings are propagated property to the User
|
94 |
+
// Level
|
95 |
+
$metabox = $user->getObject(AAM_Core_Object_Metabox::OBJECT_TYPE);
|
96 |
+
$this->assertSame(
|
97 |
+
array('dashboard|dashboard_quick_press' => true), $metabox->getOption()
|
98 |
+
);
|
99 |
+
}
|
100 |
+
|
101 |
+
/**
|
102 |
+
* Test that access settings are propagated and merged properly
|
103 |
+
*
|
104 |
+
* The test is designed to verify that access settings are propagated properly
|
105 |
+
* from the parent role and merged well with explicitly defined access settings on
|
106 |
+
* the User level.
|
107 |
+
*
|
108 |
+
* The expected result is to have combined array of access settings from the parent
|
109 |
+
* role and specific user.
|
110 |
+
*
|
111 |
+
* A. Test that access settings are stored for the parent role;
|
112 |
+
* B. Test that access settings are stored for the user;
|
113 |
+
* C. Test that access settings are propagated and merged properly;
|
114 |
+
*
|
115 |
+
* @return void
|
116 |
+
*
|
117 |
+
* @access public
|
118 |
+
* @version 6.0.0
|
119 |
+
*/
|
120 |
+
public function testInheritanceMergeFromSingleRole()
|
121 |
+
{
|
122 |
+
$user = AAM::getUser();
|
123 |
+
$parent = $user->getParent();
|
124 |
+
|
125 |
+
$object = $parent->getObject(AAM_Core_Object_Metabox::OBJECT_TYPE);
|
126 |
+
|
127 |
+
// Save access settings for the role and make sure they are saved property
|
128 |
+
// Check if save returns positive result
|
129 |
+
$this->assertTrue($object->updateOptionItem('widgets|WP_Widget_Media_Video', true)->save());
|
130 |
+
|
131 |
+
// Save access setting for the user and make sure they are saved property
|
132 |
+
$metabox = $user->getObject(AAM_Core_Object_Metabox::OBJECT_TYPE, null, true);
|
133 |
+
$this->assertTrue($metabox->updateOptionItem('dashboard|dashboard_quick_press', false)->save());
|
134 |
+
|
135 |
+
// Reset cache and try to kick-in the inheritance mechanism
|
136 |
+
$this->_resetSubjects();
|
137 |
+
|
138 |
+
$metabox = $user->getObject(AAM_Core_Object_Metabox::OBJECT_TYPE);
|
139 |
+
$this->assertSame(
|
140 |
+
array(
|
141 |
+
'widgets|WP_Widget_Media_Video' => true,
|
142 |
+
'dashboard|dashboard_quick_press' => false
|
143 |
+
),
|
144 |
+
$metabox->getOption()
|
145 |
+
);
|
146 |
+
}
|
147 |
+
|
148 |
+
/**
|
149 |
+
* Test that the full inheritance mechanism is working as expected
|
150 |
+
*
|
151 |
+
* Make sure that access settings are propagated and merged properly from the top
|
152 |
+
* (Default Level)to the bottom (User Level).
|
153 |
+
*
|
154 |
+
* A. Assert that access settings are stored properly for each Access Level;
|
155 |
+
* B. Assert that access settings are merged properly and assigned to User Level;
|
156 |
+
*
|
157 |
+
* @return void
|
158 |
+
*
|
159 |
+
* @access public
|
160 |
+
* @version 6.0.0
|
161 |
+
*/
|
162 |
+
public function testFullInheritanceChainSingeRole()
|
163 |
+
{
|
164 |
+
$user = AAM::getUser();
|
165 |
+
$role = $user->getParent();
|
166 |
+
$default = $role->getParent();
|
167 |
+
|
168 |
+
$userMetabox = $user->getObject(AAM_Core_Object_Metabox::OBJECT_TYPE, null, true);
|
169 |
+
$roleMetabox = $role->getObject(AAM_Core_Object_Metabox::OBJECT_TYPE, null, true);
|
170 |
+
$defaultMetabox = $default->getObject(AAM_Core_Object_Metabox::OBJECT_TYPE, null, true);
|
171 |
+
|
172 |
+
// Save access settings for all subjects
|
173 |
+
$this->assertTrue($userMetabox->updateOptionItem('widgets|WP_Widget_Media_Video', true)->save());
|
174 |
+
$this->assertTrue($roleMetabox->updateOptionItem('dashboard|dashboard_quick_press', true)->save());
|
175 |
+
$this->assertTrue($defaultMetabox->updateOptionItem('post|publish_post', true)->save());
|
176 |
+
|
177 |
+
// Reset cache and try to kick-in the inheritance mechanism
|
178 |
+
$this->_resetSubjects();
|
179 |
+
|
180 |
+
// All settings has to be merged into one array
|
181 |
+
$metabox = $user->getObject(AAM_Core_Object_Metabox::OBJECT_TYPE);
|
182 |
+
$this->assertSame(
|
183 |
+
array(
|
184 |
+
'post|publish_post' => true,
|
185 |
+
'dashboard|dashboard_quick_press' => true,
|
186 |
+
'widgets|WP_Widget_Media_Video' => true
|
187 |
+
),
|
188 |
+
$metabox->getOption()
|
189 |
+
);
|
190 |
+
}
|
191 |
+
|
192 |
+
/**
|
193 |
+
* Test that access settings overwrite works as expected
|
194 |
+
*
|
195 |
+
* The expected result is lower Access Level overwrite access settings from the
|
196 |
+
* higher Access Level.
|
197 |
+
*
|
198 |
+
* A. Assert that access settings are stored properly for the parent role;
|
199 |
+
* B. Assert that access settings are stored properly for the specific user;
|
200 |
+
* C. Assert that access settings are overwritten properly on the User Level;
|
201 |
+
*
|
202 |
+
* @return void
|
203 |
+
*
|
204 |
+
* @access public
|
205 |
+
* @version 6.0.0
|
206 |
+
*/
|
207 |
+
public function testInheritanceOverrideForSingleRole()
|
208 |
+
{
|
209 |
+
$user = AAM::getUser();
|
210 |
+
$parent = $user->getParent();
|
211 |
+
|
212 |
+
$object = $parent->getObject(AAM_Core_Object_Metabox::OBJECT_TYPE);
|
213 |
+
|
214 |
+
// Save access settings for the role and make sure they are saved property
|
215 |
+
// Check if save returns positive result
|
216 |
+
$this->assertTrue($object->updateOptionItem('widgets|WP_Widget_Media_Video', true)->save());
|
217 |
+
|
218 |
+
// Save access setting for the user and make sure they are saved property
|
219 |
+
$metabox = $user->getObject(AAM_Core_Object_Metabox::OBJECT_TYPE, null, true);
|
220 |
+
$this->assertTrue($metabox->updateOptionItem('widgets|WP_Widget_Media_Video', false)->save());
|
221 |
+
|
222 |
+
// Reset cache and try to kick-in the inheritance mechanism
|
223 |
+
$this->_resetSubjects();
|
224 |
+
|
225 |
+
$metabox = $user->getObject(AAM_Core_Object_Metabox::OBJECT_TYPE);
|
226 |
+
$this->assertSame(
|
227 |
+
array('widgets|WP_Widget_Media_Video' => false), $metabox->getOption()
|
228 |
+
);
|
229 |
+
}
|
230 |
+
|
231 |
+
}
|
tests/Service/Metabox/VisitorInheritanceTest.php
ADDED
@@ -0,0 +1,187 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
/**
|
4 |
+
* ======================================================================
|
5 |
+
* LICENSE: This file is subject to the terms and conditions defined in *
|
6 |
+
* file 'license.txt', which is part of this source code package. *
|
7 |
+
* ======================================================================
|
8 |
+
*/
|
9 |
+
|
10 |
+
namespace AAM\UnitTest\Service\Metabox;
|
11 |
+
|
12 |
+
use AAM,
|
13 |
+
AAM_Core_Object_Metabox,
|
14 |
+
PHPUnit\Framework\TestCase,
|
15 |
+
AAM\UnitTest\Libs\ResetTrait,
|
16 |
+
AAM\UnitTest\Libs\AuthUserTrait;
|
17 |
+
|
18 |
+
/**
|
19 |
+
* Test AAM access settings inheritance mechanism for the Metaboxes & Widgets service
|
20 |
+
* for the visitor subject
|
21 |
+
*
|
22 |
+
* @author Vasyl Martyniuk <vasyl@vasyltech.com>
|
23 |
+
* @version 6.0.0
|
24 |
+
*/
|
25 |
+
class VisitorInheritanceTest extends TestCase
|
26 |
+
{
|
27 |
+
use ResetTrait;
|
28 |
+
|
29 |
+
/**
|
30 |
+
* Test to insure that access settings are stored property on the Visitor level
|
31 |
+
*
|
32 |
+
* A. Test that metabox is stored to the database with "true" flag and true
|
33 |
+
* is returned by AAM_Core_Subject_Visitor::updateOption method;
|
34 |
+
* B. Test that information is actually stored property in the database and can
|
35 |
+
* be retrieved successfully.
|
36 |
+
*
|
37 |
+
* @return void
|
38 |
+
*
|
39 |
+
* @access public
|
40 |
+
* @see AAM_Core_Subject_Visitor::updateOption
|
41 |
+
* @version 6.0.0
|
42 |
+
*/
|
43 |
+
public function testSaveMetaboxOption()
|
44 |
+
{
|
45 |
+
$user = AAM::getUser();
|
46 |
+
$object = $user->getObject(AAM_Core_Object_Metabox::OBJECT_TYPE);
|
47 |
+
|
48 |
+
// Make sure that we actually are dealing with Visitor subject
|
49 |
+
$this->assertEquals('AAM_Core_Subject_Visitor', get_class($user));
|
50 |
+
|
51 |
+
// Check if save returns positive result
|
52 |
+
$this->assertTrue($object->updateOptionItem('widgets|WP_Widget_Media_Video', true)->save());
|
53 |
+
|
54 |
+
// Read from the database saved values and assert that we have
|
55 |
+
// Array (
|
56 |
+
// widgets|WP_Widget_Media_Video => true
|
57 |
+
// )
|
58 |
+
$option = $user->readOption(AAM_Core_Object_Metabox::OBJECT_TYPE);
|
59 |
+
$this->assertSame(array('widgets|WP_Widget_Media_Video' => true), $option);
|
60 |
+
}
|
61 |
+
|
62 |
+
/**
|
63 |
+
* Test that access settings are inherited from the parent default subject
|
64 |
+
*
|
65 |
+
* This test is designed to verify that access settings are propagated property
|
66 |
+
* from the default settings
|
67 |
+
*
|
68 |
+
* A. Test that settings can be stored for the default subject
|
69 |
+
* B. Test that access settings are propagated property to the Visitor level
|
70 |
+
*
|
71 |
+
* @return void
|
72 |
+
*
|
73 |
+
* @access public
|
74 |
+
* @version 6.0.0
|
75 |
+
*/
|
76 |
+
public function testInheritanceFromDefault()
|
77 |
+
{
|
78 |
+
$user = AAM::getUser();
|
79 |
+
$parent = $user->getParent();
|
80 |
+
$object = $parent->getObject(AAM_Core_Object_Metabox::OBJECT_TYPE);
|
81 |
+
|
82 |
+
// Make sure that we work with Default subject
|
83 |
+
$this->assertEquals('AAM_Core_Subject_Default', get_class($parent));
|
84 |
+
|
85 |
+
// Save access settings for the Default and make sure they are saved property
|
86 |
+
// Check if save returns positive result
|
87 |
+
$this->assertTrue($object->updateOptionItem('widgets|WP_Widget_Media_Video', true)->save());
|
88 |
+
|
89 |
+
// Read from the database saved values and assert that we have
|
90 |
+
// Array (
|
91 |
+
// widgets|WP_Widget_Media_Video => true
|
92 |
+
// )
|
93 |
+
$option = $parent->readOption(AAM_Core_Object_Metabox::OBJECT_TYPE);
|
94 |
+
$this->assertSame(array('widgets|WP_Widget_Media_Video' => true), $option);
|
95 |
+
|
96 |
+
// Finally verify that access settings are propagated property to the Visitor
|
97 |
+
// Level
|
98 |
+
$metabox = $user->getObject(AAM_Core_Object_Metabox::OBJECT_TYPE);
|
99 |
+
$this->assertSame(
|
100 |
+
array('widgets|WP_Widget_Media_Video' => true), $metabox->getOption()
|
101 |
+
);
|
102 |
+
}
|
103 |
+
|
104 |
+
/**
|
105 |
+
* Test that access settings are propagated and merged properly
|
106 |
+
*
|
107 |
+
* The test is designed to verify that access settings are propagated properly
|
108 |
+
* from the Default and merged well with explicitly defined access settings on
|
109 |
+
* the Visitor level.
|
110 |
+
*
|
111 |
+
* A. Test that access settings are stored for the Default subject;
|
112 |
+
* B. Test that access settings are stored for the Visitor;
|
113 |
+
* C. Test that access settings are propagated and merged properly;
|
114 |
+
*
|
115 |
+
* @return void
|
116 |
+
*
|
117 |
+
* @access public
|
118 |
+
* @version 6.0.0
|
119 |
+
*/
|
120 |
+
public function testInheritanceMergeFromDefault()
|
121 |
+
{
|
122 |
+
$visitor = AAM::getUser();
|
123 |
+
$default = $visitor->getParent();
|
124 |
+
|
125 |
+
$object = $default->getObject(AAM_Core_Object_Metabox::OBJECT_TYPE);
|
126 |
+
|
127 |
+
// Save access settings for the Default and make sure they are saved property
|
128 |
+
// Check if save returns positive result
|
129 |
+
$this->assertTrue($object->updateOptionItem('widgets|WP_Widget_Media_Video', true)->save());
|
130 |
+
|
131 |
+
// Save access setting for the Visitor and make sure they are saved property
|
132 |
+
$metabox = $visitor->getObject(AAM_Core_Object_Metabox::OBJECT_TYPE, null, true);
|
133 |
+
$this->assertTrue($metabox->updateOptionItem('widgets|WP_Widget_Media_Image', false)->save());
|
134 |
+
|
135 |
+
// Reset cache and try to kick-in the inheritance mechanism
|
136 |
+
$this->_resetSubjects();
|
137 |
+
|
138 |
+
$metabox = $visitor->getObject(AAM_Core_Object_Metabox::OBJECT_TYPE);
|
139 |
+
$this->assertSame(
|
140 |
+
array(
|
141 |
+
'widgets|WP_Widget_Media_Video' => true,
|
142 |
+
'widgets|WP_Widget_Media_Image' => false
|
143 |
+
),
|
144 |
+
$metabox->getOption()
|
145 |
+
);
|
146 |
+
}
|
147 |
+
|
148 |
+
/**
|
149 |
+
* Test that access settings overwrite works as expected
|
150 |
+
*
|
151 |
+
* The expected result is lower Access Level overwrite access settings from the
|
152 |
+
* higher Access Level.
|
153 |
+
*
|
154 |
+
* A. Assert that access settings are stored properly for the parent subject;
|
155 |
+
* B. Assert that access settings are stored properly for the Visitor;
|
156 |
+
* C. Assert that access settings are overwritten properly on the Visitor Level;
|
157 |
+
*
|
158 |
+
* @return void
|
159 |
+
*
|
160 |
+
* @access public
|
161 |
+
* @version 6.0.0
|
162 |
+
*/
|
163 |
+
public function testInheritanceOverride()
|
164 |
+
{
|
165 |
+
$user = AAM::getUser();
|
166 |
+
$parent = $user->getParent();
|
167 |
+
|
168 |
+
$object = $parent->getObject(AAM_Core_Object_Metabox::OBJECT_TYPE);
|
169 |
+
|
170 |
+
// Save access settings for the Default and make sure they are saved property
|
171 |
+
// Check if save returns positive result
|
172 |
+
$this->assertTrue($object->updateOptionItem('widgets|WP_Widget_Media_Video', true)->save());
|
173 |
+
|
174 |
+
// Save access setting for the Visitor and make sure they are saved property
|
175 |
+
$metabox = $user->getObject(AAM_Core_Object_Metabox::OBJECT_TYPE, null, true);
|
176 |
+
$this->assertTrue($metabox->updateOptionItem('widgets|WP_Widget_Media_Video', false)->save());
|
177 |
+
|
178 |
+
// Reset cache and try to kick-in the inheritance mechanism
|
179 |
+
$this->_resetSubjects();
|
180 |
+
|
181 |
+
$metabox = $user->getObject(AAM_Core_Object_Metabox::OBJECT_TYPE);
|
182 |
+
$this->assertSame(
|
183 |
+
array('widgets|WP_Widget_Media_Video' => false), $metabox->getOption()
|
184 |
+
);
|
185 |
+
}
|
186 |
+
|
187 |
+
}
|
tests/Service/NotFoundRedirect/Callback.php
ADDED
@@ -0,0 +1,14 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
namespace AAM\UnitTest\Service\NotFoundRedirect;
|
4 |
+
|
5 |
+
class Callback
|
6 |
+
{
|
7 |
+
const REDIRECT_URL = 'https://aamplugin.com/redirect';
|
8 |
+
|
9 |
+
public static function redirectCallback()
|
10 |
+
{
|
11 |
+
header('Location: ' . self::REDIRECT_URL);
|
12 |
+
}
|
13 |
+
|
14 |
+
}
|
tests/Service/NotFoundRedirect/NotFoundRedirectTest.php
ADDED
@@ -0,0 +1,141 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
/**
|
4 |
+
* ======================================================================
|
5 |
+
* LICENSE: This file is subject to the terms and conditions defined in *
|
6 |
+
* file 'license.txt', which is part of this source code package. *
|
7 |
+
* ======================================================================
|
8 |
+
*/
|
9 |
+
|
10 |
+
namespace AAM\UnitTest\Service\NotFoundRedirect;
|
11 |
+
|
12 |
+
use AAM_Core_Config,
|
13 |
+
PHPUnit\Framework\TestCase,
|
14 |
+
AAM_Service_NotFoundRedirect,
|
15 |
+
AAM\UnitTest\Libs\ResetTrait;
|
16 |
+
|
17 |
+
/**
|
18 |
+
* 404 Redirect service
|
19 |
+
*
|
20 |
+
* @package AAM\UnitTest
|
21 |
+
* @version 6.0.0
|
22 |
+
*/
|
23 |
+
class NotFoundRedirectTest extends TestCase
|
24 |
+
{
|
25 |
+
use ResetTrait;
|
26 |
+
|
27 |
+
/**
|
28 |
+
* Test the default 404 redirect
|
29 |
+
*
|
30 |
+
* AAM should not issue any redirect headers
|
31 |
+
*
|
32 |
+
* @return void
|
33 |
+
*
|
34 |
+
* @access public
|
35 |
+
* @version 6.0.0
|
36 |
+
*/
|
37 |
+
public function testDefault404Redirect()
|
38 |
+
{
|
39 |
+
global $wp_query;
|
40 |
+
|
41 |
+
// Force 404 path
|
42 |
+
$wp_query->is_404 = true;
|
43 |
+
$service = AAM_Service_NotFoundRedirect::getInstance();
|
44 |
+
|
45 |
+
// Reset any already sent "Location" headers. This way insure that no other
|
46 |
+
// redirect headers are sent
|
47 |
+
header('Location: empty');
|
48 |
+
|
49 |
+
$service->wp();
|
50 |
+
|
51 |
+
$this->assertContains('Location: empty', xdebug_get_headers());
|
52 |
+
|
53 |
+
// Reset to default
|
54 |
+
$wp_query->is_404 = null;
|
55 |
+
}
|
56 |
+
|
57 |
+
/**
|
58 |
+
* Test redirect to the existing page
|
59 |
+
*
|
60 |
+
* @return void
|
61 |
+
*
|
62 |
+
* @access public
|
63 |
+
* @version 6.0.0
|
64 |
+
*/
|
65 |
+
public function testExistingPageLogoutRedirect()
|
66 |
+
{
|
67 |
+
global $wp_query;
|
68 |
+
|
69 |
+
// Set 404 config
|
70 |
+
AAM_Core_Config::set('frontend.404redirect.type', 'page');
|
71 |
+
AAM_Core_Config::set('frontend.404redirect.page', AAM_UNITTEST_PAGE_ID);
|
72 |
+
|
73 |
+
// Force 404 path
|
74 |
+
$wp_query->is_404 = true;
|
75 |
+
$service = AAM_Service_NotFoundRedirect::getInstance();
|
76 |
+
|
77 |
+
$service->wp();
|
78 |
+
|
79 |
+
$this->assertContains('Location: ' . get_page_link(AAM_UNITTEST_PAGE_ID), xdebug_get_headers());
|
80 |
+
|
81 |
+
// Reset to default
|
82 |
+
$wp_query->is_404 = null;
|
83 |
+
}
|
84 |
+
|
85 |
+
/**
|
86 |
+
* Test redirect to the defined URL
|
87 |
+
*
|
88 |
+
* @return void
|
89 |
+
*
|
90 |
+
* @access public
|
91 |
+
* @version 6.0.0
|
92 |
+
*/
|
93 |
+
public function testUrlLogoutRedirect()
|
94 |
+
{
|
95 |
+
global $wp_query;
|
96 |
+
|
97 |
+
// Set 404 config
|
98 |
+
AAM_Core_Config::set('frontend.404redirect.type', 'url');
|
99 |
+
AAM_Core_Config::set('frontend.404redirect.url', '/hello-world');
|
100 |
+
|
101 |
+
// Force 404 path
|
102 |
+
$wp_query->is_404 = true;
|
103 |
+
$service = AAM_Service_NotFoundRedirect::getInstance();
|
104 |
+
|
105 |
+
$service->wp();
|
106 |
+
|
107 |
+
$this->assertContains('Location: /hello-world', xdebug_get_headers());
|
108 |
+
|
109 |
+
// Reset to default
|
110 |
+
$wp_query->is_404 = null;
|
111 |
+
}
|
112 |
+
|
113 |
+
/**
|
114 |
+
* Test execution of the callback function as redirect
|
115 |
+
*
|
116 |
+
* @return void
|
117 |
+
*
|
118 |
+
* @access public
|
119 |
+
* @version 6.0.0
|
120 |
+
*/
|
121 |
+
public function testCallbackLogoutRedirect()
|
122 |
+
{
|
123 |
+
global $wp_query;
|
124 |
+
|
125 |
+
// Set 404 config
|
126 |
+
AAM_Core_Config::set('frontend.404redirect.type', 'callback');
|
127 |
+
AAM_Core_Config::set('frontend.404redirect.callback', 'AAM\\UnitTest\\Service\\NotFoundRedirect\\Callback::redirectCallback');
|
128 |
+
|
129 |
+
// Force 404 path
|
130 |
+
$wp_query->is_404 = true;
|
131 |
+
$service = AAM_Service_NotFoundRedirect::getInstance();
|
132 |
+
|
133 |
+
$service->wp();
|
134 |
+
|
135 |
+
$this->assertContains('Location: ' . Callback::REDIRECT_URL, xdebug_get_headers());
|
136 |
+
|
137 |
+
// Reset to default
|
138 |
+
$wp_query->is_404 = null;
|
139 |
+
}
|
140 |
+
|
141 |
+
}
|
tests/Service/Route/RouteTest.php
ADDED
@@ -0,0 +1,99 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
/**
|
4 |
+
* ======================================================================
|
5 |
+
* LICENSE: This file is subject to the terms and conditions defined in *
|
6 |
+
* file 'license.txt', which is part of this source code package. *
|
7 |
+
* ======================================================================
|
8 |
+
*/
|
9 |
+
|
10 |
+
namespace AAM\UnitTest\Service\Route;
|
11 |
+
|
12 |
+
use AAM,
|
13 |
+
WP_REST_Request,
|
14 |
+
AAM_Core_Config,
|
15 |
+
AAM_Service_Route,
|
16 |
+
AAM_Core_Object_Route,
|
17 |
+
PHPUnit\Framework\TestCase,
|
18 |
+
AAM\UnitTest\Libs\ResetTrait;
|
19 |
+
|
20 |
+
/**
|
21 |
+
* API Routes service tests
|
22 |
+
*
|
23 |
+
* @package AAM\UnitTest
|
24 |
+
* @version 6.0.0
|
25 |
+
*/
|
26 |
+
class RouteTest extends TestCase
|
27 |
+
{
|
28 |
+
use ResetTrait;
|
29 |
+
|
30 |
+
/**
|
31 |
+
* Test that XML-PRC is disabled
|
32 |
+
*
|
33 |
+
* @return void
|
34 |
+
*
|
35 |
+
* @access public
|
36 |
+
* @version 6.0.0
|
37 |
+
*/
|
38 |
+
public function testDisabledXMLRPC()
|
39 |
+
{
|
40 |
+
AAM_Core_Config::set('core.settings.xmlrpc', false);
|
41 |
+
|
42 |
+
$this->assertFalse(apply_filters('xmlrpc_enabled', true));
|
43 |
+
}
|
44 |
+
|
45 |
+
/**
|
46 |
+
* Test that RESTful API is disabled
|
47 |
+
*
|
48 |
+
* @return void
|
49 |
+
*
|
50 |
+
* @access public
|
51 |
+
* @version 6.0.0
|
52 |
+
*/
|
53 |
+
public function testDisabledRESTfulAPI()
|
54 |
+
{
|
55 |
+
AAM_Core_Config::set('core.settings.restful', false);
|
56 |
+
|
57 |
+
$error = apply_filters('rest_authentication_errors', null);
|
58 |
+
|
59 |
+
$this->assertEquals('WP_Error', get_class($error));
|
60 |
+
$this->assertEquals('RESTful API is disabled', $error->get_error_message());
|
61 |
+
}
|
62 |
+
|
63 |
+
/**
|
64 |
+
* Assert that jwt token is generated for the authentication request
|
65 |
+
*
|
66 |
+
* @return void
|
67 |
+
*
|
68 |
+
* @access public
|
69 |
+
* @version 6.0.0
|
70 |
+
*/
|
71 |
+
public function testRestrictedRESTfulEndpoint()
|
72 |
+
{
|
73 |
+
global $wp;
|
74 |
+
|
75 |
+
$object = AAM::getUser()->getObject(AAM_Core_Object_Route::OBJECT_TYPE);
|
76 |
+
|
77 |
+
// Restrict AAM authentication endpoint
|
78 |
+
$this->assertTrue(
|
79 |
+
$object->updateOptionItem('restful|/aam/v2/authenticate|post', true)->save()
|
80 |
+
);
|
81 |
+
|
82 |
+
// Register all the necessary hooks
|
83 |
+
|
84 |
+
$wp->query_vars['rest_route'] = true;
|
85 |
+
AAM_Service_Route::getInstance()->registerRouteControllers();
|
86 |
+
|
87 |
+
$server = rest_get_server();
|
88 |
+
|
89 |
+
$request = new WP_REST_Request('POST', '/aam/v2/authenticate');
|
90 |
+
$request->set_param('username', AAM_UNITTEST_USERNAME);
|
91 |
+
$request->set_param('password', AAM_UNITTEST_PASSWORD);
|
92 |
+
|
93 |
+
$error = $server->dispatch($request);
|
94 |
+
|
95 |
+
$this->assertEquals('WP_Error', get_class($error));
|
96 |
+
$this->assertEquals('Access Denied', $error->get_error_message());
|
97 |
+
}
|
98 |
+
|
99 |
+
}
|
tests/Service/SecureLogin/SecureLoginTest.php
ADDED
@@ -0,0 +1,151 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
/**
|
4 |
+
* ======================================================================
|
5 |
+
* LICENSE: This file is subject to the terms and conditions defined in *
|
6 |
+
* file 'license.txt', which is part of this source code package. *
|
7 |
+
* ======================================================================
|
8 |
+
*/
|
9 |
+
|
10 |
+
namespace AAM\UnitTest\Service\SecureLogin;
|
11 |
+
|
12 |
+
use AAM_Core_API,
|
13 |
+
AAM_Core_Config,
|
14 |
+
WP_Session_Tokens,
|
15 |
+
PHPUnit\Framework\TestCase,
|
16 |
+
AAM\UnitTest\Libs\ResetTrait;
|
17 |
+
|
18 |
+
/**
|
19 |
+
* Secure login features
|
20 |
+
*
|
21 |
+
* @package AAM\UnitTest
|
22 |
+
* @version 6.0.0
|
23 |
+
*/
|
24 |
+
class SecureLoginTest extends TestCase
|
25 |
+
{
|
26 |
+
use ResetTrait;
|
27 |
+
|
28 |
+
/**
|
29 |
+
* Test that "One Session Per User" works as expected
|
30 |
+
*
|
31 |
+
* @return void
|
32 |
+
*
|
33 |
+
* @access public
|
34 |
+
* @version 6.0.0
|
35 |
+
*/
|
36 |
+
public function testOneSessionPerUser()
|
37 |
+
{
|
38 |
+
// Enable "One Session Per User" feature
|
39 |
+
AAM_Core_Config::set('service.secureLogin.feature.singleSession', true);
|
40 |
+
|
41 |
+
// No need to generate Auth cookies
|
42 |
+
add_filter('send_auth_cookies', '__return_false');
|
43 |
+
|
44 |
+
// Define valid credentials
|
45 |
+
$creds = array(
|
46 |
+
'user_login' => AAM_UNITTEST_USERNAME,
|
47 |
+
'user_password' => AAM_UNITTEST_PASSWORD
|
48 |
+
);
|
49 |
+
|
50 |
+
// Sign-in user first time
|
51 |
+
$user = wp_signon($creds);
|
52 |
+
$this->assertEquals('WP_User', get_class($user));
|
53 |
+
|
54 |
+
// Now try to authenticate user again
|
55 |
+
$user = wp_signon($creds);
|
56 |
+
$this->assertEquals('WP_User', get_class($user));
|
57 |
+
|
58 |
+
// Finally verify that there is only one session persisted
|
59 |
+
$sessions = WP_Session_Tokens::get_instance($user->ID);
|
60 |
+
$this->assertCount(1, $sessions->get_all());
|
61 |
+
|
62 |
+
// Reset all sessions
|
63 |
+
$sessions->destroy_all();
|
64 |
+
}
|
65 |
+
|
66 |
+
/**
|
67 |
+
* Test the "Brute Force Lockout" feature
|
68 |
+
*
|
69 |
+
* Authentication process has to return WP_Error if number of allowed attempts
|
70 |
+
* exceeded its limit
|
71 |
+
*
|
72 |
+
* @return void
|
73 |
+
*
|
74 |
+
* @access public
|
75 |
+
* @version 6.0.0
|
76 |
+
*/
|
77 |
+
public function testBruteForceLockout()
|
78 |
+
{
|
79 |
+
// Enable "Brute Force Lockout" feature
|
80 |
+
AAM_Core_Config::set('service.secureLogin.feature.bruteForceLockout', true);
|
81 |
+
|
82 |
+
// Force dummy user IP
|
83 |
+
$ip = '127.0.0.1';
|
84 |
+
$_SERVER['REMOTE_ADDR'] = $ip;
|
85 |
+
|
86 |
+
// Force to max out the number of attempts
|
87 |
+
set_transient('aam_failed_login_attempts_' . $ip, 50, time() + 10);
|
88 |
+
|
89 |
+
// No need to generate Auth cookies
|
90 |
+
add_filter('send_auth_cookies', '__return_false');
|
91 |
+
|
92 |
+
// Define valid credentials
|
93 |
+
$creds = array(
|
94 |
+
'user_login' => AAM_UNITTEST_USERNAME,
|
95 |
+
'user_password' => AAM_UNITTEST_PASSWORD
|
96 |
+
);
|
97 |
+
|
98 |
+
// Sign-in user first time
|
99 |
+
$user = wp_signon($creds);
|
100 |
+
|
101 |
+
$this->assertEquals('WP_Error', get_class($user));
|
102 |
+
$this->assertEquals('Exceeded maximum number for authentication attempts. Try again later.', $user->get_error_message());
|
103 |
+
|
104 |
+
// Also make sure that attempts counter was increased
|
105 |
+
$this->assertEquals(51, get_transient('aam_failed_login_attempts_' . $ip));
|
106 |
+
|
107 |
+
// Reset original state
|
108 |
+
delete_transient('aam_failed_login_attempts_' . $ip);
|
109 |
+
unset($_SERVER['REMOTE_ADDR']);
|
110 |
+
}
|
111 |
+
|
112 |
+
/**
|
113 |
+
* Test that it fails to authenticate locked user
|
114 |
+
*
|
115 |
+
* @return void
|
116 |
+
*
|
117 |
+
* @access public
|
118 |
+
* @version 6.0.0
|
119 |
+
*/
|
120 |
+
public function testUserLockedStatus()
|
121 |
+
{
|
122 |
+
global $wpdb;
|
123 |
+
|
124 |
+
$result = $wpdb->update(
|
125 |
+
$wpdb->users, array('user_status' => 1), array('ID' => AAM_UNITTEST_JOHN_ID)
|
126 |
+
);
|
127 |
+
|
128 |
+
// Make sure that row is updated
|
129 |
+
$this->assertEquals(1, $result);
|
130 |
+
|
131 |
+
// No need to generate Auth cookies
|
132 |
+
add_filter('send_auth_cookies', '__return_false');
|
133 |
+
|
134 |
+
// Define valid credentials
|
135 |
+
$creds = array(
|
136 |
+
'user_login' => AAM_UNITTEST_USERNAME,
|
137 |
+
'user_password' => AAM_UNITTEST_PASSWORD
|
138 |
+
);
|
139 |
+
|
140 |
+
// Sign-in user first time
|
141 |
+
$user = wp_signon($creds);
|
142 |
+
$this->assertEquals('WP_Error', get_class($user));
|
143 |
+
$this->assertEquals('<strong>ERROR</strong>: User is locked. Contact website administrator.', $user->get_error_message());
|
144 |
+
|
145 |
+
// Restore user status
|
146 |
+
$result = $wpdb->update(
|
147 |
+
$wpdb->users, array('user_status' => 0), array('ID' => AAM_UNITTEST_JOHN_ID)
|
148 |
+
);
|
149 |
+
}
|
150 |
+
|
151 |
+
}
|
tests/Service/Toolbar/MultipleRoleInheritanceTest.php
ADDED
@@ -0,0 +1,179 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
/**
|
4 |
+
* ======================================================================
|
5 |
+
* LICENSE: This file is subject to the terms and conditions defined in *
|
6 |
+
* file 'license.txt', which is part of this source code package. *
|
7 |
+
* ======================================================================
|
8 |
+
*/
|
9 |
+
|
10 |
+
namespace AAM\UnitTest\Service\Toolbar;
|
11 |
+
|
12 |
+
use AAM,
|
13 |
+
AAM_Core_Config,
|
14 |
+
AAM_Core_Object_Toolbar,
|
15 |
+
PHPUnit\Framework\TestCase,
|
16 |
+
AAM\UnitTest\Libs\ResetTrait,
|
17 |
+
AAM\UnitTest\Libs\AuthMultiRoleUserTrait,
|
18 |
+
AAM\UnitTest\Libs\MultiRoleOptionInterface;
|
19 |
+
|
20 |
+
/**
|
21 |
+
* Test AAM access settings inheritance mechanism for multiple roles per user for
|
22 |
+
* the Admin Toolbar service
|
23 |
+
*
|
24 |
+
* Admin Toolbar is available only for authenticated users so no Visitors are tested
|
25 |
+
*
|
26 |
+
* @package AAM\UnitTest
|
27 |
+
* @version 6.0.0
|
28 |
+
*/
|
29 |
+
class MultipleRoleInheritanceTest extends TestCase implements MultiRoleOptionInterface
|
30 |
+
{
|
31 |
+
use ResetTrait,
|
32 |
+
AuthMultiRoleUserTrait;
|
33 |
+
|
34 |
+
/**
|
35 |
+
* Test that access settings are inherited from multiple parent roles
|
36 |
+
*
|
37 |
+
* This test is designed to verify that access settings are propagated property
|
38 |
+
* when there access settings defined for multiple parent roles.
|
39 |
+
*
|
40 |
+
* @return void
|
41 |
+
*
|
42 |
+
* @access public
|
43 |
+
* @version 6.0.0
|
44 |
+
*/
|
45 |
+
public function testInheritanceMergeFromMultipleRoles()
|
46 |
+
{
|
47 |
+
$user = AAM::getUser();
|
48 |
+
$role = $user->getParent();
|
49 |
+
|
50 |
+
// Make sure that we have parent roles defined properly
|
51 |
+
$this->assertEquals('AAM_Core_Subject_Role', get_class($role));
|
52 |
+
|
53 |
+
// Save access settings for the base role and iterate over each sibling and
|
54 |
+
// add additional settings
|
55 |
+
$object = $role->getObject(AAM_Core_Object_Toolbar::OBJECT_TYPE, null, true);
|
56 |
+
$this->assertTrue($object->updateOptionItem('new-page', true)->save());
|
57 |
+
|
58 |
+
foreach($role->getSiblings() as $i => $sibling) {
|
59 |
+
// Save access settings for each role and make sure they are saved property
|
60 |
+
// Check if save returns positive result
|
61 |
+
$this->assertTrue(
|
62 |
+
$sibling->getObject(AAM_Core_Object_Toolbar::OBJECT_TYPE, null, true)->updateOptionItem(
|
63 |
+
'new-page-' . ($i + 1), ($i % 2 ? true : false)
|
64 |
+
)->save()
|
65 |
+
);
|
66 |
+
}
|
67 |
+
|
68 |
+
// Reset internal AAM cache
|
69 |
+
$this->_resetSubjects();
|
70 |
+
|
71 |
+
// Assert that we have both roles merged result is as following
|
72 |
+
// Array (
|
73 |
+
// new-page => true,
|
74 |
+
// new-page-1 => false
|
75 |
+
// )
|
76 |
+
$option = $user->getObject(AAM_Core_Object_Toolbar::OBJECT_TYPE)->getOption();
|
77 |
+
$this->assertSame(
|
78 |
+
array('new-page' => true, 'new-page-1' => false), $option
|
79 |
+
);
|
80 |
+
}
|
81 |
+
|
82 |
+
/**
|
83 |
+
* Test that access settings are merged with default "deny" precedence correctly
|
84 |
+
*
|
85 |
+
* @return void
|
86 |
+
*
|
87 |
+
* @access public
|
88 |
+
* @version 6.0.0
|
89 |
+
*/
|
90 |
+
public function testInheritanceDenyPrecedenceFromMultipleRoles()
|
91 |
+
{
|
92 |
+
$user = AAM::getUser();
|
93 |
+
$role = $user->getParent();
|
94 |
+
|
95 |
+
// Make sure that we have parent roles defined properly
|
96 |
+
$this->assertEquals('AAM_Core_Subject_Role', get_class($role));
|
97 |
+
|
98 |
+
// Save access settings for the base role and iterate over each sibling and
|
99 |
+
// add additional settings
|
100 |
+
$this->assertTrue(
|
101 |
+
$role->getObject(AAM_Core_Object_Toolbar::OBJECT_TYPE, null, true)->updateOptionItem(
|
102 |
+
'new-page', true
|
103 |
+
)->save()
|
104 |
+
);
|
105 |
+
|
106 |
+
foreach($role->getSiblings() as $sibling) {
|
107 |
+
// Save access settings for each role and make sure they are saved property
|
108 |
+
// Check if save returns positive result
|
109 |
+
$this->assertTrue(
|
110 |
+
$sibling->getObject(AAM_Core_Object_Toolbar::OBJECT_TYPE, null, true)->updateOptionItem(
|
111 |
+
'new-page', false
|
112 |
+
)->save()
|
113 |
+
);
|
114 |
+
}
|
115 |
+
|
116 |
+
// Reset internal AAM cache
|
117 |
+
$this->_resetSubjects();
|
118 |
+
|
119 |
+
// Assert that we have both roles merged result is as following
|
120 |
+
// Array (
|
121 |
+
// new-page => true
|
122 |
+
// )
|
123 |
+
$option = $user->getObject(AAM_Core_Object_Toolbar::OBJECT_TYPE)->getOption();
|
124 |
+
$this->assertSame(
|
125 |
+
array('new-page' => true), $option
|
126 |
+
);
|
127 |
+
}
|
128 |
+
|
129 |
+
/**
|
130 |
+
* Test that access settings are merged correctly with "allowed" precedence
|
131 |
+
* correctly
|
132 |
+
*
|
133 |
+
* @return void
|
134 |
+
* @version 6.0.0
|
135 |
+
*/
|
136 |
+
public function testInheritanceAllowPrecedenceFromMultipleRoles()
|
137 |
+
{
|
138 |
+
$user = AAM::getUser();
|
139 |
+
$role = $user->getParent();
|
140 |
+
|
141 |
+
// Make sure that we have parent roles defined properly
|
142 |
+
$this->assertEquals('AAM_Core_Subject_Role', get_class($role));
|
143 |
+
|
144 |
+
// Save access settings for the base role and iterate over each sibling and
|
145 |
+
// add additional settings
|
146 |
+
$this->assertTrue(
|
147 |
+
$role->getObject(AAM_Core_Object_Toolbar::OBJECT_TYPE, null, true)->updateOptionItem(
|
148 |
+
'new-page', true
|
149 |
+
)->save()
|
150 |
+
);
|
151 |
+
|
152 |
+
foreach($role->getSiblings() as $sibling) {
|
153 |
+
// Save access settings for each role and make sure they are saved property
|
154 |
+
// Check if save returns positive result
|
155 |
+
$this->assertTrue(
|
156 |
+
$sibling->getObject(AAM_Core_Object_Toolbar::OBJECT_TYPE, null, true)->updateOptionItem(
|
157 |
+
'new-page', false
|
158 |
+
)->save()
|
159 |
+
);
|
160 |
+
}
|
161 |
+
|
162 |
+
// Override the default "deny" precedence
|
163 |
+
AAM_Core_Config::set(
|
164 |
+
sprintf('core.settings.%s.merge.preference', AAM_Core_Object_Toolbar::OBJECT_TYPE),
|
165 |
+
'allow'
|
166 |
+
);
|
167 |
+
|
168 |
+
// Reset internal AAM cache
|
169 |
+
$this->_resetSubjects();
|
170 |
+
|
171 |
+
// Assert that we have both roles merged result is as following
|
172 |
+
// Array (
|
173 |
+
// new-page => false
|
174 |
+
// )
|
175 |
+
$option = $user->getObject(AAM_Core_Object_Toolbar::OBJECT_TYPE)->getOption();
|
176 |
+
$this->assertSame(array('new-page' => false), $option);
|
177 |
+
}
|
178 |
+
|
179 |
+
}
|
tests/Service/Toolbar/SingleRoleInheritanceTest.php
ADDED
@@ -0,0 +1,225 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
/**
|
4 |
+
* ======================================================================
|
5 |
+
* LICENSE: This file is subject to the terms and conditions defined in *
|
6 |
+
* file 'license.txt', which is part of this source code package. *
|
7 |
+
* ======================================================================
|
8 |
+
*/
|
9 |
+
|
10 |
+
namespace AAM\UnitTest\Service\Toolbar;
|
11 |
+
|
12 |
+
use AAM,
|
13 |
+
AAM_Core_Object_Toolbar,
|
14 |
+
PHPUnit\Framework\TestCase,
|
15 |
+
AAM\UnitTest\Libs\ResetTrait,
|
16 |
+
AAM\UnitTest\Libs\AuthUserTrait;
|
17 |
+
|
18 |
+
/**
|
19 |
+
* Test AAM access settings inheritance mechanism for the Toolbar service
|
20 |
+
*
|
21 |
+
* Toolbar is available only for authenticated users so no Visitors are tested
|
22 |
+
*
|
23 |
+
* @author Vasyl Martyniuk <vasyl@vasyltech.com>
|
24 |
+
* @version 6.0.0
|
25 |
+
*/
|
26 |
+
class SingleRoleInheritanceTest extends TestCase
|
27 |
+
{
|
28 |
+
use ResetTrait,
|
29 |
+
AuthUserTrait;
|
30 |
+
|
31 |
+
/**
|
32 |
+
* Test to insure that access settings are stored property on the User level
|
33 |
+
*
|
34 |
+
* @return void
|
35 |
+
*
|
36 |
+
* @access public
|
37 |
+
* @see AAM_Core_Subject_User::updateOption
|
38 |
+
* @version 6.0.0
|
39 |
+
*/
|
40 |
+
public function testSaveToolbarOption()
|
41 |
+
{
|
42 |
+
$user = AAM::getUser();
|
43 |
+
$object = $user->getObject(AAM_Core_Object_Toolbar::OBJECT_TYPE);
|
44 |
+
|
45 |
+
// Check if save returns positive result
|
46 |
+
$this->assertTrue($object->updateOptionItem('new-page', true)->save());
|
47 |
+
|
48 |
+
// Read from the database saved values and assert that we have
|
49 |
+
// Array (
|
50 |
+
// index.php => true
|
51 |
+
// )
|
52 |
+
$option = $user->readOption(AAM_Core_Object_Toolbar::OBJECT_TYPE);
|
53 |
+
$this->assertSame(array('new-page' => true), $option);
|
54 |
+
}
|
55 |
+
|
56 |
+
/**
|
57 |
+
* Test that access settings are inherited from the parent role property
|
58 |
+
*
|
59 |
+
* This test is designed to verify that access settings are propagated property
|
60 |
+
* when there is only one role assigned to a user.
|
61 |
+
*
|
62 |
+
* @return void
|
63 |
+
*
|
64 |
+
* @access public
|
65 |
+
* @version 6.0.0
|
66 |
+
*/
|
67 |
+
public function testInheritanceFromSingleRole()
|
68 |
+
{
|
69 |
+
$user = AAM::getUser();
|
70 |
+
$parent = $user->getParent();
|
71 |
+
$object = $parent->getObject(AAM_Core_Object_Toolbar::OBJECT_TYPE);
|
72 |
+
|
73 |
+
// Make sure that we have parent role defined
|
74 |
+
$this->assertEquals('AAM_Core_Subject_Role', get_class($parent));
|
75 |
+
|
76 |
+
// Save access settings for the role and make sure they are saved property
|
77 |
+
// Check if save returns positive result
|
78 |
+
$this->assertTrue($object->updateOptionItem('new-page', true)->save());
|
79 |
+
|
80 |
+
// Read from the database saved values and assert that we have
|
81 |
+
// Array (
|
82 |
+
// index.php => true
|
83 |
+
// )
|
84 |
+
$option = $parent->readOption(AAM_Core_Object_Toolbar::OBJECT_TYPE);
|
85 |
+
$this->assertSame(array('new-page' => true), $option);
|
86 |
+
|
87 |
+
// Finally verify that access settings are propagated property to the User
|
88 |
+
// Level
|
89 |
+
$menu = $user->getObject(AAM_Core_Object_Toolbar::OBJECT_TYPE);
|
90 |
+
$this->assertSame(array('new-page' => true), $menu->getOption());
|
91 |
+
}
|
92 |
+
|
93 |
+
/**
|
94 |
+
* Test that access settings are propagated and merged properly
|
95 |
+
*
|
96 |
+
* The test is designed to verify that access settings are propagated properly
|
97 |
+
* from the parent role and merged well with explicitly defined access settings on
|
98 |
+
* the User level.
|
99 |
+
*
|
100 |
+
* The expected result is to have combined array of access settings from the parent
|
101 |
+
* role and specific user.
|
102 |
+
*
|
103 |
+
* @return void
|
104 |
+
*
|
105 |
+
* @access public
|
106 |
+
* @version 6.0.0
|
107 |
+
*/
|
108 |
+
public function testInheritanceMergeFromSingleRole()
|
109 |
+
{
|
110 |
+
$user = AAM::getUser();
|
111 |
+
$parent = $user->getParent();
|
112 |
+
|
113 |
+
$object = $parent->getObject(AAM_Core_Object_Toolbar::OBJECT_TYPE);
|
114 |
+
|
115 |
+
// Save access settings for the role and make sure they are saved property
|
116 |
+
// Check if save returns positive result
|
117 |
+
$this->assertTrue($object->updateOptionItem('new-page', true)->save());
|
118 |
+
|
119 |
+
// Save access setting for the user and make sure they are saved property
|
120 |
+
$menu = $user->getObject(AAM_Core_Object_Toolbar::OBJECT_TYPE, null, true);
|
121 |
+
$this->assertTrue($menu->updateOptionItem('new-post', false)->save());
|
122 |
+
|
123 |
+
// Reset cache and try to kick-in the inheritance mechanism
|
124 |
+
$this->_resetSubjects();
|
125 |
+
|
126 |
+
$menu = $user->getObject(AAM_Core_Object_Toolbar::OBJECT_TYPE);
|
127 |
+
$this->assertSame(
|
128 |
+
array('new-page' => true, 'new-post' => false),
|
129 |
+
$menu->getOption()
|
130 |
+
);
|
131 |
+
}
|
132 |
+
|
133 |
+
/**
|
134 |
+
* Test that the full inheritance mechanism is working as expected
|
135 |
+
*
|
136 |
+
* Make sure that access settings are propagated and merged properly from the top
|
137 |
+
* (Default Level) to the bottom (User Level).
|
138 |
+
*
|
139 |
+
* @return void
|
140 |
+
*
|
141 |
+
* @access public
|
142 |
+
* @version 6.0.0
|
143 |
+
*/
|
144 |
+
public function testFullInheritanceChainSingeRole()
|
145 |
+
{
|
146 |
+
$user = AAM::getUser();
|
147 |
+
$role = $user->getParent();
|
148 |
+
$default = $role->getParent();
|
149 |
+
|
150 |
+
$userMenu = $user->getObject(AAM_Core_Object_Toolbar::OBJECT_TYPE, null, true);
|
151 |
+
$roleMenu = $role->getObject(AAM_Core_Object_Toolbar::OBJECT_TYPE, null, true);
|
152 |
+
$defaultMenu = $default->getObject(AAM_Core_Object_Toolbar::OBJECT_TYPE, null, true);
|
153 |
+
|
154 |
+
// Save access settings for all subjects
|
155 |
+
$this->assertTrue($userMenu->updateOptionItem('new-post', true)->save());
|
156 |
+
$this->assertTrue($roleMenu->updateOptionItem('new-page', true)->save());
|
157 |
+
$this->assertTrue($defaultMenu->updateOptionItem('new-media', true)->save());
|
158 |
+
|
159 |
+
// Reset cache and try to kick-in the inheritance mechanism
|
160 |
+
$this->_resetSubjects();
|
161 |
+
|
162 |
+
// All settings has to be merged into one array
|
163 |
+
$menu = $user->getObject(AAM_Core_Object_Toolbar::OBJECT_TYPE);
|
164 |
+
$this->assertSame(
|
165 |
+
array(
|
166 |
+
'new-media' => true,
|
167 |
+
'new-page' => true,
|
168 |
+
'new-post' => true
|
169 |
+
),
|
170 |
+
$menu->getOption()
|
171 |
+
);
|
172 |
+
}
|
173 |
+
|
174 |
+
/**
|
175 |
+
* Test that access settings overwrite works as expected
|
176 |
+
*
|
177 |
+
* The expected result is lower Access Level overwrite access settings from the
|
178 |
+
* higher Access Level.
|
179 |
+
*
|
180 |
+
* @return void
|
181 |
+
*
|
182 |
+
* @access public
|
183 |
+
* @version 6.0.0
|
184 |
+
*/
|
185 |
+
public function testInheritanceOverrideForSingleRole()
|
186 |
+
{
|
187 |
+
$user = AAM::getUser();
|
188 |
+
$parent = $user->getParent();
|
189 |
+
|
190 |
+
$object = $parent->getObject(AAM_Core_Object_Toolbar::OBJECT_TYPE);
|
191 |
+
|
192 |
+
// Save access settings for the role and make sure they are saved property
|
193 |
+
// Check if save returns positive result
|
194 |
+
$this->assertTrue($object->updateOptionItem('new-post', true)->save());
|
195 |
+
|
196 |
+
// Save access setting for the user and make sure they are saved property
|
197 |
+
$menu = $user->getObject(AAM_Core_Object_Toolbar::OBJECT_TYPE, null, true);
|
198 |
+
$this->assertTrue($menu->updateOptionItem('new-post', false)->save());
|
199 |
+
|
200 |
+
// Reset cache and try to kick-in the inheritance mechanism
|
201 |
+
$this->_resetSubjects();
|
202 |
+
|
203 |
+
$menu = $user->getObject(AAM_Core_Object_Toolbar::OBJECT_TYPE);
|
204 |
+
$this->assertSame(array('new-post' => false), $menu->getOption());
|
205 |
+
}
|
206 |
+
|
207 |
+
public function testToolbarRendering()
|
208 |
+
{
|
209 |
+
$_SERVER['HTTP_HOST'] = 'aamplugin.com';
|
210 |
+
$_SERVER['REQUEST_URI'] = '/wp-admin';
|
211 |
+
|
212 |
+
// Restrict access to the Log Out menu and make sure it is not rendered
|
213 |
+
$object = AAM::getUser()->getObject(AAM_Core_Object_Toolbar::OBJECT_TYPE);
|
214 |
+
$this->assertTrue($object->updateOptionItem('logout', true)->save());
|
215 |
+
|
216 |
+
ob_start();
|
217 |
+
_wp_admin_bar_init();
|
218 |
+
wp_admin_bar_render();
|
219 |
+
$content = ob_get_contents();
|
220 |
+
ob_end_clean();
|
221 |
+
|
222 |
+
$this->assertEquals(false, strpos($content, "id='wp-admin-bar-logout'"));
|
223 |
+
}
|
224 |
+
|
225 |
+
}
|
tests/Service/Uri/Callback.php
ADDED
@@ -0,0 +1,14 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
namespace AAM\UnitTest\Service\Uri;
|
4 |
+
|
5 |
+
class Callback
|
6 |
+
{
|
7 |
+
const REDIRECT_URL = 'https://aamplugin.com/redirect';
|
8 |
+
|
9 |
+
public static function redirectCallback()
|
10 |
+
{
|
11 |
+
header('Location: ' . self::REDIRECT_URL);
|
12 |
+
}
|
13 |
+
|
14 |
+
}
|
tests/Service/Uri/UriTest.php
ADDED
@@ -0,0 +1,177 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
/**
|
4 |
+
* ======================================================================
|
5 |
+
* LICENSE: This file is subject to the terms and conditions defined in *
|
6 |
+
* file 'license.txt', which is part of this source code package. *
|
7 |
+
* ======================================================================
|
8 |
+
*/
|
9 |
+
|
10 |
+
namespace AAM\UnitTest\Service\Uri;
|
11 |
+
|
12 |
+
use AAM,
|
13 |
+
AAM_Service_Uri,
|
14 |
+
AAM_Core_Object_Uri,
|
15 |
+
PHPUnit\Framework\TestCase,
|
16 |
+
AAM\UnitTest\Libs\ResetTrait;
|
17 |
+
|
18 |
+
/**
|
19 |
+
* URI Access service
|
20 |
+
*
|
21 |
+
* @package AAM\UnitTest
|
22 |
+
* @version 6.0.0
|
23 |
+
*/
|
24 |
+
class UriTest extends TestCase
|
25 |
+
{
|
26 |
+
use ResetTrait;
|
27 |
+
|
28 |
+
/**
|
29 |
+
* Test default "Access Denied" message
|
30 |
+
*
|
31 |
+
* @return void
|
32 |
+
*
|
33 |
+
* @access public
|
34 |
+
* @version 6.0.0
|
35 |
+
*/
|
36 |
+
public function testAccessDeniedMessage()
|
37 |
+
{
|
38 |
+
$object = AAM::getUser()->getObject(AAM_Core_Object_Uri::OBJECT_TYPE);
|
39 |
+
$result = $object->updateOptionItem('/hello-world', array(
|
40 |
+
'type' => 'default',
|
41 |
+
'action' => null
|
42 |
+
))->save();
|
43 |
+
|
44 |
+
$this->assertTrue($result);
|
45 |
+
|
46 |
+
// Override the default handlers so we can suppress die exit
|
47 |
+
add_filter('wp_die_handler', function() {
|
48 |
+
return function($message, $title) {
|
49 |
+
_default_wp_die_handler($message, $title, array('exit' => false));
|
50 |
+
};
|
51 |
+
}, PHP_INT_MAX);
|
52 |
+
$_SERVER['REQUEST_URI'] = '/hello-world';
|
53 |
+
|
54 |
+
ob_start();
|
55 |
+
AAM_Service_Uri::getInstance()->authorizeUri();
|
56 |
+
$content = ob_get_contents();
|
57 |
+
ob_end_clean();
|
58 |
+
|
59 |
+
$this->assertStringContainsString('Access Denied', $content);
|
60 |
+
}
|
61 |
+
|
62 |
+
/**
|
63 |
+
* Test custom wp_die message
|
64 |
+
*
|
65 |
+
* @return void
|
66 |
+
*
|
67 |
+
* @access public
|
68 |
+
* @version 6.0.0
|
69 |
+
*/
|
70 |
+
public function testCustomMessage()
|
71 |
+
{
|
72 |
+
$object = AAM::getUser()->getObject(AAM_Core_Object_Uri::OBJECT_TYPE);
|
73 |
+
$result = $object->updateOptionItem('/hello-world', array(
|
74 |
+
'type' => 'message',
|
75 |
+
'action' => 'This is not allowed'
|
76 |
+
))->save();
|
77 |
+
|
78 |
+
$this->assertTrue($result);
|
79 |
+
|
80 |
+
// Override the default handlers so we can suppress die exit
|
81 |
+
add_filter('wp_die_handler', function() {
|
82 |
+
return function($message, $title) {
|
83 |
+
_default_wp_die_handler($message, $title, array('exit' => false));
|
84 |
+
};
|
85 |
+
}, PHP_INT_MAX);
|
86 |
+
$_SERVER['REQUEST_URI'] = '/hello-world';
|
87 |
+
|
88 |
+
ob_start();
|
89 |
+
AAM_Service_Uri::getInstance()->authorizeUri();
|
90 |
+
$content = ob_get_contents();
|
91 |
+
ob_end_clean();
|
92 |
+
|
93 |
+
$this->assertStringContainsString('This is not allowed', $content);
|
94 |
+
}
|
95 |
+
|
96 |
+
/**
|
97 |
+
* Test redirect to the custom page
|
98 |
+
*
|
99 |
+
* @return void
|
100 |
+
*
|
101 |
+
* @access public
|
102 |
+
* @version 6.0.0
|
103 |
+
*/
|
104 |
+
public function testRedirectToExistingPage()
|
105 |
+
{
|
106 |
+
$object = AAM::getUser()->getObject(AAM_Core_Object_Uri::OBJECT_TYPE);
|
107 |
+
$result = $object->updateOptionItem('/hello-world', array(
|
108 |
+
'type' => 'page',
|
109 |
+
'action' => AAM_UNITTEST_PAGE_ID
|
110 |
+
))->save();
|
111 |
+
|
112 |
+
$this->assertTrue($result);
|
113 |
+
|
114 |
+
$_SERVER['REQUEST_URI'] = '/hello-world';
|
115 |
+
|
116 |
+
AAM_Service_Uri::getInstance()->authorizeUri();
|
117 |
+
|
118 |
+
$this->assertContains(
|
119 |
+
'Location: ' . get_page_link(AAM_UNITTEST_PAGE_ID), xdebug_get_headers()
|
120 |
+
);
|
121 |
+
}
|
122 |
+
|
123 |
+
/**
|
124 |
+
* Test redirect to the local URL
|
125 |
+
*
|
126 |
+
* @return void
|
127 |
+
*
|
128 |
+
* @access public
|
129 |
+
* @version 6.0.0
|
130 |
+
*/
|
131 |
+
public function testRedirectToUrl()
|
132 |
+
{
|
133 |
+
$object = AAM::getUser()->getObject(AAM_Core_Object_Uri::OBJECT_TYPE);
|
134 |
+
$result = $object->updateOptionItem('/hello-world', array(
|
135 |
+
'type' => 'url',
|
136 |
+
'action' => '/another-page'
|
137 |
+
))->save();
|
138 |
+
|
139 |
+
$this->assertTrue($result);
|
140 |
+
|
141 |
+
$_SERVER['REQUEST_URI'] = '/hello-world';
|
142 |
+
|
143 |
+
AAM_Service_Uri::getInstance()->authorizeUri();
|
144 |
+
|
145 |
+
$this->assertContains(
|
146 |
+
'Location: /another-page', xdebug_get_headers()
|
147 |
+
);
|
148 |
+
}
|
149 |
+
|
150 |
+
/**
|
151 |
+
* Test trigger of the callback function
|
152 |
+
*
|
153 |
+
* @return void
|
154 |
+
*
|
155 |
+
* @access public
|
156 |
+
* @version 6.0.0
|
157 |
+
*/
|
158 |
+
public function testTriggerCallback()
|
159 |
+
{
|
160 |
+
$object = AAM::getUser()->getObject(AAM_Core_Object_Uri::OBJECT_TYPE);
|
161 |
+
$result = $object->updateOptionItem('/hello-world', array(
|
162 |
+
'type' => 'callback',
|
163 |
+
'action' => 'AAM\\UnitTest\\Service\\Uri\\Callback::redirectCallback'
|
164 |
+
))->save();
|
165 |
+
|
166 |
+
$this->assertTrue($result);
|
167 |
+
|
168 |
+
$_SERVER['REQUEST_URI'] = '/hello-world';
|
169 |
+
|
170 |
+
AAM_Service_Uri::getInstance()->authorizeUri();
|
171 |
+
|
172 |
+
$this->assertContains(
|
173 |
+
'Location: ' . Callback::REDIRECT_URL, xdebug_get_headers()
|
174 |
+
);
|
175 |
+
}
|
176 |
+
|
177 |
+
}
|
tests/Service/UserLevelFilter/UserLevelFilterTest.php
ADDED
@@ -0,0 +1,151 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
/**
|
4 |
+
* ======================================================================
|
5 |
+
* LICENSE: This file is subject to the terms and conditions defined in *
|
6 |
+
* file 'license.txt', which is part of this source code package. *
|
7 |
+
* ======================================================================
|
8 |
+
*/
|
9 |
+
|
10 |
+
namespace AAM\UnitTest\Service\AdminMenu;
|
11 |
+
|
12 |
+
use AAM,
|
13 |
+
WP_User_Query,
|
14 |
+
PHPUnit\Framework\TestCase,
|
15 |
+
AAM\UnitTest\Libs\ResetTrait,
|
16 |
+
AAM\UnitTest\Libs\AuthManagerUserTrait;
|
17 |
+
|
18 |
+
/**
|
19 |
+
* Test User Level Filter service
|
20 |
+
*
|
21 |
+
* @package AAM\UnitTest
|
22 |
+
* @version 6.0.0
|
23 |
+
*/
|
24 |
+
class UserLevelFilterTest extends TestCase
|
25 |
+
{
|
26 |
+
use ResetTrait,
|
27 |
+
AuthManagerUserTrait;
|
28 |
+
|
29 |
+
/**
|
30 |
+
* Test that only allowed roles are returned
|
31 |
+
*
|
32 |
+
* @return void
|
33 |
+
*
|
34 |
+
* @access public
|
35 |
+
* @version 6.0.0
|
36 |
+
*/
|
37 |
+
public function testEditableRoles()
|
38 |
+
{
|
39 |
+
require_once ABSPATH . '/wp-admin/includes/user.php';
|
40 |
+
|
41 |
+
$roles = get_editable_roles();
|
42 |
+
|
43 |
+
$this->assertFalse(array_key_exists('administrator', $roles));
|
44 |
+
}
|
45 |
+
|
46 |
+
/**
|
47 |
+
* Test that restricted roles are added to the "excluded" list of roles during
|
48 |
+
* search
|
49 |
+
*
|
50 |
+
* @return void
|
51 |
+
*
|
52 |
+
* @access public
|
53 |
+
* @version 6.0.0
|
54 |
+
*/
|
55 |
+
public function testPrepareUserQuery()
|
56 |
+
{
|
57 |
+
$query = new WP_User_Query(array(
|
58 |
+
'search' => 'a'
|
59 |
+
));
|
60 |
+
|
61 |
+
$this->assertEquals(array('administrator'), $query->query_vars['role__not_in']);
|
62 |
+
}
|
63 |
+
|
64 |
+
/**
|
65 |
+
* Test that top User List table view does not have restricted roles listed
|
66 |
+
*
|
67 |
+
* @return void
|
68 |
+
*
|
69 |
+
* @access public
|
70 |
+
* @version 6.0.0
|
71 |
+
*/
|
72 |
+
public function testListTableViews()
|
73 |
+
{
|
74 |
+
if (!isset($GLOBALS['hook_suffix'])) {
|
75 |
+
$GLOBALS['hook_suffix'] = 'users';
|
76 |
+
}
|
77 |
+
|
78 |
+
require_once ABSPATH . 'wp-admin/includes/admin.php';
|
79 |
+
|
80 |
+
$table = _get_list_table( 'WP_Users_List_Table' , array('screen' => 'users'));
|
81 |
+
|
82 |
+
ob_start();
|
83 |
+
$table->views();
|
84 |
+
$content = ob_get_contents();
|
85 |
+
ob_end_clean();
|
86 |
+
|
87 |
+
$this->assertFalse(strpos($content, "class='administrator'"));
|
88 |
+
}
|
89 |
+
|
90 |
+
/**
|
91 |
+
* Test that subadmin is allowed to manage users with lower user level
|
92 |
+
*
|
93 |
+
* @return void
|
94 |
+
*
|
95 |
+
* @access public
|
96 |
+
* @version 6.0.0
|
97 |
+
*/
|
98 |
+
public function testAllowedUserEdit()
|
99 |
+
{
|
100 |
+
$this->assertTrue(current_user_can('edit_user', AAM_UNITTEST_JOHN_ID));
|
101 |
+
}
|
102 |
+
|
103 |
+
/**
|
104 |
+
* Test that subadmin is not allowed to manage users with higher user level
|
105 |
+
*
|
106 |
+
* @return void
|
107 |
+
*
|
108 |
+
* @access public
|
109 |
+
* @version 6.0.0
|
110 |
+
*/
|
111 |
+
public function testNotAllowedUserEdit()
|
112 |
+
{
|
113 |
+
$this->assertFalse(current_user_can('edit_user', AAM_UNITTEST_AUTH_USER_ID));
|
114 |
+
}
|
115 |
+
|
116 |
+
/**
|
117 |
+
* Test that subadmin is allowed to manage users with the same user level
|
118 |
+
*
|
119 |
+
* @return void
|
120 |
+
*
|
121 |
+
* @access public
|
122 |
+
* @version 6.0.0
|
123 |
+
*/
|
124 |
+
public function testAllowedSameLevelUserEdit()
|
125 |
+
{
|
126 |
+
$this->assertTrue(
|
127 |
+
current_user_can('edit_user', AAM_UNITTEST_AUTH_SUBADMIN2_USER_ID)
|
128 |
+
);
|
129 |
+
}
|
130 |
+
|
131 |
+
/**
|
132 |
+
* Test that subadmin is not allowed to manage users with the same user level
|
133 |
+
*
|
134 |
+
* @return void
|
135 |
+
*
|
136 |
+
* @access public
|
137 |
+
* @version 6.0.0
|
138 |
+
*/
|
139 |
+
public function testNotAllowedSameLevelUserEdit()
|
140 |
+
{
|
141 |
+
// Fake the un assigned `manage_same_user_level`
|
142 |
+
//wp_get_current_user()->caps['manage_same_user_level'] = false;
|
143 |
+
$user = AAM::getUser()->getPrincipal();
|
144 |
+
$user->caps['manage_same_user_level'] = false;
|
145 |
+
|
146 |
+
$this->assertFalse(
|
147 |
+
current_user_can('edit_user', AAM_UNITTEST_AUTH_SUBADMIN2_USER_ID)
|
148 |
+
);
|
149 |
+
}
|
150 |
+
|
151 |
+
}
|
tests/bootstrap.php
ADDED
@@ -0,0 +1,27 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
/**
|
4 |
+
* Make sure that path to the PHPUnit is included in the PHP.ini include_path as well
|
5 |
+
* as PHPUnit is installed on your machine
|
6 |
+
*/
|
7 |
+
|
8 |
+
// Autoloader for the PHPUnit Framework
|
9 |
+
spl_autoload_register(function ($classname) {
|
10 |
+
$filepath = null;
|
11 |
+
|
12 |
+
if (strpos($classname, 'PHPUnit') === 0) {
|
13 |
+
$filepath = __DIR__ . '\\' . $classname . '.php';
|
14 |
+
} elseif (strpos($classname, 'AAM\UnitTest') === 0) {
|
15 |
+
$filepath = __DIR__ . str_replace(array('AAM\UnitTest', '\\'), array('', '/'), $classname) . '.php';
|
16 |
+
}
|
17 |
+
|
18 |
+
if ($filepath && file_exists($filepath)) {
|
19 |
+
require $filepath;
|
20 |
+
}
|
21 |
+
});
|
22 |
+
|
23 |
+
// Load the WordPress library.
|
24 |
+
require_once dirname(__DIR__) . '/../../../wp-load.php';
|
25 |
+
|
26 |
+
// Very important to allow to test headers
|
27 |
+
ob_start();
|
vendor/composer/VersionParser.php
CHANGED
@@ -159,6 +159,11 @@ class VersionParser
|
|
159 |
try {
|
160 |
return $this->normalizeBranch($match[1]);
|
161 |
} catch (\Exception $e) {
|
|
|
|
|
|
|
|
|
|
|
162 |
}
|
163 |
}
|
164 |
|
@@ -474,6 +479,11 @@ class VersionParser
|
|
474 |
|
475 |
return array(new Constraint($matches[1] ?: '=', $version));
|
476 |
} catch (\Exception $e) {
|
|
|
|
|
|
|
|
|
|
|
477 |
}
|
478 |
}
|
479 |
|
159 |
try {
|
160 |
return $this->normalizeBranch($match[1]);
|
161 |
} catch (\Exception $e) {
|
162 |
+
_doing_it_wrong(
|
163 |
+
__CLASS__ . '::' . __METHOD__,
|
164 |
+
$e->getMessage(),
|
165 |
+
AAM_VERSION
|
166 |
+
);
|
167 |
}
|
168 |
}
|
169 |
|
479 |
|
480 |
return array(new Constraint($matches[1] ?: '=', $version));
|
481 |
} catch (\Exception $e) {
|
482 |
+
_doing_it_wrong(
|
483 |
+
__CLASS__ . '::' . __METHOD__,
|
484 |
+
$e->getMessage(),
|
485 |
+
AAM_VERSION
|
486 |
+
);
|
487 |
}
|
488 |
}
|
489 |
|
vendor/firebase/JWT.php
CHANGED
@@ -205,6 +205,8 @@ class JWT
|
|
205 |
} else {
|
206 |
return $signature;
|
207 |
}
|
|
|
|
|
208 |
}
|
209 |
}
|
210 |
|
205 |
} else {
|
206 |
return $signature;
|
207 |
}
|
208 |
+
default:
|
209 |
+
break;
|
210 |
}
|
211 |
}
|
212 |
|