mirror of
https://github.com/Combodo/iTop.git
synced 2026-02-13 07:24:13 +01:00
Merge remote-tracking branch 'origin/support/3.2' into develop
This commit is contained in:
@@ -79,17 +79,20 @@ gitGraph
|
||||
commit id: "2023-08-10" tag: "2.7.9"
|
||||
checkout support/3.1
|
||||
commit id: "2023-12-20" tag: "3.1.1"
|
||||
checkout develop
|
||||
commit id: "2024-01-15" tag: "Start 3.2" type: HIGHLIGHT
|
||||
branch support/3.2 order: 830
|
||||
checkout support/2.7
|
||||
commit id: "2024-01-17a" tag: "2.7.10"
|
||||
checkout support/3.0
|
||||
commit id: "2024-01-17b" tag: "3.0.4"
|
||||
checkout develop
|
||||
commit id: "2024-06-25" tag: "3.2.0-beta1" type: REVERSE
|
||||
commit id: "2024-08-07" tag: "3.2.0" type: HIGHLIGHT
|
||||
branch support/3.2 order: 830
|
||||
checkout support/3.2
|
||||
checkout support/2.7
|
||||
commit id: "2024-09-26" tag: "2.7.11"
|
||||
commit id: "2024-09-28" tag: "2.7.11"
|
||||
checkout support/3.1
|
||||
commit id: "2024-09-27" tag: "3.1.2"
|
||||
checkout support/3.2
|
||||
commit id: "2024-06-25" tag: "3.2.0-beta1" type: REVERSE
|
||||
commit id: "2024-08-07" tag: "3.2.0"
|
||||
```
|
||||
|
||||
To learn more, check the [iTop community versions history on the official wiki](https://www.itophub.io/wiki/page?id=latest:release:start).
|
||||
|
||||
33
.github/workflows/action.yml
vendored
33
.github/workflows/action.yml
vendored
@@ -10,7 +10,34 @@ jobs:
|
||||
name: Add PR to Combodo Project
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/add-to-project@v1.0.2
|
||||
- name: Check if author is a member of the organization
|
||||
id: check-membership
|
||||
run: |
|
||||
ORG="Combodo"
|
||||
AUTHOR=$(jq -r .pull_request.user.login "$GITHUB_EVENT_PATH")
|
||||
RESPONSE=$(curl -s -o /dev/null -w "%{http_code}" -H "Authorization: token ${{ secrets.PR_AUTOMATICALLY_ADD_TO_PROJECT }}" \
|
||||
"https://api.github.com/orgs/$ORG/members/$AUTHOR")
|
||||
if [ "$RESPONSE" == "404" ]; then
|
||||
echo "project_url=https://github.com/orgs/Combodo/projects/5" >> $GITHUB_ENV
|
||||
echo "is_member=false" >> $GITHUB_ENV
|
||||
else
|
||||
echo "project_url=https://github.com/orgs/Combodo/projects/4" >> $GITHUB_ENV
|
||||
echo "is_member=true" >> $GITHUB_ENV
|
||||
|
||||
fi
|
||||
|
||||
- name: Add internal tag if member
|
||||
if: env.is_member == 'true'
|
||||
run: |
|
||||
curl -X POST -H "Authorization: token ${{ secrets.PR_AUTOMATICALLY_ADD_TO_PROJECT }}" \
|
||||
-H "Accept: application/vnd.github.v3+json" \
|
||||
https://api.github.com/repos/Combodo/combodo-wikit-integration/issues/${{ github.event.pull_request.number }}/labels \
|
||||
-d '{"labels":["internal"]}'
|
||||
env:
|
||||
is_member: ${{ env.is_member }}
|
||||
|
||||
- name: Add PR to the appropriate project
|
||||
uses: actions/add-to-project@v1.0.2
|
||||
with:
|
||||
project-url: https://github.com/orgs/Combodo/projects/5
|
||||
github-token: ${{ secrets.PR_AUTOMATICALLY_ADD_TO_PROJECT }}
|
||||
project-url: ${{ env.project_url }}
|
||||
github-token: ${{ secrets.PR_AUTOMATICALLY_ADD_TO_PROJECT }}
|
||||
@@ -64,13 +64,13 @@ interface iLoginFSMExtension extends iLoginExtension
|
||||
* If a page is displayed, the action must exit at this point
|
||||
* if LoginWebPage::LOGIN_FSM_RETURN_ERROR is returned $iErrorCode must be set
|
||||
* if LoginWebPage::LOGIN_FSM_RETURN_OK is returned then the login is OK and terminated
|
||||
* if LoginWebPage::LOGIN_FSM_RETURN_IGNORE is returned then the FSM will proceed to next plugin or state
|
||||
* if LoginWebPage::LOGIN_FSM_CONTINUE is returned then the FSM will proceed to next plugin or state
|
||||
*
|
||||
* @api
|
||||
* @param string $sLoginState (see LoginWebPage::LOGIN_STATE_...)
|
||||
* @param int $iErrorCode (see LoginWebPage::EXIT_CODE_...)
|
||||
*
|
||||
* @return int LoginWebPage::LOGIN_FSM_RETURN_ERROR, LoginWebPage::LOGIN_FSM_RETURN_OK or LoginWebPage::LOGIN_FSM_RETURN_IGNORE
|
||||
* @return int LoginWebPage::LOGIN_FSM_RETURN_ERROR, LoginWebPage::LOGIN_FSM_RETURN_OK or LoginWebPage::LOGIN_FSM_CONTINUE
|
||||
*/
|
||||
public function LoginAction($sLoginState, &$iErrorCode);
|
||||
}
|
||||
@@ -83,7 +83,7 @@ interface iLoginFSMExtension extends iLoginExtension
|
||||
* * If a page is displayed, the action must exit at this point
|
||||
* * if LoginWebPage::LOGIN_FSM_RETURN_ERROR is returned $iErrorCode must be set
|
||||
* * if LoginWebPage::LOGIN_FSM_RETURN_OK is returned then the login is OK and terminated
|
||||
* * if LoginWebPage::LOGIN_FSM_RETURN_IGNORE is returned then the FSM will proceed to next plugin or to next state
|
||||
* * if LoginWebPage::LOGIN_FSM_CONTINUE is returned then the FSM will proceed to next plugin or to next state
|
||||
*
|
||||
* @api
|
||||
* @package LoginExtensibilityAPI
|
||||
@@ -136,7 +136,7 @@ abstract class AbstractLoginFSMExtension implements iLoginFSMExtension
|
||||
* @api
|
||||
* @param int $iErrorCode (see LoginWebPage::EXIT_CODE_...)
|
||||
*
|
||||
* @return int LoginWebPage::LOGIN_FSM_RETURN_ERROR, LoginWebPage::LOGIN_FSM_RETURN_OK or LoginWebPage::LOGIN_FSM_RETURN_IGNORE
|
||||
* @return int LoginWebPage::LOGIN_FSM_RETURN_ERROR, LoginWebPage::LOGIN_FSM_RETURN_OK or LoginWebPage::LOGIN_FSM_CONTINUE
|
||||
*/
|
||||
protected function OnStart(&$iErrorCode)
|
||||
{
|
||||
@@ -150,7 +150,7 @@ abstract class AbstractLoginFSMExtension implements iLoginFSMExtension
|
||||
* @api
|
||||
* @param int $iErrorCode (see LoginWebPage::EXIT_CODE_...)
|
||||
*
|
||||
* @return int LoginWebPage::LOGIN_FSM_RETURN_ERROR, LoginWebPage::LOGIN_FSM_RETURN_OK or LoginWebPage::LOGIN_FSM_RETURN_IGNORE
|
||||
* @return int LoginWebPage::LOGIN_FSM_RETURN_ERROR, LoginWebPage::LOGIN_FSM_RETURN_OK or LoginWebPage::LOGIN_FSM_CONTINUE
|
||||
*/
|
||||
protected function OnModeDetection(&$iErrorCode)
|
||||
{
|
||||
@@ -167,7 +167,7 @@ abstract class AbstractLoginFSMExtension implements iLoginFSMExtension
|
||||
* @api
|
||||
* @param int $iErrorCode (see LoginWebPage::EXIT_CODE_...)
|
||||
*
|
||||
* @return int LoginWebPage::LOGIN_FSM_RETURN_ERROR, LoginWebPage::LOGIN_FSM_RETURN_OK or LoginWebPage::LOGIN_FSM_RETURN_IGNORE
|
||||
* @return int LoginWebPage::LOGIN_FSM_RETURN_ERROR, LoginWebPage::LOGIN_FSM_RETURN_OK or LoginWebPage::LOGIN_FSM_CONTINUE
|
||||
*/
|
||||
protected function OnReadCredentials(&$iErrorCode)
|
||||
{
|
||||
@@ -181,7 +181,7 @@ abstract class AbstractLoginFSMExtension implements iLoginFSMExtension
|
||||
* @api
|
||||
* @param int $iErrorCode (see LoginWebPage::EXIT_CODE_...)
|
||||
*
|
||||
* @return int LoginWebPage::LOGIN_FSM_RETURN_ERROR, LoginWebPage::LOGIN_FSM_RETURN_OK or LoginWebPage::LOGIN_FSM_RETURN_IGNORE
|
||||
* @return int LoginWebPage::LOGIN_FSM_RETURN_ERROR, LoginWebPage::LOGIN_FSM_RETURN_OK or LoginWebPage::LOGIN_FSM_CONTINUE
|
||||
*/
|
||||
protected function OnCheckCredentials(&$iErrorCode)
|
||||
{
|
||||
@@ -192,7 +192,7 @@ abstract class AbstractLoginFSMExtension implements iLoginFSMExtension
|
||||
* @api
|
||||
* @param int $iErrorCode (see LoginWebPage::EXIT_CODE_...)
|
||||
*
|
||||
* @return int LoginWebPage::LOGIN_FSM_RETURN_ERROR, LoginWebPage::LOGIN_FSM_RETURN_OK or LoginWebPage::LOGIN_FSM_RETURN_IGNORE
|
||||
* @return int LoginWebPage::LOGIN_FSM_RETURN_ERROR, LoginWebPage::LOGIN_FSM_RETURN_OK or LoginWebPage::LOGIN_FSM_CONTINUE
|
||||
*/
|
||||
protected function OnCredentialsOK(&$iErrorCode)
|
||||
{
|
||||
@@ -203,7 +203,7 @@ abstract class AbstractLoginFSMExtension implements iLoginFSMExtension
|
||||
* @api
|
||||
* @param int $iErrorCode (see LoginWebPage::EXIT_CODE_...)
|
||||
*
|
||||
* @return int LoginWebPage::LOGIN_FSM_RETURN_ERROR, LoginWebPage::LOGIN_FSM_RETURN_OK or LoginWebPage::LOGIN_FSM_RETURN_IGNORE
|
||||
* @return int LoginWebPage::LOGIN_FSM_RETURN_ERROR, LoginWebPage::LOGIN_FSM_RETURN_OK or LoginWebPage::LOGIN_FSM_CONTINUE
|
||||
*/
|
||||
protected function OnUsersOK(&$iErrorCode)
|
||||
{
|
||||
@@ -214,7 +214,7 @@ abstract class AbstractLoginFSMExtension implements iLoginFSMExtension
|
||||
* @api
|
||||
* @param int $iErrorCode (see LoginWebPage::EXIT_CODE_...)
|
||||
*
|
||||
* @return int LoginWebPage::LOGIN_FSM_RETURN_ERROR, LoginWebPage::LOGIN_FSM_RETURN_OK or LoginWebPage::LOGIN_FSM_RETURN_IGNORE
|
||||
* @return int LoginWebPage::LOGIN_FSM_RETURN_ERROR, LoginWebPage::LOGIN_FSM_RETURN_OK or LoginWebPage::LOGIN_FSM_CONTINUE
|
||||
*/
|
||||
protected function OnConnected(&$iErrorCode)
|
||||
{
|
||||
@@ -225,7 +225,7 @@ abstract class AbstractLoginFSMExtension implements iLoginFSMExtension
|
||||
* @api
|
||||
* @param int $iErrorCode (see LoginWebPage::EXIT_CODE_...)
|
||||
*
|
||||
* @return int LoginWebPage::LOGIN_FSM_RETURN_ERROR, LoginWebPage::LOGIN_FSM_RETURN_OK or LoginWebPage::LOGIN_FSM_RETURN_IGNORE
|
||||
* @return int LoginWebPage::LOGIN_FSM_RETURN_ERROR, LoginWebPage::LOGIN_FSM_RETURN_OK or LoginWebPage::LOGIN_FSM_CONTINUE
|
||||
*/
|
||||
protected function OnError(&$iErrorCode)
|
||||
{
|
||||
|
||||
@@ -251,7 +251,7 @@ class appUserPreferences extends DBObject
|
||||
"key_type" => "autoincrement",
|
||||
"name_attcode" => "userid",
|
||||
"state_attcode" => "",
|
||||
"reconc_keys" => array(),
|
||||
"reconc_keys" => array("userid"),
|
||||
"db_table" => "priv_app_preferences",
|
||||
"db_key_field" => "id",
|
||||
"db_finalclass_field" => "",
|
||||
@@ -260,6 +260,8 @@ class appUserPreferences extends DBObject
|
||||
MetaModel::Init_Params($aParams);
|
||||
MetaModel::Init_AddAttribute(new AttributeExternalKey("userid", array("targetclass"=>"User", "allowed_values"=>null, "sql"=>"userid", "is_null_allowed"=>false, "on_target_delete"=>DEL_AUTO, "depends_on"=>array())));
|
||||
MetaModel::Init_AddAttribute(new AttributePropertySet("preferences", array("allowed_values"=>null, "sql"=>"preferences", "default_value"=>null, "is_null_allowed"=>true, "depends_on"=>array())));
|
||||
MetaModel::Init_SetZListItems('list', array('preferences',));
|
||||
MetaModel::Init_SetZListItems('default_search', array('userid'));
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -4,9 +4,4 @@ when@dev:
|
||||
toolbar: true
|
||||
intercept_redirects: false
|
||||
|
||||
when@test:
|
||||
web_profiler:
|
||||
toolbar: false
|
||||
intercept_redirects: false
|
||||
|
||||
|
||||
|
||||
@@ -19,33 +19,33 @@
|
||||
|
||||
namespace Combodo\iTop\Portal\Brick;
|
||||
|
||||
use DOMFormatException;
|
||||
use Combodo\iTop\DesignElement;
|
||||
use DOMFormatException;
|
||||
|
||||
/**
|
||||
* Description of UserProfileBrick
|
||||
*
|
||||
* @package Combodo\iTop\Portal\Brick
|
||||
* @since 2.7.0
|
||||
*
|
||||
* @author Guillaume Lajarige <guillaume.lajarige@combodo.com>
|
||||
* @since 2.7.0
|
||||
* @package Combodo\iTop\Portal\Brick
|
||||
*/
|
||||
class UserProfileBrick extends PortalBrick
|
||||
{
|
||||
// Overloaded constants
|
||||
const DEFAULT_PAGE_TEMPLATE_PATH = 'itop-portal-base/portal/templates/bricks/user-profile/layout.html.twig';
|
||||
const DEFAULT_TILE_TEMPLATE_PATH = 'itop-portal-base/portal/templates/bricks/user-profile/tile.html.twig';
|
||||
const DEFAULT_VISIBLE_NAVIGATION_MENU = false;
|
||||
const DEFAULT_VISIBLE_HOME = false;
|
||||
const DEFAUT_TITLE = 'Brick:Portal:UserProfile:Title';
|
||||
const DEFAULT_DECORATION_CLASS_HOME = 'glyphicon glyphicon-user';
|
||||
const DEFAULT_PAGE_TEMPLATE_PATH = 'itop-portal-base/portal/templates/bricks/user-profile/layout.html.twig';
|
||||
const DEFAULT_TILE_TEMPLATE_PATH = 'itop-portal-base/portal/templates/bricks/user-profile/tile.html.twig';
|
||||
const DEFAULT_VISIBLE_NAVIGATION_MENU = false;
|
||||
const DEFAULT_VISIBLE_HOME = false;
|
||||
const DEFAUT_TITLE = 'Brick:Portal:UserProfile:Title';
|
||||
const DEFAULT_DECORATION_CLASS_HOME = 'glyphicon glyphicon-user';
|
||||
const DEFAULT_DECORATION_CLASS_NAVIGATION_MENU = 'glyphicon glyphicon-user';
|
||||
|
||||
/** @var bool DEFAULT_SHOW_PICTURE_FORM */
|
||||
const DEFAULT_SHOW_PICTURE_FORM = true;
|
||||
/** @var bool DEFAULT_SHOW_PREFERENCES_FORM */
|
||||
const DEFAULT_SHOW_PREFERENCES_FORM = true;
|
||||
/** @var bool DEFAULT_SHOW_PASSWORD_FORM */
|
||||
const DEFAULT_SHOW_PASSWORD_FORM = true;
|
||||
const DEFAULT_SHOW_PREFERENCES_FORM = true;
|
||||
/** @var bool DEFAULT_SHOW_PASSWORD_FORM */
|
||||
const DEFAULT_SHOW_PASSWORD_FORM = true;
|
||||
|
||||
// Overloaded variables
|
||||
static $sRouteName = 'p_user_profile_brick';
|
||||
@@ -67,8 +67,8 @@ class UserProfileBrick extends PortalBrick
|
||||
parent::__construct();
|
||||
|
||||
$this->aForm = array(
|
||||
'id' => 'default-user-profile',
|
||||
'type' => 'zlist',
|
||||
'id' => 'default-user-profile',
|
||||
'type' => 'zlist',
|
||||
'fields' => 'details',
|
||||
'layout' => null,
|
||||
);
|
||||
@@ -89,67 +89,75 @@ class UserProfileBrick extends PortalBrick
|
||||
/**
|
||||
*
|
||||
* @param array $aForm
|
||||
*
|
||||
* @return \Combodo\iTop\Portal\Brick\UserProfileBrick
|
||||
*/
|
||||
public function SetForm($aForm)
|
||||
{
|
||||
$this->aForm = $aForm;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
public function GetShowPictureForm()
|
||||
{
|
||||
return $this->bShowPictureForm;
|
||||
}
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
public function GetShowPictureForm()
|
||||
{
|
||||
return $this->bShowPictureForm;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $bShowPictureForm
|
||||
* @return \Combodo\iTop\Portal\Brick\UserProfileBrick
|
||||
*/
|
||||
public function SetShowPictureForm($bShowPictureForm)
|
||||
{
|
||||
$this->bShowPictureForm = $bShowPictureForm;
|
||||
return $this;
|
||||
}
|
||||
/**
|
||||
* @param $bShowPictureForm
|
||||
*
|
||||
* @return \Combodo\iTop\Portal\Brick\UserProfileBrick
|
||||
*/
|
||||
public function SetShowPictureForm($bShowPictureForm)
|
||||
{
|
||||
$this->bShowPictureForm = $bShowPictureForm;
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
public function GetShowPreferencesForm()
|
||||
{
|
||||
return $this->bShowPreferencesForm;
|
||||
}
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $bShowPreferencesForm
|
||||
* @return \Combodo\iTop\Portal\Brick\UserProfileBrick
|
||||
*/
|
||||
public function SetShowPreferencesForm($bShowPreferencesForm)
|
||||
{
|
||||
$this->bShowPreferencesForm = $bShowPreferencesForm;
|
||||
return $this;
|
||||
}
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
public function GetShowPreferencesForm()
|
||||
{
|
||||
return $this->bShowPreferencesForm;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
public function GetShowPasswordForm()
|
||||
{
|
||||
return $this->bShowPasswordForm;
|
||||
}
|
||||
/**
|
||||
* @param $bShowPreferencesForm
|
||||
*
|
||||
* @return \Combodo\iTop\Portal\Brick\UserProfileBrick
|
||||
*/
|
||||
public function SetShowPreferencesForm($bShowPreferencesForm)
|
||||
{
|
||||
$this->bShowPreferencesForm = $bShowPreferencesForm;
|
||||
|
||||
/**
|
||||
* @param $bShowPasswordForm
|
||||
* @return \Combodo\iTop\Portal\Brick\UserProfileBrick
|
||||
*/
|
||||
public function SetShowPasswordForm($bShowPasswordForm)
|
||||
{
|
||||
$this->bShowPasswordForm = $bShowPasswordForm;
|
||||
return $this;
|
||||
}
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
public function GetShowPasswordForm()
|
||||
{
|
||||
return $this->bShowPasswordForm;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $bShowPasswordForm
|
||||
*
|
||||
* @return \Combodo\iTop\Portal\Brick\UserProfileBrick
|
||||
*/
|
||||
public function SetShowPasswordForm($bShowPasswordForm)
|
||||
{
|
||||
$this->bShowPasswordForm = $bShowPasswordForm;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Load the brick's data from the xml passed as a ModuleDesignElement.
|
||||
@@ -167,50 +175,39 @@ class UserProfileBrick extends PortalBrick
|
||||
|
||||
// Checking specific elements
|
||||
/** @var \Combodo\iTop\DesignElement $oBrickSubNode */
|
||||
foreach ($oMDElement->GetNodes('./*') as $oBrickSubNode)
|
||||
{
|
||||
switch ($oBrickSubNode->nodeName)
|
||||
{
|
||||
foreach ($oMDElement->GetNodes('./*') as $oBrickSubNode) {
|
||||
switch ($oBrickSubNode->nodeName) {
|
||||
case 'form':
|
||||
// Note : This is inspired by Combodo\iTop\Portal\Helper\ApplicationHelper::LoadFormsConfiguration()
|
||||
// Enumerating fields
|
||||
if ($oBrickSubNode->GetOptionalElement('fields') !== null)
|
||||
{
|
||||
if ($oBrickSubNode->GetOptionalElement('fields') !== null) {
|
||||
$this->aForm['type'] = 'custom_list';
|
||||
$this->aForm['fields'] = array();
|
||||
|
||||
/** @var \Combodo\iTop\DesignElement $oFieldNode */
|
||||
foreach ($oBrickSubNode->GetOptionalElement('fields')->GetNodes('field') as $oFieldNode)
|
||||
{
|
||||
foreach ($oBrickSubNode->GetOptionalElement('fields')->GetNodes('field') as $oFieldNode) {
|
||||
$sFieldId = $oFieldNode->getAttribute('id');
|
||||
if ($sFieldId !== '')
|
||||
{
|
||||
if ($sFieldId !== '') {
|
||||
$aField = array();
|
||||
// Parsing field options like read_only, hidden and mandatory
|
||||
if ($oFieldNode->GetOptionalElement('read_only'))
|
||||
{
|
||||
if ($oFieldNode->GetOptionalElement('read_only')) {
|
||||
$aField['readonly'] = ($oFieldNode->GetOptionalElement('read_only')->GetText('true') === 'true') ? true : false;
|
||||
}
|
||||
if ($oFieldNode->GetOptionalElement('mandatory'))
|
||||
{
|
||||
if ($oFieldNode->GetOptionalElement('mandatory')) {
|
||||
$aField['mandatory'] = ($oFieldNode->GetOptionalElement('mandatory')->GetText('true') === 'true') ? true : false;
|
||||
}
|
||||
if ($oFieldNode->GetOptionalElement('hidden'))
|
||||
{
|
||||
if ($oFieldNode->GetOptionalElement('hidden')) {
|
||||
$aField['hidden'] = ($oFieldNode->GetOptionalElement('hidden')->GetText('true') === 'true') ? true : false;
|
||||
}
|
||||
|
||||
$this->aForm['fields'][$sFieldId] = $aField;
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
throw new DOMFormatException('Field tag must have an id attribute', null, null, $oFieldNode);
|
||||
}
|
||||
}
|
||||
}
|
||||
// Parsing presentation
|
||||
if ($oBrickSubNode->GetOptionalElement('twig') !== null)
|
||||
{
|
||||
if ($oBrickSubNode->GetOptionalElement('twig') !== null) {
|
||||
// Extracting the twig template and removing the first and last lines (twig tags)
|
||||
$sXml = $oBrickSubNode->GetOptionalElement('twig')->Dump(true);
|
||||
//$sXml = $oMDElement->saveXML($oBrickSubNode->GetOptionalElement('twig'));
|
||||
@@ -218,25 +215,24 @@ class UserProfileBrick extends PortalBrick
|
||||
$sXml = preg_replace('/\n.+$/', '', $sXml);
|
||||
|
||||
$this->aForm['layout'] = array(
|
||||
'type' => (preg_match('/\{\{|\{\#|\{\%/', $sXml) === 1) ? 'twig' : 'xhtml',
|
||||
'type' => (preg_match('/\{\{|\{\#|\{\%/', $sXml) === 1) ? 'twig' : 'xhtml',
|
||||
'content' => $sXml,
|
||||
);
|
||||
}
|
||||
break;
|
||||
|
||||
case 'show_picture_form':
|
||||
case 'show_preferences_form':
|
||||
case 'show_password_form':
|
||||
$sConstName = 'DEFAULT_'.strtoupper($oBrickSubNode->nodeName);
|
||||
$sSetterName = 'Set'.str_replace('_', '', ucwords($oBrickSubNode->nodeName, '_'));
|
||||
case 'show_picture_form':
|
||||
case 'show_preferences_form':
|
||||
case 'show_password_form':
|
||||
$sConstName = 'DEFAULT_'.strtoupper($oBrickSubNode->nodeName);
|
||||
$sSetterName = 'Set'.str_replace('_', '', ucwords($oBrickSubNode->nodeName, '_'));
|
||||
|
||||
$bNodeValue = ($oBrickSubNode->GetText(constant('static::'.$sConstName)) === 'true') ? true : false;
|
||||
$this->$sSetterName($bNodeValue);
|
||||
break;
|
||||
$bNodeValue = ($oBrickSubNode->GetText(constant('static::'.$sConstName)) === 'true') ? true : false;
|
||||
$this->$sSetterName($bNodeValue);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -24,8 +24,13 @@ use Combodo\iTop\Portal\Brick\BrickCollection;
|
||||
use Combodo\iTop\Portal\Brick\UserProfileBrick;
|
||||
use Combodo\iTop\Portal\Form\PasswordFormManager;
|
||||
use Combodo\iTop\Portal\Form\PreferencesFormManager;
|
||||
use Combodo\iTop\Portal\Helper\ExtensibilityHelper;
|
||||
use Combodo\iTop\Portal\Helper\ObjectFormHandlerHelper;
|
||||
use Combodo\iTop\Portal\Helper\RequestManipulatorHelper;
|
||||
use Combodo\iTop\Portal\Hook\iAbstractPortalTabContentExtension;
|
||||
use Combodo\iTop\Portal\Hook\iAbstractPortalTabExtension;
|
||||
use Combodo\iTop\Portal\Hook\iUserProfileTabContentExtension;
|
||||
use Combodo\iTop\Portal\Hook\iUserProfileTabExtension;
|
||||
use Combodo\iTop\Portal\Routing\UrlGenerator;
|
||||
use Combodo\iTop\Renderer\Bootstrap\BsFormRenderer;
|
||||
use Exception;
|
||||
@@ -106,56 +111,60 @@ class UserProfileBrickController extends BrickController
|
||||
$oBrick = $this->oBrickCollection->GetBrickById($sBrickId);
|
||||
}
|
||||
|
||||
$aData = array();
|
||||
$aData = [];
|
||||
|
||||
// Setting form mode regarding the demo mode parameter
|
||||
$bDemoMode = MetaModel::GetConfig()->Get('demo_mode');
|
||||
$sFormMode = ($bDemoMode) ? ObjectFormHandlerHelper::ENUM_MODE_VIEW : ObjectFormHandlerHelper::ENUM_MODE_EDIT;
|
||||
|
||||
$sTab = $this->oRequestManipulatorHelper->ReadParam('sTab', 'user-info', FILTER_UNSAFE_RAW, FILTER_FLAG_EMPTY_STRING_NULL);
|
||||
|
||||
// If this is ajax call, we are just submitting preferences or password forms
|
||||
if ($oRequest->isXmlHttpRequest())
|
||||
{
|
||||
$aCurrentValues = $this->oRequestManipulatorHelper->ReadParam('current_values', array(), FILTER_UNSAFE_RAW, FILTER_REQUIRE_ARRAY);
|
||||
$sFormType = $aCurrentValues['form_type'];
|
||||
if ($sFormType === PreferencesFormManager::FORM_TYPE)
|
||||
{
|
||||
$aData['form'] = $this->HandlePreferencesForm($oRequest, $sFormMode);
|
||||
}
|
||||
elseif ($sFormType === PasswordFormManager::FORM_TYPE)
|
||||
{
|
||||
$aData['form'] = $this->HandlePasswordForm($oRequest, $sFormMode);
|
||||
}
|
||||
elseif ($sFormType === static::ENUM_FORM_TYPE_PICTURE)
|
||||
{
|
||||
$aData['form'] = $this->HandlePictureForm($oRequest);
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new Exception('Unknown form type.');
|
||||
if ($sTab === "user-info") {
|
||||
$aCurrentValues = $this->oRequestManipulatorHelper->ReadParam('current_values', array(), FILTER_UNSAFE_RAW,
|
||||
FILTER_REQUIRE_ARRAY);
|
||||
$sFormType = $aCurrentValues['form_type'];
|
||||
if ($sFormType === PreferencesFormManager::FORM_TYPE) {
|
||||
$aData['form'] = $this->HandlePreferencesForm($oRequest, $sFormMode);
|
||||
} elseif ($sFormType === PasswordFormManager::FORM_TYPE) {
|
||||
$aData['form'] = $this->HandlePasswordForm($oRequest, $sFormMode);
|
||||
} elseif ($sFormType === static::ENUM_FORM_TYPE_PICTURE) {
|
||||
$aData['form'] = $this->HandlePictureForm($oRequest);
|
||||
} else {
|
||||
throw new Exception('Unknown form type.');
|
||||
}
|
||||
}
|
||||
|
||||
$oResponse = new JsonResponse($aData);
|
||||
}
|
||||
// Else, we are displaying page for first time
|
||||
else
|
||||
{
|
||||
// Retrieving current contact
|
||||
/** @var \DBObject $oCurContact */
|
||||
$oCurContact = UserRights::GetContactObject();
|
||||
$sCurContactClass = get_class($oCurContact);
|
||||
$sCurContactId = $oCurContact->GetKey();
|
||||
if ($sTab === "user-info") {
|
||||
// Retrieving current contact
|
||||
/** @var \DBObject $oCurContact */
|
||||
$oCurContact = UserRights::GetContactObject();
|
||||
$sCurContactClass = get_class($oCurContact);
|
||||
$sCurContactId = $oCurContact->GetKey();
|
||||
|
||||
// Preparing forms
|
||||
$aData['forms']['contact'] = $this->ObjectFormHandlerHelper->HandleForm($oRequest, $sFormMode, $sCurContactClass, $sCurContactId,
|
||||
$oBrick->GetForm());
|
||||
$aData['forms']['preferences'] = $this->HandlePreferencesForm($oRequest, $sFormMode);
|
||||
// - If user can change password, we display the form
|
||||
$aData['forms']['password'] = (UserRights::CanChangePassword()) ? $this->HandlePasswordForm($oRequest, $sFormMode) : null;
|
||||
// Preparing forms
|
||||
$aData['forms']['contact'] = $this->ObjectFormHandlerHelper->HandleForm($oRequest, $sFormMode, $sCurContactClass,
|
||||
$sCurContactId,
|
||||
$oBrick->GetForm());
|
||||
$aData['forms']['preferences'] = $this->HandlePreferencesForm($oRequest, $sFormMode);
|
||||
// - If user can change password, we display the form
|
||||
$aData['forms']['password'] = (UserRights::CanChangePassword()) ? $this->HandlePasswordForm($oRequest, $sFormMode) : null;
|
||||
}
|
||||
|
||||
$aData = $aData + array(
|
||||
$aData = $aData + [
|
||||
'oBrick' => $oBrick,
|
||||
'sFormMode' => $sFormMode,
|
||||
'bDemoMode' => $bDemoMode,
|
||||
);
|
||||
];
|
||||
|
||||
$this->ManageUserProfileBrickExtensibility($sTab, $aData);
|
||||
|
||||
$oResponse = $this->render($oBrick->GetPageTemplatePath(), $aData);
|
||||
}
|
||||
@@ -163,6 +172,46 @@ class UserProfileBrickController extends BrickController
|
||||
return $oResponse;
|
||||
}
|
||||
|
||||
|
||||
private function ManageUserProfileBrickExtensibility(string $sTab, array &$aData): void
|
||||
{
|
||||
$aData['sTab'] = $sTab;
|
||||
|
||||
// Read the tabs From iPortalTabExtension
|
||||
$aTabExtensions = ExtensibilityHelper::GetInstance()->GetPortalTabExtensions(iUserProfileTabExtension::class);
|
||||
|
||||
/** @var iAbstractPortalTabExtension $oPortalTabExtension */
|
||||
foreach ($aTabExtensions as $oPortalTabExtension) {
|
||||
$aData['aTabsValues'][] = [
|
||||
'code' => $oPortalTabExtension->GetTabCode(),
|
||||
'label' => $oPortalTabExtension->GetTabLabel(),
|
||||
];
|
||||
}
|
||||
|
||||
// Read the current tab content From iPortalTabSectionExtension
|
||||
$aTabSectionExtensions = ExtensibilityHelper::GetInstance()->GetPortalTabContentExtensions(iUserProfileTabContentExtension::class, $sTab);
|
||||
if (count($aTabSectionExtensions) !== 0 && count($_POST) !== 0){
|
||||
$sTransactionId = utils::ReadPostedParam('transaction_id', null, utils::ENUM_SANITIZATION_FILTER_TRANSACTION_ID);
|
||||
IssueLog::Debug(__FUNCTION__.": transaction [$sTransactionId]");
|
||||
if (utils::IsNullOrEmptyString($sTransactionId) || !utils::IsTransactionValid($sTransactionId, false)) {
|
||||
throw new Exception(\Dict::S('iTopUpdate:Error:InvalidToken'));
|
||||
}
|
||||
}
|
||||
|
||||
$aData['sTransactionId'] = utils::GetNewTransactionId();
|
||||
|
||||
/** @var iAbstractPortalTabContentExtension $oPortalTabSectionExtension */
|
||||
foreach ($aTabSectionExtensions as $oPortalTabSectionExtension) {
|
||||
$oPortalTabSectionExtension->HandlePortalForm($aData);
|
||||
}
|
||||
|
||||
$aData['aPluginFormData'] = [];
|
||||
foreach ($aTabSectionExtensions as $oPortalTabSectionExtension) {
|
||||
$aData['aPluginFormData'][] = $oPortalTabSectionExtension->GetPortalTabContentTwigs();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param \Symfony\Component\HttpFoundation\Request $oRequest
|
||||
* @param string $sFormMode
|
||||
@@ -173,8 +222,6 @@ class UserProfileBrickController extends BrickController
|
||||
*/
|
||||
public function HandlePreferencesForm(Request $oRequest, $sFormMode)
|
||||
{
|
||||
|
||||
|
||||
$aFormData = array();
|
||||
|
||||
// Handling form
|
||||
@@ -393,5 +440,4 @@ class UserProfileBrickController extends BrickController
|
||||
|
||||
return $aFormData;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,96 @@
|
||||
<?php
|
||||
/**
|
||||
* @copyright Copyright (C) 2010-2024 Combodo SARL
|
||||
* @license http://opensource.org/licenses/AGPL-3.0
|
||||
*/
|
||||
|
||||
namespace Combodo\iTop\Portal\Helper;
|
||||
|
||||
use Combodo\iTop\Portal\Hook\iAbstractPortalTabContentExtension;
|
||||
use Combodo\iTop\Portal\Hook\iAbstractPortalTabExtension;
|
||||
use Combodo\iTop\Service\InterfaceDiscovery\InterfaceDiscovery;
|
||||
|
||||
/**
|
||||
* This helper is used by the bricks to manage the tab extensibility by retrieving
|
||||
* the classes implementing the corresponding interfaces
|
||||
*
|
||||
* @api
|
||||
* @see \Combodo\iTop\Portal\Hook\iAbstractPortalTabExtension
|
||||
* @see \Combodo\iTop\Portal\Hook\iAbstractPortalTabContentExtension
|
||||
* @since iTop 3.2.1
|
||||
*/
|
||||
class ExtensibilityHelper
|
||||
{
|
||||
private static ExtensibilityHelper $oInstance;
|
||||
|
||||
protected function __construct()
|
||||
{
|
||||
}
|
||||
|
||||
final public static function GetInstance(): ExtensibilityHelper
|
||||
{
|
||||
if (!isset(static::$oInstance)) {
|
||||
static::$oInstance = new static();
|
||||
}
|
||||
|
||||
return static::$oInstance;
|
||||
}
|
||||
|
||||
/**
|
||||
* Instantiate all the classes implementing the given interface
|
||||
*
|
||||
* @api
|
||||
* @see \Combodo\iTop\Portal\Hook\iAbstractPortalTabExtension
|
||||
*
|
||||
* @param string $sPortalTabExtensionInterface Extensibility interface to search for (derived from iAbstractPortalTabExtension)
|
||||
*
|
||||
* @return array[iAbstractPortalTabExtension] array of objects implementing the given interface
|
||||
*
|
||||
* @since iTop 3.2.1
|
||||
*/
|
||||
public function GetPortalTabExtensions(string $sPortalTabExtensionInterface): array
|
||||
{
|
||||
$aTabExtensions = [];
|
||||
foreach (InterfaceDiscovery::GetInstance()->FindItopClasses($sPortalTabExtensionInterface) as $sPortalTabExtension) {
|
||||
$oPortalTabExtension = new $sPortalTabExtension();
|
||||
if ($oPortalTabExtension->IsTabPresent()) {
|
||||
$aTabExtensions[] = $oPortalTabExtension;
|
||||
}
|
||||
}
|
||||
usort($aTabExtensions, function (iAbstractPortalTabExtension $a, iAbstractPortalTabExtension $b) {
|
||||
return $a->GetTabRank() - $b->GetTabRank();
|
||||
});
|
||||
|
||||
return $aTabExtensions;
|
||||
}
|
||||
|
||||
/**
|
||||
* Instantiate all the classes implementing the given interface for the given tab
|
||||
*
|
||||
* @param string $sPortalTabSectionExtensionInterface Extensibility interface to search for (derived from iAbstractPortalTabContentExtension)
|
||||
* @param string $sTab Tab code
|
||||
*
|
||||
* @return array[iPortalTabContentExtension] array of objects implementing the given interface
|
||||
*/
|
||||
public function GetPortalTabContentExtensions(string $sPortalTabSectionExtensionInterface, string $sTab): array
|
||||
{
|
||||
$aTabSectionExtensions = [];
|
||||
foreach (InterfaceDiscovery::GetInstance()->FindItopClasses($sPortalTabSectionExtensionInterface) as $sPortalTabSectionExtension) {
|
||||
$oPortalTabSectionExtension = new $sPortalTabSectionExtension();
|
||||
if (!$oPortalTabSectionExtension->IsActive()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if ($oPortalTabSectionExtension->GetTabCode() !== $sTab) {
|
||||
continue;
|
||||
}
|
||||
$aTabSectionExtensions[] = $oPortalTabSectionExtension;
|
||||
}
|
||||
|
||||
usort($aTabSectionExtensions, function (iAbstractPortalTabContentExtension $a, iAbstractPortalTabContentExtension $b) {
|
||||
return $a->GetSectionRank() - $b->GetSectionRank();
|
||||
});
|
||||
|
||||
return $aTabSectionExtensions;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,73 @@
|
||||
<?php
|
||||
/**
|
||||
* @copyright Copyright (C) 2010-2024 Combodo SARL
|
||||
* @license http://opensource.org/licenses/AGPL-3.0
|
||||
*/
|
||||
|
||||
namespace Combodo\iTop\Portal\Hook;
|
||||
|
||||
use Combodo\iTop\Portal\Twig\PortalTwigContext;
|
||||
|
||||
/**
|
||||
* Interface to provide content to a portal brick allowing tab extensibility.
|
||||
* This interface allows to provide content to existing tabs.
|
||||
*
|
||||
* This interface should not be used directly, bricks willing to provide extensibility
|
||||
* should use an interface derived from this one.
|
||||
*
|
||||
* @api
|
||||
* @since iTop 3.2.1
|
||||
* @see \Combodo\iTop\Portal\Hook\iAbstractPortalTabExtension
|
||||
*/
|
||||
interface iAbstractPortalTabContentExtension
|
||||
{
|
||||
/**
|
||||
* Indicates if the extension is active or not
|
||||
*
|
||||
* @return bool true if the content has to be displayed
|
||||
*
|
||||
* @api
|
||||
* @since iTop 3.2.1
|
||||
*/
|
||||
public function IsActive(): bool;
|
||||
|
||||
/**
|
||||
* Tab code name where to add the section
|
||||
*
|
||||
* @return string tab code (the code must contain at least one character, cannot start with a number, and must not contain whitespaces (spaces, tabs, etc.).)
|
||||
*
|
||||
* @api
|
||||
* @since iTop 3.2.1
|
||||
*/
|
||||
public function GetTabCode(): string;
|
||||
|
||||
/**
|
||||
* Handle actions based on posted vars
|
||||
*
|
||||
* @param array $aData variables to pass to the brick's twig to display the result of the action
|
||||
*
|
||||
* @api
|
||||
* @since iTop 3.2.1
|
||||
*/
|
||||
public function HandlePortalForm(array &$aData): void;
|
||||
|
||||
/**
|
||||
* List twigs and variables for the tab content per block
|
||||
*
|
||||
* @return PortalTwigContext containing twigs to display and associated variables to use
|
||||
*
|
||||
* @api
|
||||
* @since iTop 3.2.1
|
||||
*/
|
||||
public function GetPortalTabContentTwigs(): PortalTwigContext;
|
||||
|
||||
/**
|
||||
* Get the section rank in the tab (used to sort the contents of a tab)
|
||||
*
|
||||
* @return float rank order
|
||||
*
|
||||
* @api
|
||||
* @since iTop 3.2.1
|
||||
*/
|
||||
public function GetSectionRank(): float;
|
||||
}
|
||||
@@ -0,0 +1,62 @@
|
||||
<?php
|
||||
/**
|
||||
* @copyright Copyright (C) 2010-2024 Combodo SARL
|
||||
* @license http://opensource.org/licenses/AGPL-3.0
|
||||
*/
|
||||
|
||||
namespace Combodo\iTop\Portal\Hook;
|
||||
|
||||
/**
|
||||
* Interface to provide content to a portal brick allowing tab extensibility.
|
||||
* This interface allows to provide new tabs to bricks.
|
||||
*
|
||||
* This interface should not be used directly, bricks willing to provide extensibility
|
||||
* should use an interface derived from this one.
|
||||
*
|
||||
* @api
|
||||
* @since iTop 3.2.1
|
||||
* @see \Combodo\iTop\Portal\Hook\iAbstractPortalTabContentExtension
|
||||
*/
|
||||
interface iAbstractPortalTabExtension
|
||||
{
|
||||
/**
|
||||
* True if the tab must be displayed or false if the tab must be hidden.
|
||||
* When the tab is not displayed the other methods are not called.
|
||||
*
|
||||
* @return bool
|
||||
*
|
||||
* @api
|
||||
* @since iTop 3.2.1
|
||||
*/
|
||||
public function IsTabPresent(): bool;
|
||||
|
||||
/**
|
||||
* Rank of the tab to allow sorting (ascending order)
|
||||
*
|
||||
* @return float order rank
|
||||
*
|
||||
* @api
|
||||
* @since iTop 3.2.1
|
||||
*/
|
||||
public function GetTabRank(): float;
|
||||
|
||||
/**
|
||||
* Unique code for the AjaxTab (in the brick page)
|
||||
*
|
||||
* @return string the code must contain at least one character, cannot start with a number, and must not contain whitespaces (spaces, tabs, etc.).
|
||||
*
|
||||
* @api
|
||||
* @since iTop 3.2.1
|
||||
*/
|
||||
public function GetTabCode(): string;
|
||||
|
||||
/**
|
||||
* Label of the tab
|
||||
*
|
||||
* @return string
|
||||
*
|
||||
* @api
|
||||
* @since iTop 3.2.1
|
||||
*/
|
||||
public function GetTabLabel(): string;
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
<?php
|
||||
/**
|
||||
* @copyright Copyright (C) 2010-2024 Combodo SARL
|
||||
* @license http://opensource.org/licenses/AGPL-3.0
|
||||
*/
|
||||
|
||||
namespace Combodo\iTop\Portal\Hook;
|
||||
|
||||
/**
|
||||
* This interface is used to add content to the user profile brick.
|
||||
*
|
||||
* @api
|
||||
* @since iTop 3.2.1
|
||||
*/
|
||||
interface iUserProfileTabContentExtension extends iAbstractPortalTabContentExtension
|
||||
{
|
||||
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
<?php
|
||||
/**
|
||||
* @copyright Copyright (C) 2010-2024 Combodo SARL
|
||||
* @license http://opensource.org/licenses/AGPL-3.0
|
||||
*/
|
||||
|
||||
namespace Combodo\iTop\Portal\Hook;
|
||||
|
||||
/**
|
||||
* This interface is used to add content to the user profile brick.
|
||||
*
|
||||
* @api
|
||||
* @since iTop 3.2.1
|
||||
*/
|
||||
interface iUserProfileTabExtension extends iAbstractPortalTabExtension
|
||||
{
|
||||
|
||||
}
|
||||
@@ -0,0 +1,71 @@
|
||||
<?php
|
||||
/**
|
||||
* @copyright Copyright (C) 2010-2024 Combodo SARL
|
||||
* @license http://opensource.org/licenses/AGPL-3.0
|
||||
*/
|
||||
|
||||
namespace Combodo\iTop\Portal\Twig;
|
||||
|
||||
use utils;
|
||||
|
||||
/**
|
||||
* Entity used to store a twig template and the associated data
|
||||
*
|
||||
* @api
|
||||
*
|
||||
* @since iTop 3.2.1
|
||||
*/
|
||||
class PortalBlockExtension
|
||||
{
|
||||
private string $sTwig;
|
||||
private array $aData;
|
||||
|
||||
/**
|
||||
* Create a new twig extension block.
|
||||
* The given twig template can be HTML, CSS or JavaScript.
|
||||
* * CSS goes to the block named 'css' and is inline in the page.
|
||||
* * JavaScript goes to the blocks named 'script' or 'ready_script' and are inline in the page.
|
||||
* * HTML goes everywhere else.
|
||||
*
|
||||
* @api
|
||||
*
|
||||
* @param array $aData Data given to the twig template (into the variable {{ aData }})
|
||||
* @param string $sTwig name of the twig file to the absolute path given to the PortalTwigContext
|
||||
*
|
||||
* @since iTop 3.2.1
|
||||
*/
|
||||
function __construct(string $sTwig, array $aData = [])
|
||||
{
|
||||
$this->sTwig = $sTwig;
|
||||
$this->aData = $aData;
|
||||
}
|
||||
|
||||
/**
|
||||
* Used by twig templates to get the name of the template to render.
|
||||
*
|
||||
* @return string twig template to render
|
||||
*
|
||||
* @api
|
||||
*
|
||||
* @since iTop 3.2.1
|
||||
*/
|
||||
public function GetTwig(): string
|
||||
{
|
||||
return $this->sTwig;
|
||||
}
|
||||
|
||||
/**
|
||||
* Used by twig templates to get the data for the template to render.
|
||||
*
|
||||
* @return array Data used to render the template
|
||||
*
|
||||
* @api
|
||||
*
|
||||
* @since iTop 3.2.1
|
||||
*/
|
||||
public function GetData(): array
|
||||
{
|
||||
$this->aData['sTransactionId'] = utils::GetNewTransactionId();
|
||||
return $this->aData;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,61 @@
|
||||
<?php
|
||||
/**
|
||||
* @copyright Copyright (C) 2010-2024 Combodo SARL
|
||||
* @license http://opensource.org/licenses/AGPL-3.0
|
||||
*/
|
||||
|
||||
namespace Combodo\iTop\Portal\Twig;
|
||||
|
||||
/**
|
||||
* Twig context to add additional twigs and data to extensible twigs.
|
||||
* The additional twigs are ailed at blocks defined in the extensible twig.
|
||||
*
|
||||
* @api
|
||||
*
|
||||
* @since iTop 3.2.1
|
||||
*/
|
||||
class PortalTwigContext
|
||||
{
|
||||
|
||||
private array $aBlockExtension;
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$this->aBlockExtension = [];
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a Twig block extension.
|
||||
* This method is used by extensions to provide templates.
|
||||
*
|
||||
* @api
|
||||
*
|
||||
* @param PortalBlockExtension $oBlockExtension Entity containing a twig template and associated data
|
||||
* @param string $sBlockName Name of the block where to add the twig
|
||||
*
|
||||
* @since iTop 3.2.1
|
||||
*/
|
||||
function AddBlockExtension(string $sBlockName, PortalBlockExtension $oBlockExtension): void
|
||||
{
|
||||
$this->aBlockExtension[$sBlockName] = $oBlockExtension;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all the templates to render for a given block.
|
||||
* This method is used by twig templates to render extensions.
|
||||
*
|
||||
* @api
|
||||
*
|
||||
* @param string $sBlockName Name of the block currently rendered
|
||||
*
|
||||
* @return \Combodo\iTop\Portal\Twig\PortalBlockExtension|null
|
||||
*
|
||||
* @since iTop 3.2.1
|
||||
*/
|
||||
public function GetBlockExtension(string $sBlockName): ?PortalBlockExtension
|
||||
{
|
||||
/** @var PortalBlockExtension $oBlockExtension */
|
||||
$oBlockExtension = $this->aBlockExtension[$sBlockName] ?? null;
|
||||
return $oBlockExtension;
|
||||
}
|
||||
}
|
||||
@@ -2,9 +2,9 @@
|
||||
{# User profile brick base layout #}
|
||||
{% extends 'itop-portal-base/portal/templates/bricks/layout.html.twig' %}
|
||||
|
||||
{% set oContactForm = forms.contact %}
|
||||
{% set oPreferencesForm = forms.preferences %}
|
||||
{% set oPasswordForm = forms.password %}
|
||||
{% if sTab == "" %}
|
||||
{% set sTab = "user-info" %}
|
||||
{% endif %}
|
||||
|
||||
{% block pPageBodyClass %}{{ parent() }} page_user-profile_brick{% endblock %}
|
||||
|
||||
@@ -20,228 +20,82 @@
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
<div id="user-profile-wrapper">
|
||||
{% block pUserProfileWrapper %}
|
||||
<div class="row">
|
||||
<div class="col-sm-6">
|
||||
<div class="panel panel-default">
|
||||
<div class="panel-heading">
|
||||
<h3 class="panel-title">{{ 'Brick:Portal:UserProfile:PersonalInformations:Title'|dict_s }}</h3>
|
||||
</div>
|
||||
<div class="panel-body">
|
||||
<form id="{{ oContactForm.id }}" class="" method="POST" action="{{ oContactForm.renderer.GetEndpoint()|raw }}">
|
||||
<input type="hidden" name="transaction_id" value="{{ oContactForm.transaction_id }}" />
|
||||
<div class="form_alerts">
|
||||
<div class="alert alert-success" role="alert" style="display: none;"></div>
|
||||
<div class="alert alert-warning" role="alert" style="display: none;"></div>
|
||||
<div class="alert alert-error alert-danger" role="alert" style="display: none;"></div>
|
||||
</div>
|
||||
<div class="form_fields">
|
||||
{{ oContactForm.renderer.GetBaseLayout()|raw }}
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-sm-6">
|
||||
{% if oBrick.GetShowPictureForm() %}
|
||||
{% block pUserProfilePictureFormContainer %}
|
||||
<div class="panel panel-default user_profile_picture">
|
||||
<div class="panel-heading">
|
||||
<h3 class="panel-title">{{ 'Brick:Portal:UserProfile:Photo:Title'|dict_s }}</h3>
|
||||
</div>
|
||||
<div class="panel-body" style="position: relative;">
|
||||
<div class="form_alerts">
|
||||
<div class="alert alert-success" role="alert" style="display: none;"></div>
|
||||
<div class="alert alert-warning" role="alert" style="display: none;"></div>
|
||||
<div class="alert alert-error alert-danger" role="alert" style="display: none;"></div>
|
||||
</div>
|
||||
<form id="picture-form" method="POST" action="{{ app['url_generator'].generate('p_user_profile_brick') }}">
|
||||
<input type="hidden" name="current_values[form_type]" value="{{ constant('\\Combodo\\iTop\\Portal\\Controller\\UserProfileBrickController::ENUM_FORM_TYPE_PICTURE') }}" />
|
||||
<input type="hidden" name="operation" value="submit" />
|
||||
<div class="text-center">
|
||||
<span class="preview">
|
||||
<img src="{{ sUserPhotoUrl }}"/>
|
||||
</span>
|
||||
<span class="actions">
|
||||
<span type="button" class="btn btn-default btn_edit">
|
||||
<span class="fas fa-pencil-alt fa-fw"></span>
|
||||
<input id="picture" type="file" name="picture" />
|
||||
</span>
|
||||
{#<button type="button" class="btn btn-default btn_undo" title="{{ 'UI:Button:ResetImage'|dict_s }}" disabled>
|
||||
<span class="fas fa-undo fa-fw"></span>
|
||||
</button>
|
||||
<button type="button" class="btn btn-default btn_reset" title="{{ 'UI:Button:RemoveImage'|dict_s }}">
|
||||
<span class="fas fa-trash-o fa-fw"></span>
|
||||
</button>#}
|
||||
</span>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
{% endif %}
|
||||
<div class="form_alerts">
|
||||
{% if sMessage is defined %}
|
||||
<div id="success-message-content" class="alert alert-success" role="alert">{{ sMessage }}</div>
|
||||
{% else %}
|
||||
<div id="success-message-content" style="display:none;" class="alert alert-success" role="alert"></div>
|
||||
{% endif %}
|
||||
|
||||
{% if oBrick.GetShowPreferencesForm() %}
|
||||
{% block pUserProfilePreferencesFormContainer %}
|
||||
<div class="panel panel-default">
|
||||
<div class="panel-heading">
|
||||
<h3 class="panel-title">{{ 'Class:appUserPreferences/Attribute:preferences'|dict_s }}</h3>
|
||||
</div>
|
||||
<div class="panel-body">
|
||||
<form id="{{ oPreferencesForm.id }}" class="" method="POST" action="{{ oPreferencesForm.renderer.GetEndpoint()|raw }}">
|
||||
<div class="form_alerts">
|
||||
<div class="alert alert-success" role="alert" style="display: none;"></div>
|
||||
<div class="alert alert-warning" role="alert" style="display: none;"></div>
|
||||
<div class="alert alert-error alert-danger" role="alert" style="display: none;"></div>
|
||||
</div>
|
||||
<div class="form_fields">
|
||||
{{ oPreferencesForm.renderer.GetBaseLayout()|raw }}
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
{% endif %}
|
||||
{% if sError is defined %}
|
||||
<div id="error-message-content" class="alert alert-error alert-danger" role="alert">{{ sError }}</div>
|
||||
{% else %}
|
||||
<div id="error-message-content" style="display:none;" class="alert alert-error alert-danger" role="alert"></div>
|
||||
{% endif %}
|
||||
</div>
|
||||
|
||||
<ul class="nav nav-pills _tabs">
|
||||
{% if aTabsValues is defined and aTabsValues|length > 0 %}
|
||||
<li{% if sTab == "user-info" %} class="active"{% endif %} data-id="user-info" data-label="{{ 'MyAccount:UserInfo:Tab:Title'|dict_s }}">
|
||||
<a href="{{ app.url_generator.generate('p_user_profile_brick', {'sBrickId': oBrick.GetId(), 'sDisplayMode': '_self', 'sTab': "user-info"}) }}"
|
||||
id="btn_tab_for_user-info">
|
||||
{{ 'MyAccount:UserInfo:Tab:Title'|dict_s }}
|
||||
</a>
|
||||
</li>
|
||||
{% for aTab in aTabsValues %}
|
||||
<li{% if sTab == aTab.code %} class="active"{% endif %} data-id="{{ aTab.code }}" data-label="{{ aTab.label }}">
|
||||
<a href="{{ app.url_generator.generate('p_user_profile_brick', {'sBrickId': oBrick.GetId(), 'sDisplayMode': '_self', 'sTab': aTab.code}) }}"
|
||||
id="btn_tab_for_{{ aTab.code }}">
|
||||
{{ aTab.label|raw }}
|
||||
</a>
|
||||
</li>
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
</ul>
|
||||
|
||||
{% if sTab == "user-info" %}
|
||||
{% set oContactForm = forms.contact %}
|
||||
{% set oPreferencesForm = forms.preferences %}
|
||||
{% set oPasswordForm = forms.password %}
|
||||
{% include 'itop-portal-base/portal/templates/bricks/user-profile/user_info.html.twig' %}
|
||||
{% else %}
|
||||
<div id="user-profile-wrapper">
|
||||
<div class="row">
|
||||
{% import "itop-portal-base/portal/templates/helpers/macros.twig" as Macro %}
|
||||
{{ Macro.BlockExtension(aPluginFormData, 'html', oBrick) }}
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
{% if oBrick.GetShowPasswordForm() %}
|
||||
{% block pUserProfilePasswordFormContainer %}
|
||||
<div class="panel panel-default">
|
||||
<div class="panel-heading">
|
||||
<h3 class="panel-title">{{ 'Brick:Portal:UserProfile:Password:Title'|dict_s }}</h3>
|
||||
</div>
|
||||
<div class="panel-body">
|
||||
{% if oPasswordForm is not null %}
|
||||
<form id="{{ oPasswordForm.id }}" class="" method="POST" action="{{ oPasswordForm.renderer.GetEndpoint()|raw }}" autocomplete="off">
|
||||
<div class="form_alerts">
|
||||
<div class="alert alert-success" role="alert" style="display: none;"></div>
|
||||
<div class="alert alert-warning" role="alert" style="display: none;"></div>
|
||||
<div class="alert alert-error alert-danger" role="alert" style="display: none;"></div>
|
||||
</div>
|
||||
<div class="form_fields">
|
||||
{{ oPasswordForm.renderer.GetBaseLayout()|raw }}
|
||||
</div>
|
||||
</form>
|
||||
{% else %}
|
||||
{{ 'Brick:Portal:UserProfile:Password:CantChangeContactAdministrator'|dict_format(constant('ITOP_APPLICATION_SHORT')) }}
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
<div class="form_buttons">
|
||||
{% block pUserProfileFormButtons %}
|
||||
<div class="form_btn_regular">
|
||||
{% if sFormMode == constant('\\Combodo\\iTop\\Portal\\Helper\\ObjectFormHandlerHelper::ENUM_MODE_EDIT') %}
|
||||
<input class="btn btn-primary form_btn_submit" type="submit" value="{{ 'Portal:Button:Submit'|dict_s }}">
|
||||
{% endif %}
|
||||
</div>
|
||||
{% endblock %}
|
||||
</div>
|
||||
{% endblock %}
|
||||
</div>
|
||||
{% endblock %}
|
||||
|
||||
{% block pPageReadyScripts %}
|
||||
{{ parent() }}
|
||||
{% import "itop-portal-base/portal/templates/helpers/macros.twig" as Macro %}
|
||||
{{ Macro.BlockExtension(aPluginFormData, 'ready_script', oBrick) }}
|
||||
|
||||
// Personal informations form
|
||||
var oContactFormFieldSet = $('#{{ oContactForm.id }} > .form_fields').field_set({{ oContactForm.fieldset|json_encode()|raw }});
|
||||
$('#{{ oContactForm.id }}').portal_form_handler({
|
||||
formmanager_class: "{{ oContactForm.formmanager_class|escape('js') }}",
|
||||
formmanager_data: {{ oContactForm.formmanager_data|json_encode()|raw }},
|
||||
field_set: oContactFormFieldSet,
|
||||
endpoint: "{{ oContactForm.renderer.GetEndpoint()|raw }}"
|
||||
});
|
||||
|
||||
// Preferences form
|
||||
var oPreferencesFormFieldSet = $('#{{ oPreferencesForm.id }} > .form_fields').field_set({{ oPreferencesForm.fieldset|json_encode()|raw }});
|
||||
$('#{{ oPreferencesForm.id }}').portal_form_handler({
|
||||
formmanager_class: "{{ oPreferencesForm.formmanager_class|escape('js') }}",
|
||||
formmanager_data: {{ oPreferencesForm.formmanager_data|json_encode()|raw }},
|
||||
field_set: oPreferencesFormFieldSet,
|
||||
endpoint: "{{ oPreferencesForm.renderer.GetEndpoint()|raw }}"
|
||||
});
|
||||
|
||||
{% if oPasswordForm is not null %}
|
||||
// Password form
|
||||
var oPasswordFormFieldSet = $('#{{ oPasswordForm.id }} > .form_fields').field_set({{ oPasswordForm.fieldset|json_encode()|raw }});
|
||||
$('#{{ oPasswordForm.id }}').portal_form_handler({
|
||||
formmanager_class: "{{ oPasswordForm.formmanager_class|escape('js') }}",
|
||||
formmanager_data: {{ oPasswordForm.formmanager_data|json_encode()|raw }},
|
||||
field_set: oPasswordFormFieldSet,
|
||||
endpoint: "{{ oPasswordForm.renderer.GetEndpoint()|raw }}"
|
||||
});
|
||||
{% if sTab == "" %}
|
||||
{% set sTab = "user-info" %}
|
||||
{% endif %}
|
||||
|
||||
// Picture form
|
||||
// - JQuery upload widget
|
||||
$('#picture-form #picture').fileupload({
|
||||
dataType: 'json',
|
||||
acceptFileTypes: /(\.|\/)(gif|jpe?g|png)$/i,
|
||||
disableImageResize: /Android(?!.*Chrome)|Opera/.test(window.navigator.userAgent)
|
||||
})
|
||||
.on('fileuploadsend', function(oEvent, oData){
|
||||
$('.user_profile_picture .form_alerts .alert-error').hide()
|
||||
$('#page_overlay .overlay_content .content_loader').clone().prependTo('.user_profile_picture .panel-body');
|
||||
})
|
||||
.on('fileuploadalways', function(oEvent, oData){
|
||||
$('.user_profile_picture .content_loader').remove();
|
||||
})
|
||||
.on('fileuploaddone', function(oEvent, oData){
|
||||
if( (oData._response.result.form !== undefined) && (oData._response.result.form.validation.valid === true) )
|
||||
{
|
||||
// Retrieving picture url
|
||||
var sPictureUrl = oData._response.result.form.picture_url;
|
||||
// Replacing form preview image
|
||||
$('#picture-form .preview img').attr('src', sPictureUrl);
|
||||
// Replacing menu image
|
||||
$('#topbar .user_photo, #sidebar .user_photo').css('background-image', 'url("' + sPictureUrl + '")');
|
||||
}
|
||||
})
|
||||
.on('fileuploadfail', function(oEvent, oData){
|
||||
if( (oData._response.jqXHR.responseJSON !== undefined) && (oData._response.jqXHR.responseJSON.error_message !== undefined) )
|
||||
{
|
||||
$('.user_profile_picture .form_alerts .alert-error').show().text(oData._response.jqXHR.responseJSON.error_message);
|
||||
}
|
||||
});
|
||||
// - Undo button
|
||||
/*$('#user-profile-wrapper .actions .btn_undo').on('click', function(oEvent){
|
||||
//console.log('Picture undo trigger');
|
||||
});*/
|
||||
// - Reset button
|
||||
$('#user-profile-wrapper .actions .btn_reset').on('click', function(oEvent){
|
||||
//console.log('Picture reset trigger');
|
||||
});
|
||||
{% if sTab == "user-info" %}
|
||||
{% set oContactForm = forms.contact %}
|
||||
{% set oPreferencesForm = forms.preferences %}
|
||||
{% set oPasswordForm = forms.password %}
|
||||
{% include 'itop-portal-base/portal/templates/bricks/user-profile/user_info.ready.js.twig' %}
|
||||
{% endif %}
|
||||
{% endblock %}
|
||||
|
||||
// Submit button
|
||||
$('#user-profile-wrapper .form_buttons .form_btn_submit').off('click').on('click', function(oEvent){
|
||||
oEvent.preventDefault();
|
||||
{% block pPageLiveScriptHelpers %}
|
||||
{{ parent() }}
|
||||
{% import "itop-portal-base/portal/templates/helpers/macros.twig" as Macro %}
|
||||
{{ Macro.BlockExtension(aPluginFormData, 'script', oBrick) }}
|
||||
{% endblock %}
|
||||
|
||||
// Resetting feedback
|
||||
$('#user-profile-wrapper .form_alerts .alert').hide();
|
||||
$('#user-profile-wrapper .form_alerts .alert > p').remove();
|
||||
$('#user-profile-wrapper .form_field').removeClass('has-error');
|
||||
$('#user-profile-wrapper .form_field .help-block > p').remove();
|
||||
|
||||
// Submiting contact form through AJAX
|
||||
$('#{{ oContactForm.id }}').portal_form_handler('submit', oEvent);
|
||||
|
||||
// Submiting preferences form through AJAX
|
||||
$('#{{ oPreferencesForm.id }}').portal_form_handler('submit', oEvent);
|
||||
|
||||
{% if oPasswordForm is not null %}
|
||||
// Submiting password form through AJAX
|
||||
// Only if fields are filled
|
||||
$('#{{ oPasswordForm.id }} :password').each(function(iIndex, oElem){
|
||||
if($(oElem).val() !== '')
|
||||
{
|
||||
$('#{{ oPasswordForm.id }}').portal_form_handler('submit', oEvent);
|
||||
return false;
|
||||
}
|
||||
});
|
||||
{% endif %}
|
||||
});
|
||||
{% endblock %}
|
||||
{% block pStyleinline %}
|
||||
{{ parent() }}
|
||||
<style>
|
||||
{% import "itop-portal-base/portal/templates/helpers/macros.twig" as Macro %}
|
||||
{{ Macro.BlockExtension(aPluginFormData, 'css', oBrick) }}
|
||||
</style>
|
||||
{% endblock %}
|
||||
|
||||
@@ -0,0 +1,119 @@
|
||||
{# @copyright Copyright (C) 2010-2024 Combodo SARL #}
|
||||
{# @license http://opensource.org/licenses/AGPL-3.0 #}
|
||||
|
||||
<div id="user-profile-wrapper">
|
||||
{% block pUserProfileWrapper %}
|
||||
<div class="row">
|
||||
<div class="col-sm-6">
|
||||
<div class="panel panel-default">
|
||||
<div class="panel-heading">
|
||||
<h3 class="panel-title">{{ 'Brick:Portal:UserProfile:PersonalInformations:Title'|dict_s }}</h3>
|
||||
</div>
|
||||
<div class="panel-body">
|
||||
<form id="{{ oContactForm.id }}" class="" method="POST" action="{{ oContactForm.renderer.GetEndpoint()|raw }}">
|
||||
<input type="hidden" name="transaction_id" value="{{ oContactForm.transaction_id }}" />
|
||||
<div class="form_alerts">
|
||||
<div class="alert alert-success" role="alert" style="display: none;"></div>
|
||||
<div class="alert alert-warning" role="alert" style="display: none;"></div>
|
||||
<div class="alert alert-error alert-danger" role="alert" style="display: none;"></div>
|
||||
</div>
|
||||
<div class="form_fields">
|
||||
{{ oContactForm.renderer.GetBaseLayout()|raw }}
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-sm-6">
|
||||
{% if oBrick.GetShowPictureForm() %}
|
||||
{% block pUserProfilePictureFormContainer %}
|
||||
<div class="panel panel-default user_profile_picture">
|
||||
<div class="panel-heading">
|
||||
<h3 class="panel-title">{{ 'Brick:Portal:UserProfile:Photo:Title'|dict_s }}</h3>
|
||||
</div>
|
||||
<div class="panel-body" style="position: relative;">
|
||||
<div class="form_alerts">
|
||||
<div class="alert alert-success" role="alert" style="display: none;"></div>
|
||||
<div class="alert alert-warning" role="alert" style="display: none;"></div>
|
||||
<div class="alert alert-error alert-danger" role="alert" style="display: none;"></div>
|
||||
</div>
|
||||
<form id="picture-form" method="POST" action="{{ app['url_generator'].generate('p_user_profile_brick') }}">
|
||||
<input type="hidden" name="current_values[form_type]" value="{{ constant('\\Combodo\\iTop\\Portal\\Controller\\UserProfileBrickController::ENUM_FORM_TYPE_PICTURE') }}" />
|
||||
<input type="hidden" name="operation" value="submit" />
|
||||
<div class="text-center">
|
||||
<span class="preview">
|
||||
<img src="{{ sUserPhotoUrl }}"/>
|
||||
</span>
|
||||
<span class="actions">
|
||||
<span type="button" class="btn btn-default btn_edit">
|
||||
<span class="fas fa-pencil-alt fa-fw"></span>
|
||||
<input id="picture" type="file" name="picture" />
|
||||
</span>
|
||||
</span>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
{% endif %}
|
||||
|
||||
{% if oBrick.GetShowPreferencesForm() %}
|
||||
{% block pUserProfilePreferencesFormContainer %}
|
||||
<div class="panel panel-default">
|
||||
<div class="panel-heading">
|
||||
<h3 class="panel-title">{{ 'Class:appUserPreferences/Attribute:preferences'|dict_s }}</h3>
|
||||
</div>
|
||||
<div class="panel-body">
|
||||
<form id="{{ oPreferencesForm.id }}" class="" method="POST" action="{{ oPreferencesForm.renderer.GetEndpoint()|raw }}">
|
||||
<div class="form_alerts">
|
||||
<div class="alert alert-success" role="alert" style="display: none;"></div>
|
||||
<div class="alert alert-warning" role="alert" style="display: none;"></div>
|
||||
<div class="alert alert-error alert-danger" role="alert" style="display: none;"></div>
|
||||
</div>
|
||||
<div class="form_fields">
|
||||
{{ oPreferencesForm.renderer.GetBaseLayout()|raw }}
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
{% endif %}
|
||||
|
||||
{% if oBrick.GetShowPasswordForm() %}
|
||||
{% block pUserProfilePasswordFormContainer %}
|
||||
<div class="panel panel-default">
|
||||
<div class="panel-heading">
|
||||
<h3 class="panel-title">{{ 'Brick:Portal:UserProfile:Password:Title'|dict_s }}</h3>
|
||||
</div>
|
||||
<div class="panel-body">
|
||||
{% if oPasswordForm is not null %}
|
||||
<form id="{{ oPasswordForm.id }}" class="" method="POST" action="{{ oPasswordForm.renderer.GetEndpoint()|raw }}" autocomplete="off">
|
||||
<div class="form_alerts">
|
||||
<div class="alert alert-success" role="alert" style="display: none;"></div>
|
||||
<div class="alert alert-warning" role="alert" style="display: none;"></div>
|
||||
<div class="alert alert-error alert-danger" role="alert" style="display: none;"></div>
|
||||
</div>
|
||||
<div class="form_fields">
|
||||
{{ oPasswordForm.renderer.GetBaseLayout()|raw }}
|
||||
</div>
|
||||
</form>
|
||||
{% else %}
|
||||
{{ 'Brick:Portal:UserProfile:Password:CantChangeContactAdministrator'|dict_format(constant('ITOP_APPLICATION_SHORT')) }}
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
<div class="form_buttons">
|
||||
{% block pUserProfileFormButtons %}
|
||||
<div class="form_btn_regular">
|
||||
{% if sFormMode == constant('\\Combodo\\iTop\\Portal\\Helper\\ObjectFormHandlerHelper::ENUM_MODE_EDIT') %}
|
||||
<input class="btn btn-primary form_btn_submit" type="submit" value="{{ 'Portal:Button:Submit'|dict_s }}">
|
||||
{% endif %}
|
||||
</div>
|
||||
{% endblock %}
|
||||
</div>
|
||||
{% endblock %}
|
||||
</div>
|
||||
@@ -0,0 +1,100 @@
|
||||
{# @copyright Copyright (C) 2010-2024 Combodo SARL #}
|
||||
{# @license http://opensource.org/licenses/AGPL-3.0 #}
|
||||
|
||||
// Personal informations form
|
||||
var oContactFormFieldSet = $('#{{ oContactForm.id }} > .form_fields').field_set({{ oContactForm.fieldset|json_encode()|raw }});
|
||||
$('#{{ oContactForm.id }}').portal_form_handler({
|
||||
formmanager_class: "{{ oContactForm.formmanager_class|escape('js') }}",
|
||||
formmanager_data: {{ oContactForm.formmanager_data|json_encode()|raw }},
|
||||
field_set: oContactFormFieldSet,
|
||||
endpoint: "{{ oContactForm.renderer.GetEndpoint()|raw }}"
|
||||
});
|
||||
|
||||
// Preferences form
|
||||
var oPreferencesFormFieldSet = $('#{{ oPreferencesForm.id }} > .form_fields').field_set({{ oPreferencesForm.fieldset|json_encode()|raw }});
|
||||
$('#{{ oPreferencesForm.id }}').portal_form_handler({
|
||||
formmanager_class: "{{ oPreferencesForm.formmanager_class|escape('js') }}",
|
||||
formmanager_data: {{ oPreferencesForm.formmanager_data|json_encode()|raw }},
|
||||
field_set: oPreferencesFormFieldSet,
|
||||
endpoint: "{{ oPreferencesForm.renderer.GetEndpoint()|raw }}"
|
||||
});
|
||||
|
||||
{% if oPasswordForm is not null %}
|
||||
// Password form
|
||||
var oPasswordFormFieldSet = $('#{{ oPasswordForm.id }} > .form_fields').field_set({{ oPasswordForm.fieldset|json_encode()|raw }});
|
||||
$('#{{ oPasswordForm.id }}').portal_form_handler({
|
||||
formmanager_class: "{{ oPasswordForm.formmanager_class|escape('js') }}",
|
||||
formmanager_data: {{ oPasswordForm.formmanager_data|json_encode()|raw }},
|
||||
field_set: oPasswordFormFieldSet,
|
||||
endpoint: "{{ oPasswordForm.renderer.GetEndpoint()|raw }}"
|
||||
});
|
||||
{% endif %}
|
||||
|
||||
// Picture form
|
||||
// - JQuery upload widget
|
||||
$('#picture-form #picture').fileupload({
|
||||
dataType: 'json',
|
||||
acceptFileTypes: /(\.|\/)(gif|jpe?g|png)$/i,
|
||||
disableImageResize: /Android(?!.*Chrome)|Opera/.test(window.navigator.userAgent)
|
||||
})
|
||||
.on('fileuploadsend', function(oEvent, oData){
|
||||
$('.user_profile_picture .form_alerts .alert-error').hide()
|
||||
$('#page_overlay .overlay_content .content_loader').clone().prependTo('.user_profile_picture .panel-body');
|
||||
})
|
||||
.on('fileuploadalways', function(oEvent, oData){
|
||||
$('.user_profile_picture .content_loader').remove();
|
||||
})
|
||||
.on('fileuploaddone', function(oEvent, oData){
|
||||
if( (oData._response.result.form !== undefined) && (oData._response.result.form.validation.valid === true) )
|
||||
{
|
||||
// Retrieving picture url
|
||||
var sPictureUrl = oData._response.result.form.picture_url;
|
||||
// Replacing form preview image
|
||||
$('#picture-form .preview img').attr('src', sPictureUrl);
|
||||
// Replacing menu image
|
||||
$('#topbar .user_photo, #sidebar .user_photo').css('background-image', 'url("' + sPictureUrl + '")');
|
||||
}
|
||||
})
|
||||
.on('fileuploadfail', function(oEvent, oData){
|
||||
if( (oData._response.jqXHR.responseJSON !== undefined) && (oData._response.jqXHR.responseJSON.error_message !== undefined) )
|
||||
{
|
||||
$('.user_profile_picture .form_alerts .alert-error').show().text(oData._response.jqXHR.responseJSON.error_message);
|
||||
}
|
||||
});
|
||||
// - Undo button
|
||||
/*$('#user-profile-wrapper .actions .btn_undo').on('click', function(oEvent){
|
||||
//console.log('Picture undo trigger');
|
||||
});*/
|
||||
// - Reset button
|
||||
$('#user-profile-wrapper .actions .btn_reset').on('click', function(oEvent){
|
||||
//console.log('Picture reset trigger');
|
||||
});
|
||||
|
||||
// Submit button
|
||||
$('#user-profile-wrapper .form_buttons .form_btn_submit').off('click').on('click', function(oEvent){
|
||||
oEvent.preventDefault();
|
||||
|
||||
// Resetting feedback
|
||||
$('#user-profile-wrapper .form_alerts .alert').hide();
|
||||
$('#user-profile-wrapper .form_alerts .alert > p').remove();
|
||||
$('#user-profile-wrapper .form_field').removeClass('has-error');
|
||||
$('#user-profile-wrapper .form_field .help-block > p').remove();
|
||||
|
||||
// Submiting contact form through AJAX
|
||||
$('#{{ oContactForm.id }}').portal_form_handler('submit', oEvent);
|
||||
|
||||
// Submiting preferences form through AJAX
|
||||
$('#{{ oPreferencesForm.id }}').portal_form_handler('submit', oEvent);
|
||||
|
||||
{% if oPasswordForm is not null %}
|
||||
// Submiting password form through AJAX
|
||||
// Only if fields are filled
|
||||
$('#{{ oPasswordForm.id }} :password').each(function(iIndex, oElem){
|
||||
if($(oElem).val() !== '')
|
||||
{
|
||||
$('#{{ oPasswordForm.id }}').portal_form_handler('submit', oEvent);
|
||||
return false;
|
||||
}
|
||||
});
|
||||
{% endif %}
|
||||
});
|
||||
@@ -0,0 +1,13 @@
|
||||
{# @copyright Copyright (C) 2010-2024 Combodo SAS #}
|
||||
{# @license http://opensource.org/licenses/AGPL-3.0 #}
|
||||
|
||||
{% macro BlockExtension(aPluginFormData, sBlockName, oBrick) %}
|
||||
{% for oPortalData in aPluginFormData %}
|
||||
{% if (oPortalData is defined and oPortalData.GetBlockExtension(sBlockName)) %}
|
||||
{% set oBlockExtension = oPortalData.GetBlockExtension(sBlockName) %}
|
||||
{% set sTwig = oBlockExtension.GetTwig() %}
|
||||
{% set aData = oBlockExtension.GetData() %}
|
||||
{% include sTwig ignore missing %}
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
{% endmacro %}
|
||||
@@ -78,9 +78,9 @@
|
||||
{% block pStyleinline %}
|
||||
{# UI Extensions inline CSS #}
|
||||
{% if app['ui_extensions_helper'].css_inline is not null %}
|
||||
<style>
|
||||
{{ app['ui_extensions_helper'].css_inline|raw }}
|
||||
</style>
|
||||
<style>
|
||||
{{ app['ui_extensions_helper'].css_inline|raw }}
|
||||
</style>
|
||||
{% endif %}
|
||||
{% endblock %}
|
||||
|
||||
|
||||
@@ -6,5 +6,70 @@ $vendorDir = dirname(__DIR__);
|
||||
$baseDir = dirname($vendorDir);
|
||||
|
||||
return array(
|
||||
'Combodo\\iTop\\Portal\\Brick\\AbstractBrick' => $baseDir . '/src/Brick/AbstractBrick.php',
|
||||
'Combodo\\iTop\\Portal\\Brick\\AggregatePageBrick' => $baseDir . '/src/Brick/AggregatePageBrick.php',
|
||||
'Combodo\\iTop\\Portal\\Brick\\BrickCollection' => $baseDir . '/src/Brick/BrickCollection.php',
|
||||
'Combodo\\iTop\\Portal\\Brick\\BrickNotFoundException' => $baseDir . '/src/Brick/BrickNotFoundException.php',
|
||||
'Combodo\\iTop\\Portal\\Brick\\BrowseBrick' => $baseDir . '/src/Brick/BrowseBrick.php',
|
||||
'Combodo\\iTop\\Portal\\Brick\\CreateBrick' => $baseDir . '/src/Brick/CreateBrick.php',
|
||||
'Combodo\\iTop\\Portal\\Brick\\FilterBrick' => $baseDir . '/src/Brick/FilterBrick.php',
|
||||
'Combodo\\iTop\\Portal\\Brick\\ManageBrick' => $baseDir . '/src/Brick/ManageBrick.php',
|
||||
'Combodo\\iTop\\Portal\\Brick\\PortalBrick' => $baseDir . '/src/Brick/PortalBrick.php',
|
||||
'Combodo\\iTop\\Portal\\Brick\\PropertyNotFoundException' => $baseDir . '/src/Brick/PropertyNotFoundException.php',
|
||||
'Combodo\\iTop\\Portal\\Brick\\UserProfileBrick' => $baseDir . '/src/Brick/UserProfileBrick.php',
|
||||
'Combodo\\iTop\\Portal\\Controller\\AbstractController' => $baseDir . '/src/Controller/AbstractController.php',
|
||||
'Combodo\\iTop\\Portal\\Controller\\AggregatePageBrickController' => $baseDir . '/src/Controller/AggregatePageBrickController.php',
|
||||
'Combodo\\iTop\\Portal\\Controller\\BrickController' => $baseDir . '/src/Controller/BrickController.php',
|
||||
'Combodo\\iTop\\Portal\\Controller\\BrowseBrickController' => $baseDir . '/src/Controller/BrowseBrickController.php',
|
||||
'Combodo\\iTop\\Portal\\Controller\\CreateBrickController' => $baseDir . '/src/Controller/CreateBrickController.php',
|
||||
'Combodo\\iTop\\Portal\\Controller\\DefaultController' => $baseDir . '/src/Controller/DefaultController.php',
|
||||
'Combodo\\iTop\\Portal\\Controller\\ManageBrickController' => $baseDir . '/src/Controller/ManageBrickController.php',
|
||||
'Combodo\\iTop\\Portal\\Controller\\ObjectController' => $baseDir . '/src/Controller/ObjectController.php',
|
||||
'Combodo\\iTop\\Portal\\Controller\\SessionMessageController' => $baseDir . '/src/Controller/SessionMessageController.php',
|
||||
'Combodo\\iTop\\Portal\\Controller\\UserProfileBrickController' => $baseDir . '/src/Controller/UserProfileBrickController.php',
|
||||
'Combodo\\iTop\\Portal\\DependencyInjection\\SilexCompatBootstrap\\PortalXmlConfiguration\\AbstractConfiguration' => $baseDir . '/src/DependencyInjection/SilexCompatBootstrap/PortalXmlConfiguration/AbstractConfiguration.php',
|
||||
'Combodo\\iTop\\Portal\\DependencyInjection\\SilexCompatBootstrap\\PortalXmlConfiguration\\Basic' => $baseDir . '/src/DependencyInjection/SilexCompatBootstrap/PortalXmlConfiguration/Basic.php',
|
||||
'Combodo\\iTop\\Portal\\DependencyInjection\\SilexCompatBootstrap\\PortalXmlConfiguration\\Forms' => $baseDir . '/src/DependencyInjection/SilexCompatBootstrap/PortalXmlConfiguration/Forms.php',
|
||||
'Combodo\\iTop\\Portal\\DependencyInjection\\SilexCompatBootstrap\\PortalXmlConfiguration\\Lists' => $baseDir . '/src/DependencyInjection/SilexCompatBootstrap/PortalXmlConfiguration/Lists.php',
|
||||
'Combodo\\iTop\\Portal\\EventListener\\ApplicationContextSetPluginPropertyClass' => $baseDir . '/src/EventListener/ApplicationContextSetPluginPropertyClass.php',
|
||||
'Combodo\\iTop\\Portal\\EventListener\\ApplicationContextSetUrlMakerClass' => $baseDir . '/src/EventListener/ApplicationContextSetUrlMakerClass.php',
|
||||
'Combodo\\iTop\\Portal\\EventListener\\CssFromSassCompiler' => $baseDir . '/src/EventListener/CssFromSassCompiler.php',
|
||||
'Combodo\\iTop\\Portal\\EventListener\\ExceptionListener' => $baseDir . '/src/EventListener/ExceptionListener.php',
|
||||
'Combodo\\iTop\\Portal\\EventListener\\UserProvider' => $baseDir . '/src/EventListener/UserProvider.php',
|
||||
'Combodo\\iTop\\Portal\\Form\\ObjectFormManager' => $baseDir . '/src/Form/ObjectFormManager.php',
|
||||
'Combodo\\iTop\\Portal\\Form\\PasswordFormManager' => $baseDir . '/src/Form/PasswordFormManager.php',
|
||||
'Combodo\\iTop\\Portal\\Form\\PreferencesFormManager' => $baseDir . '/src/Form/PreferencesFormManager.php',
|
||||
'Combodo\\iTop\\Portal\\Helper\\ApplicationHelper' => $baseDir . '/src/Helper/ApplicationHelper.php',
|
||||
'Combodo\\iTop\\Portal\\Helper\\BrickControllerHelper' => $baseDir . '/src/Helper/BrickControllerHelper.php',
|
||||
'Combodo\\iTop\\Portal\\Helper\\BrowseBrickHelper' => $baseDir . '/src/Helper/BrowseBrickHelper.php',
|
||||
'Combodo\\iTop\\Portal\\Helper\\ContextManipulatorHelper' => $baseDir . '/src/Helper/ContextManipulatorHelper.php',
|
||||
'Combodo\\iTop\\Portal\\Helper\\ExtensibilityHelper' => $baseDir . '/src/Helper/ExtensibilityHelper.php',
|
||||
'Combodo\\iTop\\Portal\\Helper\\LifecycleValidatorHelper' => $baseDir . '/src/Helper/LifecycleValidatorHelper.php',
|
||||
'Combodo\\iTop\\Portal\\Helper\\NavigationRuleHelper' => $baseDir . '/src/Helper/NavigationRuleHelper.php',
|
||||
'Combodo\\iTop\\Portal\\Helper\\ObjectFormHandlerHelper' => $baseDir . '/src/Helper/ObjectFormHandlerHelper.php',
|
||||
'Combodo\\iTop\\Portal\\Helper\\RequestManipulatorHelper' => $baseDir . '/src/Helper/RequestManipulatorHelper.php',
|
||||
'Combodo\\iTop\\Portal\\Helper\\ScopeValidatorHelper' => $baseDir . '/src/Helper/ScopeValidatorHelper.php',
|
||||
'Combodo\\iTop\\Portal\\Helper\\SecurityHelper' => $baseDir . '/src/Helper/SecurityHelper.php',
|
||||
'Combodo\\iTop\\Portal\\Helper\\SessionMessageHelper' => $baseDir . '/src/Helper/SessionMessageHelper.php',
|
||||
'Combodo\\iTop\\Portal\\Helper\\UIExtensionsHelper' => $baseDir . '/src/Helper/UIExtensionsHelper.php',
|
||||
'Combodo\\iTop\\Portal\\Hook\\iAbstractPortalTabContentExtension' => $baseDir . '/src/Hook/iAbstractPortalTabContentExtension.php',
|
||||
'Combodo\\iTop\\Portal\\Hook\\iAbstractPortalTabExtension' => $baseDir . '/src/Hook/iAbstractPortalTabExtension.php',
|
||||
'Combodo\\iTop\\Portal\\Hook\\iUserProfileTabContentExtension' => $baseDir . '/src/Hook/iUserProfileTabContentExtension.php',
|
||||
'Combodo\\iTop\\Portal\\Hook\\iUserProfileTabExtension' => $baseDir . '/src/Hook/iUserProfileTabExtension.php',
|
||||
'Combodo\\iTop\\Portal\\Kernel' => $baseDir . '/src/Kernel.php',
|
||||
'Combodo\\iTop\\Portal\\Routing\\ItopExtensionsExtraRoutes' => $baseDir . '/src/Routing/ItopExtensionsExtraRoutes.php',
|
||||
'Combodo\\iTop\\Portal\\Routing\\UrlGenerator' => $baseDir . '/src/Routing/UrlGenerator.php',
|
||||
'Combodo\\iTop\\Portal\\Twig\\AppExtension' => $baseDir . '/src/Twig/AppExtension.php',
|
||||
'Combodo\\iTop\\Portal\\Twig\\AppGlobal' => $baseDir . '/src/Twig/AppGlobal.php',
|
||||
'Combodo\\iTop\\Portal\\Twig\\AppVariable' => $baseDir . '/src/Twig/AppVariable.php',
|
||||
'Combodo\\iTop\\Portal\\Twig\\CKEditorExtension' => $baseDir . '/src/Twig/CKEditorExtension.php',
|
||||
'Combodo\\iTop\\Portal\\Twig\\CurrentUserAccessor' => $baseDir . '/src/Twig/CurrentUserAccessor.php',
|
||||
'Combodo\\iTop\\Portal\\Twig\\PortalBlockExtension' => $baseDir . '/src/Twig/PortalBlockExtension.php',
|
||||
'Combodo\\iTop\\Portal\\Twig\\PortalTwigContext' => $baseDir . '/src/Twig/PortalTwigContext.php',
|
||||
'Combodo\\iTop\\Portal\\UrlMaker\\AbstractPortalUrlMaker' => $baseDir . '/src/UrlMaker/AbstractPortalUrlMaker.php',
|
||||
'Combodo\\iTop\\Portal\\VariableAccessor\\AbstractStringVariableAccessor' => $baseDir . '/src/VariableAccessor/AbstractStringVariableAccessor.php',
|
||||
'Combodo\\iTop\\Portal\\VariableAccessor\\AbstractVariableAccessor' => $baseDir . '/src/VariableAccessor/AbstractVariableAccessor.php',
|
||||
'Combodo\\iTop\\Portal\\VariableAccessor\\CombodoCurrentContactPhotoUrl' => $baseDir . '/src/VariableAccessor/CombodoCurrentContactPhotoUrl.php',
|
||||
'Combodo\\iTop\\Portal\\VariableAccessor\\CombodoPortalInstanceConf' => $baseDir . '/src/VariableAccessor/CombodoPortalInstanceConf.php',
|
||||
'Composer\\InstalledVersions' => $vendorDir . '/composer/InstalledVersions.php',
|
||||
);
|
||||
|
||||
@@ -29,6 +29,7 @@ class ComposerAutoloaderInitdf408f3f8ea034d298269cdf7647358b
|
||||
require __DIR__ . '/autoload_static.php';
|
||||
call_user_func(\Composer\Autoload\ComposerStaticInitdf408f3f8ea034d298269cdf7647358b::getInitializer($loader));
|
||||
|
||||
$loader->setClassMapAuthoritative(true);
|
||||
$loader->register(true);
|
||||
|
||||
return $loader;
|
||||
|
||||
@@ -26,6 +26,71 @@ class ComposerStaticInitdf408f3f8ea034d298269cdf7647358b
|
||||
);
|
||||
|
||||
public static $classMap = array (
|
||||
'Combodo\\iTop\\Portal\\Brick\\AbstractBrick' => __DIR__ . '/../..' . '/src/Brick/AbstractBrick.php',
|
||||
'Combodo\\iTop\\Portal\\Brick\\AggregatePageBrick' => __DIR__ . '/../..' . '/src/Brick/AggregatePageBrick.php',
|
||||
'Combodo\\iTop\\Portal\\Brick\\BrickCollection' => __DIR__ . '/../..' . '/src/Brick/BrickCollection.php',
|
||||
'Combodo\\iTop\\Portal\\Brick\\BrickNotFoundException' => __DIR__ . '/../..' . '/src/Brick/BrickNotFoundException.php',
|
||||
'Combodo\\iTop\\Portal\\Brick\\BrowseBrick' => __DIR__ . '/../..' . '/src/Brick/BrowseBrick.php',
|
||||
'Combodo\\iTop\\Portal\\Brick\\CreateBrick' => __DIR__ . '/../..' . '/src/Brick/CreateBrick.php',
|
||||
'Combodo\\iTop\\Portal\\Brick\\FilterBrick' => __DIR__ . '/../..' . '/src/Brick/FilterBrick.php',
|
||||
'Combodo\\iTop\\Portal\\Brick\\ManageBrick' => __DIR__ . '/../..' . '/src/Brick/ManageBrick.php',
|
||||
'Combodo\\iTop\\Portal\\Brick\\PortalBrick' => __DIR__ . '/../..' . '/src/Brick/PortalBrick.php',
|
||||
'Combodo\\iTop\\Portal\\Brick\\PropertyNotFoundException' => __DIR__ . '/../..' . '/src/Brick/PropertyNotFoundException.php',
|
||||
'Combodo\\iTop\\Portal\\Brick\\UserProfileBrick' => __DIR__ . '/../..' . '/src/Brick/UserProfileBrick.php',
|
||||
'Combodo\\iTop\\Portal\\Controller\\AbstractController' => __DIR__ . '/../..' . '/src/Controller/AbstractController.php',
|
||||
'Combodo\\iTop\\Portal\\Controller\\AggregatePageBrickController' => __DIR__ . '/../..' . '/src/Controller/AggregatePageBrickController.php',
|
||||
'Combodo\\iTop\\Portal\\Controller\\BrickController' => __DIR__ . '/../..' . '/src/Controller/BrickController.php',
|
||||
'Combodo\\iTop\\Portal\\Controller\\BrowseBrickController' => __DIR__ . '/../..' . '/src/Controller/BrowseBrickController.php',
|
||||
'Combodo\\iTop\\Portal\\Controller\\CreateBrickController' => __DIR__ . '/../..' . '/src/Controller/CreateBrickController.php',
|
||||
'Combodo\\iTop\\Portal\\Controller\\DefaultController' => __DIR__ . '/../..' . '/src/Controller/DefaultController.php',
|
||||
'Combodo\\iTop\\Portal\\Controller\\ManageBrickController' => __DIR__ . '/../..' . '/src/Controller/ManageBrickController.php',
|
||||
'Combodo\\iTop\\Portal\\Controller\\ObjectController' => __DIR__ . '/../..' . '/src/Controller/ObjectController.php',
|
||||
'Combodo\\iTop\\Portal\\Controller\\SessionMessageController' => __DIR__ . '/../..' . '/src/Controller/SessionMessageController.php',
|
||||
'Combodo\\iTop\\Portal\\Controller\\UserProfileBrickController' => __DIR__ . '/../..' . '/src/Controller/UserProfileBrickController.php',
|
||||
'Combodo\\iTop\\Portal\\DependencyInjection\\SilexCompatBootstrap\\PortalXmlConfiguration\\AbstractConfiguration' => __DIR__ . '/../..' . '/src/DependencyInjection/SilexCompatBootstrap/PortalXmlConfiguration/AbstractConfiguration.php',
|
||||
'Combodo\\iTop\\Portal\\DependencyInjection\\SilexCompatBootstrap\\PortalXmlConfiguration\\Basic' => __DIR__ . '/../..' . '/src/DependencyInjection/SilexCompatBootstrap/PortalXmlConfiguration/Basic.php',
|
||||
'Combodo\\iTop\\Portal\\DependencyInjection\\SilexCompatBootstrap\\PortalXmlConfiguration\\Forms' => __DIR__ . '/../..' . '/src/DependencyInjection/SilexCompatBootstrap/PortalXmlConfiguration/Forms.php',
|
||||
'Combodo\\iTop\\Portal\\DependencyInjection\\SilexCompatBootstrap\\PortalXmlConfiguration\\Lists' => __DIR__ . '/../..' . '/src/DependencyInjection/SilexCompatBootstrap/PortalXmlConfiguration/Lists.php',
|
||||
'Combodo\\iTop\\Portal\\EventListener\\ApplicationContextSetPluginPropertyClass' => __DIR__ . '/../..' . '/src/EventListener/ApplicationContextSetPluginPropertyClass.php',
|
||||
'Combodo\\iTop\\Portal\\EventListener\\ApplicationContextSetUrlMakerClass' => __DIR__ . '/../..' . '/src/EventListener/ApplicationContextSetUrlMakerClass.php',
|
||||
'Combodo\\iTop\\Portal\\EventListener\\CssFromSassCompiler' => __DIR__ . '/../..' . '/src/EventListener/CssFromSassCompiler.php',
|
||||
'Combodo\\iTop\\Portal\\EventListener\\ExceptionListener' => __DIR__ . '/../..' . '/src/EventListener/ExceptionListener.php',
|
||||
'Combodo\\iTop\\Portal\\EventListener\\UserProvider' => __DIR__ . '/../..' . '/src/EventListener/UserProvider.php',
|
||||
'Combodo\\iTop\\Portal\\Form\\ObjectFormManager' => __DIR__ . '/../..' . '/src/Form/ObjectFormManager.php',
|
||||
'Combodo\\iTop\\Portal\\Form\\PasswordFormManager' => __DIR__ . '/../..' . '/src/Form/PasswordFormManager.php',
|
||||
'Combodo\\iTop\\Portal\\Form\\PreferencesFormManager' => __DIR__ . '/../..' . '/src/Form/PreferencesFormManager.php',
|
||||
'Combodo\\iTop\\Portal\\Helper\\ApplicationHelper' => __DIR__ . '/../..' . '/src/Helper/ApplicationHelper.php',
|
||||
'Combodo\\iTop\\Portal\\Helper\\BrickControllerHelper' => __DIR__ . '/../..' . '/src/Helper/BrickControllerHelper.php',
|
||||
'Combodo\\iTop\\Portal\\Helper\\BrowseBrickHelper' => __DIR__ . '/../..' . '/src/Helper/BrowseBrickHelper.php',
|
||||
'Combodo\\iTop\\Portal\\Helper\\ContextManipulatorHelper' => __DIR__ . '/../..' . '/src/Helper/ContextManipulatorHelper.php',
|
||||
'Combodo\\iTop\\Portal\\Helper\\ExtensibilityHelper' => __DIR__ . '/../..' . '/src/Helper/ExtensibilityHelper.php',
|
||||
'Combodo\\iTop\\Portal\\Helper\\LifecycleValidatorHelper' => __DIR__ . '/../..' . '/src/Helper/LifecycleValidatorHelper.php',
|
||||
'Combodo\\iTop\\Portal\\Helper\\NavigationRuleHelper' => __DIR__ . '/../..' . '/src/Helper/NavigationRuleHelper.php',
|
||||
'Combodo\\iTop\\Portal\\Helper\\ObjectFormHandlerHelper' => __DIR__ . '/../..' . '/src/Helper/ObjectFormHandlerHelper.php',
|
||||
'Combodo\\iTop\\Portal\\Helper\\RequestManipulatorHelper' => __DIR__ . '/../..' . '/src/Helper/RequestManipulatorHelper.php',
|
||||
'Combodo\\iTop\\Portal\\Helper\\ScopeValidatorHelper' => __DIR__ . '/../..' . '/src/Helper/ScopeValidatorHelper.php',
|
||||
'Combodo\\iTop\\Portal\\Helper\\SecurityHelper' => __DIR__ . '/../..' . '/src/Helper/SecurityHelper.php',
|
||||
'Combodo\\iTop\\Portal\\Helper\\SessionMessageHelper' => __DIR__ . '/../..' . '/src/Helper/SessionMessageHelper.php',
|
||||
'Combodo\\iTop\\Portal\\Helper\\UIExtensionsHelper' => __DIR__ . '/../..' . '/src/Helper/UIExtensionsHelper.php',
|
||||
'Combodo\\iTop\\Portal\\Hook\\iAbstractPortalTabContentExtension' => __DIR__ . '/../..' . '/src/Hook/iAbstractPortalTabContentExtension.php',
|
||||
'Combodo\\iTop\\Portal\\Hook\\iAbstractPortalTabExtension' => __DIR__ . '/../..' . '/src/Hook/iAbstractPortalTabExtension.php',
|
||||
'Combodo\\iTop\\Portal\\Hook\\iUserProfileTabContentExtension' => __DIR__ . '/../..' . '/src/Hook/iUserProfileTabContentExtension.php',
|
||||
'Combodo\\iTop\\Portal\\Hook\\iUserProfileTabExtension' => __DIR__ . '/../..' . '/src/Hook/iUserProfileTabExtension.php',
|
||||
'Combodo\\iTop\\Portal\\Kernel' => __DIR__ . '/../..' . '/src/Kernel.php',
|
||||
'Combodo\\iTop\\Portal\\Routing\\ItopExtensionsExtraRoutes' => __DIR__ . '/../..' . '/src/Routing/ItopExtensionsExtraRoutes.php',
|
||||
'Combodo\\iTop\\Portal\\Routing\\UrlGenerator' => __DIR__ . '/../..' . '/src/Routing/UrlGenerator.php',
|
||||
'Combodo\\iTop\\Portal\\Twig\\AppExtension' => __DIR__ . '/../..' . '/src/Twig/AppExtension.php',
|
||||
'Combodo\\iTop\\Portal\\Twig\\AppGlobal' => __DIR__ . '/../..' . '/src/Twig/AppGlobal.php',
|
||||
'Combodo\\iTop\\Portal\\Twig\\AppVariable' => __DIR__ . '/../..' . '/src/Twig/AppVariable.php',
|
||||
'Combodo\\iTop\\Portal\\Twig\\CKEditorExtension' => __DIR__ . '/../..' . '/src/Twig/CKEditorExtension.php',
|
||||
'Combodo\\iTop\\Portal\\Twig\\CurrentUserAccessor' => __DIR__ . '/../..' . '/src/Twig/CurrentUserAccessor.php',
|
||||
'Combodo\\iTop\\Portal\\Twig\\PortalBlockExtension' => __DIR__ . '/../..' . '/src/Twig/PortalBlockExtension.php',
|
||||
'Combodo\\iTop\\Portal\\Twig\\PortalTwigContext' => __DIR__ . '/../..' . '/src/Twig/PortalTwigContext.php',
|
||||
'Combodo\\iTop\\Portal\\UrlMaker\\AbstractPortalUrlMaker' => __DIR__ . '/../..' . '/src/UrlMaker/AbstractPortalUrlMaker.php',
|
||||
'Combodo\\iTop\\Portal\\VariableAccessor\\AbstractStringVariableAccessor' => __DIR__ . '/../..' . '/src/VariableAccessor/AbstractStringVariableAccessor.php',
|
||||
'Combodo\\iTop\\Portal\\VariableAccessor\\AbstractVariableAccessor' => __DIR__ . '/../..' . '/src/VariableAccessor/AbstractVariableAccessor.php',
|
||||
'Combodo\\iTop\\Portal\\VariableAccessor\\CombodoCurrentContactPhotoUrl' => __DIR__ . '/../..' . '/src/VariableAccessor/CombodoCurrentContactPhotoUrl.php',
|
||||
'Combodo\\iTop\\Portal\\VariableAccessor\\CombodoPortalInstanceConf' => __DIR__ . '/../..' . '/src/VariableAccessor/CombodoPortalInstanceConf.php',
|
||||
'Composer\\InstalledVersions' => __DIR__ . '/..' . '/composer/InstalledVersions.php',
|
||||
);
|
||||
|
||||
|
||||
@@ -1063,7 +1063,7 @@
|
||||
<decoration_class>
|
||||
<default>fc fc-ongoing-request fc-2x</default>
|
||||
</decoration_class>
|
||||
<oql><![CDATA[SELECT Ticket]]></oql>
|
||||
<oql><![CDATA[SELECT Ticket AS T WHERE T.finalclass IN ('UserRequest', 'Incident')]]></oql>
|
||||
<!-- Optional tag to define if the action should be done in a modal window ("modal"), a new window ("new") or the current window ("self") -->
|
||||
<!--<opening_target>modal</opening_target>-->
|
||||
<!-- Optional tag to define the how the objects should be opened. Values can be edit|view. Note that even if this is set to edit, objects not allowed in edition mode for the user (cf. scopes and security layers) will open in view mode -->
|
||||
@@ -1129,7 +1129,7 @@
|
||||
<decoration_class>
|
||||
<default>fc fc-closed-request fc-2x</default>
|
||||
</decoration_class>
|
||||
<oql><![CDATA[SELECT Ticket WHERE operational_status = 'closed']]></oql>
|
||||
<oql><![CDATA[SELECT Ticket WHERE operational_status = 'closed' AND finalclass IN ('UserRequest', 'Incident')]]></oql>
|
||||
<!-- Can be either a class tag with the class name or an oql tag with the query -->
|
||||
<!-- <class>Ticket</class> -->
|
||||
<fields>
|
||||
|
||||
@@ -144,7 +144,7 @@ Les mots-clés sous la forme :this->attcode spécifiant un champ de l\'objet aya
|
||||
- Sinon, si l\'objet déclencheur a une icône de classe définie dans le datamodel, elle sera utilisée
|
||||
- Sinon, le logo compact de l\'application sera utilisé',
|
||||
'Class:ActionNewsroom/Attribute:priority' => 'Priorité',
|
||||
'Class:ActionNewsroom/Attribute:priority+' => 'Les news sont affichés par priorité décroissante.',
|
||||
'Class:ActionNewsroom/Attribute:priority+' => 'Les news sont affichées par priorité décroissante.',
|
||||
'Class:ActionNewsroom/Attribute:priority/Value:1' => 'Critique',
|
||||
'Class:ActionNewsroom/Attribute:priority/Value:1+' => '',
|
||||
'Class:ActionNewsroom/Attribute:priority/Value:2' => 'Urgent',
|
||||
|
||||
@@ -1061,7 +1061,7 @@ Elle s\'applique à tous les objets dans le périmètre de sa catégorie d\'audi
|
||||
'UI:Newsroom:ResetCache' => 'Ràz du cache',
|
||||
'UI:Newsroom:ResetCache:Success:Message' => 'Le cache de la newsroom a été réinitialisé avec succès',
|
||||
'UI:Newsroom:ViewAllMessages' => 'Voir tous les messages',
|
||||
'UI:Newsroom:XNewMessage' => '%1$s new message(s)~~',
|
||||
'UI:Newsroom:XNewMessage' => '%1$s nouveau(x) message(s)',
|
||||
'UI:NoInlineImage' => 'Il n\'y a aucune image de disponible sur le serveur. Utilisez le bouton "Parcourir" (ci-dessus) pour sélectionner une image sur votre ordinateur et la télécharger sur le serveur.',
|
||||
'UI:NoObjectToDisplay' => 'Aucun objet à afficher.',
|
||||
'UI:NoObject_Class_ToDisplay' => 'Aucun objet %1$s à afficher',
|
||||
|
||||
@@ -1778,6 +1778,16 @@ return array(
|
||||
'Symfony\\Bundle\\FrameworkBundle\\Secrets\\AbstractVault' => $vendorDir . '/symfony/framework-bundle/Secrets/AbstractVault.php',
|
||||
'Symfony\\Bundle\\FrameworkBundle\\Secrets\\DotenvVault' => $vendorDir . '/symfony/framework-bundle/Secrets/DotenvVault.php',
|
||||
'Symfony\\Bundle\\FrameworkBundle\\Secrets\\SodiumVault' => $vendorDir . '/symfony/framework-bundle/Secrets/SodiumVault.php',
|
||||
'Symfony\\Bundle\\FrameworkBundle\\Test\\BrowserKitAssertionsTrait' => $vendorDir . '/symfony/framework-bundle/Test/BrowserKitAssertionsTrait.php',
|
||||
'Symfony\\Bundle\\FrameworkBundle\\Test\\DomCrawlerAssertionsTrait' => $vendorDir . '/symfony/framework-bundle/Test/DomCrawlerAssertionsTrait.php',
|
||||
'Symfony\\Bundle\\FrameworkBundle\\Test\\HttpClientAssertionsTrait' => $vendorDir . '/symfony/framework-bundle/Test/HttpClientAssertionsTrait.php',
|
||||
'Symfony\\Bundle\\FrameworkBundle\\Test\\KernelTestCase' => $vendorDir . '/symfony/framework-bundle/Test/KernelTestCase.php',
|
||||
'Symfony\\Bundle\\FrameworkBundle\\Test\\MailerAssertionsTrait' => $vendorDir . '/symfony/framework-bundle/Test/MailerAssertionsTrait.php',
|
||||
'Symfony\\Bundle\\FrameworkBundle\\Test\\NotificationAssertionsTrait' => $vendorDir . '/symfony/framework-bundle/Test/NotificationAssertionsTrait.php',
|
||||
'Symfony\\Bundle\\FrameworkBundle\\Test\\TestBrowserToken' => $vendorDir . '/symfony/framework-bundle/Test/TestBrowserToken.php',
|
||||
'Symfony\\Bundle\\FrameworkBundle\\Test\\TestContainer' => $vendorDir . '/symfony/framework-bundle/Test/TestContainer.php',
|
||||
'Symfony\\Bundle\\FrameworkBundle\\Test\\WebTestAssertionsTrait' => $vendorDir . '/symfony/framework-bundle/Test/WebTestAssertionsTrait.php',
|
||||
'Symfony\\Bundle\\FrameworkBundle\\Test\\WebTestCase' => $vendorDir . '/symfony/framework-bundle/Test/WebTestCase.php',
|
||||
'Symfony\\Bundle\\FrameworkBundle\\Translation\\Translator' => $vendorDir . '/symfony/framework-bundle/Translation/Translator.php',
|
||||
'Symfony\\Bundle\\TwigBundle\\CacheWarmer\\TemplateCacheWarmer' => $vendorDir . '/symfony/twig-bundle/CacheWarmer/TemplateCacheWarmer.php',
|
||||
'Symfony\\Bundle\\TwigBundle\\Command\\LintCommand' => $vendorDir . '/symfony/twig-bundle/Command/LintCommand.php',
|
||||
|
||||
@@ -2158,6 +2158,16 @@ class ComposerStaticInit7f81b4a2a468a061c306af5e447a9a9f
|
||||
'Symfony\\Bundle\\FrameworkBundle\\Secrets\\AbstractVault' => __DIR__ . '/..' . '/symfony/framework-bundle/Secrets/AbstractVault.php',
|
||||
'Symfony\\Bundle\\FrameworkBundle\\Secrets\\DotenvVault' => __DIR__ . '/..' . '/symfony/framework-bundle/Secrets/DotenvVault.php',
|
||||
'Symfony\\Bundle\\FrameworkBundle\\Secrets\\SodiumVault' => __DIR__ . '/..' . '/symfony/framework-bundle/Secrets/SodiumVault.php',
|
||||
'Symfony\\Bundle\\FrameworkBundle\\Test\\BrowserKitAssertionsTrait' => __DIR__ . '/..' . '/symfony/framework-bundle/Test/BrowserKitAssertionsTrait.php',
|
||||
'Symfony\\Bundle\\FrameworkBundle\\Test\\DomCrawlerAssertionsTrait' => __DIR__ . '/..' . '/symfony/framework-bundle/Test/DomCrawlerAssertionsTrait.php',
|
||||
'Symfony\\Bundle\\FrameworkBundle\\Test\\HttpClientAssertionsTrait' => __DIR__ . '/..' . '/symfony/framework-bundle/Test/HttpClientAssertionsTrait.php',
|
||||
'Symfony\\Bundle\\FrameworkBundle\\Test\\KernelTestCase' => __DIR__ . '/..' . '/symfony/framework-bundle/Test/KernelTestCase.php',
|
||||
'Symfony\\Bundle\\FrameworkBundle\\Test\\MailerAssertionsTrait' => __DIR__ . '/..' . '/symfony/framework-bundle/Test/MailerAssertionsTrait.php',
|
||||
'Symfony\\Bundle\\FrameworkBundle\\Test\\NotificationAssertionsTrait' => __DIR__ . '/..' . '/symfony/framework-bundle/Test/NotificationAssertionsTrait.php',
|
||||
'Symfony\\Bundle\\FrameworkBundle\\Test\\TestBrowserToken' => __DIR__ . '/..' . '/symfony/framework-bundle/Test/TestBrowserToken.php',
|
||||
'Symfony\\Bundle\\FrameworkBundle\\Test\\TestContainer' => __DIR__ . '/..' . '/symfony/framework-bundle/Test/TestContainer.php',
|
||||
'Symfony\\Bundle\\FrameworkBundle\\Test\\WebTestAssertionsTrait' => __DIR__ . '/..' . '/symfony/framework-bundle/Test/WebTestAssertionsTrait.php',
|
||||
'Symfony\\Bundle\\FrameworkBundle\\Test\\WebTestCase' => __DIR__ . '/..' . '/symfony/framework-bundle/Test/WebTestCase.php',
|
||||
'Symfony\\Bundle\\FrameworkBundle\\Translation\\Translator' => __DIR__ . '/..' . '/symfony/framework-bundle/Translation/Translator.php',
|
||||
'Symfony\\Bundle\\TwigBundle\\CacheWarmer\\TemplateCacheWarmer' => __DIR__ . '/..' . '/symfony/twig-bundle/CacheWarmer/TemplateCacheWarmer.php',
|
||||
'Symfony\\Bundle\\TwigBundle\\Command\\LintCommand' => __DIR__ . '/..' . '/symfony/twig-bundle/Command/LintCommand.php',
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
'name' => 'combodo/itop',
|
||||
'pretty_version' => 'dev-develop',
|
||||
'version' => 'dev-develop',
|
||||
'reference' => 'd53d4970f40cbc0a8c5cd6e1d5cc3ca06ac4719e',
|
||||
'reference' => '5ae2fdee94b925808451355b98b941351e0b4fcd',
|
||||
'type' => 'project',
|
||||
'install_path' => __DIR__ . '/../../',
|
||||
'aliases' => array(),
|
||||
@@ -22,7 +22,7 @@
|
||||
'combodo/itop' => array(
|
||||
'pretty_version' => 'dev-develop',
|
||||
'version' => 'dev-develop',
|
||||
'reference' => 'd53d4970f40cbc0a8c5cd6e1d5cc3ca06ac4719e',
|
||||
'reference' => '5ae2fdee94b925808451355b98b941351e0b4fcd',
|
||||
'type' => 'project',
|
||||
'install_path' => __DIR__ . '/../../',
|
||||
'aliases' => array(),
|
||||
|
||||
197
lib/symfony/framework-bundle/Test/BrowserKitAssertionsTrait.php
Normal file
197
lib/symfony/framework-bundle/Test/BrowserKitAssertionsTrait.php
Normal file
@@ -0,0 +1,197 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Bundle\FrameworkBundle\Test;
|
||||
|
||||
use PHPUnit\Framework\Constraint\Constraint;
|
||||
use PHPUnit\Framework\Constraint\LogicalAnd;
|
||||
use PHPUnit\Framework\Constraint\LogicalNot;
|
||||
use PHPUnit\Framework\ExpectationFailedException;
|
||||
use Symfony\Component\BrowserKit\AbstractBrowser;
|
||||
use Symfony\Component\BrowserKit\Test\Constraint as BrowserKitConstraint;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
use Symfony\Component\HttpFoundation\Response;
|
||||
use Symfony\Component\HttpFoundation\Test\Constraint as ResponseConstraint;
|
||||
|
||||
/**
|
||||
* Ideas borrowed from Laravel Dusk's assertions.
|
||||
*
|
||||
* @see https://laravel.com/docs/5.7/dusk#available-assertions
|
||||
*/
|
||||
trait BrowserKitAssertionsTrait
|
||||
{
|
||||
public static function assertResponseIsSuccessful(string $message = ''): void
|
||||
{
|
||||
self::assertThatForResponse(new ResponseConstraint\ResponseIsSuccessful(), $message);
|
||||
}
|
||||
|
||||
public static function assertResponseStatusCodeSame(int $expectedCode, string $message = ''): void
|
||||
{
|
||||
self::assertThatForResponse(new ResponseConstraint\ResponseStatusCodeSame($expectedCode), $message);
|
||||
}
|
||||
|
||||
public static function assertResponseFormatSame(?string $expectedFormat, string $message = ''): void
|
||||
{
|
||||
self::assertThatForResponse(new ResponseConstraint\ResponseFormatSame(self::getRequest(), $expectedFormat), $message);
|
||||
}
|
||||
|
||||
public static function assertResponseRedirects(string $expectedLocation = null, int $expectedCode = null, string $message = ''): void
|
||||
{
|
||||
$constraint = new ResponseConstraint\ResponseIsRedirected();
|
||||
if ($expectedLocation) {
|
||||
if (class_exists(ResponseConstraint\ResponseHeaderLocationSame::class)) {
|
||||
$locationConstraint = new ResponseConstraint\ResponseHeaderLocationSame(self::getRequest(), $expectedLocation);
|
||||
} else {
|
||||
$locationConstraint = new ResponseConstraint\ResponseHeaderSame('Location', $expectedLocation);
|
||||
}
|
||||
|
||||
$constraint = LogicalAnd::fromConstraints($constraint, $locationConstraint);
|
||||
}
|
||||
if ($expectedCode) {
|
||||
$constraint = LogicalAnd::fromConstraints($constraint, new ResponseConstraint\ResponseStatusCodeSame($expectedCode));
|
||||
}
|
||||
|
||||
self::assertThatForResponse($constraint, $message);
|
||||
}
|
||||
|
||||
public static function assertResponseHasHeader(string $headerName, string $message = ''): void
|
||||
{
|
||||
self::assertThatForResponse(new ResponseConstraint\ResponseHasHeader($headerName), $message);
|
||||
}
|
||||
|
||||
public static function assertResponseNotHasHeader(string $headerName, string $message = ''): void
|
||||
{
|
||||
self::assertThatForResponse(new LogicalNot(new ResponseConstraint\ResponseHasHeader($headerName)), $message);
|
||||
}
|
||||
|
||||
public static function assertResponseHeaderSame(string $headerName, string $expectedValue, string $message = ''): void
|
||||
{
|
||||
self::assertThatForResponse(new ResponseConstraint\ResponseHeaderSame($headerName, $expectedValue), $message);
|
||||
}
|
||||
|
||||
public static function assertResponseHeaderNotSame(string $headerName, string $expectedValue, string $message = ''): void
|
||||
{
|
||||
self::assertThatForResponse(new LogicalNot(new ResponseConstraint\ResponseHeaderSame($headerName, $expectedValue)), $message);
|
||||
}
|
||||
|
||||
public static function assertResponseHasCookie(string $name, string $path = '/', string $domain = null, string $message = ''): void
|
||||
{
|
||||
self::assertThatForResponse(new ResponseConstraint\ResponseHasCookie($name, $path, $domain), $message);
|
||||
}
|
||||
|
||||
public static function assertResponseNotHasCookie(string $name, string $path = '/', string $domain = null, string $message = ''): void
|
||||
{
|
||||
self::assertThatForResponse(new LogicalNot(new ResponseConstraint\ResponseHasCookie($name, $path, $domain)), $message);
|
||||
}
|
||||
|
||||
public static function assertResponseCookieValueSame(string $name, string $expectedValue, string $path = '/', string $domain = null, string $message = ''): void
|
||||
{
|
||||
self::assertThatForResponse(LogicalAnd::fromConstraints(
|
||||
new ResponseConstraint\ResponseHasCookie($name, $path, $domain),
|
||||
new ResponseConstraint\ResponseCookieValueSame($name, $expectedValue, $path, $domain)
|
||||
), $message);
|
||||
}
|
||||
|
||||
public static function assertResponseIsUnprocessable(string $message = ''): void
|
||||
{
|
||||
self::assertThatForResponse(new ResponseConstraint\ResponseIsUnprocessable(), $message);
|
||||
}
|
||||
|
||||
public static function assertBrowserHasCookie(string $name, string $path = '/', string $domain = null, string $message = ''): void
|
||||
{
|
||||
self::assertThatForClient(new BrowserKitConstraint\BrowserHasCookie($name, $path, $domain), $message);
|
||||
}
|
||||
|
||||
public static function assertBrowserNotHasCookie(string $name, string $path = '/', string $domain = null, string $message = ''): void
|
||||
{
|
||||
self::assertThatForClient(new LogicalNot(new BrowserKitConstraint\BrowserHasCookie($name, $path, $domain)), $message);
|
||||
}
|
||||
|
||||
public static function assertBrowserCookieValueSame(string $name, string $expectedValue, bool $raw = false, string $path = '/', string $domain = null, string $message = ''): void
|
||||
{
|
||||
self::assertThatForClient(LogicalAnd::fromConstraints(
|
||||
new BrowserKitConstraint\BrowserHasCookie($name, $path, $domain),
|
||||
new BrowserKitConstraint\BrowserCookieValueSame($name, $expectedValue, $raw, $path, $domain)
|
||||
), $message);
|
||||
}
|
||||
|
||||
public static function assertRequestAttributeValueSame(string $name, string $expectedValue, string $message = ''): void
|
||||
{
|
||||
self::assertThat(self::getRequest(), new ResponseConstraint\RequestAttributeValueSame($name, $expectedValue), $message);
|
||||
}
|
||||
|
||||
public static function assertRouteSame(string $expectedRoute, array $parameters = [], string $message = ''): void
|
||||
{
|
||||
$constraint = new ResponseConstraint\RequestAttributeValueSame('_route', $expectedRoute);
|
||||
$constraints = [];
|
||||
foreach ($parameters as $key => $value) {
|
||||
$constraints[] = new ResponseConstraint\RequestAttributeValueSame($key, $value);
|
||||
}
|
||||
if ($constraints) {
|
||||
$constraint = LogicalAnd::fromConstraints($constraint, ...$constraints);
|
||||
}
|
||||
|
||||
self::assertThat(self::getRequest(), $constraint, $message);
|
||||
}
|
||||
|
||||
public static function assertThatForResponse(Constraint $constraint, string $message = ''): void
|
||||
{
|
||||
try {
|
||||
self::assertThat(self::getResponse(), $constraint, $message);
|
||||
} catch (ExpectationFailedException $exception) {
|
||||
if (($serverExceptionMessage = self::getResponse()->headers->get('X-Debug-Exception'))
|
||||
&& ($serverExceptionFile = self::getResponse()->headers->get('X-Debug-Exception-File'))) {
|
||||
$serverExceptionFile = explode(':', $serverExceptionFile);
|
||||
$exception->__construct($exception->getMessage(), $exception->getComparisonFailure(), new \ErrorException(rawurldecode($serverExceptionMessage), 0, 1, rawurldecode($serverExceptionFile[0]), $serverExceptionFile[1]), $exception->getPrevious());
|
||||
}
|
||||
|
||||
throw $exception;
|
||||
}
|
||||
}
|
||||
|
||||
public static function assertThatForClient(Constraint $constraint, string $message = ''): void
|
||||
{
|
||||
self::assertThat(self::getClient(), $constraint, $message);
|
||||
}
|
||||
|
||||
protected static function getClient(AbstractBrowser $newClient = null): ?AbstractBrowser
|
||||
{
|
||||
static $client;
|
||||
|
||||
if (0 < \func_num_args()) {
|
||||
return $client = $newClient;
|
||||
}
|
||||
|
||||
if (!$client instanceof AbstractBrowser) {
|
||||
static::fail(sprintf('A client must be set to make assertions on it. Did you forget to call "%s::createClient()"?', __CLASS__));
|
||||
}
|
||||
|
||||
return $client;
|
||||
}
|
||||
|
||||
private static function getResponse(): Response
|
||||
{
|
||||
if (!$response = self::getClient()->getResponse()) {
|
||||
static::fail('A client must have an HTTP Response to make assertions. Did you forget to make an HTTP request?');
|
||||
}
|
||||
|
||||
return $response;
|
||||
}
|
||||
|
||||
private static function getRequest(): Request
|
||||
{
|
||||
if (!$request = self::getClient()->getRequest()) {
|
||||
static::fail('A client must have an HTTP Request to make assertions. Did you forget to make an HTTP request?');
|
||||
}
|
||||
|
||||
return $request;
|
||||
}
|
||||
}
|
||||
151
lib/symfony/framework-bundle/Test/DomCrawlerAssertionsTrait.php
Normal file
151
lib/symfony/framework-bundle/Test/DomCrawlerAssertionsTrait.php
Normal file
@@ -0,0 +1,151 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Bundle\FrameworkBundle\Test;
|
||||
|
||||
use PHPUnit\Framework\Constraint\LogicalAnd;
|
||||
use PHPUnit\Framework\Constraint\LogicalNot;
|
||||
use Symfony\Component\DomCrawler\Crawler;
|
||||
use Symfony\Component\DomCrawler\Test\Constraint as DomCrawlerConstraint;
|
||||
use Symfony\Component\DomCrawler\Test\Constraint\CrawlerSelectorExists;
|
||||
|
||||
/**
|
||||
* Ideas borrowed from Laravel Dusk's assertions.
|
||||
*
|
||||
* @see https://laravel.com/docs/5.7/dusk#available-assertions
|
||||
*/
|
||||
trait DomCrawlerAssertionsTrait
|
||||
{
|
||||
public static function assertSelectorExists(string $selector, string $message = ''): void
|
||||
{
|
||||
self::assertThat(self::getCrawler(), new DomCrawlerConstraint\CrawlerSelectorExists($selector), $message);
|
||||
}
|
||||
|
||||
public static function assertSelectorNotExists(string $selector, string $message = ''): void
|
||||
{
|
||||
self::assertThat(self::getCrawler(), new LogicalNot(new DomCrawlerConstraint\CrawlerSelectorExists($selector)), $message);
|
||||
}
|
||||
|
||||
public static function assertSelectorCount(int $expectedCount, string $selector, string $message = ''): void
|
||||
{
|
||||
self::assertThat(self::getCrawler(), new DomCrawlerConstraint\CrawlerSelectorCount($expectedCount, $selector), $message);
|
||||
}
|
||||
|
||||
public static function assertSelectorTextContains(string $selector, string $text, string $message = ''): void
|
||||
{
|
||||
self::assertThat(self::getCrawler(), LogicalAnd::fromConstraints(
|
||||
new DomCrawlerConstraint\CrawlerSelectorExists($selector),
|
||||
new DomCrawlerConstraint\CrawlerSelectorTextContains($selector, $text)
|
||||
), $message);
|
||||
}
|
||||
|
||||
public static function assertAnySelectorTextContains(string $selector, string $text, string $message = ''): void
|
||||
{
|
||||
self::assertThat(self::getCrawler(), LogicalAnd::fromConstraints(
|
||||
new DomCrawlerConstraint\CrawlerSelectorExists($selector),
|
||||
new DomCrawlerConstraint\CrawlerAnySelectorTextContains($selector, $text)
|
||||
), $message);
|
||||
}
|
||||
|
||||
public static function assertSelectorTextSame(string $selector, string $text, string $message = ''): void
|
||||
{
|
||||
self::assertThat(self::getCrawler(), LogicalAnd::fromConstraints(
|
||||
new DomCrawlerConstraint\CrawlerSelectorExists($selector),
|
||||
new DomCrawlerConstraint\CrawlerSelectorTextSame($selector, $text)
|
||||
), $message);
|
||||
}
|
||||
|
||||
public static function assertAnySelectorTextSame(string $selector, string $text, string $message = ''): void
|
||||
{
|
||||
self::assertThat(self::getCrawler(), LogicalAnd::fromConstraints(
|
||||
new DomCrawlerConstraint\CrawlerSelectorExists($selector),
|
||||
new DomCrawlerConstraint\CrawlerAnySelectorTextSame($selector, $text)
|
||||
), $message);
|
||||
}
|
||||
|
||||
public static function assertSelectorTextNotContains(string $selector, string $text, string $message = ''): void
|
||||
{
|
||||
self::assertThat(self::getCrawler(), LogicalAnd::fromConstraints(
|
||||
new DomCrawlerConstraint\CrawlerSelectorExists($selector),
|
||||
new LogicalNot(new DomCrawlerConstraint\CrawlerSelectorTextContains($selector, $text))
|
||||
), $message);
|
||||
}
|
||||
|
||||
public static function assertAnySelectorTextNotContains(string $selector, string $text, string $message = ''): void
|
||||
{
|
||||
self::assertThat(self::getCrawler(), LogicalAnd::fromConstraints(
|
||||
new DomCrawlerConstraint\CrawlerSelectorExists($selector),
|
||||
new LogicalNot(new DomCrawlerConstraint\CrawlerAnySelectorTextContains($selector, $text))
|
||||
), $message);
|
||||
}
|
||||
|
||||
public static function assertPageTitleSame(string $expectedTitle, string $message = ''): void
|
||||
{
|
||||
self::assertSelectorTextSame('title', $expectedTitle, $message);
|
||||
}
|
||||
|
||||
public static function assertPageTitleContains(string $expectedTitle, string $message = ''): void
|
||||
{
|
||||
self::assertSelectorTextContains('title', $expectedTitle, $message);
|
||||
}
|
||||
|
||||
public static function assertInputValueSame(string $fieldName, string $expectedValue, string $message = ''): void
|
||||
{
|
||||
self::assertThat(self::getCrawler(), LogicalAnd::fromConstraints(
|
||||
new DomCrawlerConstraint\CrawlerSelectorExists("input[name=\"$fieldName\"]"),
|
||||
new DomCrawlerConstraint\CrawlerSelectorAttributeValueSame("input[name=\"$fieldName\"]", 'value', $expectedValue)
|
||||
), $message);
|
||||
}
|
||||
|
||||
public static function assertInputValueNotSame(string $fieldName, string $expectedValue, string $message = ''): void
|
||||
{
|
||||
self::assertThat(self::getCrawler(), LogicalAnd::fromConstraints(
|
||||
new DomCrawlerConstraint\CrawlerSelectorExists("input[name=\"$fieldName\"]"),
|
||||
new LogicalNot(new DomCrawlerConstraint\CrawlerSelectorAttributeValueSame("input[name=\"$fieldName\"]", 'value', $expectedValue))
|
||||
), $message);
|
||||
}
|
||||
|
||||
public static function assertCheckboxChecked(string $fieldName, string $message = ''): void
|
||||
{
|
||||
self::assertThat(self::getCrawler(), new CrawlerSelectorExists("input[name=\"$fieldName\"]:checked"), $message);
|
||||
}
|
||||
|
||||
public static function assertCheckboxNotChecked(string $fieldName, string $message = ''): void
|
||||
{
|
||||
self::assertThat(self::getCrawler(), new LogicalNot(new CrawlerSelectorExists("input[name=\"$fieldName\"]:checked")), $message);
|
||||
}
|
||||
|
||||
public static function assertFormValue(string $formSelector, string $fieldName, string $value, string $message = ''): void
|
||||
{
|
||||
$node = self::getCrawler()->filter($formSelector);
|
||||
self::assertNotEmpty($node, sprintf('Form "%s" not found.', $formSelector));
|
||||
$values = $node->form()->getValues();
|
||||
self::assertArrayHasKey($fieldName, $values, $message ?: sprintf('Field "%s" not found in form "%s".', $fieldName, $formSelector));
|
||||
self::assertSame($value, $values[$fieldName]);
|
||||
}
|
||||
|
||||
public static function assertNoFormValue(string $formSelector, string $fieldName, string $message = ''): void
|
||||
{
|
||||
$node = self::getCrawler()->filter($formSelector);
|
||||
self::assertNotEmpty($node, sprintf('Form "%s" not found.', $formSelector));
|
||||
$values = $node->form()->getValues();
|
||||
self::assertArrayNotHasKey($fieldName, $values, $message ?: sprintf('Field "%s" has a value in form "%s".', $fieldName, $formSelector));
|
||||
}
|
||||
|
||||
private static function getCrawler(): Crawler
|
||||
{
|
||||
if (!$crawler = self::getClient()->getCrawler()) {
|
||||
static::fail('A client must have a crawler to make assertions. Did you forget to make an HTTP request?');
|
||||
}
|
||||
|
||||
return $crawler;
|
||||
}
|
||||
}
|
||||
134
lib/symfony/framework-bundle/Test/HttpClientAssertionsTrait.php
Normal file
134
lib/symfony/framework-bundle/Test/HttpClientAssertionsTrait.php
Normal file
@@ -0,0 +1,134 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Bundle\FrameworkBundle\Test;
|
||||
|
||||
use Symfony\Bundle\FrameworkBundle\KernelBrowser;
|
||||
use Symfony\Component\HttpClient\DataCollector\HttpClientDataCollector;
|
||||
|
||||
/*
|
||||
* @author Mathieu Santostefano <msantostefano@protonmail.com>
|
||||
*/
|
||||
|
||||
trait HttpClientAssertionsTrait
|
||||
{
|
||||
public static function assertHttpClientRequest(string $expectedUrl, string $expectedMethod = 'GET', string|array $expectedBody = null, array $expectedHeaders = [], string $httpClientId = 'http_client'): void
|
||||
{
|
||||
/** @var KernelBrowser $client */
|
||||
$client = static::getClient();
|
||||
|
||||
if (!($profile = $client->getProfile())) {
|
||||
static::fail('The Profiler must be enabled for the current request. Please ensure to call "$client->enableProfiler()" before making the request.');
|
||||
}
|
||||
|
||||
/** @var HttpClientDataCollector $httpClientDataCollector */
|
||||
$httpClientDataCollector = $profile->getCollector('http_client');
|
||||
$expectedRequestHasBeenFound = false;
|
||||
|
||||
if (!\array_key_exists($httpClientId, $httpClientDataCollector->getClients())) {
|
||||
static::fail(sprintf('HttpClient "%s" is not registered.', $httpClientId));
|
||||
}
|
||||
|
||||
foreach ($httpClientDataCollector->getClients()[$httpClientId]['traces'] as $trace) {
|
||||
if (($expectedUrl !== $trace['info']['url'] && $expectedUrl !== $trace['url'])
|
||||
|| $expectedMethod !== $trace['method']
|
||||
) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (null !== $expectedBody) {
|
||||
$actualBody = null;
|
||||
|
||||
if (null !== $trace['options']['body'] && null === $trace['options']['json']) {
|
||||
$actualBody = \is_string($trace['options']['body']) ? $trace['options']['body'] : $trace['options']['body']->getValue(true);
|
||||
}
|
||||
|
||||
if (null === $trace['options']['body'] && null !== $trace['options']['json']) {
|
||||
$actualBody = $trace['options']['json']->getValue(true);
|
||||
}
|
||||
|
||||
if (!$actualBody) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if ($expectedBody === $actualBody) {
|
||||
$expectedRequestHasBeenFound = true;
|
||||
|
||||
if (!$expectedHeaders) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ($expectedHeaders) {
|
||||
$actualHeaders = $trace['options']['headers'] ?? [];
|
||||
|
||||
foreach ($actualHeaders as $headerKey => $actualHeader) {
|
||||
if (\array_key_exists($headerKey, $expectedHeaders)
|
||||
&& $expectedHeaders[$headerKey] === $actualHeader->getValue(true)
|
||||
) {
|
||||
$expectedRequestHasBeenFound = true;
|
||||
break 2;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$expectedRequestHasBeenFound = true;
|
||||
break;
|
||||
}
|
||||
|
||||
self::assertTrue($expectedRequestHasBeenFound, 'The expected request has not been called: "'.$expectedMethod.'" - "'.$expectedUrl.'"');
|
||||
}
|
||||
|
||||
public function assertNotHttpClientRequest(string $unexpectedUrl, string $expectedMethod = 'GET', string $httpClientId = 'http_client'): void
|
||||
{
|
||||
/** @var KernelBrowser $client */
|
||||
$client = static::getClient();
|
||||
|
||||
if (!$profile = $client->getProfile()) {
|
||||
static::fail('The Profiler must be enabled for the current request. Please ensure to call "$client->enableProfiler()" before making the request.');
|
||||
}
|
||||
|
||||
/** @var HttpClientDataCollector $httpClientDataCollector */
|
||||
$httpClientDataCollector = $profile->getCollector('http_client');
|
||||
$unexpectedUrlHasBeenFound = false;
|
||||
|
||||
if (!\array_key_exists($httpClientId, $httpClientDataCollector->getClients())) {
|
||||
static::fail(sprintf('HttpClient "%s" is not registered.', $httpClientId));
|
||||
}
|
||||
|
||||
foreach ($httpClientDataCollector->getClients()[$httpClientId]['traces'] as $trace) {
|
||||
if (($unexpectedUrl === $trace['info']['url'] || $unexpectedUrl === $trace['url'])
|
||||
&& $expectedMethod === $trace['method']
|
||||
) {
|
||||
$unexpectedUrlHasBeenFound = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
self::assertFalse($unexpectedUrlHasBeenFound, sprintf('Unexpected URL called: "%s" - "%s"', $expectedMethod, $unexpectedUrl));
|
||||
}
|
||||
|
||||
public static function assertHttpClientRequestCount(int $count, string $httpClientId = 'http_client'): void
|
||||
{
|
||||
/** @var KernelBrowser $client */
|
||||
$client = static::getClient();
|
||||
|
||||
if (!($profile = $client->getProfile())) {
|
||||
static::fail('The Profiler must be enabled for the current request. Please ensure to call "$client->enableProfiler()" before making the request.');
|
||||
}
|
||||
|
||||
/** @var HttpClientDataCollector $httpClientDataCollector */
|
||||
$httpClientDataCollector = $profile->getCollector('http_client');
|
||||
|
||||
self::assertCount($count, $httpClientDataCollector->getClients()[$httpClientId]['traces']);
|
||||
}
|
||||
}
|
||||
137
lib/symfony/framework-bundle/Test/KernelTestCase.php
Normal file
137
lib/symfony/framework-bundle/Test/KernelTestCase.php
Normal file
@@ -0,0 +1,137 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Bundle\FrameworkBundle\Test;
|
||||
|
||||
use PHPUnit\Framework\TestCase;
|
||||
use Symfony\Component\DependencyInjection\Container;
|
||||
use Symfony\Component\DependencyInjection\ContainerInterface;
|
||||
use Symfony\Component\DependencyInjection\Exception\ServiceNotFoundException;
|
||||
use Symfony\Component\HttpKernel\KernelInterface;
|
||||
use Symfony\Contracts\Service\ResetInterface;
|
||||
|
||||
/**
|
||||
* KernelTestCase is the base class for tests needing a Kernel.
|
||||
*
|
||||
* @author Fabien Potencier <fabien@symfony.com>
|
||||
*/
|
||||
abstract class KernelTestCase extends TestCase
|
||||
{
|
||||
use MailerAssertionsTrait;
|
||||
use NotificationAssertionsTrait;
|
||||
|
||||
protected static $class;
|
||||
|
||||
/**
|
||||
* @var KernelInterface
|
||||
*/
|
||||
protected static $kernel;
|
||||
|
||||
protected static $booted = false;
|
||||
|
||||
protected function tearDown(): void
|
||||
{
|
||||
static::ensureKernelShutdown();
|
||||
static::$class = null;
|
||||
static::$kernel = null;
|
||||
static::$booted = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws \RuntimeException
|
||||
* @throws \LogicException
|
||||
*/
|
||||
protected static function getKernelClass(): string
|
||||
{
|
||||
if (!isset($_SERVER['KERNEL_CLASS']) && !isset($_ENV['KERNEL_CLASS'])) {
|
||||
throw new \LogicException(sprintf('You must set the KERNEL_CLASS environment variable to the fully-qualified class name of your Kernel in phpunit.xml / phpunit.xml.dist or override the "%1$s::createKernel()" or "%1$s::getKernelClass()" method.', static::class));
|
||||
}
|
||||
|
||||
if (!class_exists($class = $_ENV['KERNEL_CLASS'] ?? $_SERVER['KERNEL_CLASS'])) {
|
||||
throw new \RuntimeException(sprintf('Class "%s" doesn\'t exist or cannot be autoloaded. Check that the KERNEL_CLASS value in phpunit.xml matches the fully-qualified class name of your Kernel or override the "%s::createKernel()" method.', $class, static::class));
|
||||
}
|
||||
|
||||
return $class;
|
||||
}
|
||||
|
||||
/**
|
||||
* Boots the Kernel for this test.
|
||||
*/
|
||||
protected static function bootKernel(array $options = []): KernelInterface
|
||||
{
|
||||
static::ensureKernelShutdown();
|
||||
|
||||
$kernel = static::createKernel($options);
|
||||
$kernel->boot();
|
||||
static::$kernel = $kernel;
|
||||
static::$booted = true;
|
||||
|
||||
return static::$kernel;
|
||||
}
|
||||
|
||||
/**
|
||||
* Provides a dedicated test container with access to both public and private
|
||||
* services. The container will not include private services that have been
|
||||
* inlined or removed. Private services will be removed when they are not
|
||||
* used by other services.
|
||||
*
|
||||
* Using this method is the best way to get a container from your test code.
|
||||
*
|
||||
* @return Container
|
||||
*/
|
||||
protected static function getContainer(): ContainerInterface
|
||||
{
|
||||
if (!static::$booted) {
|
||||
static::bootKernel();
|
||||
}
|
||||
|
||||
try {
|
||||
return self::$kernel->getContainer()->get('test.service_container');
|
||||
} catch (ServiceNotFoundException $e) {
|
||||
throw new \LogicException('Could not find service "test.service_container". Try updating the "framework.test" config to "true".', 0, $e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a Kernel.
|
||||
*
|
||||
* Available options:
|
||||
*
|
||||
* * environment
|
||||
* * debug
|
||||
*/
|
||||
protected static function createKernel(array $options = []): KernelInterface
|
||||
{
|
||||
static::$class ??= static::getKernelClass();
|
||||
|
||||
$env = $options['environment'] ?? $_ENV['APP_ENV'] ?? $_SERVER['APP_ENV'] ?? 'test';
|
||||
$debug = $options['debug'] ?? $_ENV['APP_DEBUG'] ?? $_SERVER['APP_DEBUG'] ?? true;
|
||||
|
||||
return new static::$class($env, $debug);
|
||||
}
|
||||
|
||||
/**
|
||||
* Shuts the kernel down if it was used in the test - called by the tearDown method by default.
|
||||
*/
|
||||
protected static function ensureKernelShutdown()
|
||||
{
|
||||
if (null !== static::$kernel) {
|
||||
static::$kernel->boot();
|
||||
$container = static::$kernel->getContainer();
|
||||
static::$kernel->shutdown();
|
||||
static::$booted = false;
|
||||
|
||||
if ($container instanceof ResetInterface) {
|
||||
$container->reset();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
138
lib/symfony/framework-bundle/Test/MailerAssertionsTrait.php
Normal file
138
lib/symfony/framework-bundle/Test/MailerAssertionsTrait.php
Normal file
@@ -0,0 +1,138 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Bundle\FrameworkBundle\Test;
|
||||
|
||||
use PHPUnit\Framework\Constraint\LogicalNot;
|
||||
use Symfony\Component\Mailer\Event\MessageEvent;
|
||||
use Symfony\Component\Mailer\Event\MessageEvents;
|
||||
use Symfony\Component\Mailer\Test\Constraint as MailerConstraint;
|
||||
use Symfony\Component\Mime\RawMessage;
|
||||
use Symfony\Component\Mime\Test\Constraint as MimeConstraint;
|
||||
|
||||
trait MailerAssertionsTrait
|
||||
{
|
||||
public static function assertEmailCount(int $count, string $transport = null, string $message = ''): void
|
||||
{
|
||||
self::assertThat(self::getMessageMailerEvents(), new MailerConstraint\EmailCount($count, $transport), $message);
|
||||
}
|
||||
|
||||
public static function assertQueuedEmailCount(int $count, string $transport = null, string $message = ''): void
|
||||
{
|
||||
self::assertThat(self::getMessageMailerEvents(), new MailerConstraint\EmailCount($count, $transport, true), $message);
|
||||
}
|
||||
|
||||
public static function assertEmailIsQueued(MessageEvent $event, string $message = ''): void
|
||||
{
|
||||
self::assertThat($event, new MailerConstraint\EmailIsQueued(), $message);
|
||||
}
|
||||
|
||||
public static function assertEmailIsNotQueued(MessageEvent $event, string $message = ''): void
|
||||
{
|
||||
self::assertThat($event, new LogicalNot(new MailerConstraint\EmailIsQueued()), $message);
|
||||
}
|
||||
|
||||
public static function assertEmailAttachmentCount(RawMessage $email, int $count, string $message = ''): void
|
||||
{
|
||||
self::assertThat($email, new MimeConstraint\EmailAttachmentCount($count), $message);
|
||||
}
|
||||
|
||||
public static function assertEmailTextBodyContains(RawMessage $email, string $text, string $message = ''): void
|
||||
{
|
||||
self::assertThat($email, new MimeConstraint\EmailTextBodyContains($text), $message);
|
||||
}
|
||||
|
||||
public static function assertEmailTextBodyNotContains(RawMessage $email, string $text, string $message = ''): void
|
||||
{
|
||||
self::assertThat($email, new LogicalNot(new MimeConstraint\EmailTextBodyContains($text)), $message);
|
||||
}
|
||||
|
||||
public static function assertEmailHtmlBodyContains(RawMessage $email, string $text, string $message = ''): void
|
||||
{
|
||||
self::assertThat($email, new MimeConstraint\EmailHtmlBodyContains($text), $message);
|
||||
}
|
||||
|
||||
public static function assertEmailHtmlBodyNotContains(RawMessage $email, string $text, string $message = ''): void
|
||||
{
|
||||
self::assertThat($email, new LogicalNot(new MimeConstraint\EmailHtmlBodyContains($text)), $message);
|
||||
}
|
||||
|
||||
public static function assertEmailHasHeader(RawMessage $email, string $headerName, string $message = ''): void
|
||||
{
|
||||
self::assertThat($email, new MimeConstraint\EmailHasHeader($headerName), $message);
|
||||
}
|
||||
|
||||
public static function assertEmailNotHasHeader(RawMessage $email, string $headerName, string $message = ''): void
|
||||
{
|
||||
self::assertThat($email, new LogicalNot(new MimeConstraint\EmailHasHeader($headerName)), $message);
|
||||
}
|
||||
|
||||
public static function assertEmailHeaderSame(RawMessage $email, string $headerName, string $expectedValue, string $message = ''): void
|
||||
{
|
||||
self::assertThat($email, new MimeConstraint\EmailHeaderSame($headerName, $expectedValue), $message);
|
||||
}
|
||||
|
||||
public static function assertEmailHeaderNotSame(RawMessage $email, string $headerName, string $expectedValue, string $message = ''): void
|
||||
{
|
||||
self::assertThat($email, new LogicalNot(new MimeConstraint\EmailHeaderSame($headerName, $expectedValue)), $message);
|
||||
}
|
||||
|
||||
public static function assertEmailAddressContains(RawMessage $email, string $headerName, string $expectedValue, string $message = ''): void
|
||||
{
|
||||
self::assertThat($email, new MimeConstraint\EmailAddressContains($headerName, $expectedValue), $message);
|
||||
}
|
||||
|
||||
public static function assertEmailSubjectContains(RawMessage $email, string $expectedValue, string $message = ''): void
|
||||
{
|
||||
self::assertThat($email, new MimeConstraint\EmailSubjectContains($expectedValue), $message);
|
||||
}
|
||||
|
||||
public static function assertEmailSubjectNotContains(RawMessage $email, string $expectedValue, string $message = ''): void
|
||||
{
|
||||
self::assertThat($email, new LogicalNot(new MimeConstraint\EmailSubjectContains($expectedValue)), $message);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return MessageEvent[]
|
||||
*/
|
||||
public static function getMailerEvents(string $transport = null): array
|
||||
{
|
||||
return self::getMessageMailerEvents()->getEvents($transport);
|
||||
}
|
||||
|
||||
public static function getMailerEvent(int $index = 0, string $transport = null): ?MessageEvent
|
||||
{
|
||||
return self::getMailerEvents($transport)[$index] ?? null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return RawMessage[]
|
||||
*/
|
||||
public static function getMailerMessages(string $transport = null): array
|
||||
{
|
||||
return self::getMessageMailerEvents()->getMessages($transport);
|
||||
}
|
||||
|
||||
public static function getMailerMessage(int $index = 0, string $transport = null): ?RawMessage
|
||||
{
|
||||
return self::getMailerMessages($transport)[$index] ?? null;
|
||||
}
|
||||
|
||||
private static function getMessageMailerEvents(): MessageEvents
|
||||
{
|
||||
$container = static::getContainer();
|
||||
if ($container->has('mailer.message_logger_listener')) {
|
||||
return $container->get('mailer.message_logger_listener')->getEvents();
|
||||
}
|
||||
|
||||
static::fail('A client must have Mailer enabled to make email assertions. Did you forget to require symfony/mailer?');
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,100 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Bundle\FrameworkBundle\Test;
|
||||
|
||||
use PHPUnit\Framework\Constraint\LogicalNot;
|
||||
use Symfony\Component\Notifier\Event\MessageEvent;
|
||||
use Symfony\Component\Notifier\Event\NotificationEvents;
|
||||
use Symfony\Component\Notifier\Message\MessageInterface;
|
||||
use Symfony\Component\Notifier\Test\Constraint as NotifierConstraint;
|
||||
|
||||
/*
|
||||
* @author Smaïne Milianni <smaine.milianni@gmail.com>
|
||||
*/
|
||||
trait NotificationAssertionsTrait
|
||||
{
|
||||
public static function assertNotificationCount(int $count, string $transportName = null, string $message = ''): void
|
||||
{
|
||||
self::assertThat(self::getNotificationEvents(), new NotifierConstraint\NotificationCount($count, $transportName), $message);
|
||||
}
|
||||
|
||||
public static function assertQueuedNotificationCount(int $count, string $transportName = null, string $message = ''): void
|
||||
{
|
||||
self::assertThat(self::getNotificationEvents(), new NotifierConstraint\NotificationCount($count, $transportName, true), $message);
|
||||
}
|
||||
|
||||
public static function assertNotificationIsQueued(MessageEvent $event, string $message = ''): void
|
||||
{
|
||||
self::assertThat($event, new NotifierConstraint\NotificationIsQueued(), $message);
|
||||
}
|
||||
|
||||
public static function assertNotificationIsNotQueued(MessageEvent $event, string $message = ''): void
|
||||
{
|
||||
self::assertThat($event, new LogicalNot(new NotifierConstraint\NotificationIsQueued()), $message);
|
||||
}
|
||||
|
||||
public static function assertNotificationSubjectContains(MessageInterface $notification, string $text, string $message = ''): void
|
||||
{
|
||||
self::assertThat($notification, new NotifierConstraint\NotificationSubjectContains($text), $message);
|
||||
}
|
||||
|
||||
public static function assertNotificationSubjectNotContains(MessageInterface $notification, string $text, string $message = ''): void
|
||||
{
|
||||
self::assertThat($notification, new LogicalNot(new NotifierConstraint\NotificationSubjectContains($text)), $message);
|
||||
}
|
||||
|
||||
public static function assertNotificationTransportIsEqual(MessageInterface $notification, string $transportName = null, string $message = ''): void
|
||||
{
|
||||
self::assertThat($notification, new NotifierConstraint\NotificationTransportIsEqual($transportName), $message);
|
||||
}
|
||||
|
||||
public static function assertNotificationTransportIsNotEqual(MessageInterface $notification, string $transportName = null, string $message = ''): void
|
||||
{
|
||||
self::assertThat($notification, new LogicalNot(new NotifierConstraint\NotificationTransportIsEqual($transportName)), $message);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return MessageEvent[]
|
||||
*/
|
||||
public static function getNotifierEvents(string $transportName = null): array
|
||||
{
|
||||
return self::getNotificationEvents()->getEvents($transportName);
|
||||
}
|
||||
|
||||
public static function getNotifierEvent(int $index = 0, string $transportName = null): ?MessageEvent
|
||||
{
|
||||
return self::getNotifierEvents($transportName)[$index] ?? null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return MessageInterface[]
|
||||
*/
|
||||
public static function getNotifierMessages(string $transportName = null): array
|
||||
{
|
||||
return self::getNotificationEvents()->getMessages($transportName);
|
||||
}
|
||||
|
||||
public static function getNotifierMessage(int $index = 0, string $transportName = null): ?MessageInterface
|
||||
{
|
||||
return self::getNotifierMessages($transportName)[$index] ?? null;
|
||||
}
|
||||
|
||||
public static function getNotificationEvents(): NotificationEvents
|
||||
{
|
||||
$container = static::getContainer();
|
||||
if ($container->has('notifier.notification_logger_listener')) {
|
||||
return $container->get('notifier.notification_logger_listener')->getEvents();
|
||||
}
|
||||
|
||||
static::fail('A client must have Notifier enabled to make notifications assertions. Did you forget to require symfony/notifier?');
|
||||
}
|
||||
}
|
||||
58
lib/symfony/framework-bundle/Test/TestBrowserToken.php
Normal file
58
lib/symfony/framework-bundle/Test/TestBrowserToken.php
Normal file
@@ -0,0 +1,58 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Bundle\FrameworkBundle\Test;
|
||||
|
||||
use Symfony\Component\Security\Core\Authentication\Token\AbstractToken;
|
||||
use Symfony\Component\Security\Core\User\UserInterface;
|
||||
|
||||
/**
|
||||
* A very limited token that is used to login in tests using the KernelBrowser.
|
||||
*
|
||||
* @author Wouter de Jong <wouter@wouterj.nl>
|
||||
*/
|
||||
class TestBrowserToken extends AbstractToken
|
||||
{
|
||||
private string $firewallName;
|
||||
|
||||
public function __construct(array $roles = [], UserInterface $user = null, string $firewallName = 'main')
|
||||
{
|
||||
parent::__construct($roles);
|
||||
|
||||
if (null !== $user) {
|
||||
$this->setUser($user);
|
||||
}
|
||||
|
||||
$this->firewallName = $firewallName;
|
||||
}
|
||||
|
||||
public function getFirewallName(): string
|
||||
{
|
||||
return $this->firewallName;
|
||||
}
|
||||
|
||||
public function getCredentials(): mixed
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
public function __serialize(): array
|
||||
{
|
||||
return [$this->firewallName, parent::__serialize()];
|
||||
}
|
||||
|
||||
public function __unserialize(array $data): void
|
||||
{
|
||||
[$this->firewallName, $parentData] = $data;
|
||||
|
||||
parent::__unserialize($parentData);
|
||||
}
|
||||
}
|
||||
126
lib/symfony/framework-bundle/Test/TestContainer.php
Normal file
126
lib/symfony/framework-bundle/Test/TestContainer.php
Normal file
@@ -0,0 +1,126 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Bundle\FrameworkBundle\Test;
|
||||
|
||||
use Psr\Container\ContainerInterface;
|
||||
use Symfony\Component\DependencyInjection\Container;
|
||||
use Symfony\Component\DependencyInjection\Exception\InvalidArgumentException;
|
||||
use Symfony\Component\DependencyInjection\ParameterBag\ParameterBagInterface;
|
||||
use Symfony\Component\HttpKernel\KernelInterface;
|
||||
|
||||
/**
|
||||
* A special container used in tests. This gives access to both public and
|
||||
* private services. The container will not include private services that have
|
||||
* been inlined or removed. Private services will be removed when they are not
|
||||
* used by other services.
|
||||
*
|
||||
* @author Nicolas Grekas <p@tchwork.com>
|
||||
*
|
||||
* @internal
|
||||
*/
|
||||
class TestContainer extends Container
|
||||
{
|
||||
public function __construct(
|
||||
private KernelInterface $kernel,
|
||||
private string $privateServicesLocatorId,
|
||||
private array $renamedIds = [],
|
||||
) {
|
||||
}
|
||||
|
||||
public function compile(): void
|
||||
{
|
||||
$this->getPublicContainer()->compile();
|
||||
}
|
||||
|
||||
public function isCompiled(): bool
|
||||
{
|
||||
return $this->getPublicContainer()->isCompiled();
|
||||
}
|
||||
|
||||
public function getParameterBag(): ParameterBagInterface
|
||||
{
|
||||
return $this->getPublicContainer()->getParameterBag();
|
||||
}
|
||||
|
||||
public function getParameter(string $name): array|bool|string|int|float|\UnitEnum|null
|
||||
{
|
||||
return $this->getPublicContainer()->getParameter($name);
|
||||
}
|
||||
|
||||
public function hasParameter(string $name): bool
|
||||
{
|
||||
return $this->getPublicContainer()->hasParameter($name);
|
||||
}
|
||||
|
||||
public function setParameter(string $name, mixed $value): void
|
||||
{
|
||||
$this->getPublicContainer()->setParameter($name, $value);
|
||||
}
|
||||
|
||||
public function set(string $id, mixed $service): void
|
||||
{
|
||||
$container = $this->getPublicContainer();
|
||||
$renamedId = $this->renamedIds[$id] ?? $id;
|
||||
|
||||
try {
|
||||
$container->set($renamedId, $service);
|
||||
} catch (InvalidArgumentException $e) {
|
||||
if (!str_starts_with($e->getMessage(), "The \"$renamedId\" service is private")) {
|
||||
throw $e;
|
||||
}
|
||||
if (isset($container->privates[$renamedId])) {
|
||||
throw new InvalidArgumentException(sprintf('The "%s" service is already initialized, you cannot replace it.', $id));
|
||||
}
|
||||
$container->privates[$renamedId] = $service;
|
||||
}
|
||||
}
|
||||
|
||||
public function has(string $id): bool
|
||||
{
|
||||
return $this->getPublicContainer()->has($id) || $this->getPrivateContainer()->has($id);
|
||||
}
|
||||
|
||||
public function get(string $id, int $invalidBehavior = self::EXCEPTION_ON_INVALID_REFERENCE): ?object
|
||||
{
|
||||
return $this->getPrivateContainer()->has($id) ? $this->getPrivateContainer()->get($id) : $this->getPublicContainer()->get($id, $invalidBehavior);
|
||||
}
|
||||
|
||||
public function initialized(string $id): bool
|
||||
{
|
||||
return $this->getPublicContainer()->initialized($id);
|
||||
}
|
||||
|
||||
public function reset(): void
|
||||
{
|
||||
// ignore the call
|
||||
}
|
||||
|
||||
public function getServiceIds(): array
|
||||
{
|
||||
return $this->getPublicContainer()->getServiceIds();
|
||||
}
|
||||
|
||||
public function getRemovedIds(): array
|
||||
{
|
||||
return $this->getPublicContainer()->getRemovedIds();
|
||||
}
|
||||
|
||||
private function getPublicContainer(): Container
|
||||
{
|
||||
return $this->kernel->getContainer() ?? throw new \LogicException('Cannot access the container on a non-booted kernel. Did you forget to boot it?');
|
||||
}
|
||||
|
||||
private function getPrivateContainer(): ContainerInterface
|
||||
{
|
||||
return $this->getPublicContainer()->get($this->privateServicesLocatorId);
|
||||
}
|
||||
}
|
||||
19
lib/symfony/framework-bundle/Test/WebTestAssertionsTrait.php
Normal file
19
lib/symfony/framework-bundle/Test/WebTestAssertionsTrait.php
Normal file
@@ -0,0 +1,19 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Bundle\FrameworkBundle\Test;
|
||||
|
||||
trait WebTestAssertionsTrait
|
||||
{
|
||||
use BrowserKitAssertionsTrait;
|
||||
use DomCrawlerAssertionsTrait;
|
||||
use HttpClientAssertionsTrait;
|
||||
}
|
||||
59
lib/symfony/framework-bundle/Test/WebTestCase.php
Normal file
59
lib/symfony/framework-bundle/Test/WebTestCase.php
Normal file
@@ -0,0 +1,59 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Bundle\FrameworkBundle\Test;
|
||||
|
||||
use Symfony\Bundle\FrameworkBundle\KernelBrowser;
|
||||
use Symfony\Component\DependencyInjection\Exception\ServiceNotFoundException;
|
||||
|
||||
/**
|
||||
* WebTestCase is the base class for functional tests.
|
||||
*
|
||||
* @author Fabien Potencier <fabien@symfony.com>
|
||||
*/
|
||||
abstract class WebTestCase extends KernelTestCase
|
||||
{
|
||||
use WebTestAssertionsTrait;
|
||||
|
||||
protected function tearDown(): void
|
||||
{
|
||||
parent::tearDown();
|
||||
self::getClient(null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a KernelBrowser.
|
||||
*
|
||||
* @param array $options An array of options to pass to the createKernel method
|
||||
* @param array $server An array of server parameters
|
||||
*/
|
||||
protected static function createClient(array $options = [], array $server = []): KernelBrowser
|
||||
{
|
||||
if (static::$booted) {
|
||||
throw new \LogicException(sprintf('Booting the kernel before calling "%s()" is not supported, the kernel should only be booted once.', __METHOD__));
|
||||
}
|
||||
|
||||
$kernel = static::bootKernel($options);
|
||||
|
||||
try {
|
||||
$client = $kernel->getContainer()->get('test.client');
|
||||
} catch (ServiceNotFoundException) {
|
||||
if (class_exists(KernelBrowser::class)) {
|
||||
throw new \LogicException('You cannot create the client used in functional tests if the "framework.test" config is not set to true.');
|
||||
}
|
||||
throw new \LogicException('You cannot create the client used in functional tests if the BrowserKit component is not available. Try running "composer require symfony/browser-kit".');
|
||||
}
|
||||
|
||||
$client->setServerParameters($server);
|
||||
|
||||
return self::getClient($client);
|
||||
}
|
||||
}
|
||||
@@ -40,6 +40,7 @@ class iTopComposer extends AbstractFolderAnalyzer
|
||||
{
|
||||
return [
|
||||
'twig/twig/src/Node/Expression/Test',
|
||||
'symfony/framework-bundle/Test', // Tools for testing Symfony applications
|
||||
];
|
||||
}
|
||||
|
||||
@@ -87,7 +88,6 @@ class iTopComposer extends AbstractFolderAnalyzer
|
||||
'symfony/http-foundation/Test',
|
||||
'symfony/http-kernel/Tests',
|
||||
'symfony/service-contracts/Test',
|
||||
'symfony/framework-bundle/Test',
|
||||
'symfony/mime/Test',
|
||||
'symfony/routing/Tests',
|
||||
'symfony/stopwatch/Tests',
|
||||
|
||||
@@ -0,0 +1,76 @@
|
||||
<?php
|
||||
namespace Combodo\iTop\Test\UnitTest\HubConnector;
|
||||
|
||||
use Combodo\iTop\Application\Helper\Session;
|
||||
use Combodo\iTop\Test\UnitTest\ItopDataTestCase;
|
||||
use PHPUnit\Framework\SkippedTestCase;
|
||||
|
||||
class AjaxPageTest extends ItopDataTestCase {
|
||||
const USE_TRANSACTION = false;
|
||||
const AUTHENTICATION_TOKEN = '14b5da9d092f84044187421419a0347e7317bc8cd2b486fdda631be06b959269';
|
||||
const AUTHENTICATION_PASSWORD = "tagada-Secret,007";
|
||||
|
||||
protected function setUp(): void
|
||||
{
|
||||
$this->SkipIfModuleNotPresent('itop-hub-connector');
|
||||
parent::setUp();
|
||||
}
|
||||
|
||||
public function testCompileOperation()
|
||||
{
|
||||
// Given
|
||||
static::RecurseMkdir(APPROOT.'data/hub');
|
||||
file_put_contents(APPROOT.'data/hub/compile_authent', self::AUTHENTICATION_TOKEN);
|
||||
$sLogin = $this->GivenUserInDB(self::AUTHENTICATION_PASSWORD, ['Administrator']);
|
||||
|
||||
$iLastCompilation = filemtime(APPROOT.'env-production');
|
||||
|
||||
// When
|
||||
$sOutput = $this->CallItopUrl(
|
||||
"/pages/exec.php?exec_module=itop-hub-connector&exec_page=ajax.php",
|
||||
[
|
||||
'auth_user' => $sLogin,
|
||||
'auth_pwd' => self::AUTHENTICATION_PASSWORD,
|
||||
'operation' => "compile",
|
||||
'authent' => self::AUTHENTICATION_TOKEN,
|
||||
]
|
||||
);
|
||||
|
||||
// Then
|
||||
$aRes = json_decode($sOutput, true);
|
||||
$this->assertNotNull($aRes, "Response should be a valid json, found instead:" . PHP_EOL . $sOutput);
|
||||
$this->assertEquals(
|
||||
[
|
||||
'code' => 0,
|
||||
'message' => 'Ok',
|
||||
'fields' => []
|
||||
],
|
||||
$aRes
|
||||
);
|
||||
|
||||
clearstatcache();
|
||||
$this->assertGreaterThan($iLastCompilation, filemtime(APPROOT.'env-production'), 'The env-production directory should have been rebuilt');
|
||||
}
|
||||
|
||||
protected function CallItopUrl($sUri, ?array $aPostFields = null, bool $bXDebugEnabled = false)
|
||||
{
|
||||
$ch = curl_init();
|
||||
if ($bXDebugEnabled) {
|
||||
curl_setopt($ch, CURLOPT_COOKIE, 'XDEBUG_SESSION=phpstorm');
|
||||
}
|
||||
|
||||
$sUrl = \MetaModel::GetConfig()->Get('app_root_url')."/$sUri";
|
||||
var_dump($sUrl);
|
||||
curl_setopt($ch, CURLOPT_URL, $sUrl);
|
||||
curl_setopt($ch, CURLOPT_POST, 1);// set post data to true
|
||||
curl_setopt($ch, CURLOPT_POSTFIELDS, $aPostFields);
|
||||
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
|
||||
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 0);
|
||||
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, 0);
|
||||
$sOutput = curl_exec($ch);
|
||||
//echo "$sUrl error code:".curl_error($ch);
|
||||
curl_close($ch);
|
||||
|
||||
return $sOutput;
|
||||
}
|
||||
}
|
||||
@@ -2,7 +2,7 @@
|
||||
<phpunit
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:noNamespaceSchemaLocation="https://schema.phpunit.de/8.5/phpunit.xsd"
|
||||
bootstrap="vendor/autoload.php"
|
||||
bootstrap="unittestautoload.php"
|
||||
backupGlobals="true"
|
||||
colors="true"
|
||||
columns="120"
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
<phpunit
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:noNamespaceSchemaLocation="https://schema.phpunit.de/8.5/phpunit.xsd"
|
||||
bootstrap="vendor/autoload.php"
|
||||
bootstrap="unittestautoload.php"
|
||||
backupGlobals="true"
|
||||
colors="true"
|
||||
columns="120"
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
<phpunit
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:noNamespaceSchemaLocation="https://schema.phpunit.de/8.5/phpunit.xsd"
|
||||
bootstrap="vendor/autoload.php"
|
||||
bootstrap="unittestautoload.php"
|
||||
backupGlobals="true"
|
||||
colors="true"
|
||||
columns="120"
|
||||
|
||||
@@ -1368,4 +1368,42 @@ abstract class ItopDataTestCase extends ItopTestCase
|
||||
]);
|
||||
return $sLogin;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $sPassword
|
||||
* @param array $aProfiles Profile names Example: ['Administrator']
|
||||
*
|
||||
* @return string The unique login
|
||||
* @throws \Exception
|
||||
*/
|
||||
protected function GivenUserInDB(string $sPassword, array $aProfiles): string
|
||||
{
|
||||
$sLogin = 'demo_test_'.uniqid(__CLASS__, true);
|
||||
|
||||
$aProfileList = array_map(function($sProfileId) {
|
||||
return 'profileid:'.self::$aURP_Profiles[$sProfileId];
|
||||
}, $aProfiles);
|
||||
|
||||
$iUser = $this->GivenObjectInDB('UserLocal', [
|
||||
'login' => $sLogin,
|
||||
'password' => $sPassword,
|
||||
'language' => 'EN US',
|
||||
'profile_list' => $aProfileList,
|
||||
]);
|
||||
return $sLogin;
|
||||
}
|
||||
|
||||
/**
|
||||
* Can be invoked in setUp or any test method to skip the test if the module is not present
|
||||
*
|
||||
* @param string $sModule e.g: itop-hub-connector
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function SkipIfModuleNotPresent(string $sModule): void
|
||||
{
|
||||
if (!file_exists(\utils::GetAbsoluteModulePath($sModule))) {
|
||||
self::markTestSkipped("Test skipped: module '$sModule' is not present");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,19 +9,21 @@ namespace Combodo\iTop\Test\UnitTest;
|
||||
use CMDBSource;
|
||||
use DeprecatedCallsLog;
|
||||
use MySQLTransactionNotClosedException;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
use ReflectionMethod;
|
||||
use SetupUtils;
|
||||
use Symfony\Bundle\FrameworkBundle\Test\KernelTestCase;
|
||||
use Symfony\Component\HttpKernel\KernelInterface;
|
||||
use const DEBUG_BACKTRACE_IGNORE_ARGS;
|
||||
|
||||
/**
|
||||
* Class ItopTestCase
|
||||
*
|
||||
* Helper class to extend for tests that DO NOT need to access the DataModel or the Database
|
||||
* Helper class to extend for tests that DO NOT need to access the DataModel or the Database,
|
||||
* but still need to access the iTop core classes and optionally boot the Symfony kernel (to access the services container).
|
||||
*
|
||||
* @since 3.0.4 3.1.1 3.2.0 N°6658 move some setUp/tearDown code to the corresponding methods *BeforeClass to speed up tests process time.
|
||||
*/
|
||||
abstract class ItopTestCase extends TestCase
|
||||
abstract class ItopTestCase extends KernelTestCase
|
||||
{
|
||||
public const TEST_LOG_DIR = 'test';
|
||||
|
||||
@@ -70,6 +72,9 @@ abstract class ItopTestCase extends TestCase
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Required to boot the portal symfony Kernel
|
||||
$_ENV['PORTAL_ID'] = 'itop-portal';
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -142,6 +147,9 @@ abstract class ItopTestCase extends TestCase
|
||||
protected function setUp(): void {
|
||||
parent::setUp();
|
||||
|
||||
// Hack - Required the first time the Portal kernel is booted on a newly installed iTop
|
||||
$_ENV['COMBODO_PORTAL_BASE_ABSOLUTE_PATH'] = __DIR__ . '/../../../../../env-production/itop-portal-base/portal/public/';
|
||||
|
||||
$this->LoadRequiredItopFiles();
|
||||
$this->LoadRequiredTestFiles();
|
||||
}
|
||||
@@ -212,7 +220,7 @@ abstract class ItopTestCase extends TestCase
|
||||
protected function LoadRequiredItopFiles(): void
|
||||
{
|
||||
// At least make sure that the autoloader will be loaded, and that the APPROOT constant is defined
|
||||
require_once __DIR__.'/../../../../approot.inc.php';
|
||||
require_once __DIR__.'/../../../../approot.inc.php';
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -541,4 +549,27 @@ abstract class ItopTestCase extends TestCase
|
||||
|
||||
$this->AssertArraysHaveSameItems($aExpected, $aFiles, $sMessage);
|
||||
}
|
||||
|
||||
/**
|
||||
* Control which Kernel will be loaded when invoking the bootKernel method
|
||||
*
|
||||
* @see static::bootKernel(), static::getContainer()
|
||||
* @see \Combodo\iTop\Kernel, \Combodo\iTop\Portal\Kernel
|
||||
*
|
||||
* @param string $sKernelClass
|
||||
*
|
||||
* @since 3.2.1
|
||||
*/
|
||||
static protected function SetKernelClass(string $sKernelClass): void
|
||||
{
|
||||
$_SERVER['KERNEL_CLASS'] = $sKernelClass;
|
||||
}
|
||||
|
||||
static protected function bootKernel(array $options = []): KernelInterface
|
||||
{
|
||||
if (!array_key_exists('KERNEL_CLASS', $_SERVER)) {
|
||||
throw new \LogicException('static::SetKernelClass() must be called before booting the kernel.');
|
||||
}
|
||||
return parent::bootKernel($options);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -79,21 +79,18 @@ class UpdateImpactedItemsTest extends ItopDataTestCase
|
||||
{
|
||||
/**
|
||||
* Server1 +----> Hypervisor1
|
||||
* Server2 +----> Hypervisor1
|
||||
*/
|
||||
$this->GivenCITreeInDB(<<<EOF
|
||||
Hypervisor_1 -> Server_1
|
||||
Hypervisor_1 -> Server_2
|
||||
EOF);
|
||||
$oTicket = $this->GivenTicketWithCIsOrPersons([
|
||||
'Server_1' => 'manual'
|
||||
'Hypervisor_1' => 'manual'
|
||||
]);
|
||||
|
||||
$oTicket->UpdateImpactedItems(); // impact analysis
|
||||
|
||||
$this->assertCIsOrPersonsListEquals($oTicket, [
|
||||
'Server_1' => 'manual',
|
||||
'Hypervisor_1' => 'computed'
|
||||
'Hypervisor_1' => 'manual',
|
||||
]);
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,49 @@
|
||||
<?php
|
||||
|
||||
|
||||
namespace Combodo\iTop\Test\UnitTest\Sources\Controller;
|
||||
|
||||
use Combodo\iTop\Portal\Controller\AggregatePageBrickController;
|
||||
use Combodo\iTop\Test\UnitTest\ItopDataTestCase;
|
||||
|
||||
class BootSymfonyKernelTest extends ItopDataTestCase
|
||||
{
|
||||
public function testInstantiateServiceWithAnExplicitCallToBootTheKernel()
|
||||
{
|
||||
$this->SetKernelClass(\Combodo\iTop\Portal\Kernel::class);
|
||||
self::bootKernel();
|
||||
$controller = static::getContainer()->get(AggregatePageBrickController::class);
|
||||
|
||||
$this->assertInstanceOf(AggregatePageBrickController::class, $controller);
|
||||
}
|
||||
|
||||
public function testInstantiateServiceWithAnAutomaticKernelBoot()
|
||||
{
|
||||
$this->SetKernelClass(\Combodo\iTop\Portal\Kernel::class);
|
||||
$controller = static::getContainer()->get(AggregatePageBrickController::class);
|
||||
|
||||
$this->assertInstanceOf(AggregatePageBrickController::class, $controller);
|
||||
}
|
||||
|
||||
public function testUnspecifiedKernelClassThrowsAnException()
|
||||
{
|
||||
$this->expectException(\LogicException::class);
|
||||
$this->expectExceptionMessage('static::SetKernelClass() must be called before booting the kernel');
|
||||
|
||||
static::getContainer();
|
||||
}
|
||||
|
||||
public function testTwoDifferentKernelsCanBeStartedConsecutively()
|
||||
{
|
||||
self::markTestSkipped('This test is still failing: the second kernel container does not find the requested service');
|
||||
|
||||
$this->SetKernelClass(\Combodo\iTop\Kernel::class);
|
||||
self::bootKernel();
|
||||
|
||||
$this->SetKernelClass(\Combodo\iTop\Portal\Kernel::class);
|
||||
self::bootKernel();
|
||||
$controller = static::getContainer()->get(AggregatePageBrickController::class);
|
||||
|
||||
$this->assertInstanceOf(AggregatePageBrickController::class, $controller);
|
||||
}
|
||||
}
|
||||
@@ -2,6 +2,8 @@
|
||||
|
||||
// Main autoload, this is the one to use in the PHPUnit configuration
|
||||
//
|
||||
// It was previously used to include both the vendor autoloader and our custom base test case classes, but these are now autoloaded from ./src/BasetestCase
|
||||
// This file should then no longer be necessary, but we have to keep it until projects / branches / modules have been corrected.
|
||||
// This file was previously mentioned as deprecated, and now it HAS to be used (see phpunit.xml/bootstrap attribute)
|
||||
require_once 'vendor/autoload.php';
|
||||
|
||||
// Required to benefit from symfony/framework-bundle's KernelTestCase, which is in a package which is a mix of runtime and test tools
|
||||
require_once __DIR__.'/../../lib/autoload.php';
|
||||
|
||||
Reference in New Issue
Block a user