Version 4.5.0
This commit is contained in:
1 parent
1a0c7fd3c2
commit
f79dcf067a
3791 files changed
+248032
-76372
No files matched your search
@@ -5,19 +5,22 @@
|
||||
* @author <a href='https://www.invisioncommunity.com'>Invision Power Services, Inc.</a>
|
||||
* @copyright (c) Invision Power Services, Inc.
|
||||
* @package Invision Community
|
||||
* @subpackage Converter
|
||||
* @subpackage convert
|
||||
* @since 14 June 2016
|
||||
*/
|
||||
|
||||
namespace IPS\convert\Software\Core;
|
||||
|
||||
/* To prevent PHP errors (extending class does not exist) revealing path */
|
||||
if ( !defined( '\IPS\SUITE_UNIQUE_KEY' ) )
|
||||
if ( !\defined( '\IPS\SUITE_UNIQUE_KEY' ) )
|
||||
{
|
||||
header( ( isset( $_SERVER['SERVER_PROTOCOL'] ) ? $_SERVER['SERVER_PROTOCOL'] : 'HTTP/1.0' ) . ' 403 Forbidden' );
|
||||
exit;
|
||||
}
|
||||
|
||||
/**
|
||||
* ExpressionEngine Core Converter
|
||||
*/
|
||||
class _Expressionengine extends \IPS\convert\Software
|
||||
{
|
||||
/**
|
||||
@@ -87,23 +90,20 @@ class _Expressionengine extends \IPS\convert\Software
|
||||
/**
|
||||
* Allows software to add additional menu row options
|
||||
*
|
||||
* @param array $rows Existing rows
|
||||
* @return array
|
||||
*/
|
||||
public function extraMenuRows( $rows )
|
||||
public function extraMenuRows()
|
||||
{
|
||||
if( isset( $rows['convertPrivateMessageReplies'] ) )
|
||||
{
|
||||
$rows['convertPmAttachments'] = array(
|
||||
'step_method' => 'convertPmAttachments',
|
||||
'step_title' => 'convert_attachments',
|
||||
'ips_rows' => \IPS\Db::i()->select( 'COUNT(*)', 'core_attachments' ),
|
||||
'source_rows' => array( 'table' => static::canConvert()['convertPmAttachments']['table'], 'where' => static::canConvert()['convertPmAttachments']['where'] ),
|
||||
'per_cycle' => 100,
|
||||
'dependencies' => array( 'convertPrivateMessageReplies' ),
|
||||
'link_type' => 'core_attachments',
|
||||
);
|
||||
}
|
||||
$rows = array();
|
||||
$rows['convertPmAttachments'] = array(
|
||||
'step_method' => 'convertPmAttachments',
|
||||
'step_title' => 'convert_attachments',
|
||||
'ips_rows' => \IPS\Db::i()->select( 'COUNT(*)', 'core_attachments' ),
|
||||
'source_rows' => array( 'table' => static::canConvert()['convertPmAttachments']['table'], 'where' => static::canConvert()['convertPmAttachments']['where'] ),
|
||||
'per_cycle' => 10,
|
||||
'dependencies' => array( 'convertPrivateMessageReplies' ),
|
||||
'link_type' => 'core_attachments',
|
||||
);
|
||||
|
||||
return $rows;
|
||||
}
|
||||
@@ -147,8 +147,8 @@ class _Expressionengine extends \IPS\convert\Software
|
||||
/**
|
||||
* Fix post data
|
||||
*
|
||||
* @param string raw post data
|
||||
* @return string parsed post data
|
||||
* @param string $post Raw post data
|
||||
* @return string Parsed post data
|
||||
*/
|
||||
public static function fixPostData( $post )
|
||||
{
|
||||
@@ -290,7 +290,7 @@ class _Expressionengine extends \IPS\convert\Software
|
||||
/**
|
||||
* Finish
|
||||
*
|
||||
* @return array
|
||||
* @return array Messages to display
|
||||
*/
|
||||
public function finish()
|
||||
{
|
||||
@@ -391,11 +391,11 @@ class _Expressionengine extends \IPS\convert\Software
|
||||
$info['pf_type'] = ucwords( $row['m_field_type'] );
|
||||
$info['pf_name'] = $row['m_field_label'];
|
||||
$info['pf_desc'] = $row['m_field_description'];
|
||||
$info['pf_content'] = ( !in_array( $row['m_field_type'], array( 'textbox', 'textarea' ) ) ) ? explode( "\r", $row['field_choices'] ) : NULL;
|
||||
$info['pf_content'] = ( !\in_array( $row['m_field_type'], array( 'textbox', 'textarea' ) ) ) ? explode( "\r", $row['field_choices'] ) : NULL;
|
||||
$info['pf_not_null'] = $row['m_field_required'] == 'y' ? 1 : 0;
|
||||
$info['pf_member_hide'] = $row['m_field_public'] == 'n' ? 1 : 0;
|
||||
$info['pf_member_hide'] = $row['m_field_public'] == 'n' ? 'hide' : 'all';
|
||||
$info['pf_max_input'] = $row['m_field_maxl'];
|
||||
$info['pf_member_edit'] = ( in_array( $row['user_editable'], array( 'yes', 'once' ) ) ) ? 0 : 1;
|
||||
$info['pf_member_edit'] = ( \in_array( $row['user_editable'], array( 'yes', 'once' ) ) ) ? 0 : 1;
|
||||
$info['pf_position'] = $row['m_field_order'];
|
||||
$info['pf_show_on_reg'] = $row['m_field_reg'] == 'y' ? 1 : 0;
|
||||
$info['pf_input_format'] = NULL;
|
||||
@@ -437,7 +437,7 @@ class _Expressionengine extends \IPS\convert\Software
|
||||
}
|
||||
|
||||
/* Now check for group promotions */
|
||||
if( count( $libraryClass->groupPromotions ) )
|
||||
if( \count( $libraryClass->groupPromotions ) )
|
||||
{
|
||||
foreach( $libraryClass->groupPromotions as $groupPromotion )
|
||||
{
|
||||
@@ -526,11 +526,10 @@ class _Expressionengine extends \IPS\convert\Software
|
||||
'pf_desc' => '',
|
||||
'pf_type' => 'Text',
|
||||
'pf_content' => '[]',
|
||||
'pf_member_hide' => 0,
|
||||
'pf_member_hide' => 'all',
|
||||
'pf_max_input' => 500,
|
||||
'pf_member_edit' => 1,
|
||||
'pf_show_on_reg' => 0,
|
||||
'pf_admin_only' => 0,
|
||||
) );
|
||||
}
|
||||
|
||||
|
||||
@@ -5,19 +5,22 @@
|
||||
* @author <a href='https://www.invisioncommunity.com'>Invision Power Services, Inc.</a>
|
||||
* @copyright (c) Invision Power Services, Inc.
|
||||
* @package Invision Community
|
||||
* @subpackage Converter
|
||||
* @subpackage convert
|
||||
* @since 12 July 2017
|
||||
*/
|
||||
|
||||
namespace IPS\convert\Software\Core;
|
||||
|
||||
/* To prevent PHP errors (extending class does not exist) revealing path */
|
||||
if ( !defined( '\IPS\SUITE_UNIQUE_KEY' ) )
|
||||
if ( !\defined( '\IPS\SUITE_UNIQUE_KEY' ) )
|
||||
{
|
||||
header( ( isset( $_SERVER['SERVER_PROTOCOL'] ) ? $_SERVER['SERVER_PROTOCOL'] : 'HTTP/1.0' ) . ' 403 Forbidden' );
|
||||
exit;
|
||||
}
|
||||
|
||||
/**
|
||||
* Invision Core Converter
|
||||
*/
|
||||
class _Invisioncommunity extends \IPS\convert\Software
|
||||
{
|
||||
/**
|
||||
@@ -30,6 +33,14 @@ class _Invisioncommunity extends \IPS\convert\Software
|
||||
*/
|
||||
public static $dbNeeded = FALSE;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param \IPS\convert\App $app The application to reference for database and other information.
|
||||
* @param bool $needDB Establish a DB connection
|
||||
* @return void
|
||||
* @throws \InvalidArgumentException
|
||||
*/
|
||||
public function __construct( \IPS\convert\App $app, $needDB=TRUE )
|
||||
{
|
||||
/* Set filename obscuring flag */
|
||||
@@ -188,6 +199,10 @@ class _Invisioncommunity extends \IPS\convert\Software
|
||||
'table' => 'core_clubs_memberships',
|
||||
'where' => NULL
|
||||
),
|
||||
'convertClubPages' => array(
|
||||
'table' => 'core_club_pages',
|
||||
'where' => NULL
|
||||
),
|
||||
'convertAttachments' => array(
|
||||
'table' => 'core_attachments',
|
||||
'where' => NULL
|
||||
@@ -491,7 +506,7 @@ class _Invisioncommunity extends \IPS\convert\Software
|
||||
}
|
||||
|
||||
/* Now check for group promotions */
|
||||
if( count( $libraryClass->groupPromotions ) )
|
||||
if( \count( $libraryClass->groupPromotions ) )
|
||||
{
|
||||
foreach( $libraryClass->groupPromotions as $groupPromotion )
|
||||
{
|
||||
@@ -592,15 +607,17 @@ class _Invisioncommunity extends \IPS\convert\Software
|
||||
$this->unsetNonStandardColumns( $row, 'core_members' );
|
||||
|
||||
$profilePhotoName = NULL;
|
||||
if( !in_array( $row['pp_photo_type'], array( 'letter', 'none', 'twitter', 'facebook', 'microsoft', '' ) ) )
|
||||
if( !\in_array( $row['pp_photo_type'], array( 'letter', 'none', 'twitter', 'facebook', 'microsoft', '' ) ) )
|
||||
{
|
||||
$profilePhotoName = array_pop( explode( '/', $row['pp_main_photo'] ) );
|
||||
$bits = explode( '/', $row['pp_main_photo'] );
|
||||
$profilePhotoName = array_pop( $bits );
|
||||
}
|
||||
|
||||
$coverPhotoName = NULL;
|
||||
if( $row['pp_cover_photo'] )
|
||||
{
|
||||
$coverPhotoName = array_pop( explode( '/', $row['pp_cover_photo'] ) );
|
||||
$coverBits = explode( '/', $row['pp_cover_photo'] );
|
||||
$coverPhotoName = array_pop( $coverBits );
|
||||
}
|
||||
|
||||
/* Profile Fields */
|
||||
@@ -620,6 +637,11 @@ class _Invisioncommunity extends \IPS\convert\Software
|
||||
{
|
||||
$profileFields = array();
|
||||
}
|
||||
|
||||
/* Rename bit options so we can pass them through the conversion method */
|
||||
$row['ips_members_bitoptions'] = $row['members_bitoptions'];
|
||||
$row['ips_members_bitoptions2'] = $row['members_bitoptions2'];
|
||||
unset( $row['members_bitoptions'], $row['members_bitoptions2'] );
|
||||
|
||||
$path = $this->app->_session['more_info']['convertMembers']['upload_path'] . '/profile';
|
||||
$libraryClass->convertMember( $row, $profileFields, $profilePhotoName, $path, NULL, $coverPhotoName, $path );
|
||||
@@ -972,7 +994,7 @@ class _Invisioncommunity extends \IPS\convert\Software
|
||||
$coverFile = $row['cover_photo'] ? $this->app->_session['more_info']['convertClubs']['upload_path'] . '/' . $row['cover_photo'] : NULL;
|
||||
|
||||
$libraryClass->convertClub( $row, $iconFile, NULL, $coverFile );
|
||||
$libraryClass->setLastKeyValue( $row['id'] );
|
||||
$libraryClass->setLastKeyValue( $row['club_id'] );
|
||||
}
|
||||
}
|
||||
|
||||
@@ -996,6 +1018,26 @@ class _Invisioncommunity extends \IPS\convert\Software
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert club pages
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function convertClubPages()
|
||||
{
|
||||
$libraryClass = $this->getLibrary();
|
||||
$libraryClass::setKey( 'page_id' );
|
||||
|
||||
foreach( $this->fetch( 'core_club_pages', 'page_id' ) AS $row )
|
||||
{
|
||||
/* Remove non-standard columns */
|
||||
$this->unsetNonStandardColumns( $row, 'core_club_pages' );
|
||||
|
||||
$libraryClass->convertClubPage( $row );
|
||||
$libraryClass->setLastKeyValue( $row['page_id'] );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert attachments
|
||||
*
|
||||
@@ -1027,7 +1069,39 @@ class _Invisioncommunity extends \IPS\convert\Software
|
||||
/* Remove non-standard columns */
|
||||
$this->unsetNonStandardColumns( $row, 'core_attachments' );
|
||||
$this->unsetNonStandardColumns( $attachmentMap, 'core_attachments_map' );
|
||||
|
||||
|
||||
/* Attach Types */
|
||||
switch( $attachmentMap['location_key'] )
|
||||
{
|
||||
case 'core_Messaging':
|
||||
$attachmentMap['id1_type'] = 'core_message_topics';
|
||||
$attachmentMap['id2_type'] = 'core_message_posts';
|
||||
$attachmentMap['id2_from_parent'] = FALSE;
|
||||
break;
|
||||
case 'core_Signatures':
|
||||
$attachmentMap['id1_type'] = 'core_members';
|
||||
break;
|
||||
case 'core_CustomField':
|
||||
$attachmentMap['id1_type'] = 'core_members';
|
||||
$attachmentMap['id2_type'] = 'core_pfields_data';
|
||||
$attachmentMap['id2_from_parent'] = FALSE;
|
||||
break;
|
||||
case 'core_ClubPage':
|
||||
$attachmentMap['id1_type'] = 'core_club_page';
|
||||
break;
|
||||
case 'core_Announcement':
|
||||
$attachmentMap['id1_type'] = 'core_announcement';
|
||||
break;
|
||||
default:
|
||||
// Can't convert this type
|
||||
$libraryClass->setLastKeyValue( $row['attach_id'] );
|
||||
continue 2;
|
||||
break;
|
||||
}
|
||||
|
||||
/* This applies to all options */
|
||||
$attachmentMap['id1_from_parent'] = FALSE;
|
||||
|
||||
/* Remap rows */
|
||||
$name = explode( '/', $row['attach_location'] );
|
||||
$row['attach_container'] = isset( $name[1] ) ? $name[0] : NULL;
|
||||
@@ -1066,7 +1140,7 @@ class _Invisioncommunity extends \IPS\convert\Software
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief default language
|
||||
* @brief Default language
|
||||
*/
|
||||
protected $_defaultLanguage = NULL;
|
||||
|
||||
@@ -1086,14 +1160,14 @@ class _Invisioncommunity extends \IPS\convert\Software
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief word storage
|
||||
* @brief Word storage
|
||||
*/
|
||||
protected $_words = [];
|
||||
|
||||
/**
|
||||
* Get word from language system
|
||||
*
|
||||
* @param string $key word key
|
||||
* @param string $key Word key
|
||||
* @return string
|
||||
*/
|
||||
public function getWord( $key )
|
||||
@@ -1123,17 +1197,17 @@ class _Invisioncommunity extends \IPS\convert\Software
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief table schema storage
|
||||
* @brief Table schema storage
|
||||
*/
|
||||
protected $_schemas = array();
|
||||
|
||||
/**
|
||||
* Remove non-standard columns from row data
|
||||
*
|
||||
* @param array $row database result row
|
||||
* @param string $table table name
|
||||
* @param string $app app to check
|
||||
* @return string
|
||||
* @param array $row Database result row
|
||||
* @param string $table Table name
|
||||
* @param string $app App to check
|
||||
* @return void
|
||||
*/
|
||||
public function unsetNonStandardColumns( &$row, $table, $app=NULL )
|
||||
{
|
||||
@@ -1165,14 +1239,20 @@ class _Invisioncommunity extends \IPS\convert\Software
|
||||
* Check if we can redirect the legacy URLs from this software to the new locations
|
||||
*
|
||||
* @return NULL|\IPS\Http\Url
|
||||
* @todo The proxy.php redirection is not validating the hash that XenForo set previously, derived from the globalSalt and the option imageLinkProxyKey. We need
|
||||
* to either validate the hash (there is an open proxy concern), or we need to convert all calls to proxy.php in posted content to prevent broken images in posts.
|
||||
*/
|
||||
public function checkRedirects()
|
||||
{
|
||||
$url = \IPS\Request::i()->url();
|
||||
|
||||
if( preg_match( '#/ips4merge/profile/([0-9]+)-(.+?)#i', $url->data[ \IPS\Http\Url::COMPONENT_PATH ], $matches ) )
|
||||
if( !\stristr( $url->data[ \IPS\Http\Url::COMPONENT_PATH ], 'ic-merge-' . $this->app->app_id ) )
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* account for non-mod_rewrite links */
|
||||
$searchOn = \stristr( $url->data[ \IPS\Http\Url::COMPONENT_PATH ], 'index.php' ) ? $url->data[ \IPS\Http\Url::COMPONENT_QUERY ] : $url->data[ \IPS\Http\Url::COMPONENT_PATH ];
|
||||
|
||||
if( preg_match( '#/profile/([0-9]+)-(.+?)#i', $searchOn, $matches ) )
|
||||
{
|
||||
/* If we can't access profiles, don't bother trying to redirect */
|
||||
if( !\IPS\Member::loggedIn()->canAccessModule( \IPS\Application\Module::get( 'core', 'members' ) ) )
|
||||
|
||||
@@ -5,19 +5,22 @@
|
||||
* @author <a href='https://www.invisioncommunity.com'>Invision Power Services, Inc.</a>
|
||||
* @copyright (c) Invision Power Services, Inc.
|
||||
* @package Invision Community
|
||||
* @subpackage Converter
|
||||
* @subpackage convert
|
||||
* @since 21 Jan 2015
|
||||
*/
|
||||
|
||||
namespace IPS\convert\Software\Core;
|
||||
|
||||
/* To prevent PHP errors (extending class does not exist) revealing path */
|
||||
if ( !defined( '\IPS\SUITE_UNIQUE_KEY' ) )
|
||||
if ( !\defined( '\IPS\SUITE_UNIQUE_KEY' ) )
|
||||
{
|
||||
header( ( isset( $_SERVER['SERVER_PROTOCOL'] ) ? $_SERVER['SERVER_PROTOCOL'] : 'HTTP/1.0' ) . ' 403 Forbidden' );
|
||||
exit;
|
||||
}
|
||||
|
||||
/**
|
||||
* Joomla Core Converter
|
||||
*/
|
||||
class _Joomla extends \IPS\convert\Software
|
||||
{
|
||||
/**
|
||||
@@ -171,7 +174,7 @@ class _Joomla extends \IPS\convert\Software
|
||||
}
|
||||
|
||||
/* Now check for group promotions */
|
||||
if( count( $libraryClass->groupPromotions ) )
|
||||
if( \count( $libraryClass->groupPromotions ) )
|
||||
{
|
||||
foreach( $libraryClass->groupPromotions as $groupPromotion )
|
||||
{
|
||||
|
||||
@@ -5,19 +5,22 @@
|
||||
* @author <a href='https://www.invisioncommunity.com'>Invision Power Services, Inc.</a>
|
||||
* @copyright (c) Invision Power Services, Inc.
|
||||
* @package Invision Community
|
||||
* @subpackage Converter
|
||||
* @subpackage convert
|
||||
* @since 21 Jan 2015
|
||||
*/
|
||||
|
||||
namespace IPS\convert\Software\Core;
|
||||
|
||||
/* To prevent PHP errors (extending class does not exist) revealing path */
|
||||
if ( !defined( '\IPS\SUITE_UNIQUE_KEY' ) )
|
||||
if ( !\defined( '\IPS\SUITE_UNIQUE_KEY' ) )
|
||||
{
|
||||
header( ( isset( $_SERVER['SERVER_PROTOCOL'] ) ? $_SERVER['SERVER_PROTOCOL'] : 'HTTP/1.0' ) . ' 403 Forbidden' );
|
||||
exit;
|
||||
}
|
||||
|
||||
/**
|
||||
* MyBB Core Converter
|
||||
*/
|
||||
class _Mybb extends \IPS\convert\Software
|
||||
{
|
||||
/**
|
||||
@@ -88,11 +91,11 @@ class _Mybb extends \IPS\convert\Software
|
||||
),
|
||||
'convertPrivateMessages' => array(
|
||||
'table' => 'privatemessages',
|
||||
'where' => NULL
|
||||
'where' => array( 'fromid<>uid' )
|
||||
),
|
||||
'convertPrivateMessageReplies' => array(
|
||||
'table' => 'privatemessages',
|
||||
'where' => NULL,
|
||||
'where' => array( 'fromid<>uid' ),
|
||||
),
|
||||
'convertProfanityFilters' => array(
|
||||
'table' => 'badwords',
|
||||
@@ -293,17 +296,20 @@ class _Mybb extends \IPS\convert\Software
|
||||
/**
|
||||
* Fix post data
|
||||
*
|
||||
* @param string raw post data
|
||||
* @return string parsed post data
|
||||
* @param string $post Raw post data
|
||||
* @return string Parsed post data
|
||||
*/
|
||||
public static function fixPostData( $post )
|
||||
{
|
||||
/* Replace align tags with left/right/center/justify */
|
||||
$post = preg_replace( '/\[align=(justify|left|right)\](.+?)\[\/align\]/i', '[$1]$2[/$1]', $post );
|
||||
$post = preg_replace( '/\[align=(justify|left|center|right)\](.+?)\[\/align\]/i', '[$1]$2[/$1]', $post );
|
||||
|
||||
/* remove justify, since we don't support it */
|
||||
$post = str_replace( array( '[justify]', '[/justify]' ), '', $post );
|
||||
|
||||
/* Quotes */
|
||||
$post = preg_replace("#\[quote=('|\")(.+?)('|\") pid='(\d+)' dateline='(\d+)'\]#i", "[quote name=\"$2\" timestamp=\"$5\"]", $post);
|
||||
|
||||
return $post;
|
||||
}
|
||||
|
||||
@@ -544,12 +550,12 @@ class _Mybb extends \IPS\convert\Software
|
||||
'pf_desc' => $row['description'],
|
||||
'pf_content' => $options,
|
||||
'pf_not_null' => $row['required'],
|
||||
'pf_member_hide' => $row['profile'],
|
||||
'pf_member_hide' => $row['profile'] ? 'all' : 'hide',
|
||||
'pf_max_input' => $row['maxlength'],
|
||||
'pf_position' => $row['disporder'],
|
||||
'pf_show_on_reg' => $row['registration'],
|
||||
'pf_input_format' => '/' . $row['regex'] . '/i',
|
||||
'pf_admin_only' => ( $row['editableby'] == -1 ) ? 0 : 1, # MyBB allows you to define which groups can edit, so if this value is anything other than -1, assume it's admin only
|
||||
'pf_member_edit' => ( $row['editableby'] == -1 ) ? 1 : 0, # MyBB allows you to define which groups can edit, so if this value is anything other than -1, assume it's admin only
|
||||
'pf_multiple' => ( $theirType == 'multiselect' ) ? 1 : 0
|
||||
);
|
||||
|
||||
@@ -564,7 +570,7 @@ class _Mybb extends \IPS\convert\Software
|
||||
/**
|
||||
* Maps a MyBB Profile Field type to IPS
|
||||
*
|
||||
* @param string MyBB Type
|
||||
* @param string $type MyBB Type
|
||||
* @return string IPS Type
|
||||
*/
|
||||
protected function _fieldMap( $type )
|
||||
@@ -621,7 +627,7 @@ class _Mybb extends \IPS\convert\Software
|
||||
switch( $promotion['requirements'] )
|
||||
{
|
||||
case 'postcount':
|
||||
if ( !in_array( $promotion['posttype'], array( '>', '>=', '=' ) ) )
|
||||
if ( !\in_array( $promotion['posttype'], array( '>', '>=', '=' ) ) )
|
||||
{
|
||||
/* Bubble up */
|
||||
throw new \UnderflowException;
|
||||
@@ -631,7 +637,7 @@ class _Mybb extends \IPS\convert\Software
|
||||
break;
|
||||
|
||||
case 'timeregistered':
|
||||
if ( !in_array( $promotion['registeredtype'], array( '>', '>=', '=' ) ) )
|
||||
if ( !\in_array( $promotion['registeredtype'], array( '>', '>=', '=' ) ) )
|
||||
{
|
||||
throw new \UnderflowException;
|
||||
}
|
||||
@@ -685,7 +691,7 @@ class _Mybb extends \IPS\convert\Software
|
||||
}
|
||||
|
||||
/* Now check for group promotions */
|
||||
if( count( $libraryClass->groupPromotions ) )
|
||||
if( \count( $libraryClass->groupPromotions ) )
|
||||
{
|
||||
foreach( $libraryClass->groupPromotions as $groupPromotion )
|
||||
{
|
||||
@@ -794,7 +800,7 @@ class _Mybb extends \IPS\convert\Software
|
||||
|
||||
$info = array(
|
||||
'member_id' => $row['uid'],
|
||||
'name' => $row['username'],
|
||||
'name' => html_entity_decode( $row['username'], \ENT_QUOTES | \ENT_HTML5, 'UTF-8' ),
|
||||
'email' => $row['email'],
|
||||
'password' => $row['password'],
|
||||
'password_extra' => $row['salt'],
|
||||
@@ -806,7 +812,7 @@ class _Mybb extends \IPS\convert\Software
|
||||
'restrict_post' => $restrict_post,
|
||||
'bday_day' => str_pad( $bday_day, 2, '0', STR_PAD_LEFT ),
|
||||
'bday_month' => str_pad( $bday_month, 2, '0', STR_PAD_LEFT ),
|
||||
'bday_year' => $bday_year ? intval( $bday_year ) : NULL,
|
||||
'bday_year' => $bday_year ? \intval( $bday_year ) : NULL,
|
||||
'msg_count_new' => $row['unreadpms'],
|
||||
'msg_count_total' => $row['totalpms'],
|
||||
'msg_show_notification' => $row['pmnotify'],
|
||||
@@ -833,11 +839,20 @@ class _Mybb extends \IPS\convert\Software
|
||||
);
|
||||
|
||||
$pfields = array();
|
||||
foreach( $this->db->select( '*', 'userfields', array( "ufid=?", $row['uid'] ) ) AS $key => $field )
|
||||
try
|
||||
{
|
||||
$key = str_replace( 'fid', '', $key );
|
||||
$pfields[ $key ] = $field;
|
||||
foreach ( $this->db->select( '*', 'userfields', array( "ufid=?", $row['uid'] ) )->first() AS $key => $field )
|
||||
{
|
||||
if ( $key == 'ufid' )
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
$key = str_replace( 'fid', '', $key );
|
||||
$pfields[ $key ] = $field;
|
||||
}
|
||||
}
|
||||
catch( \UnderflowException $e ) {}
|
||||
|
||||
foreach( array( 'website', 'icq', 'aim', 'yahoo', 'skype', 'google' ) AS $pseudo )
|
||||
{
|
||||
@@ -875,21 +890,14 @@ class _Mybb extends \IPS\convert\Software
|
||||
/* Photo */
|
||||
$filename = NULL;
|
||||
$filepath = NULL;
|
||||
switch( $row['avatartype'] )
|
||||
if( $row['avatartype'] == 'upload' )
|
||||
{
|
||||
case 'gravatar':
|
||||
$info['pp_gravatar'] = $row['email'];
|
||||
$info['pp_photo_type'] = 'gravatar';
|
||||
break;
|
||||
|
||||
case 'upload':
|
||||
$info['pp_photo_type'] = 'custom';
|
||||
|
||||
$avatar = trim( '.', $row['avatar'] );
|
||||
$filepath = explode( '/', $avatar );
|
||||
$filename = array_pop( $filepath );
|
||||
$filepath = rtrim( $this->app->_session['more_info']['convertMembers']['photo_location'], '/' ) . implode( '/', $filepath );
|
||||
break;
|
||||
$info['pp_photo_type'] = 'custom';
|
||||
|
||||
$avatar = trim( $row['avatar'], '.' );
|
||||
$filepath = explode( '/', $avatar );
|
||||
$filename = parse_url( array_pop( $filepath ), PHP_URL_PATH );
|
||||
$filepath = rtrim( $this->app->_session['more_info']['convertMembers']['photo_location'], '/' ) . implode( '/', $filepath );
|
||||
}
|
||||
|
||||
$libraryClass->convertMember( $info, $pfields, $filename, $filepath );
|
||||
@@ -899,7 +907,7 @@ class _Mybb extends \IPS\convert\Software
|
||||
{
|
||||
$libraryClass->convertFollow( array(
|
||||
'follow_app' => 'core',
|
||||
'follow_area' => 'members',
|
||||
'follow_area' => 'member',
|
||||
'follow_rel_id' => $buddy,
|
||||
'follow_rel_id_type' => 'core_members',
|
||||
'follow_member_id' => $row['uid'],
|
||||
@@ -981,24 +989,29 @@ class _Mybb extends \IPS\convert\Software
|
||||
|
||||
$libraryClass::setKey( 'pmid' );
|
||||
|
||||
foreach( $this->fetch( 'privatemessages', 'pmid' ) AS $row )
|
||||
foreach( $this->fetch( 'privatemessages', 'pmid', array( 'fromid<>uid' ) ) AS $row )
|
||||
{
|
||||
/* My hands are kind of tied here... every individual message is stored separately, rather than grouped into conversations. In this instance, we'll bring over each individual message as it's own topic for archival purposes. */
|
||||
$recipients = \unserialize( $row['recipients'] );
|
||||
/* In MyBB, replies to messages are stored as full conversations, and there is a row for both the sender and the recipient. We'll bring over every reply for archival purposes, but if the fromid == uid, skip because otherwise we end up with duplicates. */
|
||||
|
||||
$topic = array(
|
||||
'mt_id' => $row['pmid'],
|
||||
'mt_date' => $row['dateline'],
|
||||
'mt_title' => $row['subject'],
|
||||
'mt_starter_id' => $row['uid'],
|
||||
'mt_starter_id' => $row['fromid'],
|
||||
'mt_start_time' => $row['dateline'],
|
||||
'mt_last_post_time' => $row['dateline'],
|
||||
'mt_to_count' => 1,
|
||||
);
|
||||
|
||||
$maps = array();
|
||||
$maps[$row['uid']] = array(
|
||||
'map_user_id' => $row['uid'],
|
||||
$maps[$row['fromid']] = array(
|
||||
'map_user_id' => $row['fromid'],
|
||||
'map_read_time' => $row['readtime'],
|
||||
'map_is_starter' => true
|
||||
);
|
||||
|
||||
$maps[$row['toid']] = array(
|
||||
'map_user_id' => $row['toid'],
|
||||
'map_read_time' => $row['readtime'],
|
||||
);
|
||||
|
||||
@@ -1019,14 +1032,14 @@ class _Mybb extends \IPS\convert\Software
|
||||
|
||||
$libraryClass::setKey( 'pmid' );
|
||||
|
||||
foreach( $this->fetch( 'privatemessages', 'pmid' ) AS $row )
|
||||
foreach( $this->fetch( 'privatemessages', 'pmid', array( 'fromid<>uid' ) ) AS $row )
|
||||
{
|
||||
$libraryClass->convertPrivateMessageReply( array(
|
||||
'msg_id' => $row['pmid'],
|
||||
'msg_topic_id' => $row['pmid'],
|
||||
'msg_date' => $row['dateline'],
|
||||
'msg_post' => $row['message'],
|
||||
'msg_author_id' => $row['uid'],
|
||||
'msg_author_id' => $row['fromid'],
|
||||
'msg_ip_address' => $row['ipaddress'],
|
||||
) );
|
||||
|
||||
|
||||
@@ -5,19 +5,22 @@
|
||||
* @author <a href='https://www.invisioncommunity.com'>Invision Power Services, Inc.</a>
|
||||
* @copyright (c) Invision Power Services, Inc.
|
||||
* @package Invision Community
|
||||
* @subpackage Converter
|
||||
* @subpackage convert
|
||||
* @since 6 December 2016
|
||||
*/
|
||||
|
||||
namespace IPS\convert\Software\Core;
|
||||
|
||||
/* To prevent PHP errors (extending class does not exist) revealing path */
|
||||
if ( !defined( '\IPS\SUITE_UNIQUE_KEY' ) )
|
||||
if ( !\defined( '\IPS\SUITE_UNIQUE_KEY' ) )
|
||||
{
|
||||
header( ( isset( $_SERVER['SERVER_PROTOCOL'] ) ? $_SERVER['SERVER_PROTOCOL'] : 'HTTP/1.0' ) . ' 403 Forbidden' );
|
||||
exit;
|
||||
}
|
||||
|
||||
/**
|
||||
* Photopost Core Converter
|
||||
*/
|
||||
class _Photopost extends \IPS\convert\Software
|
||||
{
|
||||
/**
|
||||
@@ -152,7 +155,7 @@ class _Photopost extends \IPS\convert\Software
|
||||
/**
|
||||
* Finish - Adds everything it needs to the queues and clears data store
|
||||
*
|
||||
* @return array Message to display
|
||||
* @return array Messages to display
|
||||
*/
|
||||
public function finish()
|
||||
{
|
||||
@@ -197,7 +200,7 @@ class _Photopost extends \IPS\convert\Software
|
||||
}
|
||||
|
||||
/* Now check for group promotions */
|
||||
if( count( $libraryClass->groupPromotions ) )
|
||||
if( \count( $libraryClass->groupPromotions ) )
|
||||
{
|
||||
foreach( $libraryClass->groupPromotions as $groupPromotion )
|
||||
{
|
||||
@@ -267,11 +270,10 @@ class _Photopost extends \IPS\convert\Software
|
||||
'pf_desc' => '',
|
||||
'pf_type' => 'Text',
|
||||
'pf_content' => '[]',
|
||||
'pf_member_hide' => 0,
|
||||
'pf_member_hide' => 'all',
|
||||
'pf_max_input' => 255,
|
||||
'pf_member_edit' => 1,
|
||||
'pf_show_on_reg' => 0,
|
||||
'pf_admin_only' => 0,
|
||||
) );
|
||||
}
|
||||
|
||||
|
||||
@@ -5,19 +5,22 @@
|
||||
* @author <a href='https://www.invisioncommunity.com'>Invision Power Services, Inc.</a>
|
||||
* @copyright (c) Invision Power Services, Inc.
|
||||
* @package Invision Community
|
||||
* @subpackage Converter
|
||||
* @subpackage convert
|
||||
* @since 21 Jan 2015
|
||||
*/
|
||||
|
||||
namespace IPS\convert\Software\Core;
|
||||
|
||||
/* To prevent PHP errors (extending class does not exist) revealing path */
|
||||
if ( !defined( '\IPS\SUITE_UNIQUE_KEY' ) )
|
||||
if ( !\defined( '\IPS\SUITE_UNIQUE_KEY' ) )
|
||||
{
|
||||
header( ( isset( $_SERVER['SERVER_PROTOCOL'] ) ? $_SERVER['SERVER_PROTOCOL'] : 'HTTP/1.0' ) . ' 403 Forbidden' );
|
||||
exit;
|
||||
}
|
||||
|
||||
/**
|
||||
* PhpBB Core Converter
|
||||
*/
|
||||
class _Phpbb extends \IPS\convert\Software
|
||||
{
|
||||
/**
|
||||
@@ -101,17 +104,20 @@ class _Phpbb extends \IPS\convert\Software
|
||||
/**
|
||||
* Allows software to add additional menu row options
|
||||
*
|
||||
* @param array $rows Existing rows
|
||||
* @return array
|
||||
*/
|
||||
public function extraMenuRows( $rows )
|
||||
public function extraMenuRows()
|
||||
{
|
||||
if( isset( $rows['convertBanfilters'] ) )
|
||||
{
|
||||
$rows['convertBanfilters2'] = $rows['convertBanfilters'];
|
||||
$rows['convertBanfilters2']['step_method'] = 'convertBanfilters2';
|
||||
$rows['convertBanfilters2']['source_rows'] = array( 'table' => static::canConvert()['convertBanfilters2']['table'], 'where' => static::canConvert()['convertBanfilters2']['where'] );
|
||||
}
|
||||
$rows = array();
|
||||
$rows['convertBanfilters2'] = array(
|
||||
'step_title' => 'convert_banfilters',
|
||||
'step_method' => 'convertBanfilters2',
|
||||
'ips_rows' => \IPS\Db::i()->select( 'COUNT(*)', 'core_banfilters' ),
|
||||
'source_rows' => array( 'table' => static::canConvert()['convertBanfilters2']['table'], 'where' => static::canConvert()['convertBanfilters2']['where'] ),
|
||||
'per_cycle' => 200,
|
||||
'dependencies' => array( 'convertBanfilters' ),
|
||||
'link_type' => 'core_banfilters'
|
||||
);
|
||||
|
||||
return $rows;
|
||||
}
|
||||
@@ -131,9 +137,16 @@ class _Phpbb extends \IPS\convert\Software
|
||||
{
|
||||
case 'banfilters':
|
||||
case 'disallow':
|
||||
$count = 0;
|
||||
$count += $this->db->select( 'COUNT(*)', 'banlist', array( "ban_userid=?", 0 ) )->first();
|
||||
$count += $this->db->select( 'COUNT(*)', 'disallow' )->first();
|
||||
try
|
||||
{
|
||||
$count = 0;
|
||||
$count += $this->db->select( 'COUNT(*)', 'banlist', array( "ban_userid=?", 0 ) )->first();
|
||||
$count += $this->db->select( 'COUNT(*)', 'disallow' )->first();
|
||||
}
|
||||
catch( \Exception $e )
|
||||
{
|
||||
throw new \IPS\convert\Exception( sprintf( \IPS\Member::loggedIn()->language()->get( 'could_not_count_rows' ), $table ) );
|
||||
}
|
||||
return $count;
|
||||
break;
|
||||
|
||||
@@ -261,15 +274,28 @@ class _Phpbb extends \IPS\convert\Software
|
||||
|
||||
case 'convertMembers':
|
||||
$return['convertMembers'] = array();
|
||||
|
||||
/* We can only retain one type of photo */
|
||||
$return['convertMembers']['photo_hash'] = array(
|
||||
'field_class' => 'IPS\\Helpers\\Form\\Text',
|
||||
'field_default' => NULL,
|
||||
'field_required' => TRUE,
|
||||
'field_extra' => array(),
|
||||
'field_hint' => \IPS\Member::loggedIn()->language()->addToStack('convert_phpbb_randstring'),
|
||||
);
|
||||
|
||||
try
|
||||
{
|
||||
/* Try to auto detect the salt */
|
||||
$salt = $this->db->select( 'config_value', 'config', array( 'config_name=?', 'avatar_salt' ) )->first();
|
||||
|
||||
if( empty( $salt ) )
|
||||
{
|
||||
throw new \UnderflowException();
|
||||
}
|
||||
}
|
||||
catch( \UnderflowException $e )
|
||||
{
|
||||
/* We can only retain one type of photo */
|
||||
$return['convertMembers']['photo_hash'] = array(
|
||||
'field_class' => 'IPS\\Helpers\\Form\\Text',
|
||||
'field_default' => NULL,
|
||||
'field_required' => TRUE,
|
||||
'field_extra' => array(),
|
||||
'field_hint' => \IPS\Member::loggedIn()->language()->addToStack('convert_phpbb_randstring'),
|
||||
);
|
||||
}
|
||||
|
||||
/* Find out where the photos live */
|
||||
\IPS\Member::loggedIn()->language()->words['photo_location_desc'] = \IPS\Member::loggedIn()->language()->addToStack( 'photo_location_nodb_desc' );
|
||||
@@ -353,8 +379,8 @@ class _Phpbb extends \IPS\convert\Software
|
||||
/**
|
||||
* Fix post data
|
||||
*
|
||||
* @param string raw post data
|
||||
* @return string parsed post data
|
||||
* @param string $post Raw post data
|
||||
* @return string Parsed post data
|
||||
*/
|
||||
public static function fixPostData( $post )
|
||||
{
|
||||
@@ -524,7 +550,7 @@ class _Phpbb extends \IPS\convert\Software
|
||||
'pf_type' => $type,
|
||||
'pf_content' => $default,
|
||||
'pf_not_null' => $row['field_required'],
|
||||
'pf_member_hide' => $row['field_hide'],
|
||||
'pf_member_hide' => $row['field_hide'] ? 'hide' : 'all',
|
||||
'pf_max_input' => ( $field_type == 'dropdown' ) ? NULL : $row['field_maxlen'], # ignore this for selects
|
||||
'pf_member_edit' => $row['field_active'],
|
||||
'pf_position' => $row['field_order'],
|
||||
@@ -579,7 +605,7 @@ class _Phpbb extends \IPS\convert\Software
|
||||
}
|
||||
|
||||
/* Now check for group promotions */
|
||||
if( count( $libraryClass->groupPromotions ) )
|
||||
if( \count( $libraryClass->groupPromotions ) )
|
||||
{
|
||||
foreach( $libraryClass->groupPromotions as $groupPromotion )
|
||||
{
|
||||
@@ -596,8 +622,22 @@ class _Phpbb extends \IPS\convert\Software
|
||||
public function convertMembers()
|
||||
{
|
||||
$libraryClass = $this->getLibrary();
|
||||
|
||||
$libraryClass::setKey( 'user_id' );
|
||||
|
||||
try
|
||||
{
|
||||
/* Try to auto detect the salt */
|
||||
$avatarSalt = $this->db->select( 'config_value', 'config', array( 'config_name=?', 'avatar_salt' ) )->first();
|
||||
|
||||
if( empty( $avatarSalt ) )
|
||||
{
|
||||
throw new \UnderflowException();
|
||||
}
|
||||
}
|
||||
catch( \UnderflowException $e )
|
||||
{
|
||||
$avatarSalt = rtrim( $this->app->_session['more_info']['convertMembers']['photo_hash'], '_' );
|
||||
}
|
||||
|
||||
foreach( $this->fetch( 'users', 'user_id', array( "user_type<>?", 2 ) ) AS $row )
|
||||
{
|
||||
@@ -694,7 +734,7 @@ class _Phpbb extends \IPS\convert\Software
|
||||
if ( $row['user_avatar_type'] )
|
||||
{
|
||||
/* Is it numeric? Apparently phpBB doesn't clean up after itself. */
|
||||
if ( is_numeric( $row['user_avatar_type'] ) )
|
||||
if ( \is_numeric( $row['user_avatar_type'] ) )
|
||||
{
|
||||
switch( $row['user_avatar_type'] )
|
||||
{
|
||||
@@ -718,12 +758,7 @@ class _Phpbb extends \IPS\convert\Software
|
||||
$fileext = explode( '.', $row['user_avatar'] );
|
||||
$fileext = array_pop( $fileext );
|
||||
$filepath = $this->app->_session['more_info']['convertMembers']['photo_location'];
|
||||
$filename = $this->app->_session['more_info']['convertMembers']['photo_hash'] . '_' . $row['user_id'] . '.' . $fileext;
|
||||
break;
|
||||
|
||||
case 'avatar.driver.gravatar':
|
||||
$info['pp_photo_type'] = 'gravatar';
|
||||
$info['pp_gravatar'] = $row['user_avatar'];
|
||||
$filename = $avatarSalt . '_' . $row['user_id'] . '.' . $fileext;
|
||||
break;
|
||||
|
||||
case 'avatar.driver.remote':
|
||||
@@ -772,7 +807,7 @@ class _Phpbb extends \IPS\convert\Software
|
||||
|
||||
/* PM Folders */
|
||||
$pmFolders = iterator_to_array( $this->db->select( 'folder_name', 'privmsgs_folder', array( 'user_id=?', $row['user_id'] ) ) );
|
||||
$info['pconversation_filters'] = count( $pmFolders ) ? $pmFolders : NULL;
|
||||
$info['pconversation_filters'] = \count( $pmFolders ) ? $pmFolders : NULL;
|
||||
|
||||
/* Finally */
|
||||
$libraryClass->convertMember( $info, $pfields, $filename, $filepath );
|
||||
@@ -782,7 +817,7 @@ class _Phpbb extends \IPS\convert\Software
|
||||
{
|
||||
$libraryClass->convertFollow( array(
|
||||
'follow_app' => 'core',
|
||||
'follow_area' => 'members',
|
||||
'follow_area' => 'member',
|
||||
'follow_rel_id' => $follower['zebra_id'],
|
||||
'follow_rel_id_type' => 'core_members',
|
||||
'follow_member_id' => $follower['user_id'],
|
||||
@@ -930,7 +965,7 @@ class _Phpbb extends \IPS\convert\Software
|
||||
}
|
||||
|
||||
/* If Type is null - skip */
|
||||
if ( is_null( $type ) )
|
||||
if ( \is_null( $type ) )
|
||||
{
|
||||
$libraryClass->setLastKeyValue( $row['ban_id'] );
|
||||
continue;
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
* @author <a href='https://www.invisioncommunity.com'>Invision Power Services, Inc.</a>
|
||||
* @copyright (c) Invision Power Services, Inc.
|
||||
* @package Invision Community
|
||||
* @subpackage Converter
|
||||
* @subpackage convert
|
||||
* @since 6 December 2016
|
||||
* @note Only redirect scripts are supported right now
|
||||
*/
|
||||
@@ -13,12 +13,15 @@
|
||||
namespace IPS\convert\Software\Core;
|
||||
|
||||
/* To prevent PHP errors (extending class does not exist) revealing path */
|
||||
if ( !defined( '\IPS\SUITE_UNIQUE_KEY' ) )
|
||||
if ( !\defined( '\IPS\SUITE_UNIQUE_KEY' ) )
|
||||
{
|
||||
header( ( isset( $_SERVER['SERVER_PROTOCOL'] ) ? $_SERVER['SERVER_PROTOCOL'] : 'HTTP/1.0' ) . ' 403 Forbidden' );
|
||||
exit;
|
||||
}
|
||||
|
||||
/**
|
||||
* PhpMyForum Core Converter
|
||||
*/
|
||||
class _Phpmyforum extends \IPS\convert\Software
|
||||
{
|
||||
/**
|
||||
|
||||
@@ -5,19 +5,22 @@
|
||||
* @author <a href='https://www.invisioncommunity.com'>Invision Power Services, Inc.</a>
|
||||
* @copyright (c) Invision Power Services, Inc.
|
||||
* @package Invision Community
|
||||
* @subpackage Converter
|
||||
* @subpackage convert
|
||||
* @since 21 Jan 2015
|
||||
*/
|
||||
|
||||
namespace IPS\convert\Software\Core;
|
||||
|
||||
/* To prevent PHP errors (extending class does not exist) revealing path */
|
||||
if ( !defined( '\IPS\SUITE_UNIQUE_KEY' ) )
|
||||
if ( !\defined( '\IPS\SUITE_UNIQUE_KEY' ) )
|
||||
{
|
||||
header( ( isset( $_SERVER['SERVER_PROTOCOL'] ) ? $_SERVER['SERVER_PROTOCOL'] : 'HTTP/1.0' ) . ' 403 Forbidden' );
|
||||
exit;
|
||||
}
|
||||
|
||||
/**
|
||||
* PunBB Core Converter
|
||||
*/
|
||||
class _Punbb extends \IPS\convert\Software
|
||||
{
|
||||
/**
|
||||
@@ -189,8 +192,8 @@ class _Punbb extends \IPS\convert\Software
|
||||
/**
|
||||
* Fix post data
|
||||
*
|
||||
* @param string raw post data
|
||||
* @return string parsed post data
|
||||
* @param string $post Raw post data
|
||||
* @return string Parsed post data
|
||||
*/
|
||||
public static function fixPostData( $post )
|
||||
{
|
||||
@@ -239,7 +242,7 @@ class _Punbb extends \IPS\convert\Software
|
||||
}
|
||||
|
||||
/* Now check for group promotions */
|
||||
if( count( $libraryClass->groupPromotions ) )
|
||||
if( \count( $libraryClass->groupPromotions ) )
|
||||
{
|
||||
foreach( $libraryClass->groupPromotions as $groupPromotion )
|
||||
{
|
||||
@@ -304,11 +307,10 @@ class _Punbb extends \IPS\convert\Software
|
||||
'pf_desc' => '',
|
||||
'pf_type' => 'Text',
|
||||
'pf_content' => '[]',
|
||||
'pf_member_hide' => 0,
|
||||
'pf_member_hide' => 'all',
|
||||
'pf_max_input' => 255,
|
||||
'pf_member_edit' => 1,
|
||||
'pf_show_on_reg' => 0,
|
||||
'pf_admin_only' => 0,
|
||||
) );
|
||||
}
|
||||
|
||||
|
||||
@@ -4,20 +4,22 @@
|
||||
* @author <a href='https://www.invisioncommunity.com'>Invision Power Services, Inc.</a>
|
||||
* @copyright (c) Invision Power Services, Inc.
|
||||
* @package IPS Social Suite
|
||||
* @subpackage Converter
|
||||
* @subpackage convert
|
||||
* @since 21 Jan 2015
|
||||
* @version
|
||||
*/
|
||||
|
||||
namespace IPS\convert\Software\Core;
|
||||
|
||||
/* To prevent PHP errors (extending class does not exist) revealing path */
|
||||
if ( !defined( '\IPS\SUITE_UNIQUE_KEY' ) )
|
||||
if ( !\defined( '\IPS\SUITE_UNIQUE_KEY' ) )
|
||||
{
|
||||
header( ( isset( $_SERVER['SERVER_PROTOCOL'] ) ? $_SERVER['SERVER_PROTOCOL'] : 'HTTP/1.0' ) . ' 403 Forbidden' );
|
||||
exit;
|
||||
}
|
||||
|
||||
/**
|
||||
* SMF Core Converter
|
||||
*/
|
||||
class _Smf extends \IPS\convert\Software
|
||||
{
|
||||
/**
|
||||
@@ -132,6 +134,10 @@ class _Smf extends \IPS\convert\Software
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
catch( \Exception $e )
|
||||
{
|
||||
throw new \IPS\convert\Exception( sprintf( \IPS\Member::loggedIn()->language()->get( 'could_not_count_rows' ), $table ) );
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
@@ -276,7 +282,7 @@ class _Smf extends \IPS\convert\Software
|
||||
/**
|
||||
* Finish - Adds everything it needs to the queues and clears data store
|
||||
*
|
||||
* @return array Message to display
|
||||
* @return array Messages to display
|
||||
*/
|
||||
public function finish()
|
||||
{
|
||||
@@ -306,8 +312,8 @@ class _Smf extends \IPS\convert\Software
|
||||
/**
|
||||
* Fix post data
|
||||
*
|
||||
* @param string raw post data
|
||||
* @return string parsed post data
|
||||
* @param string $post Raw post data
|
||||
* @return string Parsed post data
|
||||
*/
|
||||
public static function fixPostData( $post )
|
||||
{
|
||||
@@ -321,7 +327,7 @@ class _Smf extends \IPS\convert\Software
|
||||
$post = preg_replace("#\[img width=(\d+)(?: height=(\d+))?\]([a-zA-Z0-9.:\-/%\?&_=~\#\(\);:]+)\[\/img\]#i", "[img]$3[/img]", $post);
|
||||
|
||||
//Quotes
|
||||
$post = preg_replace("#\[quote author=(.+?) link=(.+?)=(\d+)\.msg(\d+)(.+?)date=(\d+)\](.+)\[\/quote\]#i", "[quote name=\"$1\" post=\"$4\" timestamp=\"$6\"]$7[/quote]", $post);
|
||||
$post = preg_replace("#\[quote author=(.+?) link=(.+?)=(\d+)\.msg(\d+)(.+?)date=(\d+)\](.+)\[\/quote\]#i", "[quote name=\"$1\" timestamp=\"$6\"]$7[/quote]", $post);
|
||||
|
||||
return $post;
|
||||
}
|
||||
@@ -524,15 +530,14 @@ class _Smf extends \IPS\convert\Software
|
||||
'pf_type' => $type,
|
||||
'pf_name' => $row['field_name'],
|
||||
'pf_desc' => $row['field_desc'],
|
||||
'pf_content' => ( in_array( $row['field_type'], array( 'select', 'radio' ) ) ) ? json_encode( explode( ',', $row['field_options'] ) ) : NULL,
|
||||
'pf_content' => ( \in_array( $row['field_type'], array( 'select', 'radio' ) ) ) ? json_encode( explode( ',', $row['field_options'] ) ) : NULL,
|
||||
'pf_not_null' => ( $row['show_reg'] == 2 ) ? 1 : 0,
|
||||
'pf_member_hide' => ( $row['private'] >= 3 ) ? 1 : 0,
|
||||
'pf_max_input' => ( !in_array( $row['field_type'], array( 'select', 'radio', 'check' ) ) ) ? $row['field_length'] : NULL,
|
||||
'pf_member_hide' => ( $row['private'] >= 3 ) ? 'hide' : 'all',
|
||||
'pf_max_input' => ( !\in_array( $row['field_type'], array( 'select', 'radio', 'check' ) ) ) ? $row['field_length'] : NULL,
|
||||
'pf_member_edit' => ( $row['private'] < 4 ) ? 1 : 0,
|
||||
'pf_position' => $row['placement'],
|
||||
'pf_show_on_reg' => ( $row['show_reg'] >= 1 ) ? 1 : 0,
|
||||
'pf_input_format' => ( mb_substr( $row['mask'], 0, 5 ) == 'regex' ) ? str_replace( 'regex', '', $row['mask'] ) : NULL,
|
||||
'pf_admin_only' => ( $row['private'] == 4 ) ? 1 : 0,
|
||||
);
|
||||
|
||||
$merge = ( $this->app->_session['more_info']['convertProfileFields']["map_pfield_{$row['id_field']}"] != 'none' ) ? $this->app->_session['more_info']['convertProfileFields']["map_pfield_{$row['id_field']}"] : NULL;
|
||||
@@ -581,7 +586,7 @@ class _Smf extends \IPS\convert\Software
|
||||
}
|
||||
|
||||
/* Now check for group promotions */
|
||||
if( count( $libraryClass->groupPromotions ) )
|
||||
if( \count( $libraryClass->groupPromotions ) )
|
||||
{
|
||||
foreach( $libraryClass->groupPromotions as $groupPromotion )
|
||||
{
|
||||
|
||||
@@ -4,20 +4,22 @@
|
||||
* @author <a href='https://www.invisioncommunity.com'>Invision Power Services, Inc.</a>
|
||||
* @copyright (c) Invision Power Services, Inc.
|
||||
* @package IPS Social Suite
|
||||
* @subpackage Converter
|
||||
* @subpackage convert
|
||||
* @since 21 Jan 2015
|
||||
* @version
|
||||
*/
|
||||
|
||||
namespace IPS\convert\Software\Core;
|
||||
|
||||
/* To prevent PHP errors (extending class does not exist) revealing path */
|
||||
if ( !defined( '\IPS\SUITE_UNIQUE_KEY' ) )
|
||||
if ( !\defined( '\IPS\SUITE_UNIQUE_KEY' ) )
|
||||
{
|
||||
header( ( isset( $_SERVER['SERVER_PROTOCOL'] ) ? $_SERVER['SERVER_PROTOCOL'] : 'HTTP/1.0' ) . ' 403 Forbidden' );
|
||||
exit;
|
||||
}
|
||||
|
||||
/**
|
||||
* UBBThreads Core Converter
|
||||
*/
|
||||
class _UBBthreads extends \IPS\convert\Software
|
||||
{
|
||||
/**
|
||||
@@ -78,7 +80,7 @@ class _UBBthreads extends \IPS\convert\Software
|
||||
public static function softwareKey()
|
||||
{
|
||||
/* Child classes must override this method */
|
||||
return "UBBthreads";
|
||||
return "ubbthreads";
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -136,11 +138,11 @@ class _UBBthreads extends \IPS\convert\Software
|
||||
/**
|
||||
* Allows software to add additional menu row options
|
||||
*
|
||||
* @param array $rows Existing rows
|
||||
* @return array
|
||||
*/
|
||||
public function extraMenuRows( $rows )
|
||||
public function extraMenuRows()
|
||||
{
|
||||
$rows = array();
|
||||
$count = $this->countRows( static::canConvert()['convertMembersFollowers']['table'], static::canConvert()['convertMembersFollowers']['where'] );
|
||||
|
||||
if( $count )
|
||||
@@ -150,7 +152,7 @@ class _UBBthreads extends \IPS\convert\Software
|
||||
'step_title' => 'convert_follows',
|
||||
'ips_rows' => \IPS\Db::i()->select( 'COUNT(*)', 'core_follow', array( 'follow_app=? and follow_area=?', 'core', 'member' ) ),
|
||||
'source_rows' => $count,
|
||||
'per_cycle' => 500,
|
||||
'per_cycle' => 200,
|
||||
'dependencies' => array( 'convertMembers' ),
|
||||
'link_type' => 'core_follow',
|
||||
);
|
||||
@@ -208,7 +210,7 @@ class _UBBthreads extends \IPS\convert\Software
|
||||
/**
|
||||
* Attempt to convert a textual date(time) representation to a DateTime instance
|
||||
*
|
||||
* @param string $date
|
||||
* @param string $date Date to try to convert
|
||||
* @return \IPS\DateTime|null
|
||||
*/
|
||||
protected function stringToDateTime( $date )
|
||||
@@ -358,12 +360,13 @@ class _UBBthreads extends \IPS\convert\Software
|
||||
/**
|
||||
* Fix post data
|
||||
*
|
||||
* @param string raw post data
|
||||
* @return string parsed post data
|
||||
* @param string $post Raw post data
|
||||
* @return string Parsed post data
|
||||
*/
|
||||
public static function fixPostData( $post )
|
||||
{
|
||||
$post = preg_replace( "#\[quote=(.+?)\]#i", "[quote name=\"$1\"]", $post );
|
||||
$post = preg_replace( '#\[img:(left|center|right)\](.+?)\[\/img\]#i', '[$1][img]$2[/img][/$1]', $post );
|
||||
$post = str_ireplace( [ "[image]", '[/image]', '[size:', '[color:' ], [ '[img]', '[/img]', '[size=', '[color=' ], $post );
|
||||
|
||||
return $post;
|
||||
@@ -457,7 +460,7 @@ class _UBBthreads extends \IPS\convert\Software
|
||||
|
||||
foreach ( $this->fetch( 'GROUPS', 'GROUP_ID', static::$groupsWhere ) as $row )
|
||||
{
|
||||
/* @TODO: Can we enable custom titles per group? */
|
||||
/* @todo: Can we enable custom titles per group? */
|
||||
$info = array(
|
||||
'g_id' => $row['GROUP_ID'],
|
||||
'g_name' => $row['GROUP_NAME'],
|
||||
@@ -470,7 +473,7 @@ class _UBBthreads extends \IPS\convert\Software
|
||||
}
|
||||
|
||||
/* Now check for group promotions */
|
||||
if( count( $libraryClass->groupPromotions ) )
|
||||
if( \count( $libraryClass->groupPromotions ) )
|
||||
{
|
||||
foreach( $libraryClass->groupPromotions as $groupPromotion )
|
||||
{
|
||||
@@ -604,11 +607,10 @@ class _UBBthreads extends \IPS\convert\Software
|
||||
'pf_desc' => '',
|
||||
'pf_type' => 'Text',
|
||||
'pf_content' => '[]',
|
||||
'pf_member_hide' => 0,
|
||||
'pf_member_hide' => 'all',
|
||||
'pf_max_input' => 255,
|
||||
'pf_member_edit' => 1,
|
||||
'pf_show_on_reg' => 0,
|
||||
'pf_admin_only' => 0,
|
||||
) );
|
||||
}
|
||||
|
||||
@@ -678,7 +680,7 @@ class _UBBthreads extends \IPS\convert\Software
|
||||
foreach ( $this->fetch( 'USER_TITLES', 'USER_TITLE_ID' ) as $row )
|
||||
{
|
||||
/**
|
||||
* @TODO: We should probably prompt to keep or overwrite existing titles, since this can currently result...
|
||||
* @todo: We should probably prompt to keep or overwrite existing titles, since this can currently result...
|
||||
* ...in duplicate entries for the same post counts if the local rows are not dropped
|
||||
*/
|
||||
$libraryClass->convertRank( array(
|
||||
|
||||
@@ -4,19 +4,22 @@
|
||||
* @author <a href='https://www.invisioncommunity.com'>Invision Power Services, Inc.</a>
|
||||
* @copyright (c) Invision Power Services, Inc.
|
||||
* @package IPS Social Suite
|
||||
* @subpackage Converter
|
||||
* @subpackage convert
|
||||
* @since 21 Jan 2015
|
||||
*/
|
||||
|
||||
namespace IPS\convert\Software\Core;
|
||||
|
||||
/* To prevent PHP errors (extending class does not exist) revealing path */
|
||||
if ( !defined( '\IPS\SUITE_UNIQUE_KEY' ) )
|
||||
if ( !\defined( '\IPS\SUITE_UNIQUE_KEY' ) )
|
||||
{
|
||||
header( ( isset( $_SERVER['SERVER_PROTOCOL'] ) ? $_SERVER['SERVER_PROTOCOL'] : 'HTTP/1.0' ) . ' 403 Forbidden' );
|
||||
exit;
|
||||
}
|
||||
|
||||
/**
|
||||
* Vanilla Core Converter
|
||||
*/
|
||||
class _Vanilla extends \IPS\convert\Software
|
||||
{
|
||||
/**
|
||||
@@ -49,7 +52,9 @@ class _Vanilla extends \IPS\convert\Software
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param \IPS\convert\App The application to reference for database and other information.
|
||||
* @param \IPS\convert\App $app The application to reference for database and other information.
|
||||
* @param bool $needDB Establish a DB connection
|
||||
* @return void
|
||||
* @throws \InvalidArgumentException
|
||||
*/
|
||||
public function __construct( \IPS\convert\App $app, $needDB=TRUE )
|
||||
@@ -173,7 +178,7 @@ class _Vanilla extends \IPS\convert\Software
|
||||
* Attempt to convert a MySQL datetime string into a unix timestamp
|
||||
*
|
||||
* @param string $date Date(Time) string
|
||||
* @return int|null Timestamp on successful conversion, otherwise NULL
|
||||
* @return \IPS\DateTime Timestamp on successful conversion, otherwise NULL
|
||||
*/
|
||||
public static function mysqlToDateTime( $date )
|
||||
{
|
||||
@@ -300,7 +305,7 @@ class _Vanilla extends \IPS\convert\Software
|
||||
/**
|
||||
* Finish - Adds everything it needs to the queues and clears data store
|
||||
*
|
||||
* @return string Message to display
|
||||
* @return array Messages to display
|
||||
*/
|
||||
public function finish()
|
||||
{
|
||||
@@ -333,8 +338,8 @@ class _Vanilla extends \IPS\convert\Software
|
||||
/**
|
||||
* Fix post data
|
||||
*
|
||||
* @param string raw post data
|
||||
* @return string parsed post data
|
||||
* @param string $post Raw post data
|
||||
* @return string Parsed post data
|
||||
*/
|
||||
public static function fixPostData( $post )
|
||||
{
|
||||
@@ -371,7 +376,7 @@ class _Vanilla extends \IPS\convert\Software
|
||||
}
|
||||
|
||||
/* Now check for group promotions */
|
||||
if( count( $libraryClass->groupPromotions ) )
|
||||
if( \count( $libraryClass->groupPromotions ) )
|
||||
{
|
||||
foreach( $libraryClass->groupPromotions as $groupPromotion )
|
||||
{
|
||||
@@ -459,7 +464,7 @@ class _Vanilla extends \IPS\convert\Software
|
||||
}
|
||||
|
||||
/* Finally */
|
||||
$libraryClass->convertMember( $info, NULL, $filename, $filepath );
|
||||
$libraryClass->convertMember( $info, array(), $filename, $filepath );
|
||||
$libraryClass->setLastKeyValue( $row['UserID'] );
|
||||
}
|
||||
}
|
||||
@@ -517,7 +522,7 @@ class _Vanilla extends \IPS\convert\Software
|
||||
'mt_date' => static::mysqlToDateTime( $row['DateInserted'] ),
|
||||
'mt_starter_id' => $row['InsertUserID'],
|
||||
'mt_last_post_time' => static::mysqlToDateTime( $row['DateUpdated'] ),
|
||||
'mt_to_count' => ( isset( $row['CountParticipants'] ) ) ? $row['CountParticipants'] : count( \unserialize( $row['Contributors'] ) ),
|
||||
'mt_to_count' => ( isset( $row['CountParticipants'] ) ) ? $row['CountParticipants'] : \count( \unserialize( $row['Contributors'] ) ),
|
||||
'mt_replies' => $row['CountMessages'],
|
||||
);
|
||||
|
||||
|
||||
@@ -5,19 +5,22 @@
|
||||
* @author <a href='https://www.invisioncommunity.com'>Invision Power Services, Inc.</a>
|
||||
* @copyright (c) Invision Power Services, Inc.
|
||||
* @package Invision Community
|
||||
* @subpackage Converter
|
||||
* @subpackage convert
|
||||
* @since 21 Jan 2015
|
||||
*/
|
||||
|
||||
namespace IPS\convert\Software\Core;
|
||||
|
||||
/* To prevent PHP errors (extending class does not exist) revealing path */
|
||||
if ( !defined( '\IPS\SUITE_UNIQUE_KEY' ) )
|
||||
if ( !\defined( '\IPS\SUITE_UNIQUE_KEY' ) )
|
||||
{
|
||||
header( ( isset( $_SERVER['SERVER_PROTOCOL'] ) ? $_SERVER['SERVER_PROTOCOL'] : 'HTTP/1.0' ) . ' 403 Forbidden' );
|
||||
exit;
|
||||
}
|
||||
|
||||
/**
|
||||
* vBulletin Core Converter
|
||||
*/
|
||||
class _Vbulletin extends \IPS\convert\Software
|
||||
{
|
||||
/**
|
||||
@@ -38,8 +41,8 @@ class _Vbulletin extends \IPS\convert\Software
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param \IPS\convert\App The application to reference for database and other information.
|
||||
* @param bool Establish a DB connection
|
||||
* @param \IPS\convert\App $app The application to reference for database and other information.
|
||||
* @param bool $needDB Establish a DB connection
|
||||
* @return void
|
||||
* @throws \InvalidArgumentException
|
||||
*/
|
||||
@@ -65,10 +68,9 @@ class _Vbulletin extends \IPS\convert\Software
|
||||
static::$isLegacy = FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* If this is vB4, what is the content type ID for posts? */
|
||||
if ( static::$postContentType === NULL AND ( static::$isLegacy === FALSE OR is_null( static::$isLegacy ) ) )
|
||||
if ( static::$postContentType === NULL AND ( static::$isLegacy === FALSE OR \is_null( static::$isLegacy ) ) )
|
||||
{
|
||||
static::$postContentType = $this->db->select( 'contenttypeid', 'contenttype', array( "class=?", 'Post' ) )->first();
|
||||
}
|
||||
@@ -155,7 +157,7 @@ class _Vbulletin extends \IPS\convert\Software
|
||||
),
|
||||
'convertPrivateMessageReplies' => array(
|
||||
'table' => 'pm',
|
||||
'where' => array( 'folderid!=?', -1 )
|
||||
'where' => array( 'NOT (folderid= -1 AND parentpmid > 0)' )
|
||||
),
|
||||
'convertRanks' => array(
|
||||
'table' => 'usertitle',
|
||||
@@ -177,7 +179,7 @@ class _Vbulletin extends \IPS\convert\Software
|
||||
*
|
||||
* @param string $table The table containing the rows to count.
|
||||
* @param array|NULL $where WHERE clause to only count specific rows, or NULL to count all.
|
||||
* @param bool $recache Skip cache and pull directly (updating cache)
|
||||
* @param bool $recache Skip cache and pull directly (updating cache)
|
||||
* @return integer
|
||||
* @throws \IPS\convert\Exception
|
||||
*/
|
||||
@@ -186,18 +188,32 @@ class _Vbulletin extends \IPS\convert\Software
|
||||
switch( $table )
|
||||
{
|
||||
case 'userchangelog':
|
||||
return $this->db->select( 'count(changeid)', 'userchangelog', array( $this->db->in( 'fieldname', array_keys( static::$changeLogTypes ) ) ) )->first();
|
||||
try
|
||||
{
|
||||
return $this->db->select( 'count(changeid)', 'userchangelog', array( $this->db->in( 'fieldname', array_keys( static::$changeLogTypes ) ) ) )->first();
|
||||
}
|
||||
catch( \Exception $e )
|
||||
{
|
||||
throw new \IPS\convert\Exception( sprintf( \IPS\Member::loggedIn()->language()->get( 'could_not_count_rows' ), $table ) );
|
||||
}
|
||||
break;
|
||||
|
||||
case 'pm':
|
||||
/* vB doesn't put an index on a column that makes this converison much quicker, so we'll do it. */
|
||||
if( !$this->db->checkForIndex( 'pm', 'parent_id' ) )
|
||||
try
|
||||
{
|
||||
$this->db->addIndex( 'pm', array(
|
||||
'type' => 'key',
|
||||
'name' => 'parent_id',
|
||||
'columns' => array( 'parentpmid', 'folderid' )
|
||||
) );
|
||||
/* vB doesn't put an index on a column that makes this converison much quicker, so we'll do it. */
|
||||
if( !$this->db->checkForIndex( 'pm', 'parent_id' ) )
|
||||
{
|
||||
$this->db->addIndex( 'pm', array(
|
||||
'type' => 'key',
|
||||
'name' => 'parent_id',
|
||||
'columns' => array( 'parentpmid', 'folderid' )
|
||||
) );
|
||||
}
|
||||
}
|
||||
catch( \Exception $e )
|
||||
{
|
||||
throw new \IPS\convert\Exception( sprintf( \IPS\Member::loggedIn()->language()->get( 'could_not_count_rows' ), $table ) );
|
||||
}
|
||||
|
||||
return parent::countRows( $table, $where, $recache );
|
||||
@@ -445,14 +461,24 @@ class _Vbulletin extends \IPS\convert\Software
|
||||
'field_required' => TRUE,
|
||||
'field_extra' => array(
|
||||
'options' => array(
|
||||
'database' => \IPS\Member::loggedIn()->language()->addToStack( 'database' ),
|
||||
'file_system' => \IPS\Member::loggedIn()->language()->addToStack( 'file_system' ),
|
||||
'database' => \IPS\Member::loggedIn()->language()->addToStack( 'conv_store_database' ),
|
||||
'file_system' => \IPS\Member::loggedIn()->language()->addToStack( 'conv_store_file_system' ),
|
||||
),
|
||||
'userSuppliedInput' => 'file_system',
|
||||
),
|
||||
'field_hint' => NULL,
|
||||
'field_validation' => function( $value ) { if ( $value != 'database' AND !@is_dir( $value ) ) { throw new \DomainException( 'path_invalid' ); } },
|
||||
);
|
||||
|
||||
/* Find out where the avatar gallery photos live */
|
||||
$return['convertMembers']['avatar_gallery_location'] = array(
|
||||
'field_class' => 'IPS\\Helpers\\Form\\Text',
|
||||
'field_default' => NULL,
|
||||
'field_required' => TRUE,
|
||||
'field_extra' => array(),
|
||||
'field_hint' => \IPS\Member::loggedIn()->language()->addToStack('convert_vb_avatar_gallery_path'),
|
||||
'field_validation' => function( $value ) { if ( !@is_dir( $value ) ) { throw new \DomainException( 'path_invalid' ); } },
|
||||
);
|
||||
|
||||
/* And decide what to do about these... */
|
||||
foreach( array( 'homepage', 'icq', 'aim', 'yahoo', 'msn', 'skype' ) AS $field )
|
||||
@@ -476,15 +502,17 @@ class _Vbulletin extends \IPS\convert\Software
|
||||
break;
|
||||
|
||||
case 'convertClubs':
|
||||
\IPS\Member::loggedIn()->language()->words['club_photo_location'] = \IPS\Member::loggedIn()->language()->addToStack( 'photo_location' );
|
||||
|
||||
$return['convertClubs'] = array();
|
||||
$return['convertClubs']['photo_location'] = array(
|
||||
$return['convertClubs']['club_photo_location'] = array(
|
||||
'field_class' => 'IPS\\Helpers\\Form\\Radio',
|
||||
'field_default' => 'database',
|
||||
'field_required' => TRUE,
|
||||
'field_extra' => array(
|
||||
'options' => array(
|
||||
'database' => \IPS\Member::loggedIn()->language()->addToStack( 'database' ),
|
||||
'file_system' => \IPS\Member::loggedIn()->language()->addToStack( 'file_system' ),
|
||||
'database' => \IPS\Member::loggedIn()->language()->addToStack( 'conv_store_database' ),
|
||||
'file_system' => \IPS\Member::loggedIn()->language()->addToStack( 'conv_store_file_system' ),
|
||||
),
|
||||
'userSuppliedInput' => 'file_system',
|
||||
),
|
||||
@@ -521,6 +549,7 @@ class _Vbulletin extends \IPS\convert\Software
|
||||
|
||||
/* Content Counts */
|
||||
\IPS\Task::queue( 'core', 'RecountMemberContent', array( 'app' => $this->app->app_id ), 4, array( 'app' ) );
|
||||
\IPS\Task::queue( 'core', 'RebuildItemCounts', array( 'class' => 'IPS\core\Messenger\Message' ), 3, array( 'class' ) );
|
||||
|
||||
/* Clubs */
|
||||
\IPS\Task::queue( 'convert', 'RecountClubMembers', array( 'app' => $this->app->app_id ), 2, array( 'app' ) );
|
||||
@@ -537,30 +566,39 @@ class _Vbulletin extends \IPS\convert\Software
|
||||
/**
|
||||
* Fix post data
|
||||
*
|
||||
* @param string raw post data
|
||||
* @return string parsed post data
|
||||
* @param string $post Raw post data
|
||||
* @return string Parsed post data
|
||||
*/
|
||||
public static function fixPostData( $post )
|
||||
{
|
||||
$post = preg_replace( "#\[sigpic\](.+?)\[\/sigpic\]#i", "", $post );
|
||||
if( \preg_match( "#\[sigpic]#i", $post ) )
|
||||
{
|
||||
$post = preg_replace( "#\[sigpic\](.+?)\[\/sigpic\]#i", "", $post );
|
||||
}
|
||||
$post = str_replace( "<", "<", $post );
|
||||
$post = str_replace( ">", ">", $post );
|
||||
$post = str_replace( "'", "'", $post );
|
||||
|
||||
$post = preg_replace( "#\[quote=([^\];]+?)\]#i", "[quote name='$1']", $post );
|
||||
$post = preg_replace( "#\[quote=([^\];]+?);\d+\]#i", "[quote name='$1']", $post );
|
||||
$post = preg_replace( "#\[quote=([^\];]+?);n\d+\]#i", "[quote name='$1']", $post );
|
||||
if( \preg_match( "#\[quote=#i", $post ) )
|
||||
{
|
||||
$post = preg_replace( "#\[quote=([^\];]+?)\]#i", "[quote name='$1']", $post );
|
||||
$post = preg_replace( "#\[quote=([^\];]+?);\d+\]#i", "[quote name='$1']", $post );
|
||||
$post = preg_replace( "#\[quote=([^\];]+?);n\d+\]#i", "[quote name='$1']", $post );
|
||||
}
|
||||
|
||||
/* Remove video tags and allow our parser to handle the embeds it supports */
|
||||
$post = preg_replace( "#\[video=[a-z]+;[a-z0-9_]+\](.*?)\[\/video\]#i", '$1', $post );
|
||||
if( \preg_match( "#\[video=#i", $post ) )
|
||||
{
|
||||
$post = preg_replace( "#\[video=[a-z_]+;[a-z0-9_]+\](.*?)\[\/video\]#i", '$1', $post );
|
||||
}
|
||||
|
||||
/* This is not a core feature in vBulletin, but is a popular addon and the code was supplied below.
|
||||
Addon URL: https://www.dragonbyte-tech.com/store/product/20-advanced-user-tagging/ */
|
||||
if( mb_stristr( $post, '[mention=' ) )
|
||||
if( \preg_match( "#\[mention=#i", $post ) )
|
||||
{
|
||||
preg_match_all( '#\[MENTION=(\d+)\](.+?)\[\/MENTION\]#i', $post, $matches );
|
||||
|
||||
if ( count( $matches ) )
|
||||
if ( \count( $matches ) )
|
||||
{
|
||||
/* Make sure we actually have mention data */
|
||||
if ( isset( $matches[1] ) AND \count( $matches[1] ) )
|
||||
@@ -574,22 +612,17 @@ class _Vbulletin extends \IPS\convert\Software
|
||||
}
|
||||
}
|
||||
|
||||
$maps = array();
|
||||
$urls = array();
|
||||
$cardUrls = array();
|
||||
foreach ( new \IPS\Patterns\ActiveRecordIterator( \IPS\Db::i()->select( '*', 'core_members', array(\IPS\Db::i()->in( 'name', array_keys( $mentions ) )) ), 'IPS\Member' ) AS $member )
|
||||
{
|
||||
$maps[ $member->name ] = $member->member_id;
|
||||
$urls[ $member->name ] = $member->url();
|
||||
$cardUrls[$member->name] = $member->url()->setQueryString( 'do', 'hovercard' );
|
||||
}
|
||||
$maps = iterator_to_array( \IPS\Db::i()->select( 'name, member_id', 'core_members', array( \IPS\Db::i()->in( 'name', array_keys( $mentions ) ) ) )->setKeyField( 'name' )->setValueField( 'member_id' ) );
|
||||
|
||||
foreach ( $mentions AS $member_name => $member_id )
|
||||
foreach ( $mentions AS $memberName => $memberId )
|
||||
{
|
||||
$maps[ $member_name ] = preg_quote( $maps[ $member_name ], '#' );
|
||||
$member_name = preg_quote( $member_name, '#' );
|
||||
if( !isset( $maps[ $memberName ] ) )
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
$post = preg_replace( "#\[MENTION={$member_id}\]{$member_name}\[\/MENTION\]#i", "<a contenteditable=\"false\" rel=\"\" href=\"{$urls[ $member_name ]}\" data-mentionid=\"{$maps[ $member_name ]}\" data-ipshover-target=\"{$cardUrls[ $member_name ]}\" data-ipshover=\"\">@{$member_name}</a>", $post );
|
||||
$memberNameQuoted = preg_quote( $memberName, '#' );
|
||||
$post = preg_replace( "#\[MENTION={$memberId}\]{$memberNameQuoted}\[\/MENTION\]#i", "[mention={$maps[ $memberName ]}]{$memberName}[/mention]", $post );
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -711,10 +744,31 @@ class _Vbulletin extends \IPS\convert\Software
|
||||
}
|
||||
|
||||
$merge = ( $this->app->_session['more_info']['convertProfileFields']["map_pfield_{$field['profilefieldid']}"] != 'none' ) ? $this->app->_session['more_info']['convertProfileFields']["map_pfield_{$field['profilefieldid']}"] : NULL;
|
||||
|
||||
if ( in_array( mb_strtolower( $field['type'] ), array( 'select', 'radio', 'checkbox', 'select_multiple' ) ) )
|
||||
|
||||
if ( \in_array( mb_strtolower( $field['type'] ), array( 'select', 'radio', 'checkbox', 'select_multiple' ) ) )
|
||||
{
|
||||
$content = json_encode( \unserialize( $field['data'] ) );
|
||||
$options = @\unserialize( $field['data'] );
|
||||
if ( $options )
|
||||
{
|
||||
$content = json_encode( $options );
|
||||
}
|
||||
else
|
||||
{
|
||||
/* We can try to restore the serialized value */
|
||||
$data = preg_replace_callback( '/s:(\d+):"(.*?)";/i', function( $match ) {
|
||||
return ( $match[1] == \strlen( $match[2] ) ) ? $match[0] : 's:' . \strlen( $match[2] ) . ':"' . $match[2] . '";';
|
||||
}, $field['data'] );
|
||||
|
||||
if( $options = @\unserialize( $data ) )
|
||||
{
|
||||
$content = json_encode( $options );
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Nothing else we can really do here */
|
||||
$content = json_encode( array() );
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -735,14 +789,13 @@ class _Vbulletin extends \IPS\convert\Software
|
||||
'pf_desc' => $desc,
|
||||
'pf_type' => $type,
|
||||
'pf_content' => $content,
|
||||
'pf_not_null' => ( in_array( $field['required'], array( 1, 3 ) ) ) ? 1 : 0,
|
||||
'pf_member_hide' => $field['hidden'],
|
||||
'pf_not_null' => ( \in_array( $field['required'], array( 1, 3 ) ) ) ? 1 : 0,
|
||||
'pf_member_hide' => $field['hidden'] ? 'hide' : 'all',
|
||||
'pf_max_input' => $field['maxlength'],
|
||||
'pf_member_edit' => ( $field['editable'] >= 1 ) ? 1 : 0,
|
||||
'pf_position' => $field['displayorder'],
|
||||
'pf_show_on_reg' => ( $field['required'] == 2 ) ? 1 : 0,
|
||||
'pf_input_format' => $field['regex'],
|
||||
'pf_admin_only' => ( $field['editable'] == 0 ) ? 1 : 0,
|
||||
'pf_group_id' => $field['profilefieldcategoryid'],
|
||||
'pf_multiple' => $multiple
|
||||
);
|
||||
@@ -756,7 +809,7 @@ class _Vbulletin extends \IPS\convert\Software
|
||||
/**
|
||||
* Maps vBulletin Profile Field type to the IPS Equivalent
|
||||
*
|
||||
* @param string The vB Field Type
|
||||
* @param string $type The vB Field Type
|
||||
* @return string The IPS Field Type
|
||||
*/
|
||||
protected static function _pfieldMap( $type )
|
||||
@@ -819,7 +872,7 @@ class _Vbulletin extends \IPS\convert\Software
|
||||
$promotion = $this->db->select( '*', 'userpromotion', array( "usergroupid=?", $group['usergroupid'] ) )->first();
|
||||
|
||||
/* We only support Posts or Join Date */
|
||||
if ( in_array( $promotion['strategy'], array( 17, 18 ) ) )
|
||||
if ( \in_array( $promotion['strategy'], array( 17, 18 ) ) )
|
||||
{
|
||||
switch( $promotion['strategy'] )
|
||||
{
|
||||
@@ -917,7 +970,7 @@ class _Vbulletin extends \IPS\convert\Software
|
||||
}
|
||||
|
||||
/* Now check for group promotions */
|
||||
if( count( $libraryClass->groupPromotions ) )
|
||||
if( \count( $libraryClass->groupPromotions ) )
|
||||
{
|
||||
foreach( $libraryClass->groupPromotions as $groupPromotion )
|
||||
{
|
||||
@@ -929,7 +982,7 @@ class _Vbulletin extends \IPS\convert\Software
|
||||
/**
|
||||
* @brief Member history type map
|
||||
*/
|
||||
protected static $changeLogTypes = array( 'username' => 'display_name', 'email' => 'email_change', 'usergroupid' => 'member_group_id', 'membergroupids' => 'mgroup_others' );
|
||||
protected static $changeLogTypes = array( 'username' => 'display_name', 'email' => 'email_change', 'usergroupid' => 'group', 'membergroupids' => 'group' );
|
||||
|
||||
/**
|
||||
* Convert member history
|
||||
@@ -943,16 +996,23 @@ class _Vbulletin extends \IPS\convert\Software
|
||||
|
||||
foreach( $this->fetch( 'userchangelog', 'changeid', array( $this->db->in( 'fieldname', array_keys( static::$changeLogTypes ) ) ) ) AS $change )
|
||||
{
|
||||
$libraryClass->convertMemberHistory( array(
|
||||
'log_id' => $change['changeid'],
|
||||
'log_member' => $change['userid'],
|
||||
'log_by' => $change['adminid'],
|
||||
'log_type' => static::$changeLogTypes[ $change['fieldname'] ],
|
||||
'log_data' => array( 'old' => $change['oldvalue'], 'new' => $change['newvalue'] ),
|
||||
'log_date' => $change['change_time']
|
||||
)
|
||||
$info = array(
|
||||
'log_id' => $change['changeid'],
|
||||
'log_member' => $change['userid'],
|
||||
'log_by' => $change['adminid'],
|
||||
'log_type' => static::$changeLogTypes[ $change['fieldname'] ],
|
||||
'log_data' => array( 'old' => $change['oldvalue'], 'new' => $change['newvalue'] ),
|
||||
'log_date' => $change['change_time']
|
||||
);
|
||||
|
||||
/* Add extra data for group change */
|
||||
if( static::$changeLogTypes[ $change['fieldname'] ] == 'group' )
|
||||
{
|
||||
$info['log_data']['type'] = $change['fieldname'] == 'usergroupid' ? 'primary' : 'secondary';
|
||||
$info['log_data']['by'] = 'manual';
|
||||
}
|
||||
|
||||
$libraryClass->convertMemberHistory( $info );
|
||||
$libraryClass->setLastKeyValue( $change['changeid'] );
|
||||
}
|
||||
}
|
||||
@@ -968,6 +1028,9 @@ class _Vbulletin extends \IPS\convert\Software
|
||||
|
||||
$libraryClass::setKey( 'user.userid' );
|
||||
|
||||
/* User titles */
|
||||
$userTitles = iterator_to_array( $this->db->select( 'title', 'usertitle' ) );
|
||||
|
||||
foreach( $this->fetch( 'user', 'user.userid', NULL, 'user.*, usertextfield.signature' )->join( 'usertextfield', 'user.userid = usertextfield.userid' ) AS $user )
|
||||
{
|
||||
/* <3 Closures */
|
||||
@@ -1054,13 +1117,13 @@ class _Vbulletin extends \IPS\convert\Software
|
||||
'member_id' => $user['userid'],
|
||||
'member_group_id' => $user['usergroupid'],
|
||||
'mgroup_others' => $user['membergroupids'],
|
||||
'name' => $user['username'],
|
||||
'name' => html_entity_decode( $user['username'], \ENT_QUOTES | \ENT_HTML5, 'UTF-8' ),
|
||||
'email' => $user['email'],
|
||||
'member_title' => $user['usertitle'],
|
||||
'member_title' => \in_array( $user['usertitle'], $userTitles ) ? NULL : $user['usertitle'],
|
||||
'joined' => $user['joindate'],
|
||||
'ip_address' => $user['ipaddress'],
|
||||
'warn_level' => ( $user['ipoints'] > 2147483647 ) ? 2147483647 : $user['ipoints'],
|
||||
'warn_lastwarn' => $lastWarning['dateline'],
|
||||
'warn_lastwarn' => ( \is_array( $lastWarning ) ) ? $lastWarning['dateline'] : $lastWarning,
|
||||
'bday_day' => $bday_day,
|
||||
'bday_month' => $bday_month,
|
||||
'bday_year' => $bday_year,
|
||||
@@ -1074,10 +1137,10 @@ class _Vbulletin extends \IPS\convert\Software
|
||||
'members_bitoptions' => array(
|
||||
'view_sigs' => $checkpermission( 'useroptions', 'showsignatures' ), // View signatures?
|
||||
'coppa_user' => $checkpermission( 'useroptions', 'coppauser' ), // Was the member validated using coppa?
|
||||
'timezone_override' => !$checkpermission( 'useroptions', 'dstauto' ), // If TRUE, user's timezone will not be detected automatically
|
||||
),
|
||||
'members_bitoptions2' => array(
|
||||
'show_pm_popup' => $user['pmpopup'], // "Show pop-up when I have a new message"
|
||||
'is_anon' => $checkpermission( 'useroptions', 'invisible' ), // Anonymous status
|
||||
),
|
||||
'pp_setting_count_comments' => $checkpermission( 'useroptions', 'vm_enable' ),
|
||||
'pp_reputation_points' => $user['reputation'],
|
||||
@@ -1086,6 +1149,18 @@ class _Vbulletin extends \IPS\convert\Software
|
||||
'members_disable_pm' => !$checkpermission( 'useroptions', 'receivepm' ),
|
||||
'member_posts' => $user['posts'],
|
||||
);
|
||||
|
||||
/* If there is a validation record for this user, treat them as validating */
|
||||
try
|
||||
{
|
||||
$activation = $this->db->select( '*', 'useractivation', array( "userid=?", $user['userid'] ) )->first();
|
||||
|
||||
$info['members_bitoptions']['validating'] = TRUE;
|
||||
}
|
||||
catch( \UnderflowException $e )
|
||||
{
|
||||
$activation = NULL;
|
||||
}
|
||||
|
||||
/* Profile Fields */
|
||||
try
|
||||
@@ -1129,11 +1204,10 @@ class _Vbulletin extends \IPS\convert\Software
|
||||
'pf_desc' => '',
|
||||
'pf_type' => 'Text',
|
||||
'pf_content' => '[]',
|
||||
'pf_member_hide' => 0,
|
||||
'pf_member_hide' => 'all',
|
||||
'pf_max_input' => 255,
|
||||
'pf_member_edit' => 1,
|
||||
'pf_show_on_reg' => 0,
|
||||
'pf_admin_only' => 0,
|
||||
) );
|
||||
}
|
||||
|
||||
@@ -1257,15 +1331,42 @@ class _Vbulletin extends \IPS\convert\Software
|
||||
list( $filedata, $filename, $filepath ) = array( NULL, NULL, NULL );
|
||||
}
|
||||
}
|
||||
|
||||
/* We'll try the avatar gallery */
|
||||
if( empty( $filename ) AND empty( $filedata ) AND (int) $user['avatarid'] )
|
||||
{
|
||||
$avatar = $this->_getFromAvatarGallery( (int) $user['avatarid'] );
|
||||
|
||||
if( \is_array( $avatar ) )
|
||||
{
|
||||
$filename = $avatar['name'];
|
||||
$filedata = $avatar['data'];
|
||||
}
|
||||
}
|
||||
|
||||
$libraryClass->convertMember( $info, $profileFields, $filename, $filepath, $filedata );
|
||||
$memberId = $libraryClass->convertMember( $info, $profileFields, $filename, $filepath, $filedata );
|
||||
|
||||
/* If we are validating, store our validation row entry */
|
||||
if( $activation !== NULL AND $memberId )
|
||||
{
|
||||
\IPS\Db::i()->replace( 'core_validating', array(
|
||||
'vid' => md5( $activation['activationid'] . $activation['useractivationid'] ),
|
||||
'member_id' => $memberId,
|
||||
'entry_date' => $activation['dateline'],
|
||||
'new_reg' => ( $activation['emailchange'] == 0 ? TRUE : FALSE ),
|
||||
'email_chg' => ( $activation['emailchange'] == 1 ? TRUE : FALSE ),
|
||||
'user_verified' => FALSE,
|
||||
'ip_address' => $user['ipaddress'],
|
||||
'email_sent' => $activation['dateline']
|
||||
) );
|
||||
}
|
||||
|
||||
/* Any friends need converting to followers? */
|
||||
foreach( $this->db->select( '*', 'userlist', array( "type=? AND friend=? AND userid=?", 'buddy', 'yes', $user['userid'] ) ) AS $follower )
|
||||
{
|
||||
$libraryClass->convertFollow( array(
|
||||
'follow_app' => 'core',
|
||||
'follow_area' => 'members',
|
||||
'follow_area' => 'member',
|
||||
'follow_rel_id' => $follower['relationid'],
|
||||
'follow_rel_id_type' => 'core_members',
|
||||
'follow_member_id' => $follower['userid'],
|
||||
@@ -1482,78 +1583,10 @@ class _Vbulletin extends \IPS\convert\Software
|
||||
$libraryClass->setLastKeyValue( $pm['pmid'] );
|
||||
continue;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
$replies = $this->db->select( 'COUNT(*)', 'pm', array( "parentpmid=? AND folderid!=?", $pm['pmid'], -1 ) )->first();
|
||||
$replies += 1;
|
||||
}
|
||||
catch( \UnderflowException $e )
|
||||
{
|
||||
$replies = 1;
|
||||
}
|
||||
|
||||
$topic = array(
|
||||
'mt_id' => $pm['pmid'],
|
||||
'mt_date' => $pm['dateline'],
|
||||
'mt_title' => $pm['title'],
|
||||
'mt_starter_id' => $pm['fromuserid'],
|
||||
'mt_start_time' => $pm['dateline'],
|
||||
'mt_last_post_time' => $pm['dateline'],
|
||||
'mt_to_count' => count( @\unserialize( $pm['touserarray'] ) ),
|
||||
'mt_to_member_id' => $pm['userid'],
|
||||
'mt_replies' => $replies,
|
||||
'mt_first_msg_id' => $pm['pmid'],
|
||||
);
|
||||
|
||||
$authors = array();
|
||||
$authors[ $pm['fromuserid'] ] = $pm['fromuserid'];
|
||||
|
||||
try
|
||||
{
|
||||
foreach( $this->db->select( '*', 'pm', array( "parentpmid=?", $pm['pmid'] ) )->join( 'pmtext', 'pm.pmtextid = pmtext.pmtextid' ) AS $post )
|
||||
{
|
||||
if ( $post['folderid'] != -1 )
|
||||
{
|
||||
$authors[ $post['fromuserid'] ] = $post['fromuserid'];
|
||||
}
|
||||
}
|
||||
}
|
||||
catch( \UnderflowException $e ) {}
|
||||
|
||||
/* Use stored author ids */
|
||||
$toUsers = \unserialize( $pm['touserarray'] );
|
||||
if( isset( $toUsers['cc'] ) )
|
||||
{
|
||||
foreach( array_keys( $toUsers['cc'] ) as $id )
|
||||
{
|
||||
$authors[ $id ] = $id;
|
||||
}
|
||||
}
|
||||
elseif( \count( $toUsers ) AND isset( $toUsers['cc'] ) AND isset( $toUsers['bcc'] ) )
|
||||
{
|
||||
foreach( array_keys( $toUsers ) as $id )
|
||||
{
|
||||
$authors[ $id ] = $id;
|
||||
}
|
||||
}
|
||||
|
||||
$maps = array();
|
||||
|
||||
foreach( $authors AS $mapAuthor )
|
||||
{
|
||||
$maps[ $mapAuthor ] = array(
|
||||
'map_user_id' => $mapAuthor,
|
||||
'map_topic_id' => $pm['pmid'],
|
||||
'map_user_active' => 1,
|
||||
'map_user_banned' => 0,
|
||||
'map_has_unread' => 0,
|
||||
'map_is_starter' => ( $mapAuthor == $pm['fromuserid'] ) ? 1 : 0,
|
||||
);
|
||||
}
|
||||
|
||||
$libraryClass->convertPrivateMessage( $topic, $maps );
|
||||
|
||||
/* Convert PM */
|
||||
$this->_convertPm( $libraryClass, $pm );
|
||||
|
||||
$libraryClass->setLastKeyValue( $pm['pmid'] );
|
||||
}
|
||||
}
|
||||
@@ -1569,11 +1602,22 @@ class _Vbulletin extends \IPS\convert\Software
|
||||
|
||||
$libraryClass::setKey( 'pm.pmid' );
|
||||
|
||||
foreach( $this->fetch( 'pm', 'pm.pmid', array( 'pm.folderid!=?', -1 ), "pm.*, pmtext.*" )->join( 'pmtext', 'pm.pmtextid = pmtext.pmtextid' ) AS $pm )
|
||||
foreach( $this->fetch( 'pm', 'pm.pmid', array( 'NOT (pm.folderid= -1 AND pm.parentpmid > 0)' ), "pm.*, pmtext.*, test.pmid as parent_test" )
|
||||
->join( 'pmtext', 'pm.pmtextid = pmtext.pmtextid' )
|
||||
->join( array( 'pm', 'test' ), 'pm.parentpmid=test.pmid' )
|
||||
AS $pm )
|
||||
{
|
||||
/* See if the parent exists, or whether it's already been deleted in vBulletin. */
|
||||
$parentId = FALSE;
|
||||
if( $pm['parentpmid'] AND !$pm['parent_test'] )
|
||||
{
|
||||
/* It has previously been deleted, so this message can become it's own conversation */
|
||||
$parentId = $this->_convertPm( $libraryClass, $pm );
|
||||
}
|
||||
|
||||
$libraryClass->convertPrivateMessageReply( array(
|
||||
'msg_id' => $pm['pmid'],
|
||||
'msg_topic_id' => !$pm['parentpmid'] ? $pm['pmid'] : $pm['parentpmid'],
|
||||
'msg_topic_id' => (!$pm['parentpmid'] OR $parentId ) ? $pm['pmid'] : $pm['parentpmid'],
|
||||
'msg_date' => $pm['dateline'],
|
||||
'msg_post' => $pm['message'],
|
||||
'msg_author_id' => $pm['fromuserid'],
|
||||
@@ -1658,13 +1702,13 @@ class _Vbulletin extends \IPS\convert\Software
|
||||
$icondata = NULL;
|
||||
if ( $icon )
|
||||
{
|
||||
if ( $this->app->_session['more_info']['convertClubs']['photo_location'] == 'database' )
|
||||
if ( $this->app->_session['more_info']['convertClubs']['club_photo_location'] == 'database' )
|
||||
{
|
||||
$icondata = $icon['filedata'];
|
||||
}
|
||||
else
|
||||
{
|
||||
$iconpath = $this->app->_session['more_info']['convertClubs']['photo_location'] . "/socialgroupicon_{$icon['groupid']}_{$icon['dateline']}.gif";
|
||||
$iconpath = $this->app->_session['more_info']['convertClubs']['club_photo_location'] . "/socialgroupicon_{$icon['groupid']}_{$icon['dateline']}.gif";
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1907,7 +1951,7 @@ class _Vbulletin extends \IPS\convert\Software
|
||||
/**
|
||||
* Get Setting Value - useful for global settings that need to be translated to group or member settings
|
||||
*
|
||||
* @param $key The setting key
|
||||
* @param string $key The setting key
|
||||
* @return mixed
|
||||
*/
|
||||
protected function _setting( $key )
|
||||
@@ -1951,22 +1995,49 @@ class _Vbulletin extends \IPS\convert\Software
|
||||
/* Attachment URLs are the same across VB 3.8 and VB 4 */
|
||||
if( mb_strpos( $url->data[ \IPS\Http\Url::COMPONENT_PATH ], 'attachment.php' ) !== FALSE )
|
||||
{
|
||||
$id = NULL;
|
||||
try
|
||||
{
|
||||
$data = (string) $this->app->getLink( \IPS\Request::i()->attachmentid, array( 'attachments', 'core_attachments' ) );
|
||||
|
||||
return \IPS\Http\Url::external( \IPS\Settings::i()->base_url . 'applications/core/interface/file/attachment.php' )->setQueryString( 'id', $data );
|
||||
$id = (string) $this->app->getLink( \IPS\Request::i()->attachmentid, array( 'attachments', 'core_attachments' ) );
|
||||
}
|
||||
/* Try any child conversions */
|
||||
catch( \Exception $e )
|
||||
{
|
||||
foreach( $this->app->children() as $child )
|
||||
{
|
||||
try
|
||||
{
|
||||
$id = (string) $child->getLink( \IPS\Request::i()->attachmentid, array( 'attachments', 'core_attachments' ) );
|
||||
break;
|
||||
}
|
||||
catch( \Exception $e ) {}
|
||||
}
|
||||
}
|
||||
|
||||
if( !$id )
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return \IPS\Http\Url::external( \IPS\Settings::i()->base_url . 'applications/core/interface/file/attachment.php' )->setQueryString( 'id', $id );
|
||||
}
|
||||
/* Tag URLs are straightforward */
|
||||
elseif( mb_strpos( $url->data[ \IPS\Http\Url::COMPONENT_PATH ], 'tags.php' ) !== FALSE AND isset( \IPS\Request::i()->tag ) )
|
||||
{
|
||||
return \IPS\Http\Url::internal( "app=core&module=search&controller=search&tags=" . \IPS\Request::i()->tag, 'front', 'search' );
|
||||
}
|
||||
/* Club Index */
|
||||
elseif( mb_strpos( $url->data[ \IPS\Http\Url::COMPONENT_PATH ], 'group.php' ) !== FALSE AND isset( \IPS\Request::i()->groupid ) )
|
||||
{
|
||||
try
|
||||
{
|
||||
return \IPS\Member\Club::loadAndCheckPerms( (string) $this->app->getLink( \IPS\Request::i()->groupid, array( 'core_clubs' ) ) )->url();
|
||||
}
|
||||
catch( \Exception $e )
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* If we can't access profiles, don't bother trying to redirect */
|
||||
@@ -2038,4 +2109,149 @@ class _Vbulletin extends \IPS\convert\Software
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Centralised PM conversation conversion
|
||||
*
|
||||
* @param $libraryClass \IPS\convert\Library
|
||||
* @param $pm array
|
||||
* @return mixed
|
||||
*/
|
||||
protected function _convertPm( \IPS\convert\Library $libraryClass, array $pm )
|
||||
{
|
||||
try
|
||||
{
|
||||
$replies = $this->db->select( 'COUNT(*)', 'pm', array( "parentpmid=? AND folderid!=?", $pm['pmid'], -1 ) )->first();
|
||||
$replies += 1;
|
||||
}
|
||||
catch( \UnderflowException $e )
|
||||
{
|
||||
$replies = 1;
|
||||
}
|
||||
|
||||
$toUserArray = @\unserialize( $pm['touserarray'] );
|
||||
|
||||
$topic = array(
|
||||
'mt_id' => $pm['pmid'],
|
||||
'mt_date' => $pm['dateline'],
|
||||
'mt_title' => $pm['title'],
|
||||
'mt_starter_id' => $pm['fromuserid'],
|
||||
'mt_start_time' => $pm['dateline'],
|
||||
'mt_last_post_time' => $pm['dateline'],
|
||||
'mt_to_count' => ( $toUserArray AND \is_array( $toUserArray ) ) ? \count( $toUserArray ) : 1,
|
||||
'mt_to_member_id' => $pm['userid'],
|
||||
'mt_replies' => $replies,
|
||||
'mt_first_msg_id' => $pm['pmid'],
|
||||
);
|
||||
|
||||
$authors = array();
|
||||
$authors[ $pm['fromuserid'] ] = $pm['fromuserid'];
|
||||
|
||||
try
|
||||
{
|
||||
foreach( $this->db->select( '*', 'pm', array( "parentpmid=?", $pm['pmid'] ) )->join( 'pmtext', 'pm.pmtextid = pmtext.pmtextid' ) AS $post )
|
||||
{
|
||||
if ( $post['folderid'] != -1 )
|
||||
{
|
||||
$authors[ $post['fromuserid'] ] = $post['fromuserid'];
|
||||
}
|
||||
}
|
||||
}
|
||||
catch( \UnderflowException $e ) {}
|
||||
|
||||
/* Use stored author ids */
|
||||
if( isset( $toUserArray['cc'] ) AND \is_array( $toUserArray['cc'] ) )
|
||||
{
|
||||
foreach( array_keys( $toUserArray['cc'] ) as $id )
|
||||
{
|
||||
$authors[ $id ] = $id;
|
||||
}
|
||||
}
|
||||
elseif( $toUserArray AND \is_array( $toUserArray ) AND \count( $toUserArray ) )
|
||||
{
|
||||
foreach( array_keys( $toUserArray ) as $id )
|
||||
{
|
||||
$authors[ $id ] = $id;
|
||||
}
|
||||
}
|
||||
|
||||
$maps = array();
|
||||
|
||||
foreach( $authors AS $mapAuthor )
|
||||
{
|
||||
$maps[ $mapAuthor ] = array(
|
||||
'map_user_id' => $mapAuthor,
|
||||
'map_topic_id' => $pm['pmid'],
|
||||
'map_user_active' => 1,
|
||||
'map_user_banned' => 0,
|
||||
'map_has_unread' => 0,
|
||||
'map_is_starter' => ( $mapAuthor == $pm['fromuserid'] ) ? 1 : 0,
|
||||
);
|
||||
}
|
||||
|
||||
return $libraryClass->convertPrivateMessage( $topic, $maps );
|
||||
}
|
||||
|
||||
protected $_avatars = array();
|
||||
|
||||
/**
|
||||
* Fetch Avatar from Avatar Gallery
|
||||
*
|
||||
* @param int $id Avatar ID
|
||||
* @return array|bool Array of data/name or FALSE
|
||||
*/
|
||||
protected function _getFromAvatarGallery( int $id )
|
||||
{
|
||||
if( isset( $this->_avatars[ $id ] ) )
|
||||
{
|
||||
return $this->_avatars[ $id ];
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
$avatar = $this->db->select( 'avatarpath', 'avatar', array( 'avatarid=?', $id ) )->first();
|
||||
}
|
||||
catch( \UnderflowException $e )
|
||||
{
|
||||
return $this->_avatars[ $id ] = FALSE;
|
||||
}
|
||||
|
||||
/* It might be a remote image */
|
||||
if( \substr( $avatar, 0, 8 ) === 'https://' OR \substr( $avatar, 0, 7 ) === 'http://' )
|
||||
{
|
||||
try
|
||||
{
|
||||
$profilePhotoName = pathinfo( parse_url( $avatar, PHP_URL_PATH ), PATHINFO_BASENAME );
|
||||
$profilePhotoData = \IPS\Http\Url::external( $avatar )->request()->get();
|
||||
|
||||
/* Check it's really an image */
|
||||
try
|
||||
{
|
||||
\IPS\Image::create( $profilePhotoData );
|
||||
}
|
||||
catch( \InvalidArgumentException $e )
|
||||
{
|
||||
return $this->_avatars[ $id ] = FALSE;
|
||||
}
|
||||
|
||||
return $this->_avatars[ $id ] = array( 'data' => $profilePhotoData, 'name' => $profilePhotoName );
|
||||
}
|
||||
catch ( \IPS\Http\Request\Exception $e )
|
||||
{
|
||||
return $this->_avatars[ $id ] = FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
/* nope, it's a file */
|
||||
$dirName = pathinfo( $avatar, PATHINFO_DIRNAME );
|
||||
if( \substr( $this->app->_session['more_info']['convertMembers']['avatar_gallery_location'], -\strlen( $dirName ) ) == $dirName )
|
||||
{
|
||||
$profilePhotoName = pathinfo( $avatar, PATHINFO_BASENAME );
|
||||
$profilePhotoData = file_get_contents( rtrim( $this->app->_session['more_info']['convertMembers']['avatar_gallery_location'], '/' ) . '/' . $profilePhotoName );
|
||||
|
||||
return $this->_avatars[ $id ] = array( 'data' => $profilePhotoData, 'name' => $profilePhotoName );
|
||||
}
|
||||
|
||||
return $this->_avatars[ $id ] = FALSE;
|
||||
}
|
||||
}
|
||||
@@ -5,21 +5,58 @@
|
||||
* @author <a href='https://www.invisioncommunity.com'>Invision Power Services, Inc.</a>
|
||||
* @copyright (c) Invision Power Services, Inc.
|
||||
* @package Invision Community
|
||||
* @subpackage Converter
|
||||
* @subpackage convert
|
||||
* @since 21 Jan 2015
|
||||
*/
|
||||
|
||||
namespace IPS\convert\Software\Core;
|
||||
|
||||
/* To prevent PHP errors (extending class does not exist) revealing path */
|
||||
if ( !defined( '\IPS\SUITE_UNIQUE_KEY' ) )
|
||||
if ( !\defined( '\IPS\SUITE_UNIQUE_KEY' ) )
|
||||
{
|
||||
header( ( isset( $_SERVER['SERVER_PROTOCOL'] ) ? $_SERVER['SERVER_PROTOCOL'] : 'HTTP/1.0' ) . ' 403 Forbidden' );
|
||||
exit;
|
||||
}
|
||||
|
||||
/**
|
||||
* vBulletin 5 Core Converter
|
||||
*/
|
||||
class _Vbulletin5 extends \IPS\convert\Software
|
||||
{
|
||||
/**
|
||||
* @brief is vB 5.5.3 or newer
|
||||
*/
|
||||
protected static $skipCustomProfilePic = NULL;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param \IPS\convert\App $app The application to reference for database and other information.
|
||||
* @param bool $needDB Establish a DB connection
|
||||
* @return void
|
||||
* @throws \InvalidArgumentException
|
||||
*/
|
||||
public function __construct( \IPS\convert\App $app, $needDB=TRUE )
|
||||
{
|
||||
$return = parent::__construct( $app, $needDB );
|
||||
|
||||
if ( $needDB )
|
||||
{
|
||||
try
|
||||
{
|
||||
/* Is this vB 5.5.3 or newer? */
|
||||
if ( static::$skipCustomProfilePic === NULL )
|
||||
{
|
||||
$version = $this->db->select( 'value', 'setting', array( "varname=?", 'templateversion' ) )->first();
|
||||
static::$skipCustomProfilePic = version_compare( $version, '5.5.3', '>=' );
|
||||
}
|
||||
}
|
||||
catch( \Exception $e ) {} # If we can't query, we won't be able to do anything anyway
|
||||
}
|
||||
|
||||
return $return;
|
||||
}
|
||||
|
||||
/**
|
||||
* Software Name
|
||||
*
|
||||
@@ -135,12 +172,16 @@ class _Vbulletin5 extends \IPS\convert\Software
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
catch( \Exception $e )
|
||||
{
|
||||
throw new \IPS\convert\Exception( sprintf( \IPS\Member::loggedIn()->language()->get( 'could_not_count_rows' ), $table ) );
|
||||
}
|
||||
break;
|
||||
|
||||
case 'node':
|
||||
if ( $where === 'clubs' )
|
||||
{
|
||||
return count( $this->fetchClubs() );
|
||||
return \count( $this->fetchClubs() );
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -160,7 +201,14 @@ class _Vbulletin5 extends \IPS\convert\Software
|
||||
break;
|
||||
|
||||
case 'userchangelog':
|
||||
return $this->db->select( 'count(changeid)', 'userchangelog', array( $this->db->in( 'fieldname', array_keys( static::$changeLogTypes ) ) ) )->first();
|
||||
try
|
||||
{
|
||||
return $this->db->select( 'count(changeid)', 'userchangelog', array( $this->db->in( 'fieldname', array_keys( static::$changeLogTypes ) ) ) )->first();
|
||||
}
|
||||
catch( \Exception $e )
|
||||
{
|
||||
throw new \IPS\convert\Exception( sprintf( \IPS\Member::loggedIn()->language()->get( 'could_not_count_rows' ), $table ) );
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
@@ -395,8 +443,8 @@ class _Vbulletin5 extends \IPS\convert\Software
|
||||
'field_required' => TRUE,
|
||||
'field_extra' => array(
|
||||
'options' => array(
|
||||
'database' => \IPS\Member::loggedIn()->language()->addToStack( 'database' ),
|
||||
'file_system' => \IPS\Member::loggedIn()->language()->addToStack( 'file_system' ),
|
||||
'database' => \IPS\Member::loggedIn()->language()->addToStack( 'conv_store_database' ),
|
||||
'file_system' => \IPS\Member::loggedIn()->language()->addToStack( 'conv_store_file_system' ),
|
||||
),
|
||||
'userSuppliedInput' => 'file_system',
|
||||
),
|
||||
@@ -426,15 +474,17 @@ class _Vbulletin5 extends \IPS\convert\Software
|
||||
break;
|
||||
|
||||
case 'convertClubs':
|
||||
\IPS\Member::loggedIn()->language()->words['club_photo_location'] = \IPS\Member::loggedIn()->language()->addToStack( 'photo_location' );
|
||||
|
||||
$return['convertClubs'] = array();
|
||||
$return['convertClubs']['photo_location'] = array(
|
||||
$return['convertClubs']['club_photo_location'] = array(
|
||||
'field_class' => 'IPS\\Helpers\\Form\\Radio',
|
||||
'field_default' => 'database',
|
||||
'field_required' => TRUE,
|
||||
'field_extra' => array(
|
||||
'options' => array(
|
||||
'database' => \IPS\Member::loggedIn()->language()->addToStack( 'database' ),
|
||||
'file_system' => \IPS\Member::loggedIn()->language()->addToStack( 'file_system' ),
|
||||
'database' => \IPS\Member::loggedIn()->language()->addToStack( 'conv_store_database' ),
|
||||
'file_system' => \IPS\Member::loggedIn()->language()->addToStack( 'conv_store_file_system' ),
|
||||
),
|
||||
'userSuppliedInput' => 'file_system',
|
||||
),
|
||||
@@ -483,24 +533,16 @@ class _Vbulletin5 extends \IPS\convert\Software
|
||||
/**
|
||||
* Fix post data
|
||||
*
|
||||
* @param string raw post data
|
||||
* @return string parsed post data
|
||||
* @param string $post Raw post data
|
||||
* @return string Parsed post data
|
||||
*/
|
||||
public static function fixPostData( $post )
|
||||
{
|
||||
/* Fix Quotes */
|
||||
$post = preg_replace( "#\[quote=([^\];]+?)\]#i", "[quote name='$1']", $post );
|
||||
$post = preg_replace( "#\[quote=([^\];]+?);\d+\]#i", "[quote name='$1']", $post );
|
||||
$post = preg_replace( "#\[quote=([^\];]+?);n\d+\]#i", "[quote name='$1']", $post );
|
||||
|
||||
/* Remove video tags and allow our parser to handle the embeds it supports */
|
||||
$post = preg_replace( "#\[video=[a-z]+;[a-z0-9_]+\](.*?)\[\/video\]#i", '$1', $post );
|
||||
|
||||
/* IMG2 BBcode */
|
||||
/* IMG2 BBcode - Needs to be ran before htmlspecialchars due to it containing JSON */
|
||||
$matches = array();
|
||||
preg_match_all( "/\[IMG2=JSON](.+?)\[\/IMG2\]/i", $post, $matches );
|
||||
|
||||
if ( count( $matches ) )
|
||||
if ( \count( $matches ) )
|
||||
{
|
||||
foreach( $matches[0] as $k => $v )
|
||||
{
|
||||
@@ -533,40 +575,46 @@ class _Vbulletin5 extends \IPS\convert\Software
|
||||
$matches = array();
|
||||
preg_match_all( '#\[user(=\"?(\d+)\"?)?\](.+?)\[\/user\]#i', $post, $matches ); // this purposefully matches more than the default vB mention.
|
||||
|
||||
if ( count( $matches ) )
|
||||
if ( \count( $matches ) )
|
||||
{
|
||||
if ( isset( $matches[1] ) )
|
||||
/* Make sure we actually have mention data */
|
||||
if ( isset( $matches[1] ) AND \count( $matches[1] ) )
|
||||
{
|
||||
$mentions = array();
|
||||
foreach( $matches[1] AS $k => $v )
|
||||
foreach ( $matches[1] AS $k => $v )
|
||||
{
|
||||
if ( isset( $matches[3][$k] ) )
|
||||
if ( isset( $matches[3][ $k ] ) )
|
||||
{
|
||||
$name = trim( $matches[3][ $k ], '@' );
|
||||
$mentions[ $name ] = $v;
|
||||
$mentions[ $matches[3][ $k ] ] = $v;
|
||||
}
|
||||
}
|
||||
|
||||
$maps = array();
|
||||
$urls = array();
|
||||
$cardUrls = array();
|
||||
foreach( new \IPS\Patterns\ActiveRecordIterator( \IPS\Db::i()->select( '*', 'core_members', array( \IPS\Db::i()->in( 'name', array_keys( $mentions ) ) ) ), 'IPS\Member' ) AS $member )
|
||||
{
|
||||
$maps[ $member->name ] = $member->member_id;
|
||||
$urls[ $member->name ] = $member->url();
|
||||
$cardUrls[ $member->name ] = $member->url()->setQueryString( 'do', 'hovercard' );
|
||||
}
|
||||
$maps = iterator_to_array( \IPS\Db::i()->select( 'name, member_id', 'core_members', array( \IPS\Db::i()->in( 'name', array_keys( $mentions ) ) ) )->setKeyField( 'name' )->setValueField( 'member_id' ) );
|
||||
|
||||
foreach( $mentions AS $member_name => $member_id )
|
||||
foreach ( $mentions AS $memberName => $memberId )
|
||||
{
|
||||
$maps[ $member_name ] = preg_quote( $maps[ $member_name ], '#' );
|
||||
$memberNameEscaped = preg_quote( $member_name, '#' );
|
||||
if ( !isset( $maps[ $memberName ] ) )
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
$post = preg_replace( "#\[user(=\"?(\d+)\"?)?\]@?{$memberNameEscaped}\[\/user\]#i", "<a contenteditable=\"false\" rel=\"\" href=\"{$urls[ $member_name ]}\" data-mentionid=\"{$maps[ $member_name ]}\" data-ipshover-target=\"{$cardUrls[ $member_name ]}\" data-ipshover=\"\">@{$member_name}</a>", $post );
|
||||
$memberNameQuoted = preg_quote( $memberName, '#' );
|
||||
$post = preg_replace( "#\[user(=\"?(\d+)\"?)?\]@?{$memberNameQuoted}\[\/user\]#i", "[mention={$maps[ $memberName ]}]{$memberName}[/mention]", $post );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// run everything through htmlspecialchars to prevent XSS
|
||||
$post = htmlspecialchars( $post, ENT_DISALLOWED | ENT_QUOTES, 'UTF-8', FALSE );
|
||||
|
||||
/* Fix Quotes */
|
||||
$post = preg_replace( "#\[quote=([^\];]+?)\]#i", "[quote name='$1']", $post );
|
||||
$post = preg_replace( "#\[quote=([^\];]+?);\d+\]#i", "[quote name='$1']", $post );
|
||||
$post = preg_replace( "#\[quote=([^\];]+?);n\d+\]#i", "[quote name='$1']", $post );
|
||||
|
||||
/* Remove video tags and allow our parser to handle the embeds it supports */
|
||||
$post = preg_replace( "#\[video=[a-z_]+;[a-z0-9_]+\](.*?)\[\/video\]#i", '$1', $post );
|
||||
|
||||
return $post;
|
||||
}
|
||||
|
||||
@@ -684,7 +732,7 @@ class _Vbulletin5 extends \IPS\convert\Software
|
||||
|
||||
$merge = ( $this->app->_session['more_info']['convertProfileFields']["map_pfield_{$field['profilefieldid']}"] != 'none' ) ? $this->app->_session['more_info']['convertProfileFields']["map_pfield_{$field['profilefieldid']}"] : NULL;
|
||||
|
||||
if ( in_array( mb_strtolower( $field['type'] ), array( 'select', 'radio', 'checkbox', 'select_multiple' ) ) )
|
||||
if ( \in_array( mb_strtolower( $field['type'] ), array( 'select', 'radio', 'checkbox', 'select_multiple' ) ) )
|
||||
{
|
||||
$content = json_encode( @\unserialize( $field['data'] ) );
|
||||
}
|
||||
@@ -707,14 +755,13 @@ class _Vbulletin5 extends \IPS\convert\Software
|
||||
'pf_desc' => $desc,
|
||||
'pf_type' => $type,
|
||||
'pf_content' => $content,
|
||||
'pf_not_null' => ( in_array( $field['required'], array( 1, 3 ) ) ) ? 1 : 0,
|
||||
'pf_member_hide' => $field['hidden'],
|
||||
'pf_not_null' => ( \in_array( $field['required'], array( 1, 3 ) ) ) ? 1 : 0,
|
||||
'pf_member_hide' => $field['hidden'] ? 'hide' : 'all',
|
||||
'pf_max_input' => $field['maxlength'],
|
||||
'pf_member_edit' => ( $field['editable'] >= 1 ) ? 1 : 0,
|
||||
'pf_position' => $field['displayorder'],
|
||||
'pf_show_on_reg' => ( $field['required'] == 2 ) ? 1 : 0,
|
||||
'pf_input_format' => $field['regex'],
|
||||
'pf_admin_only' => ( $field['editable'] == 0 ) ? 1 : 0,
|
||||
'pf_group_id' => $field['profilefieldcategoryid'],
|
||||
'pf_multiple' => $multiple
|
||||
);
|
||||
@@ -728,7 +775,7 @@ class _Vbulletin5 extends \IPS\convert\Software
|
||||
/**
|
||||
* Maps vBulletin Profile Field type to the IPS Equivalent
|
||||
*
|
||||
* @param string The vB Field Type
|
||||
* @param string $type The vB Field Type
|
||||
* @return string The IPS Field Type
|
||||
*/
|
||||
protected static function _pfieldMap( $type )
|
||||
@@ -791,7 +838,7 @@ class _Vbulletin5 extends \IPS\convert\Software
|
||||
$promotion = $this->db->select( '*', 'userpromotion', array( "usergroupid=?", $group['usergroupid'] ) )->first();
|
||||
|
||||
/* We only support Posts or Join Date */
|
||||
if ( in_array( $promotion['strategy'], array( 17, 18 ) ) )
|
||||
if ( \in_array( $promotion['strategy'], array( 17, 18 ) ) )
|
||||
{
|
||||
switch( $promotion['strategy'] )
|
||||
{
|
||||
@@ -889,7 +936,7 @@ class _Vbulletin5 extends \IPS\convert\Software
|
||||
}
|
||||
|
||||
/* Now check for group promotions */
|
||||
if( count( $libraryClass->groupPromotions ) )
|
||||
if( \count( $libraryClass->groupPromotions ) )
|
||||
{
|
||||
foreach( $libraryClass->groupPromotions as $groupPromotion )
|
||||
{
|
||||
@@ -901,7 +948,7 @@ class _Vbulletin5 extends \IPS\convert\Software
|
||||
/**
|
||||
* @brief Member history type map
|
||||
*/
|
||||
protected static $changeLogTypes = array( 'username' => 'display_name', 'email' => 'email_change', 'usergroupid' => 'member_group_id', 'membergroupids' => 'mgroup_others' );
|
||||
protected static $changeLogTypes = array( 'username' => 'display_name', 'email' => 'email_change', 'usergroupid' => 'group', 'membergroupids' => 'group' );
|
||||
|
||||
/**
|
||||
* Convert member history
|
||||
@@ -915,17 +962,24 @@ class _Vbulletin5 extends \IPS\convert\Software
|
||||
|
||||
foreach( $this->fetch( 'userchangelog', 'changeid', array( $this->db->in( 'fieldname', array_keys( static::$changeLogTypes ) ) ) ) AS $change )
|
||||
{
|
||||
$libraryClass->convertMemberHistory( array(
|
||||
'log_id' => $change['changeid'],
|
||||
'log_member' => $change['userid'],
|
||||
'log_by' => $change['adminid'],
|
||||
'log_type' => static::$changeLogTypes[ $change['fieldname'] ],
|
||||
'log_data' => array( 'old' => $change['oldvalue'], 'new' => $change['newvalue'] ),
|
||||
'log_date' => $change['change_time'],
|
||||
'log_ip_address' => long2ip( (int) $change['ipaddress'] )
|
||||
)
|
||||
$info = array(
|
||||
'log_id' => $change['changeid'],
|
||||
'log_member' => $change['userid'],
|
||||
'log_by' => $change['adminid'],
|
||||
'log_type' => static::$changeLogTypes[ $change['fieldname'] ],
|
||||
'log_data' => array( 'old' => $change['oldvalue'], 'new' => $change['newvalue'] ),
|
||||
'log_date' => $change['change_time'],
|
||||
'log_ip_address' => long2ip( (int) $change['ipaddress'] )
|
||||
);
|
||||
|
||||
/* Add extra data for group change */
|
||||
if( static::$changeLogTypes[ $change['fieldname'] ] == 'group' )
|
||||
{
|
||||
$info['log_data']['type'] = $change['fieldname'] == 'usergroupid' ? 'primary' : 'secondary';
|
||||
$info['log_data']['by'] = 'manual';
|
||||
}
|
||||
|
||||
$libraryClass->convertMemberHistory( $info );
|
||||
$libraryClass->setLastKeyValue( $change['changeid'] );
|
||||
}
|
||||
}
|
||||
@@ -941,6 +995,9 @@ class _Vbulletin5 extends \IPS\convert\Software
|
||||
|
||||
$libraryClass::setKey( 'user.userid' );
|
||||
|
||||
/* User titles */
|
||||
$userTitles = iterator_to_array( $this->db->select( 'title', 'usertitle' ) );
|
||||
|
||||
foreach( $this->fetch( 'user', 'user.userid', NULL, 'user.*, usertextfield.signature' )->join( 'usertextfield', 'user.userid = usertextfield.userid' ) AS $user )
|
||||
{
|
||||
/* <3 Closures */
|
||||
@@ -1036,9 +1093,9 @@ class _Vbulletin5 extends \IPS\convert\Software
|
||||
'member_id' => $user['userid'],
|
||||
'member_group_id' => $user['usergroupid'],
|
||||
'mgroup_others' => $user['membergroupids'],
|
||||
'name' => $user['username'],
|
||||
'name' => html_entity_decode( $user['username'], \ENT_QUOTES | \ENT_HTML5, 'UTF-8' ),
|
||||
'email' => $user['email'],
|
||||
'member_title' => $user['usertitle'],
|
||||
'member_title' => \in_array( $user['usertitle'], $userTitles ) ? NULL : $user['usertitle'],
|
||||
'joined' => $user['joindate'],
|
||||
'ip_address' => $user['ipaddress'],
|
||||
'warn_level' => $user['ipoints'],
|
||||
@@ -1056,10 +1113,10 @@ class _Vbulletin5 extends \IPS\convert\Software
|
||||
'members_bitoptions' => array(
|
||||
'view_sigs' => $checkpermission( 'useroptions', 'showsignatures' ), // View signatures?
|
||||
'coppa_user' => $checkpermission( 'useroptions', 'coppauser' ), // Was the member validated using coppa?
|
||||
'timezone_override' => !$checkpermission( 'useroptions', 'dstauto' ), // If TRUE, user's timezone will not be detected automatically
|
||||
),
|
||||
'members_bitoptions2' => array(
|
||||
'show_pm_popup' => $user['pmpopup'], // "Show pop-up when I have a new message"
|
||||
'is_anon' => $checkpermission( 'useroptions', 'invisible' ), // Anonymous status
|
||||
),
|
||||
'pp_setting_count_comments' => $checkpermission( 'useroptions', 'vm_enable' ),
|
||||
'pp_reputation_points' => $user['reputation'],
|
||||
@@ -1070,6 +1127,18 @@ class _Vbulletin5 extends \IPS\convert\Software
|
||||
'fb_uid' => $user['fbuserid'],
|
||||
'fb_token' => $user['fbaccesstoken']
|
||||
);
|
||||
|
||||
/* If there is a validation record for this user, treat them as validating */
|
||||
try
|
||||
{
|
||||
$activation = $this->db->select( '*', 'useractivation', array( "userid=?", $user['userid'] ) )->first();
|
||||
|
||||
$info['members_bitoptions']['validating'] = TRUE;
|
||||
}
|
||||
catch( \UnderflowException $e )
|
||||
{
|
||||
$activation = NULL;
|
||||
}
|
||||
|
||||
/* Profile Fields */
|
||||
try
|
||||
@@ -1113,11 +1182,10 @@ class _Vbulletin5 extends \IPS\convert\Software
|
||||
'pf_desc' => '',
|
||||
'pf_type' => 'Text',
|
||||
'pf_content' => '[]',
|
||||
'pf_member_hide' => 0,
|
||||
'pf_member_hide' => 'all',
|
||||
'pf_max_input' => 255,
|
||||
'pf_member_edit' => 1,
|
||||
'pf_show_on_reg' => 0,
|
||||
'pf_admin_only' => 0,
|
||||
) );
|
||||
}
|
||||
|
||||
@@ -1126,16 +1194,21 @@ class _Vbulletin5 extends \IPS\convert\Software
|
||||
|
||||
/* Profile Photos */
|
||||
$firstTable = 'customavatar';
|
||||
$secondTable = 'customprofilepic';
|
||||
$secondTable = !static::$skipCustomProfilePic ? 'customprofilepic' : FALSE; # vB 5.5.3 removes the customprofilepic table
|
||||
if ( $this->app->_session['more_info']['convertMembers']['photo_type'] == 'profile_photos' )
|
||||
{
|
||||
$firstTable = 'customprofilepic';
|
||||
$firstTable = !static::$skipCustomProfilePic ? 'customprofilepic' : FALSE; # vB 5.5.3 removes the customprofilepic table
|
||||
$secondTable = 'customavatar';
|
||||
}
|
||||
if ( $this->app->_session['more_info']['convertMembers']['photo_location'] == 'database' )
|
||||
{
|
||||
try
|
||||
{
|
||||
if( $firstTable === FALSE )
|
||||
{
|
||||
throw new \UnderflowException();
|
||||
}
|
||||
|
||||
foreach( $this->db->select( 'filedata, filename', $firstTable, array( "userid=?", $user['userid'] ) )->first() AS $key => $value )
|
||||
{
|
||||
if ( $key == 'filedata' )
|
||||
@@ -1153,6 +1226,11 @@ class _Vbulletin5 extends \IPS\convert\Software
|
||||
{
|
||||
try
|
||||
{
|
||||
if( $secondTable === FALSE )
|
||||
{
|
||||
throw new \UnderflowException();
|
||||
}
|
||||
|
||||
foreach( $this->db->select( 'filedata, filename', $secondTable, array( "userid=?", $user['userid'] ) )->first() AS $key => $value )
|
||||
{
|
||||
if ( $key == 'filedata' )
|
||||
@@ -1188,6 +1266,11 @@ class _Vbulletin5 extends \IPS\convert\Software
|
||||
{
|
||||
try
|
||||
{
|
||||
if( $firstTable === FALSE )
|
||||
{
|
||||
throw new \UnderflowException();
|
||||
}
|
||||
|
||||
$ext = $this->db->select( 'filename', $firstTable, array( "userid=?", $user['userid'] ) )->first();
|
||||
$ext = explode( '.', $ext );
|
||||
$ext = array_pop( $ext );
|
||||
@@ -1204,6 +1287,11 @@ class _Vbulletin5 extends \IPS\convert\Software
|
||||
}
|
||||
catch( \UnderflowException $e )
|
||||
{
|
||||
if( $secondTable === FALSE )
|
||||
{
|
||||
throw new \UnderflowException();
|
||||
}
|
||||
|
||||
$ext = $this->db->select( 'filename', $secondTable, array( "userid=?", $user['userid'] ) )->first();
|
||||
$ext = explode( '.', $ext );
|
||||
$ext = array_pop( $ext );
|
||||
@@ -1225,14 +1313,29 @@ class _Vbulletin5 extends \IPS\convert\Software
|
||||
}
|
||||
}
|
||||
|
||||
$libraryClass->convertMember( $info, $profileFields, $filename, $filepath, $filedata );
|
||||
$memberId = $libraryClass->convertMember( $info, $profileFields, $filename, $filepath, $filedata );
|
||||
|
||||
/* If we are validating, store our validation row entry */
|
||||
if( $activation !== NULL AND $memberId )
|
||||
{
|
||||
\IPS\Db::i()->replace( 'core_validating', array(
|
||||
'vid' => md5( $activation['activationid'] . $activation['useractivationid'] ),
|
||||
'member_id' => $memberId,
|
||||
'entry_date' => $activation['dateline'],
|
||||
'new_reg' => ( $activation['emailchange'] == 0 ? TRUE : FALSE ),
|
||||
'email_chg' => ( $activation['emailchange'] == 1 ? TRUE : FALSE ),
|
||||
'user_verified' => FALSE,
|
||||
'ip_address' => $user['ipaddress'],
|
||||
'email_sent' => $activation['dateline']
|
||||
) );
|
||||
}
|
||||
|
||||
/* Any friends need converting to followers? */
|
||||
foreach( $this->db->select( '*', 'userlist', array( "type=? AND friend=? AND userid=?", 'buddy', 'yes', $user['userid'] ) ) AS $follower )
|
||||
{
|
||||
$libraryClass->convertFollow( array(
|
||||
'follow_app' => 'core',
|
||||
'follow_area' => 'members',
|
||||
'follow_area' => 'member',
|
||||
'follow_rel_id' => $follower['relationid'],
|
||||
'follow_rel_id_type' => 'core_members',
|
||||
'follow_member_id' => $follower['userid'],
|
||||
@@ -1360,7 +1463,7 @@ class _Vbulletin5 extends \IPS\convert\Software
|
||||
foreach( $this->db->select( 'userid', 'node', array( "parentid=?", $pm['nodeid'] ) ) AS $userid )
|
||||
{
|
||||
$to[$userid] = $userid;
|
||||
if ( is_null( $toId ) AND $userid != $pm['userid'] )
|
||||
if ( \is_null( $toId ) AND $userid != $pm['userid'] )
|
||||
{
|
||||
$toId = $userid;
|
||||
}
|
||||
@@ -1373,7 +1476,7 @@ class _Vbulletin5 extends \IPS\convert\Software
|
||||
'mt_starter_id' => $pm['userid'],
|
||||
'mt_start_time' => $pm['publishdate'],
|
||||
'mt_last_post_time' => $pm['lastcontent'],
|
||||
'mt_to_count' => count( $to ),
|
||||
'mt_to_count' => \count( $to ),
|
||||
'mt_to_member_id' => $toId,
|
||||
'mt_replies' => $replies,
|
||||
'mt_first_msg_id' => $pm['nodeid'],
|
||||
@@ -1549,7 +1652,7 @@ class _Vbulletin5 extends \IPS\convert\Software
|
||||
$iconpath = NULL;
|
||||
if ( $filedata )
|
||||
{
|
||||
if ( $this->app->_session['more_info']['convertClubs']['photo_location'] == 'database' )
|
||||
if ( $this->app->_session['more_info']['convertClubs']['club_photo_location'] == 'database' )
|
||||
{
|
||||
$icondata = $filedata['filedata'];
|
||||
}
|
||||
@@ -1557,7 +1660,7 @@ class _Vbulletin5 extends \IPS\convert\Software
|
||||
{
|
||||
$folder = preg_split( '//', $filedata['userid'], NULL, PREG_SPLIT_NO_EMPTY );
|
||||
$folder = implode( '/', $folder );
|
||||
$iconpath = $this->app->_session['more_info']['convertClubs']['photo_location'] . '/' . $folder . '/' . $filedata['filedataid'] . '.attach';
|
||||
$iconpath = $this->app->_session['more_info']['convertClubs']['club_photo_location'] . '/' . $folder . '/' . $filedata['filedataid'] . '.attach';
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1779,7 +1882,7 @@ class _Vbulletin5 extends \IPS\convert\Software
|
||||
/**
|
||||
* Get Setting Value - useful for global settings that need to be translated to group or member settings
|
||||
*
|
||||
* @param $key The setting key
|
||||
* @param string $key The setting key
|
||||
* @return mixed
|
||||
*/
|
||||
protected function _setting( $key )
|
||||
@@ -1876,7 +1979,8 @@ class _Vbulletin5 extends \IPS\convert\Software
|
||||
/**
|
||||
* Helper method to retrieve content type ids
|
||||
*
|
||||
* @return void
|
||||
* @param string $type Content type
|
||||
* @return string
|
||||
*/
|
||||
protected function fetchType( $type )
|
||||
{
|
||||
|
||||
@@ -0,0 +1,812 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @brief Converter Woltlab Suite Core Class
|
||||
* @author <a href='https://www.invisioncommunity.com'>Invision Power Services, Inc.</a>
|
||||
* @copyright (c) Invision Power Services, Inc.
|
||||
* @package Invision Community
|
||||
* @subpackage convert
|
||||
* @since 26 Mar 2020
|
||||
*/
|
||||
|
||||
namespace IPS\convert\Software\Core;
|
||||
|
||||
/* To prevent PHP errors (extending class does not exist) revealing path */
|
||||
if ( !\defined( '\IPS\SUITE_UNIQUE_KEY' ) )
|
||||
{
|
||||
header( ( isset( $_SERVER['SERVER_PROTOCOL'] ) ? $_SERVER['SERVER_PROTOCOL'] : 'HTTP/1.0' ) . ' 403 Forbidden' );
|
||||
exit;
|
||||
}
|
||||
|
||||
/**
|
||||
* Woltlab Suite Core Converter
|
||||
*/
|
||||
class _Woltlab extends \IPS\convert\Software
|
||||
{
|
||||
/**
|
||||
* @brief The WCF table prefix can change depending on the number of installs
|
||||
*/
|
||||
public static $installId = 1;
|
||||
|
||||
/**
|
||||
* Software Name
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function softwareName()
|
||||
{
|
||||
/* Child classes must override this method */
|
||||
return "WoltLab Suite (3.1)";
|
||||
}
|
||||
|
||||
/**
|
||||
* Software Key
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function softwareKey()
|
||||
{
|
||||
/* Child classes must override this method */
|
||||
return "woltlab";
|
||||
}
|
||||
|
||||
/**
|
||||
* Content we can convert from this software.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public static function canConvert()
|
||||
{
|
||||
return array(
|
||||
'convertProfileFieldGroups' => array(
|
||||
'table' => 'wcf' . static::$installId . '_user_option_category',
|
||||
'where' => array( 'parentCategoryName=?', 'profile' )
|
||||
),
|
||||
'convertProfileFields' => array(
|
||||
'table' => 'wcf' . static::$installId . '_user_option',
|
||||
'where' => NULL
|
||||
),
|
||||
'convertEmoticons' => array(
|
||||
'table' => 'wcf' . static::$installId . '_smiley',
|
||||
'where' => NULL
|
||||
),
|
||||
'convertIgnoredUsers' => array(
|
||||
'table' => 'wcf' . static::$installId . '_user_ignore',
|
||||
'where' => NULL
|
||||
),
|
||||
'convertGroups' => array(
|
||||
'table' => 'wcf' . static::$installId . '_user_group',
|
||||
'where' => NULL
|
||||
),
|
||||
'convertMembers' => array(
|
||||
'table' => 'wcf' . static::$installId . '_user',
|
||||
'where' => NULL
|
||||
),
|
||||
'convertRanks' => array(
|
||||
'table' => 'wcf' . static::$installId . '_user_rank',
|
||||
'where' => array( 'requiredPoints>0' )
|
||||
),
|
||||
'convertPrivateMessages' => array(
|
||||
'table' => 'wcf' . static::$installId . '_conversation',
|
||||
'where' => NULL
|
||||
),
|
||||
'convertPrivateMessageReplies' => array(
|
||||
'table' => 'wcf' . static::$installId . '_conversation_message',
|
||||
'where' => NULL,
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Count Source Rows for a specific step
|
||||
*
|
||||
* @param string $table The table containing the rows to count.
|
||||
* @param array|NULL $where WHERE clause to only count specific rows, or NULL to count all.
|
||||
* @param bool $recache Skip cache and pull directly (updating cache)
|
||||
* @return integer
|
||||
* @throws \IPS\convert\Exception
|
||||
*/
|
||||
public function countRows( $table, $where=NULL, $recache=FALSE )
|
||||
{
|
||||
switch( $table )
|
||||
{
|
||||
case 'wcf' . static::$installId . '_user_option':
|
||||
try
|
||||
{
|
||||
$where = array( "categoryName LIKE 'profile.%' OR " . $this->db->in( 'categoryName', iterator_to_array( $this->db->select( 'categoryName', static::canConvert()['convertProfileFieldGroups']['table'], static::canConvert()['convertProfileFieldGroups']['where'] ) ) ) );
|
||||
return $this->db->select( 'count(optionID)', 'wcf' . static::$installId . '_user_option', $where )->first();
|
||||
}
|
||||
catch( \Exception $e )
|
||||
{
|
||||
throw new \IPS\convert\Exception( sprintf( \IPS\Member::loggedIn()->language()->get( 'could_not_count_rows' ), $table ) );
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
return parent::countRows( $table, $where, $recache );
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Can we convert passwords from this software.
|
||||
*
|
||||
* @return boolean
|
||||
*/
|
||||
public static function loginEnabled()
|
||||
{
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* List of conversion methods that require additional information
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public static function checkConf()
|
||||
{
|
||||
return array(
|
||||
'convertProfileFieldGroups',
|
||||
'convertProfileFields',
|
||||
'convertEmoticons',
|
||||
'convertGroups',
|
||||
'convertMembers'
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get More Information
|
||||
*
|
||||
* @param string $method Conversion method
|
||||
* @return array
|
||||
*/
|
||||
public function getMoreInfo( $method )
|
||||
{
|
||||
$return = array();
|
||||
switch( $method )
|
||||
{
|
||||
case 'convertProfileFieldGroups':
|
||||
$return['convertProfileFieldGroups'] = array();
|
||||
$options = array();
|
||||
$options['none'] = \IPS\Member::loggedIn()->language()->addToStack( 'none' );
|
||||
foreach( new \IPS\Patterns\ActiveRecordIterator( \IPS\Db::i()->select( '*', 'core_pfields_groups' ), 'IPS\core\ProfileFields\Group' ) AS $group )
|
||||
{
|
||||
$options[ $group->_id ] = $group->_title;
|
||||
}
|
||||
|
||||
foreach( $this->db->select( '*', 'wcf' . static::$installId . '_user_option_category', array( 'parentCategoryName=?', 'profile' ) ) AS $group )
|
||||
{
|
||||
\IPS\Member::loggedIn()->language()->words["map_pfgroup_{$group['categoryID']}"] = $this->getLanguage( $group['categoryName'], 'wcf.user.option.category' );
|
||||
\IPS\Member::loggedIn()->language()->words["map_pfgroup_{$group['categoryID']}_desc"] = \IPS\Member::loggedIn()->language()->addToStack( 'map_pfgroup_desc' );
|
||||
|
||||
$return['convertProfileFieldGroups']["map_pfgroup_{$group['categoryID']}"] = array(
|
||||
'field_class' => 'IPS\\Helpers\\Form\\Select',
|
||||
'field_default' => NULL,
|
||||
'field_required' => FALSE,
|
||||
'field_extra' => array( 'options' => $options ),
|
||||
'field_hint' => NULL,
|
||||
);
|
||||
}
|
||||
break;
|
||||
|
||||
case 'convertProfileFields':
|
||||
$return['convertProfileFields'] = array();
|
||||
|
||||
$options = array();
|
||||
$options['none'] = \IPS\Member::loggedIn()->language()->addToStack( 'none' );
|
||||
foreach( new \IPS\Patterns\ActiveRecordIterator( \IPS\Db::i()->select( '*', 'core_pfields_data' ), 'IPS\core\ProfileFields\Field' ) AS $field )
|
||||
{
|
||||
$options[ $field->_id ] = $field->_title;
|
||||
}
|
||||
|
||||
$where = array( "categoryName LIKE 'profile.%' OR " . $this->db->in( 'categoryName', iterator_to_array( $this->db->select( 'categoryName', static::canConvert()['convertProfileFieldGroups']['table'], static::canConvert()['convertProfileFieldGroups']['where'] ) ) ) );
|
||||
foreach( $this->db->select( '*', 'wcf' . static::$installId . '_user_option', $where ) AS $field )
|
||||
{
|
||||
\IPS\Member::loggedIn()->language()->words["map_pfield_{$field['optionID']}"] = $this->getLanguage( $field['optionName'], 'wcf.user.option' );
|
||||
\IPS\Member::loggedIn()->language()->words["map_pfield_{$field['optionID']}_desc"] = \IPS\Member::loggedIn()->language()->addToStack( 'map_pfield_desc' );
|
||||
|
||||
$return['convertProfileFields']["map_pfield_{$field['optionID']}"] = array(
|
||||
'field_class' => 'IPS\\Helpers\\Form\\Select',
|
||||
'field_default' => NULL,
|
||||
'field_required' => FALSE,
|
||||
'field_extra' => array( 'options' => $options ),
|
||||
'field_hint' => NULL,
|
||||
);
|
||||
}
|
||||
break;
|
||||
|
||||
case 'convertEmoticons':
|
||||
\IPS\Member::loggedIn()->language()->words['emoticon_path'] = \IPS\Member::loggedIn()->language()->addToStack( 'source_path', FALSE, array( 'sprintf' => array( 'Woltlab' ) ) );
|
||||
$return['convertEmoticons'] = array(
|
||||
'emoticon_path' => array(
|
||||
'field_class' => 'IPS\\Helpers\\Form\\Text',
|
||||
'field_default' => NULL,
|
||||
'field_required' => TRUE,
|
||||
'field_extra' => array(),
|
||||
'field_hint' => NULL,
|
||||
'field_validation' => function( $value ) { if ( !@is_dir( $value ) ) { throw new \DomainException( 'path_invalid' ); } },
|
||||
),
|
||||
'keep_existing_emoticons' => array(
|
||||
'field_class' => 'IPS\\Helpers\\Form\\Checkbox',
|
||||
'field_default' => TRUE,
|
||||
'field_required' => FALSE,
|
||||
'field_extra' => array(),
|
||||
'field_hint' => NULL,
|
||||
)
|
||||
);
|
||||
break;
|
||||
|
||||
case 'convertGroups':
|
||||
$return['convertGroups'] = array();
|
||||
|
||||
$options = array();
|
||||
$options['none'] = \IPS\Member::loggedIn()->language()->addToStack( 'none' );
|
||||
foreach( new \IPS\Patterns\ActiveRecordIterator( \IPS\Db::i()->select( '*', 'core_groups' ), 'IPS\Member\Group' ) AS $group )
|
||||
{
|
||||
$options[ $group->g_id ] = $group->name;
|
||||
}
|
||||
|
||||
foreach( $this->db->select( '*', 'wcf' . static::$installId . '_user_group' ) AS $group )
|
||||
{
|
||||
\IPS\Member::loggedIn()->language()->words["map_group_{$group['groupID']}"] = $this->getLanguage( $group['groupName'] );
|
||||
\IPS\Member::loggedIn()->language()->words["map_group_{$group['groupID']}_desc"] = \IPS\Member::loggedIn()->language()->addToStack( 'map_group_desc' );
|
||||
|
||||
$return['convertGroups']["map_group_{$group['groupID']}"] = array(
|
||||
'field_class' => 'IPS\\Helpers\\Form\\Select',
|
||||
'field_default' => NULL,
|
||||
'field_required' => FALSE,
|
||||
'field_extra' => array( 'options' => $options ),
|
||||
'field_hint' => NULL
|
||||
);
|
||||
}
|
||||
break;
|
||||
|
||||
case 'convertMembers':
|
||||
$return['convertMembers'] = array();
|
||||
|
||||
/* Find out where the photos live */
|
||||
\IPS\Member::loggedIn()->language()->words['photo_location'] = \IPS\Member::loggedIn()->language()->addToStack( 'convert_woltlab_avatar' );
|
||||
\IPS\Member::loggedIn()->language()->words['photo_location_desc'] = \IPS\Member::loggedIn()->language()->addToStack( 'convert_woltlab_avatar_desc' );
|
||||
$return['convertMembers']['photo_location'] = array(
|
||||
'field_class' => 'IPS\\Helpers\\Form\\Text',
|
||||
'field_default' => NULL,
|
||||
'field_required' => TRUE,
|
||||
'field_extra' => array(),
|
||||
'field_hint' => NULL,
|
||||
'field_validation' => function( $value ) { if ( !@is_dir( $value ) ) { throw new \DomainException( 'path_invalid' ); } },
|
||||
);
|
||||
\IPS\Member::loggedIn()->language()->words['coverphoto_location'] = \IPS\Member::loggedIn()->language()->addToStack( 'convert_woltlab_cover' );
|
||||
\IPS\Member::loggedIn()->language()->words['coverphoto_location_desc'] = \IPS\Member::loggedIn()->language()->addToStack( 'convert_woltlab_cover_desc' );
|
||||
$return['convertMembers']['coverphoto_location'] = array(
|
||||
'field_class' => 'IPS\\Helpers\\Form\\Text',
|
||||
'field_default' => NULL,
|
||||
'field_required' => TRUE,
|
||||
'field_extra' => array(),
|
||||
'field_hint' => NULL,
|
||||
'field_validation' => function( $value ) { if ( !@is_dir( $value ) ) { throw new \DomainException( 'path_invalid' ); } },
|
||||
);
|
||||
break;
|
||||
}
|
||||
|
||||
return ( isset( $return[ $method ] ) ) ? $return[ $method ] : array();
|
||||
}
|
||||
|
||||
/**
|
||||
* Finish - Adds everything it needs to the queues and clears data store
|
||||
*
|
||||
* @return array Messages to display
|
||||
*/
|
||||
public function finish()
|
||||
{
|
||||
/* Search Index Rebuild */
|
||||
\IPS\Content\Search\Index::i()->rebuild();
|
||||
|
||||
/* Clear Cache and Store */
|
||||
\IPS\Data\Store::i()->clearAll();
|
||||
\IPS\Data\Cache::i()->clearAll();
|
||||
|
||||
/* Non-Content Rebuilds */
|
||||
\IPS\Task::queue( 'convert', 'RebuildNonContent', array( 'app' => $this->app->app_id, 'link' => 'core_announcements', 'extension' => 'core_Announcement' ), 2, array( 'app', 'link', 'extension' ) );
|
||||
\IPS\Task::queue( 'convert', 'RebuildNonContent', array( 'app' => $this->app->app_id, 'link' => 'core_message_posts', 'extension' => 'core_Messaging' ), 2, array( 'app', 'link', 'extension' ) );
|
||||
\IPS\Task::queue( 'convert', 'RebuildNonContent', array( 'app' => $this->app->app_id, 'link' => 'core_members', 'extension' => 'core_Signatures' ), 2, array( 'app', 'link', 'extension' ) );
|
||||
|
||||
/* Content Counts */
|
||||
\IPS\Task::queue( 'core', 'RecountMemberContent', array( 'app' => $this->app->app_id ), 4, array( 'app' ) );
|
||||
\IPS\Task::queue( 'core', 'RebuildItemCounts', array( 'class' => 'IPS\core\Messenger\Message' ), 3, array( 'class' ) );
|
||||
|
||||
/* First Post Data */
|
||||
\IPS\Task::queue( 'convert', 'RebuildConversationFirstIds', array( 'app' => $this->app->app_id ), 2, array( 'app' ) );
|
||||
|
||||
/* Attachments */
|
||||
\IPS\Task::queue( 'core', 'RebuildAttachmentThumbnails', array( 'app' => $this->app->app_id ), 1, array( 'app' ) );
|
||||
|
||||
return array( "f_search_index_rebuild", "f_clear_caches", "f_rebuild_pms", "f_signatures_rebuild" );
|
||||
}
|
||||
|
||||
/**
|
||||
* Fix Post Data
|
||||
*
|
||||
* @param string $post Post
|
||||
* @return string Fixed Post
|
||||
*/
|
||||
public static function fixPostData( $post )
|
||||
{
|
||||
return $post;
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert profile field groups
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function convertProfileFieldGroups()
|
||||
{
|
||||
$libraryClass = $this->getLibrary();
|
||||
$libraryClass::setKey( 'categoryID' );
|
||||
|
||||
foreach( $this->fetch( 'wcf' . static::$installId . '_user_option_category', 'categoryID', array( 'parentCategoryName=?', 'profile' ) ) AS $group )
|
||||
{
|
||||
$name = $this->getLanguage( $group['categoryName'], 'wcf.user.option.category' );
|
||||
|
||||
$merge = ( $this->app->_session['more_info']['convertProfileFieldGroups']["map_pfgroup_{$group['categoryID']}"] != 'none' ) ? $this->app->_session['more_info']['convertProfileFieldGroups']["map_pfgroup_{$group['categoryID']}"] : NULL;
|
||||
|
||||
$libraryClass->convertProfileFieldGroup( array(
|
||||
'pf_group_id' => $group['categoryID'],
|
||||
'pf_group_name' => $name,
|
||||
'pf_group_order' => $group['showOrder']
|
||||
), $merge );
|
||||
|
||||
$libraryClass->setLastKeyValue( $group['categoryID'] );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert profile fields
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function convertProfileFields()
|
||||
{
|
||||
$libraryClass = $this->getLibrary();
|
||||
$libraryClass::setKey( 'optionID' );
|
||||
|
||||
$where = array( "categoryName LIKE 'profile.%' OR " . $this->db->in( 'categoryName', iterator_to_array( $this->db->select( 'categoryName', static::canConvert()['convertProfileFieldGroups']['table'], static::canConvert()['convertProfileFieldGroups']['where'] ) ) ) );
|
||||
foreach ( $this->fetch( 'wcf' . static::$installId . '_user_option', 'optionID', $where ) AS $field )
|
||||
{
|
||||
/* Birthday is special */
|
||||
if( \in_array( $field['optionName'], ['birthday', 'birthdayShowYear'] ) )
|
||||
{
|
||||
$libraryClass->setLastKeyValue( $field['optionID'] );
|
||||
continue;
|
||||
}
|
||||
|
||||
$content = [];
|
||||
switch( $field['optionType'] )
|
||||
{
|
||||
case 'aboutMe':
|
||||
$type = 'Editor';
|
||||
break;
|
||||
case 'boolean':
|
||||
$type = 'YesNo';
|
||||
break;
|
||||
case 'text':
|
||||
case 'URL':
|
||||
$type = ucwords( mb_strtolower( $field['optionType'] ) );
|
||||
break;
|
||||
case 'textarea':
|
||||
$type = 'TextArea';
|
||||
break;
|
||||
case 'select':
|
||||
$type = 'Select';
|
||||
|
||||
foreach( explode( "\n", $field['selectOptions'] ) as $opt )
|
||||
{
|
||||
list( $id, $lang ) = explode( ':', $opt );
|
||||
$content[ $id ] = $this->getLanguage( $lang );
|
||||
}
|
||||
|
||||
break;
|
||||
default:
|
||||
$type = 'Text';
|
||||
break;
|
||||
}
|
||||
|
||||
$category = $this->db->select( 'categoryID', 'wcf' . static::$installId . '_user_option_category', array( 'categoryName=?', $field['categoryName'] ) )->first();
|
||||
$info = array(
|
||||
'pf_id' => $field['optionID'],
|
||||
'pf_name' => $this->getLanguage( $field['optionName'], 'wcf.user.option' ),
|
||||
'pf_desc' => $this->getLanguage( $field['optionName'], 'wcf.user.option.' . $field['optionName'] . '.description' ),
|
||||
'pf_type' => $type,
|
||||
'pf_content' => json_encode( $content ),
|
||||
'pf_not_null' => $field['required'],
|
||||
'pf_member_hide' => $field['visible'] == 15 ? 'all' : 'hide',
|
||||
'pf_member_edit' => ( $field['editable'] >= 1 ) ? 1 : 0,
|
||||
'pf_position' => $field['showOrder'],
|
||||
'pf_show_on_reg' => $field['askDuringRegistration'],
|
||||
'pf_input_format' => $field['validationPattern'],
|
||||
'pf_group_id' => $category
|
||||
);
|
||||
|
||||
$merge = ( $this->app->_session['more_info']['convertProfileFields']["map_pfield_{$field['optionID']}"] != 'none' ) ? $this->app->_session['more_info']['convertProfileFields']["map_pfield_{$field['optionID']}"] : NULL;
|
||||
$libraryClass->convertProfileField( $info, $merge );
|
||||
$libraryClass->setLastKeyValue( $field['optionID'] );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert emoticons
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function convertEmoticons()
|
||||
{
|
||||
$libraryClass = $this->getLibrary();
|
||||
$libraryClass::setKey( 'smileyID' );
|
||||
|
||||
foreach( $this->fetch( 'wcf' . static::$installId . '_smiley', 'smileyID' ) AS $row )
|
||||
{
|
||||
/* We need to figure out where our file lives - if it's remote, then we need to use file_get_contents() and pass the raw data. */
|
||||
$filepathx2 = NULL;
|
||||
$filenamex2 = NULL;
|
||||
|
||||
$filename = basename( $row['smileyPath'] );
|
||||
$filepath = rtrim( $this->app->_session['more_info']['convertEmoticons']['emoticon_path'], '/' ) . '/' . $row['smileyPath'];
|
||||
|
||||
if( !empty( $row['smileyPath2x'] ) )
|
||||
{
|
||||
$filenamex2 = basename( $row['smileyPath2x'] );
|
||||
$filepathx2 = rtrim( $this->app->_session['more_info']['convertEmoticons']['emoticon_path'], '/' ) . '/' . $row['smileyPath2x'];
|
||||
}
|
||||
|
||||
$category = array(
|
||||
'display_order' => 1,
|
||||
);
|
||||
|
||||
$title = "Converted";
|
||||
$set = array(
|
||||
'set' => md5( $title ),
|
||||
'title' => $title,
|
||||
'position' => $category['display_order']
|
||||
);
|
||||
|
||||
$info = array(
|
||||
'id' => $row['smileyID'],
|
||||
'typed' => $row['smileyCode'],
|
||||
'filename' => $filename,
|
||||
'filenamex2' => $filenamex2,
|
||||
'emo_position' => $row['showOrder'],
|
||||
);
|
||||
|
||||
$libraryClass->convertEmoticon( $info, $set, $this->app->_session['more_info']['convertEmoticons']['keep_existing_emoticons'], $filepath, NULL, $filepathx2, NULL );
|
||||
$libraryClass->setLastKeyValue( $row['smileyID'] );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert groups
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function convertGroups()
|
||||
{
|
||||
$libraryClass = $this->getLibrary();
|
||||
$libraryClass::setKey( 'groupID' );
|
||||
|
||||
foreach( $this->fetch( 'wcf' . static::$installId . '_user_group', 'groupID' ) AS $row )
|
||||
{
|
||||
/* Username Styles */
|
||||
$style = explode( '%s', $row['userOnlineMarking'] );
|
||||
$prefix = isset( $style[0] ) ? $style[0] : '';
|
||||
$suffix = isset( $style[1] ) ? $style[1] : '';
|
||||
|
||||
$info = array(
|
||||
'g_id' => $row['groupID'],
|
||||
'g_name' => $this->getLanguage( $row['groupName'] ),
|
||||
'prefix' => $prefix,
|
||||
'suffix' => $suffix,
|
||||
);
|
||||
|
||||
$merge = $this->app->_session['more_info']['convertGroups']["map_group_{$row['groupID']}"] != 'none' ? $this->app->_session['more_info']['convertGroups']["map_group_{$row['groupID']}"] : NULL;
|
||||
|
||||
$libraryClass->convertGroup( $info, $merge );
|
||||
$libraryClass->setLastKeyValue( $row['groupID'] );
|
||||
}
|
||||
|
||||
/* Now check for group promotions */
|
||||
if( \count( $libraryClass->groupPromotions ) )
|
||||
{
|
||||
foreach( $libraryClass->groupPromotions as $groupPromotion )
|
||||
{
|
||||
$libraryClass->convertGroupPromotion( $groupPromotion );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert members
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function convertMembers()
|
||||
{
|
||||
$libraryClass = $this->getLibrary();
|
||||
$libraryClass::setKey( 'userID' );
|
||||
|
||||
$options = iterator_to_array( $this->db->select( 'optionID, optionName', 'wcf' . static::$installId . '_user_option' )->setKeyField( 'optionName' )->setValueField( 'optionID' ) );
|
||||
|
||||
/* Profile Fields */
|
||||
$where = array( "categoryName LIKE 'profile.%' OR " . $this->db->in( 'categoryName', iterator_to_array( $this->db->select( 'categoryName', static::canConvert()['convertProfileFieldGroups']['table'], static::canConvert()['convertProfileFieldGroups']['where'] ) ) ) );
|
||||
$userProfileOptions = iterator_to_array( $this->db->select( 'optionID, optionName', 'wcf' . static::$installId . '_user_option', $where )->setKeyField('optionID')->setValueField('optionName') );
|
||||
|
||||
/* User titles */
|
||||
$userTitles = [];
|
||||
foreach( $this->db->select( 'rankTitle', 'wcf' . static::$installId . '_user_rank' ) as $rank )
|
||||
{
|
||||
$userTitle[] = $this->getLanguage( $rank );
|
||||
}
|
||||
|
||||
foreach ( $this->fetch( 'wcf' . static::$installId . '_user', 'userID' ) AS $row )
|
||||
{
|
||||
$fields = $this->db->select( '*', 'wcf' . static::$installId . '_user_option_value', array( 'userID=?', $row['userID'] ) )->first();
|
||||
$userFields = array();
|
||||
foreach( $options as $name => $opt )
|
||||
{
|
||||
$userFields[ $name ] = $fields[ 'userOption' . $opt ];
|
||||
}
|
||||
|
||||
/* Is there a birthdate? */
|
||||
$birthdayYear = $birthdayMonth = $birthdayDay = NULL;
|
||||
if( !empty( $userFields['birthday'] ) )
|
||||
{
|
||||
list( $birthdayYear, $birthdayMonth, $birthdayDay ) = explode( '-', $userFields['birthday'] );
|
||||
}
|
||||
|
||||
/* Member Groups */
|
||||
$memberGroups = iterator_to_array( $this->db->select( 'groupID', 'wcf' . static::$installId . '_user_to_group', array( 'userID=?', $row['userID'] ) )->setKeyField('groupID') );
|
||||
unset( $memberGroups[ $row['userOnlineGroupID'] ] );
|
||||
|
||||
$info = array(
|
||||
'member_id' => $row['userID'],
|
||||
'name' => html_entity_decode( $row['username'], \ENT_QUOTES | \ENT_HTML5, 'UTF-8' ),
|
||||
'email' => $row['email'],
|
||||
'password' => $row['password'],
|
||||
'member_group_id' => $row['userOnlineGroupID'],
|
||||
'joined' => $row['registrationDate'],
|
||||
'member_title' => \in_array( $row['userTitle'], $userTitles ) OR empty( $row['userTitle'] ) ? NULL : $row['userTitle'],
|
||||
'bday_day' => $birthdayDay,
|
||||
'bday_month' => $birthdayMonth,
|
||||
'bday_year' => $birthdayYear,
|
||||
'last_visit' => $row['lastActivityTime'],
|
||||
'last_activity' => $row['lastActivityTime'],
|
||||
'temp_ban' => $row['banned'] ? ( $row['banExpires'] ?: -1 ) : NULL,
|
||||
'mgroup_others' => $memberGroups,
|
||||
'signature' => $row['signature'],
|
||||
'allow_admin_mails' => $userFields['adminCanMail'],
|
||||
'member_posts' => $row['wbbPosts'],
|
||||
'auto_track' => $userFields['watchThreadOnReply'] ? array( 'content' => 1, 'comments' => 1, 'method' => 'immediate' ) : NULL,
|
||||
'members_profile_views' => $row['profileHits']
|
||||
);
|
||||
|
||||
/* Avatars */
|
||||
$filename = $filepath = NULL;
|
||||
if( !empty( $row['avatarID'] ) )
|
||||
{
|
||||
try
|
||||
{
|
||||
$avatar = $this->db->select( '*', 'wcf' . static::$installId . '_user_avatar', array( 'avatarID=?', $row['avatarID'] ) )->first();
|
||||
$filename = $row['avatarID'] . '-' . $avatar['fileHash'] . '.' . $avatar['avatarExtension'];
|
||||
$filepath = rtrim( $this->app->_session['more_info']['convertMembers']['photo_location'], '/' ) . '/' . mb_substr( $avatar['fileHash'], 0, 2 );
|
||||
}
|
||||
catch( \UnderflowException $e ) {}
|
||||
}
|
||||
|
||||
/* Cover Photo */
|
||||
$coverFileName = $coverFilePath = NULL;
|
||||
if( !empty( $row['coverPhotoHash'] ) )
|
||||
{
|
||||
$coverFileName = $row['userID'] . '-' . $row['coverPhotoHash'] . '.' . $row['coverPhotoExtension'];
|
||||
$coverFilePath = rtrim( $this->app->_session['more_info']['convertMembers']['coverphoto_location'], '/' ) . '/' . mb_substr( $row['coverPhotoHash'], 0, 2 );
|
||||
}
|
||||
|
||||
/* Profile Fields */
|
||||
$profileFields = array();
|
||||
foreach( $userProfileOptions as $k => $v )
|
||||
{
|
||||
$profileFields[ $k ] = $userFields[ $v ];
|
||||
}
|
||||
|
||||
$libraryClass->convertMember( $info, $profileFields, $filename, $filepath, NULL, $coverFileName, $coverFilePath );
|
||||
|
||||
/* Any friends need converting to followers? */
|
||||
foreach( $this->db->select( '*', 'wcf' . static::$installId . '_user_follow', array( "userID=?", $row['userID'] ) ) AS $follower )
|
||||
{
|
||||
$libraryClass->convertFollow( array(
|
||||
'follow_app' => 'core',
|
||||
'follow_area' => 'member',
|
||||
'follow_rel_id' => $follower['followUserID'],
|
||||
'follow_rel_id_type' => 'core_members',
|
||||
'follow_member_id' => $follower['userID'],
|
||||
'follow_added' => $follower['time']
|
||||
) );
|
||||
}
|
||||
|
||||
$libraryClass->setLastKeyValue( $row['userID'] );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert ignored users
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function convertIgnoredUsers()
|
||||
{
|
||||
$libraryClass = $this->getLibrary();
|
||||
$libraryClass::setKey( 'ignoreID' );
|
||||
|
||||
foreach( $this->fetch( 'wcf' . static::$installId . '_user_ignore', 'ignoreID' ) AS $ignore )
|
||||
{
|
||||
$info = array(
|
||||
'ignore_id' => $ignore['ignoreID'],
|
||||
'ignore_owner_id' => $ignore['userID'],
|
||||
'ignore_ignore_id' => $ignore['ignoreUserID'],
|
||||
'ignore_messages' => 1,
|
||||
'ignore_topics' => 1
|
||||
);
|
||||
|
||||
$libraryClass->convertIgnoredUser( $info );
|
||||
$libraryClass->setLastKeyValue( $ignore['ignoreID'] );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert ranks
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function convertRanks()
|
||||
{
|
||||
$libraryClass = $this->getLibrary();
|
||||
$libraryClass::setKey( 'rankID' );
|
||||
|
||||
foreach( $this->fetch( 'wcf' . static::$installId . '_user_rank', 'rankID', array( 'requiredPoints>0' ) ) AS $row )
|
||||
{
|
||||
$libraryClass->convertRank( array(
|
||||
'id' => $row['rankID'],
|
||||
'title' => $row['rankTitle'],
|
||||
'posts' => $row['requiredPoints']
|
||||
) );
|
||||
|
||||
$libraryClass->setLastKeyValue( $row['rankID'] );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert PMs
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function convertPrivateMessages()
|
||||
{
|
||||
$libraryClass = $this->getLibrary();
|
||||
$libraryClass::setKey( 'conversationID' );
|
||||
|
||||
foreach( $this->fetch( 'wcf' . static::$installId . '_conversation', 'conversationID' ) AS $row )
|
||||
{
|
||||
$participants = iterator_to_array( $this->db->select( '*', 'wcf' . static::$installId . '_conversation_to_user', array( 'conversationID=?', $row['conversationID'] ) )->setKeyField('participantID') );
|
||||
|
||||
$topic = array(
|
||||
'mt_id' => $row['conversationID'],
|
||||
'mt_date' => $row['time'],
|
||||
'mt_title' => $row['subject'],
|
||||
'mt_starter_id' => $row['userID'],
|
||||
'mt_start_time' => $row['time'],
|
||||
'mt_last_post_time' => $row['lastPostTime'],
|
||||
'mt_to_count' => $row['participants'],
|
||||
);
|
||||
|
||||
$maps = array();
|
||||
$maps[ $row['userID'] ] = array(
|
||||
'map_user_id' => $row['userID'],
|
||||
'map_read_time' => $row['time'],
|
||||
'map_is_starter' => true
|
||||
);
|
||||
|
||||
unset( $participants[ $row['userID'] ] );
|
||||
|
||||
foreach( $participants as $participant )
|
||||
{
|
||||
$maps[ $participant['participantID'] ] = array(
|
||||
'map_user_id' => $participant['participantID'],
|
||||
'map_read_time' => $participant['lastVisitTime'],
|
||||
'map_user_active' => $participant['hideConversation'] ? 0 : 1,
|
||||
);
|
||||
}
|
||||
|
||||
$libraryClass->convertPrivateMessage( $topic, $maps );
|
||||
$libraryClass->setLastKeyValue( $row['conversationID'] );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert PM replies
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function convertPrivateMessageReplies()
|
||||
{
|
||||
$libraryClass = $this->getLibrary();
|
||||
$libraryClass::setKey( 'messageID' );
|
||||
|
||||
foreach( $this->fetch( 'wcf' . static::$installId . '_conversation_message', 'messageID' ) AS $row )
|
||||
{
|
||||
$libraryClass->convertPrivateMessageReply( array(
|
||||
'msg_id' => $row['messageID'],
|
||||
'msg_topic_id' => $row['conversationID'],
|
||||
'msg_date' => $row['time'],
|
||||
'msg_post' => $row['message'],
|
||||
'msg_author_id' => $row['userID'],
|
||||
'msg_ip_address' => $row['ipAddress'],
|
||||
) );
|
||||
|
||||
$libraryClass->setLastKeyValue( $row['messageID'] );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Cache default language
|
||||
*/
|
||||
static $_defaultLanguage = NULL;
|
||||
|
||||
/**
|
||||
* Helper to fetch a WCF lang string
|
||||
*
|
||||
* @param string $itemName WCF Language Name
|
||||
* @param string $itemPrefix WCF Prefix for end-user input
|
||||
* @return string Translated string, or original if no customisation exists
|
||||
* @throws \UnderflowException
|
||||
*/
|
||||
protected function getLanguage( string $itemName, string $itemPrefix=NULL ): string
|
||||
{
|
||||
if( static::$_defaultLanguage === NULL )
|
||||
{
|
||||
static::$_defaultLanguage = $this->db->select( 'languageID', 'wcf' . static::$installId . '_language', array( 'isDefault=?', 1 ) )->first();
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
return $this->db->select( 'languageItemValue', 'wcf' . static::$installId . '_language_item', array( "languageID=? AND languageItem=?", static::$_defaultLanguage, $itemName ) )->first();
|
||||
}
|
||||
catch( \UnderflowException $e )
|
||||
{
|
||||
try
|
||||
{
|
||||
return $this->db->select( 'languageItemValue', 'wcf' . static::$installId . '_language_item', array( "languageID=? AND languageItem=?", static::$_defaultLanguage, $itemPrefix . '.' . $itemName ) )->first();
|
||||
}
|
||||
catch( \UnderflowException $e ) { }
|
||||
|
||||
return $itemName;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Process a login
|
||||
*
|
||||
* @param \IPS\Member $member The member
|
||||
* @param string $password Password from form
|
||||
* @return bool
|
||||
*/
|
||||
public static function login( $member, $password )
|
||||
{
|
||||
/* If it's not blowfish, then we don't have a salt for it. fail. */
|
||||
if( preg_match( '/^\$2[ay]\$(0[4-9]|[1-2][0-9]|3[0-1])\$[a-zA-Z0-9.\/]{53}/', $member->conv_password ) )
|
||||
{
|
||||
$salt = mb_substr( $member->conv_password, 0, 29 );
|
||||
$test = crypt( crypt( $password, $salt ), $salt );
|
||||
|
||||
return \IPS\Login::compareHashes( $member->conv_password, $test );
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
@@ -5,19 +5,22 @@
|
||||
* @author <a href='https://www.invisioncommunity.com'>Invision Power Services, Inc.</a>
|
||||
* @copyright (c) Invision Power Services, Inc.
|
||||
* @package Invision Community
|
||||
* @subpackage Converter
|
||||
* @subpackage convert
|
||||
* @since 12 December 2015
|
||||
*/
|
||||
|
||||
namespace IPS\convert\Software\Core;
|
||||
|
||||
/* To prevent PHP errors (extending class does not exist) revealing path */
|
||||
if ( !defined( '\IPS\SUITE_UNIQUE_KEY' ) )
|
||||
if ( !\defined( '\IPS\SUITE_UNIQUE_KEY' ) )
|
||||
{
|
||||
header( ( isset( $_SERVER['SERVER_PROTOCOL'] ) ? $_SERVER['SERVER_PROTOCOL'] : 'HTTP/1.0' ) . ' 403 Forbidden' );
|
||||
exit;
|
||||
}
|
||||
|
||||
/**
|
||||
* Wordpress Core Converter
|
||||
*/
|
||||
class _Wordpress extends \IPS\convert\Software
|
||||
{
|
||||
/**
|
||||
@@ -92,8 +95,8 @@ class _Wordpress extends \IPS\convert\Software
|
||||
/**
|
||||
* Fix post data
|
||||
*
|
||||
* @param string raw post data
|
||||
* @return string parsed post data
|
||||
* @param string $post Raw post data
|
||||
* @return string Parsed post data
|
||||
*/
|
||||
public static function fixPostData( $post )
|
||||
{
|
||||
@@ -166,9 +169,7 @@ class _Wordpress extends \IPS\convert\Software
|
||||
'name' => $this->app->_session['more_info']['convertMembers']['username'] == 'username' ? $user['user_login'] : $user['display_name'],
|
||||
'email' => $user['user_email'],
|
||||
'joined' => new \IPS\DateTime( $user['user_registered'] ),
|
||||
'conv_password' => $user['user_pass'],
|
||||
'pp_photo_type' => 'gravatar',
|
||||
'pp_gravatar' => $user['user_email'], # WordPress always uses gravatar, as it's their service
|
||||
'conv_password' => $user['user_pass']
|
||||
);
|
||||
|
||||
$fields = array();
|
||||
@@ -188,11 +189,10 @@ class _Wordpress extends \IPS\convert\Software
|
||||
'pf_desc' => '',
|
||||
'pf_type' => 'Text',
|
||||
'pf_content' => '[]',
|
||||
'pf_member_hide' => 0,
|
||||
'pf_member_hide' => 'all',
|
||||
'pf_max_input' => 255,
|
||||
'pf_member_edit' => 1,
|
||||
'pf_show_on_reg' => 0,
|
||||
'pf_admin_only' => 0,
|
||||
) );
|
||||
}
|
||||
|
||||
|
||||
@@ -5,31 +5,49 @@
|
||||
* @author <a href='https://www.invisioncommunity.com'>Invision Power Services, Inc.</a>
|
||||
* @copyright (c) Invision Power Services, Inc.
|
||||
* @package Invision Community
|
||||
* @subpackage Converter
|
||||
* @subpackage convert
|
||||
* @since 21 Jan 2015
|
||||
*/
|
||||
|
||||
namespace IPS\convert\Software\Core;
|
||||
|
||||
/* To prevent PHP errors (extending class does not exist) revealing path */
|
||||
if ( !defined( '\IPS\SUITE_UNIQUE_KEY' ) )
|
||||
if ( !\defined( '\IPS\SUITE_UNIQUE_KEY' ) )
|
||||
{
|
||||
header( ( isset( $_SERVER['SERVER_PROTOCOL'] ) ? $_SERVER['SERVER_PROTOCOL'] : 'HTTP/1.0' ) . ' 403 Forbidden' );
|
||||
exit;
|
||||
}
|
||||
|
||||
/**
|
||||
* Xenforo Core Converter
|
||||
*/
|
||||
class _Xenforo extends \IPS\convert\Software
|
||||
{
|
||||
use \IPS\convert\Tools\Xenforo;
|
||||
|
||||
/**
|
||||
* @brief The similarities between XF1 and XF2 are close enough that we can use the same converter
|
||||
*/
|
||||
public static $isLegacy = NULL;
|
||||
|
||||
/**
|
||||
* @brief XF2.1 changed serialized data to json decoded
|
||||
*/
|
||||
public static $useJson = FALSE;
|
||||
|
||||
/**
|
||||
* @brief XF1&2 have different pseudo fields
|
||||
*/
|
||||
public static $pseudoFields = array(
|
||||
1 => array( 'homepage', 'location', 'occupation', 'about' ),
|
||||
2 => array( 'website', 'location', 'about' )
|
||||
);
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param \IPS\convert\App The application to reference for database and other information.
|
||||
* @param bool Establish a DB connection
|
||||
* @param \IPS\convert\App $app The application to reference for database and other information.
|
||||
* @param bool $needDB Establish a DB connection
|
||||
* @return void
|
||||
* @throws \InvalidArgumentException
|
||||
*/
|
||||
@@ -44,7 +62,7 @@ class _Xenforo extends \IPS\convert\Software
|
||||
/* Is this XF1 or XF2 */
|
||||
if ( static::$isLegacy === NULL )
|
||||
{
|
||||
$version = $this->db->select( 'MAX(version_id)', 'xf_template', array( "addon_id=?", 'XF' ) )->first();
|
||||
$version = $this->db->select( 'MAX(version_id)', 'xf_template', array( \IPS\Db::i()->in( 'addon_id', array( 'XF', 'XenForo' ) ) ) )->first();
|
||||
|
||||
if ( $version < 2000010 )
|
||||
{
|
||||
@@ -53,6 +71,12 @@ class _Xenforo extends \IPS\convert\Software
|
||||
else
|
||||
{
|
||||
static::$isLegacy = FALSE;
|
||||
|
||||
/* Is this XF 2.1 */
|
||||
if ( $version > 2010010 )
|
||||
{
|
||||
static::$useJson = TRUE;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -69,7 +93,7 @@ class _Xenforo extends \IPS\convert\Software
|
||||
*/
|
||||
public static function softwareName()
|
||||
{
|
||||
return "XenForo (1.5.x/2.0.x)";
|
||||
return "XenForo (1.5.x/2.0.x/2.1.x)";
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -109,7 +133,7 @@ class _Xenforo extends \IPS\convert\Software
|
||||
*/
|
||||
public static function canConvert()
|
||||
{
|
||||
return array(
|
||||
$return = array(
|
||||
'convertEmoticons' => array(
|
||||
'table' => 'xf_smilie',
|
||||
'where' => NULL
|
||||
@@ -127,7 +151,7 @@ class _Xenforo extends \IPS\convert\Software
|
||||
'where' => NULL
|
||||
),
|
||||
'convertMemberHistory' => array(
|
||||
'table' => ( static::$isLegacy === FALSE OR is_null( static::$isLegacy ) ) ? 'xf_change_log' : 'xf_user_change_log',
|
||||
'table' => ( static::$isLegacy === FALSE OR \is_null( static::$isLegacy ) ) ? 'xf_change_log' : 'xf_user_change_log',
|
||||
'where' => NULL
|
||||
),
|
||||
'convertWarnReasons' => array(
|
||||
@@ -163,6 +187,17 @@ class _Xenforo extends \IPS\convert\Software
|
||||
'where' => NULL
|
||||
)
|
||||
);
|
||||
|
||||
/* XF 2.1 */
|
||||
if( static::$useJson )
|
||||
{
|
||||
$return['convertReactions'] = array(
|
||||
'table' => 'xf_reaction',
|
||||
'where' => NULL
|
||||
);
|
||||
}
|
||||
|
||||
return $return;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -170,7 +205,7 @@ class _Xenforo extends \IPS\convert\Software
|
||||
*
|
||||
* @param string $table The table containing the rows to count.
|
||||
* @param array|NULL $where WHERE clause to only count specific rows, or NULL to count all.
|
||||
* @param bool $recache Skip cache and pull directly (updating cache)
|
||||
* @param bool $recache Skip cache and pull directly (updating cache)
|
||||
* @return integer
|
||||
* @throws \IPS\convert\Exception
|
||||
*/
|
||||
@@ -180,11 +215,25 @@ class _Xenforo extends \IPS\convert\Software
|
||||
{
|
||||
/* XF1 */
|
||||
case 'xf_user_change_log':
|
||||
return $this->db->select( 'count(log_id)', 'xf_user_change_log', array( $this->db->in( 'field', array_keys( static::$changeLogTypes ) ) ) )->first();
|
||||
try
|
||||
{
|
||||
return $this->db->select( 'count(log_id)', 'xf_user_change_log', array( $this->db->in( 'field', array_keys( static::$changeLogTypes ) ) ) )->first();
|
||||
}
|
||||
catch( \Exception $e )
|
||||
{
|
||||
throw new \IPS\convert\Exception( sprintf( \IPS\Member::loggedIn()->language()->get( 'could_not_count_rows' ), $table ) );
|
||||
}
|
||||
break;
|
||||
/* XF2 */
|
||||
case 'xf_change_log':
|
||||
return $this->db->select( 'count(log_id)', 'xf_change_log', array( 'content_type=? AND ' . $this->db->in( 'field', array_keys( static::$changeLogTypes ) ), 'user' ) )->first();
|
||||
try
|
||||
{
|
||||
return $this->db->select( 'count(log_id)', 'xf_change_log', array( 'content_type=? AND ' . $this->db->in( 'field', array_keys( static::$changeLogTypes ) ), 'user' ) )->first();
|
||||
}
|
||||
catch( \Exception $e )
|
||||
{
|
||||
throw new \IPS\convert\Exception( sprintf( \IPS\Member::loggedIn()->language()->get( 'could_not_count_rows' ), $table ) );
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
@@ -220,13 +269,21 @@ class _Xenforo extends \IPS\convert\Software
|
||||
*/
|
||||
public static function checkConf()
|
||||
{
|
||||
return array(
|
||||
$return = array(
|
||||
'convertAttachments',
|
||||
'convertEmoticons',
|
||||
'convertProfileFields',
|
||||
'convertGroups',
|
||||
'convertMembers',
|
||||
);
|
||||
|
||||
/* XF 2.1 */
|
||||
if( static::$useJson )
|
||||
{
|
||||
$return[] = 'convertReactions';
|
||||
}
|
||||
|
||||
return $return;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -339,7 +396,7 @@ class _Xenforo extends \IPS\convert\Software
|
||||
'field_validation' => function( $value ) { if ( !@is_dir( $value ) ) { throw new \DomainException( 'path_invalid' ); } },
|
||||
);
|
||||
|
||||
foreach( array( 'homepage', 'location', 'occupation', 'about', 'gender' ) AS $field )
|
||||
foreach( static::$pseudoFields[ static::$isLegacy ? 1 : 2 ] AS $field )
|
||||
{
|
||||
\IPS\Member::loggedIn()->language()->words["field_{$field}"] = \IPS\Member::loggedIn()->language()->addToStack( 'pseudo_field', FALSE, array( 'sprintf' => $field ) );
|
||||
\IPS\Member::loggedIn()->language()->words["field_{$field}_desc"] = \IPS\Member::loggedIn()->language()->addToStack( 'pseudo_field_desc' );
|
||||
@@ -358,6 +415,47 @@ class _Xenforo extends \IPS\convert\Software
|
||||
);
|
||||
}
|
||||
break;
|
||||
|
||||
case 'convertReactions':
|
||||
$return['convertReactions'] = array();
|
||||
/* XF2.1 */
|
||||
if ( !static::$isLegacy )
|
||||
{
|
||||
$reactions = array();
|
||||
foreach( iterator_to_array( $this->db->select( '*', 'xf_reaction' ) ) as $reaction )
|
||||
{
|
||||
$title = $this->getPhrase( '', 'reaction_title.' . $reaction['reaction_id'] );
|
||||
if( !empty( $reaction['text_color'] ) AND mb_substr( $reaction['text_color'], 0, 1 ) === '#' )
|
||||
{
|
||||
$title = "<span style='color:{$reaction['text_color']}'>{$title}</span>";
|
||||
}
|
||||
$reactions[ $reaction['reaction_id'] ] = array(
|
||||
'title' => $title,
|
||||
'icon' => FALSE
|
||||
);
|
||||
}
|
||||
|
||||
$return['convertReactions']['reactions'] = array(
|
||||
'field_class' => 'IPS\\convert\\Form\\Reactionmapper',
|
||||
'field_default' => NULL,
|
||||
'field_required' => TRUE,
|
||||
'field_extra' => array( 'reactions' => $reactions ),
|
||||
'field_hint' => NULL,
|
||||
'field_validation' => NULL,
|
||||
);
|
||||
|
||||
/* XenForo stores emoticons either as a remotely linked image, or relative to the installation path, so we need to change the verbiage here a bit. */
|
||||
\IPS\Member::loggedIn()->language()->words['reaction_path'] = \IPS\Member::loggedIn()->language()->addToStack( 'source_path', FALSE, array( 'sprintf' => array( 'XenForo' ) ) );
|
||||
$return['convertReactions']['reaction_path'] = array(
|
||||
'field_class' => 'IPS\\Helpers\\Form\\Text',
|
||||
'field_default' => NULL,
|
||||
'field_required' => TRUE,
|
||||
'field_extra' => array(),
|
||||
'field_hint' => NULL,
|
||||
'field_validation' => function( $value ) { if ( !@is_dir( $value ) ) { throw new \DomainException( 'path_invalid' ); } },
|
||||
);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
return ( isset( $return[ $method ] ) ) ? $return[ $method ] : array();
|
||||
@@ -407,25 +505,6 @@ class _Xenforo extends \IPS\convert\Software
|
||||
return $settings;
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper to fetch a xenforo phrase
|
||||
*
|
||||
* @param string $xfOneTitle XF1 Phrase title
|
||||
* @param string $xfTwoTitle XF2 Phrase Title
|
||||
* @return string|null
|
||||
*/
|
||||
protected function getPhrase( $xfOneTitle, $xfTwoTitle )
|
||||
{
|
||||
try
|
||||
{
|
||||
$title = ( static::$isLegacy === FALSE OR is_null( static::$isLegacy ) ) ? $xfTwoTitle : $xfOneTitle;
|
||||
return $this->db->select( 'phrase_text', 'xf_phrase', array( "title=?", $title ) )->first();
|
||||
}
|
||||
catch( \UnderflowException $e )
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Finish
|
||||
@@ -464,8 +543,8 @@ class _Xenforo extends \IPS\convert\Software
|
||||
/**
|
||||
* Fix post data
|
||||
*
|
||||
* @param string raw post data
|
||||
* @return string parsed post data
|
||||
* @param string $post Raw post data
|
||||
* @return string Parsed post data
|
||||
*/
|
||||
public static function fixPostData( $post )
|
||||
{
|
||||
@@ -473,17 +552,21 @@ class _Xenforo extends \IPS\convert\Software
|
||||
$post = htmlspecialchars( $post, ENT_DISALLOWED | ENT_QUOTES, 'UTF-8', FALSE );
|
||||
|
||||
// find YouTube ID's and replace.
|
||||
$post = preg_replace( '#\[media=youtube\](.+?)\[/media\]#i', 'https://www.youtube.com/watch?v=$1', $post );
|
||||
$post = preg_replace( '#\[media=facebook\](.+?)\[/media\]#i', 'https://www.facebook.com/video.php?v=$1', $post );
|
||||
if( \preg_match( "#\[media=#i", $post ) )
|
||||
{
|
||||
$post = preg_replace( '#\[media=youtube\](.+?)\[/media\]#i', 'https://www.youtube.com/watch?v=$1', $post );
|
||||
$post = preg_replace( '#\[media=facebook\](.+?)\[/media\]#i', 'https://www.facebook.com/video.php?v=$1', $post );
|
||||
}
|
||||
|
||||
/* Quick check for the presence of user tags */
|
||||
if( mb_stristr( $post, '[user=' ) )
|
||||
if( \preg_match( "#\[user=#i", $post ) )
|
||||
{
|
||||
/* Mentions */
|
||||
preg_match_all( '#\[user=(\d+)\](.+?)\[\/user\]#i', $post, $matches );
|
||||
|
||||
if ( count( $matches ) )
|
||||
if ( \count( $matches ) )
|
||||
{
|
||||
/* Make sure we actually have mention data */
|
||||
if ( isset( $matches[1] ) AND \count( $matches[1] ) )
|
||||
{
|
||||
$mentions = array();
|
||||
@@ -491,34 +574,31 @@ class _Xenforo extends \IPS\convert\Software
|
||||
{
|
||||
if ( isset( $matches[2][ $k ] ) )
|
||||
{
|
||||
$name = trim( $matches[2][ $k ], '@' );
|
||||
$mentions[ $name ] = $v;
|
||||
$mentions[ trim( $matches[2][ $k ], '@' ) ] = $v;
|
||||
}
|
||||
}
|
||||
|
||||
$maps = array();
|
||||
$urls = array();
|
||||
$cardUrls = array();
|
||||
foreach ( new \IPS\Patterns\ActiveRecordIterator( \IPS\Db::i()->select( '*', 'core_members', array( \IPS\Db::i()->in( 'name', array_keys( $mentions ) )) ), 'IPS\Member' ) AS $member )
|
||||
{
|
||||
$maps[ $member->name ] = $member->member_id;
|
||||
$urls[ $member->name ] = $member->url();
|
||||
$cardUrls[ $member->name ] = $member->url()->setQueryString( 'do', 'hovercard' );
|
||||
}
|
||||
$maps = iterator_to_array( \IPS\Db::i()->select( 'name, member_id', 'core_members', array( \IPS\Db::i()->in( 'name', array_keys( $mentions ) ) ) )->setKeyField( 'name' )->setValueField( 'member_id' ) );
|
||||
|
||||
foreach ( $mentions AS $member_name => $member_id )
|
||||
foreach ( $mentions AS $memberName => $memberId )
|
||||
{
|
||||
$maps[ $member_name ] = preg_quote( $maps[ $member_name ], '#' );
|
||||
$memberNameEscaped = preg_quote( $member_name, '#' );
|
||||
if ( !isset( $maps[ $memberName ] ) )
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
$post = preg_replace( "#\[user={$member_id}\]@?{$memberNameEscaped}\[\/user\]#i", "<a contenteditable=\"false\" rel=\"\" href=\"{$urls[ $member_name ]}\" data-mentionid=\"{$maps[ $member_name ]}\" data-ipshover-target=\"{$cardUrls[ $member_name ]}\" data-ipshover=\"\">@{$member_name}</a>", $post );
|
||||
$memberNameQuoted = preg_quote( $memberName, '#' );
|
||||
$post = preg_replace( "#\[user={$memberId}\]@?{$memberNameQuoted}\[\/user\]#i", "[mention={$maps[ $memberName ]}]{$memberName}[/mention]", $post );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Quotes */
|
||||
$post = preg_replace( '#\[quote="([a-zA-Z0-9]+)(,(.?)+)?"]#i', "[quote name='$1']", $post );
|
||||
if( \preg_match( "#\[quote=#i", $post ) )
|
||||
{
|
||||
$post = preg_replace( '#\[quote="([a-zA-Z0-9-_ ]+)(,(.?)+)?"]#i', "[quote name='$1']", $post );
|
||||
}
|
||||
|
||||
// finally, give us the post back.
|
||||
return $post;
|
||||
@@ -579,9 +659,9 @@ class _Xenforo extends \IPS\convert\Software
|
||||
|
||||
$post = \IPS\Db::i()->select( 'msg_post', 'core_message_posts', array( "msg_id=?", $messagePostId ) )->first();
|
||||
|
||||
if ( preg_match( "/\[ATTACH(.+?)?\]" . $row['attachment_id'] . "\[\/ATTACH\]/i", $post ) )
|
||||
if ( preg_match( "/\[ATTACH([^\]]+?)?\]" . $row['attachment_id'] . "\[\/ATTACH\]/i", $post ) )
|
||||
{
|
||||
$post = preg_replace( "/\[ATTACH(.+?)?\]" . $row['attachment_id'] . "\[\/ATTACH\]/i", '[attachment=' . $attachId . ':name]', $post );
|
||||
$post = preg_replace( "/\[ATTACH([^\]]+?)?\]" . $row['attachment_id'] . "\[\/ATTACH\]/i", '[attachment=' . $attachId . ':name]', $post );
|
||||
}
|
||||
|
||||
\IPS\Db::i()->update( 'core_message_posts', array( 'msg_post' => $post ), array( "msg_id=?", $messagePostId ) );
|
||||
@@ -617,12 +697,21 @@ class _Xenforo extends \IPS\convert\Software
|
||||
/* Sprites */
|
||||
if( $row['sprite_mode'] )
|
||||
{
|
||||
$images = $this->_emoticonsFromSprite( rtrim( $this->app->_session['more_info']['convertEmoticons']['emoticon_path'], '/' ) . '/' . $row['image_url'], \unserialize( $row['sprite_params'] ) );
|
||||
$filedata = $images['emoticon'];
|
||||
|
||||
if( isset( $images['emoticon_x2'] ) )
|
||||
try
|
||||
{
|
||||
$filedatax2 = $images['emoticon_x2'];
|
||||
$images = $this->_imageFromSprite( rtrim( $this->app->_session['more_info']['convertEmoticons']['emoticon_path'], '/' ) . '/' . $row['image_url'], static::unpack( $row['sprite_params'] ) );
|
||||
}
|
||||
catch( \InvalidArgumentException | \OutOfRangeException $e )
|
||||
{
|
||||
$this->app->log( 'xf_emo_sprite_convert_invalid_image', __METHOD__, \IPS\convert\App::LOG_WARNING, $row['smilie_id'] );
|
||||
$libraryClass->setLastKeyValue( $row['smilie_id'] );
|
||||
continue;
|
||||
}
|
||||
$filedata = $images['image'];
|
||||
|
||||
if( isset( $images['image_x2'] ) )
|
||||
{
|
||||
$filedatax2 = $images['image_x2'];
|
||||
|
||||
/* We always save the sprites to PNG */
|
||||
$filenamex2 = "{$row['title']}.png";
|
||||
@@ -668,7 +757,7 @@ class _Xenforo extends \IPS\convert\Software
|
||||
$category = $this->db->select( '*', 'xf_smilie_category', array( "smilie_category_id=?", $row['smilie_category_id'] ) )->first();
|
||||
$title = $this->getPhrase( "smilie_category_{$category['smilie_category_id']}_title", "smilie_category_title.{$category['smilie_category_id']}" );
|
||||
|
||||
if ( is_null( $title ) )
|
||||
if ( \is_null( $title ) )
|
||||
{
|
||||
/* Bubble Up */
|
||||
throw new \UnderflowException;
|
||||
@@ -720,14 +809,16 @@ class _Xenforo extends \IPS\convert\Software
|
||||
$info['pf_type'] = $this->_fieldMap( $row['field_type'] );
|
||||
$info['pf_name'] = $this->getPhrase( "user_field_{$row['field_id']}", "user_field_title.{$row['field_id']}" );
|
||||
$info['pf_desc'] = $this->getPhrase( "user_field_{$row['field_id']}_desc", "user_field_desc.{$row['field_id']}" );
|
||||
$info['pf_content'] = ( !in_array( $row['field_type'], array( 'textbox', 'textarea' ) ) ) ? \unserialize( $row['field_choices'] ) : NULL;
|
||||
$info['pf_content'] = ( !\in_array( $row['field_type'], array( 'textbox', 'textarea' ) ) ) ? ( static::$isLegacy ? \unserialize( $row['field_choices'] ) : json_decode( $row['field_choices'], TRUE ) ) : NULL;
|
||||
$info['pf_not_null'] = $row['required'];
|
||||
$info['pf_member_hide'] = ( $row['viewable_profile'] > 0 ) ? 0 : 1;
|
||||
$info['pf_member_hide'] = ( $row['viewable_profile'] > 0 ) ? 'all' : 'hide';
|
||||
$info['pf_max_input'] = $row['max_length'];
|
||||
$info['pf_member_edit'] = ( in_array( $row['user_editable'], array( 'yes', 'once' ) ) ) ? 0 : 1;
|
||||
$info['pf_member_edit'] = ( \in_array( $row['user_editable'], array( 'yes', 'once' ) ) ) ? 0 : 1;
|
||||
$info['pf_position'] = $row['display_order'];
|
||||
$info['pf_show_on_reg'] = ( $row['show_registration'] > 0 ) ? 1 : 0;
|
||||
$info['pf_input_format'] = ( $row['match_type'] == 'regex' AND $row['match_regex'] ) ? '/' . $row['match_regex'] . '/i' : NULL;
|
||||
$info['pf_input_format'] = static::$isLegacy ?
|
||||
( ( $row['match_type'] == 'regex' AND $row['match_regex'] ) ? '/' . $row['match_regex'] . '/i' : NULL ) :
|
||||
( ( $row['match_type'] == 'regex' AND $params = json_decode( $row['match_params'], TRUE ) AND $params['regex'] ) ? '/' . $params['regex'] . '/i' : NULL );
|
||||
$info['pf_multiple'] = ( $row['field_type'] == 'multiselect' ) ? 1 : 0;
|
||||
|
||||
$libraryClass->convertProfileField( $info, $merge );
|
||||
@@ -737,7 +828,7 @@ class _Xenforo extends \IPS\convert\Software
|
||||
/**
|
||||
* Maps the XenForo field ttype to IPS field type
|
||||
*
|
||||
* @param string XF Field Type
|
||||
* @param string $type XF Field Type
|
||||
* @return string IPS Field Type
|
||||
*/
|
||||
protected function _fieldMap( $type )
|
||||
@@ -835,7 +926,7 @@ class _Xenforo extends \IPS\convert\Software
|
||||
}
|
||||
|
||||
/* Now check for group promotions */
|
||||
if( count( $libraryClass->groupPromotions ) )
|
||||
if( \count( $libraryClass->groupPromotions ) )
|
||||
{
|
||||
foreach( $libraryClass->groupPromotions as $groupPromotion )
|
||||
{
|
||||
@@ -892,7 +983,7 @@ class _Xenforo extends \IPS\convert\Software
|
||||
/**
|
||||
* @brief Member history type map
|
||||
*/
|
||||
protected static $changeLogTypes = array( 'username' => 'display_name', 'email' => 'email_change', 'user_group_id' => 'member_group_id', 'secondary_group_ids' => 'mgroup_others' );
|
||||
protected static $changeLogTypes = array( 'username' => 'display_name', 'email' => 'email_change', 'user_group_id' => 'group', 'secondary_group_ids' => 'group' );
|
||||
|
||||
/**
|
||||
* Convert member history
|
||||
@@ -908,7 +999,7 @@ class _Xenforo extends \IPS\convert\Software
|
||||
$userField = 'user_id';
|
||||
$table = 'xf_user_change_log';
|
||||
|
||||
if( ( static::$isLegacy === FALSE OR is_null( static::$isLegacy ) ) )
|
||||
if( ( static::$isLegacy === FALSE OR \is_null( static::$isLegacy ) ) )
|
||||
{
|
||||
$table = 'xf_change_log';
|
||||
$userField = 'content_id';
|
||||
@@ -921,16 +1012,23 @@ class _Xenforo extends \IPS\convert\Software
|
||||
|
||||
foreach( $this->fetch( $table, 'log_id', $where ) AS $change )
|
||||
{
|
||||
$libraryClass->convertMemberHistory( array(
|
||||
'log_id' => $change['log_id'],
|
||||
'log_member' => $change[ $userField ],
|
||||
'log_by' => ( $change['edit_user_id'] !== $change[ $userField ] ) ? $change['edit_user_id'] : null,
|
||||
'log_type' => static::$changeLogTypes[ $change['field'] ],
|
||||
'log_data' => array( 'old' => $change['old_value'], 'new' => $change['new_value'] ),
|
||||
'log_date' => $change['edit_date']
|
||||
)
|
||||
$info = array(
|
||||
'log_id' => $change['log_id'],
|
||||
'log_member' => $change[ $userField ],
|
||||
'log_by' => ( $change['edit_user_id'] !== $change[ $userField ] ) ? $change['edit_user_id'] : null,
|
||||
'log_type' => static::$changeLogTypes[ $change['field'] ],
|
||||
'log_data' => array( 'old' => $change['old_value'], 'new' => $change['new_value'] ),
|
||||
'log_date' => $change['edit_date']
|
||||
);
|
||||
|
||||
/* Add extra data for group change */
|
||||
if( static::$changeLogTypes[ $change['field'] ] == 'group' )
|
||||
{
|
||||
$info['log_data']['type'] = $change['field'] == 'user_group_id' ? 'primary' : 'secondary';
|
||||
$info['log_data']['by'] = 'manual';
|
||||
}
|
||||
|
||||
$libraryClass->convertMemberHistory( $info );
|
||||
$libraryClass->setLastKeyValue( $change['log_id'] );
|
||||
}
|
||||
}
|
||||
@@ -1024,7 +1122,7 @@ class _Xenforo extends \IPS\convert\Software
|
||||
|
||||
/* Auto Track */
|
||||
$auto_track = 0;
|
||||
if ( $row['default_watch_state'] == 'watch_email' )
|
||||
if ( $row['creation_watch_state'] == 'watch_email' )
|
||||
{
|
||||
$auto_track = array(
|
||||
'content' => 1,
|
||||
@@ -1061,7 +1159,7 @@ class _Xenforo extends \IPS\convert\Software
|
||||
/* Main Member Information */
|
||||
$info = array(
|
||||
'member_id' => $row['user_id'],
|
||||
'name' => $row['username'],
|
||||
'name' => html_entity_decode( $row['username'], \ENT_QUOTES | \ENT_HTML5, 'UTF-8' ),
|
||||
'email' => $row['email'],
|
||||
'conv_password' => $hash,
|
||||
'conv_password_extra' => $salt,
|
||||
@@ -1084,7 +1182,7 @@ class _Xenforo extends \IPS\convert\Software
|
||||
'view_sigs' => $row['content_show_signature']
|
||||
),
|
||||
'pp_setting_count_comments' => 1, # always on for XF
|
||||
'pp_reputation_points' => $row['like_count'],
|
||||
'pp_reputation_points' => ( static::$useJson ) ? $row['reaction_score'] : $row['like_count'],
|
||||
'timezone' => $timezone,
|
||||
'allow_admin_mails' => $row['receive_admin_email'],
|
||||
'member_title' => $row['custom_title'],
|
||||
@@ -1102,14 +1200,6 @@ class _Xenforo extends \IPS\convert\Software
|
||||
$filename = $row['user_id'] . '.jpg';
|
||||
$filepath = $path . '/l/' . $group;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Got a gravatar? */
|
||||
if ( $row['gravatar'] )
|
||||
{
|
||||
$info['pp_gravatar'] = $row['gravatar'];
|
||||
}
|
||||
}
|
||||
|
||||
/* Profile Fields */
|
||||
$pfields = array();
|
||||
@@ -1119,7 +1209,7 @@ class _Xenforo extends \IPS\convert\Software
|
||||
}
|
||||
|
||||
/* Pseudo Fields */
|
||||
foreach( array( 'homepage', 'location', 'occupation', 'about', 'gender' ) AS $pseudo )
|
||||
foreach( static::$pseudoFields[ static::$isLegacy ? 1 : 2 ] AS $pseudo )
|
||||
{
|
||||
/* Are we retaining? */
|
||||
if ( $this->app->_session['more_info']['convertMembers']["field_{$pseudo}"] == 'no_convert' )
|
||||
@@ -1149,7 +1239,7 @@ class _Xenforo extends \IPS\convert\Software
|
||||
) );
|
||||
}
|
||||
|
||||
$pfields[$pseudo] = $row[$pseudo];
|
||||
$pfields[ $pseudo ] = $row[ $pseudo ];
|
||||
}
|
||||
|
||||
$libraryClass->convertMember( $info, $pfields, $filename, $filepath );
|
||||
@@ -1159,7 +1249,7 @@ class _Xenforo extends \IPS\convert\Software
|
||||
{
|
||||
$libraryClass->convertFollow( array(
|
||||
'follow_app' => 'core',
|
||||
'follow_area' => 'members',
|
||||
'follow_area' => 'member',
|
||||
'follow_rel_id' => $follower['follow_user_id'],
|
||||
'follow_rel_id_type' => 'core_members',
|
||||
'follow_member_id' => $follower['user_id'],
|
||||
@@ -1246,7 +1336,24 @@ class _Xenforo extends \IPS\convert\Software
|
||||
'status_approved' => $approved,
|
||||
);
|
||||
|
||||
$libraryClass->convertStatus( $info );
|
||||
$id = $libraryClass->convertStatus( $info );
|
||||
|
||||
if( static::$useJson AND $id )
|
||||
{
|
||||
foreach( $this->db->select( '*', 'xf_reaction_content', array( "content_type=? AND content_id=?", 'profile_post', $row['profile_post_id'] ) ) as $reaction )
|
||||
{
|
||||
$libraryClass->convertReputation( array(
|
||||
'id' => $reaction['reaction_content_id'],
|
||||
'app' => 'core',
|
||||
'type' => 'status_id',
|
||||
'type_id' => $row['profile_post_id'],
|
||||
'member_id' => $reaction['reaction_user_id'],
|
||||
'member_received' => $row['profile_user_id'],
|
||||
'reaction' => $reaction['reaction_id'],
|
||||
'rep_date' => $reaction['reaction_date']
|
||||
) );
|
||||
}
|
||||
}
|
||||
|
||||
$libraryClass->setLastKeyValue( $row['profile_post_id'] );
|
||||
}
|
||||
@@ -1329,7 +1436,24 @@ class _Xenforo extends \IPS\convert\Software
|
||||
'reply_ip_address' => $ip,
|
||||
);
|
||||
|
||||
$libraryClass->convertStatusReply( $info );
|
||||
$id = $libraryClass->convertStatusReply( $info );
|
||||
|
||||
if( static::$useJson AND $id )
|
||||
{
|
||||
foreach( $this->db->select( '*', 'xf_reaction_content', array( "content_type=? AND content_id=?", 'profile_post_comment', $row['profile_post_comment_id'] ) ) as $reaction )
|
||||
{
|
||||
$libraryClass->convertReputation( array(
|
||||
'id' => $reaction['reaction_content_id'],
|
||||
'app' => 'core',
|
||||
'type' => 'status_reply_id',
|
||||
'type_id' => $row['profile_post_comment_id'],
|
||||
'member_id' => $reaction['reaction_user_id'],
|
||||
'member_received' => $row['user_id'],
|
||||
'reaction' => $reaction['reaction_id'],
|
||||
'rep_date' => $reaction['reaction_date']
|
||||
) );
|
||||
}
|
||||
}
|
||||
|
||||
$libraryClass->setLastKeyValue( $row['profile_post_comment_id'] );
|
||||
}
|
||||
@@ -1377,6 +1501,89 @@ class _Xenforo extends \IPS\convert\Software
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert reactions
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function convertReactions()
|
||||
{
|
||||
$libraryClass = $this->getLibrary();
|
||||
$libraryClass::setKey( 'reaction_id' );
|
||||
|
||||
foreach( $this->fetch( 'xf_reaction', 'reaction_id' ) AS $row )
|
||||
{
|
||||
/* We need to figure out where our file lives - if it's remote, then we need to use file_get_contents() and pass the raw data. */
|
||||
$filepath = NULL;
|
||||
$filedata = NULL;
|
||||
$filepathx2 = NULL;
|
||||
$filedatax2 = NULL;
|
||||
$filenamex2 = NULL;
|
||||
$title = $this->getPhrase( '', 'reaction_title.' . $row['reaction_id'] );
|
||||
|
||||
/* Sprites */
|
||||
if( $row['sprite_mode'] )
|
||||
{
|
||||
try
|
||||
{
|
||||
$images = $this->_imageFromSprite( rtrim( $this->app->_session['more_info']['convertReactions']['reaction_path'], '/' ) . '/' . $row['image_url'], static::unpack( $row['sprite_params'] ) );
|
||||
}
|
||||
catch( \InvalidArgumentException | \OutOfRangeException $e )
|
||||
{
|
||||
$this->app->log( 'xf_sprite_convert_invalid_image', __METHOD__, \IPS\convert\App::LOG_WARNING, $row['reaction_id'] );
|
||||
$libraryClass->setLastKeyValue( $row['reaction_id'] );
|
||||
continue;
|
||||
}
|
||||
|
||||
$filedata = $images['image'];
|
||||
|
||||
if( isset( $images['image_x2'] ) )
|
||||
{
|
||||
$filedatax2 = $images['image_x2'];
|
||||
}
|
||||
|
||||
/* We always save the sprites to PNG */
|
||||
$filename = \IPS\Http\Url\Friendly::seoTitle( $title ) . ".png";
|
||||
}
|
||||
elseif ( mb_substr( $row['image_url'], 0, 4 ) == 'http' )
|
||||
{
|
||||
$filedata = file_get_contents( $row['image_url'] );
|
||||
$fileurl = explode( '/', $row['image_url'] );
|
||||
$filename = array_pop( $fileurl );
|
||||
|
||||
if( !empty( $row['image_url_2x'] ) )
|
||||
{
|
||||
$filedata = file_get_contents( $row['image_url_2x'] );
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
$fileurl = explode( '/', $row['image_url'] );
|
||||
$filename = array_pop( $fileurl );
|
||||
$filepath = rtrim( $this->app->_session['more_info']['convertReactions']['reaction_path'], '/' ) . '/' . implode( '/', $fileurl );
|
||||
|
||||
if( !empty( $row['image_url_2x'] ) )
|
||||
{
|
||||
$fileurlx2 = explode( '/', $row['image_url_2x'] );
|
||||
$filepathx2 = rtrim( $this->app->_session['more_info']['convertReactions']['reaction_path'], '/' ) . '/' . implode( '/', $fileurlx2 );
|
||||
}
|
||||
}
|
||||
|
||||
$info = array(
|
||||
'reaction_id' => $row['reaction_id'],
|
||||
'reaction_title' => $title,
|
||||
'filename' => $filename,
|
||||
'reaction_value' => $row['reaction_score'],
|
||||
'reaction_position' => $row['display_order'] / 100,
|
||||
'reaction_enabled' => $row['active']
|
||||
);
|
||||
|
||||
$merge = ( $this->app->_session['more_info']['convertReactions']['reactions'][ $row['reaction_id'] ] != 'none' ) ? $this->app->_session['more_info']['convertReactions']['reactions'][ $row['reaction_id'] ] : NULL;
|
||||
$libraryClass->convertReaction( $info, $filepathx2 ?? $filepath, $filedatax2 ?? $filedata, $merge );
|
||||
$libraryClass->setLastKeyValue( $row['reaction_id'] );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert private messages
|
||||
*
|
||||
@@ -1476,8 +1683,7 @@ class _Xenforo extends \IPS\convert\Software
|
||||
* Check if we can redirect the legacy URLs from this software to the new locations
|
||||
*
|
||||
* @return NULL|\IPS\Http\Url
|
||||
* @todo The proxy.php redirection is not validating the hash that XenForo set previously, derived from the globalSalt and the option imageLinkProxyKey. We need
|
||||
* to either validate the hash (there is an open proxy concern), or we need to convert all calls to proxy.php in posted content to prevent broken images in posts.
|
||||
* @todo The proxy.php redirection is not validating the hash that XenForo set previously, derived from the globalSalt and the option imageLinkProxyKey. We need to either validate the hash (there is an open proxy concern), or we need to convert all calls to proxy.php in posted content to prevent broken images in posts.
|
||||
*/
|
||||
public function checkRedirects()
|
||||
{
|
||||
@@ -1503,9 +1709,10 @@ class _Xenforo extends \IPS\convert\Software
|
||||
}
|
||||
elseif( mb_strpos( $url->data[ \IPS\Http\Url::COMPONENT_PATH ], 'proxy.php' ) !== FALSE AND isset( \IPS\Request::i()->image ) )
|
||||
{
|
||||
return \IPS\Http\Url::internal( "applications/core/interface/imageproxy/imageproxy.php", 'none' )->setQueryString( array(
|
||||
'img' => \IPS\Request::i()->image,
|
||||
'key' => hash_hmac( "sha256", (string) \IPS\Request::i()->image, \IPS\Settings::i()->site_secret_key )
|
||||
return \IPS\Http\Url::internal( "app=core&module=system&controller=redirect", 'front' )->setQueryString( array(
|
||||
'url' => \IPS\Request::i()->image,
|
||||
'resource' => TRUE,
|
||||
'key' => hash_hmac( "sha256", (string) \IPS\Request::i()->image, \IPS\Settings::i()->site_secret_key . 'r' )
|
||||
) );
|
||||
}
|
||||
|
||||
@@ -1533,7 +1740,7 @@ class _Xenforo extends \IPS\convert\Software
|
||||
}
|
||||
|
||||
// XF 1.1
|
||||
if ( extension_loaded( 'hash' ) )
|
||||
if ( \extension_loaded( 'hash' ) )
|
||||
{
|
||||
$hashedPassword = hash( 'sha256', hash( 'sha256', $password ) . $member->misc );
|
||||
}
|
||||
@@ -1550,64 +1757,4 @@ class _Xenforo extends \IPS\convert\Software
|
||||
// If they converted vB > XF > IPB then passwords may be in vB format still - try that.
|
||||
return \IPS\convert\Software\Core\Vbulletin::login( $member, $password );
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Cache sprite image objects
|
||||
*/
|
||||
protected $_spriteImages = array();
|
||||
|
||||
/**
|
||||
* Return image from sprite - We must use GD for this, it's generally available on most servers
|
||||
* And we don't have any relevant methods in either image handler for doing this completly within
|
||||
* the image class
|
||||
*
|
||||
* @param string $sprite Sprite path
|
||||
* @param array $spriteParams Sprite parameters
|
||||
* @return array
|
||||
*/
|
||||
protected function _emoticonsFromSprite( $sprite, $spriteParams )
|
||||
{
|
||||
$key = md5( $sprite );
|
||||
|
||||
/* Set up image canvas */
|
||||
if( !isset( $this->_spriteImages[ $key ] ) )
|
||||
{
|
||||
if( !file_exists( $sprite ) )
|
||||
{
|
||||
return array( 'emoticon' => NULL );
|
||||
}
|
||||
$this->_spriteImages[ $key ] = new \IPS\Image\Gd( file_get_contents( $sprite ) );
|
||||
}
|
||||
|
||||
/* x2 Emoticon? */
|
||||
$multiplier = 1;
|
||||
if( $this->_spriteImages[ $key ]->width > $spriteParams['w'] )
|
||||
{
|
||||
$multiplier = 2;
|
||||
}
|
||||
|
||||
$emoticon = \IPS\Image\Gd::newImageCanvas( $spriteParams['w'] * $multiplier, $spriteParams['h'] * $multiplier, array( 0, 0, 0 ) );
|
||||
|
||||
/* Set the background to transparent */
|
||||
imagefill( $emoticon->image, 0, 0, imagecolorallocatealpha( $emoticon->image, 0, 0, 0, 127 ) );
|
||||
|
||||
/* Extract sprite */
|
||||
imagecopy( $emoticon->image, $this->_spriteImages[ $key ]->image, 0, 0, abs( $spriteParams['x'] ) * $multiplier, abs( $spriteParams['y'] ) * $multiplier, $spriteParams['w'] * $multiplier, $spriteParams['h'] * $multiplier );
|
||||
|
||||
/* x2 Emoticon? */
|
||||
$return = array();
|
||||
if( $multiplier == 2 )
|
||||
{
|
||||
$return['emoticon_x2'] = (string) $emoticon;
|
||||
|
||||
/* Resize */
|
||||
$emoticon->resize( $spriteParams['w'], $spriteParams['h'] );
|
||||
}
|
||||
|
||||
$return['emoticon'] = (string) $emoticon;
|
||||
|
||||
unset( $emoticon );
|
||||
|
||||
return $return;
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user