Version 4.3.0
This commit is contained in:
1 parent
96997ddd8e
commit
fe1acf984a
1349 files changed
+116159
-67711
No files matched your search
@@ -84,6 +84,30 @@ 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 )
|
||||
{
|
||||
if( isset( $rows['convertPrivateMessageReplies'] ) )
|
||||
{
|
||||
$rows['convertPmAttachments'] = array(
|
||||
'step_method' => 'convertPmAttachments',
|
||||
'step_title' => 'convert_attachments',
|
||||
'ips_rows' => \IPS\Db::i()->select( 'COUNT(*)', 'core_attachments' )->first(),
|
||||
'source_rows' => $this->countRows( static::canConvert()['convertPmAttachments']['table'], static::canConvert()['convertPmAttachments']['where'] ),
|
||||
'per_cycle' => 100,
|
||||
'dependencies' => array( 'convertPrivateMessageReplies' ),
|
||||
'link_type' => 'core_attachments',
|
||||
);
|
||||
}
|
||||
|
||||
return $rows;
|
||||
}
|
||||
|
||||
/**
|
||||
* Can we convert passwords from this software.
|
||||
*
|
||||
@@ -288,7 +312,7 @@ class _Expressionengine extends \IPS\convert\Software
|
||||
\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 ), 4, array( 'app' ) );
|
||||
\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", "f_rebuild_attachments" );
|
||||
}
|
||||
@@ -724,4 +748,39 @@ class _Expressionengine extends \IPS\convert\Software
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Process a login
|
||||
*
|
||||
* @param \IPS\Member $member The member
|
||||
* @param string $password Password from form
|
||||
* @return bool
|
||||
*/
|
||||
public function login( $member, $password )
|
||||
{
|
||||
$length = \strlen( $member->conv_password );
|
||||
$providedHash = FALSE;
|
||||
|
||||
switch( $length )
|
||||
{
|
||||
/* MD5 */
|
||||
case 32:
|
||||
$providedHash = md5( $password );
|
||||
break;
|
||||
/* SHA1 */
|
||||
case 40:
|
||||
$providedHash = sha1( $password );
|
||||
break;
|
||||
/* SHA256 */
|
||||
case 64:
|
||||
$providedHash = hash( 'sha256', $password );
|
||||
break;
|
||||
/* SHA512 */
|
||||
case 128:
|
||||
$providedHash = hash( 'sha512', $password );
|
||||
break;
|
||||
}
|
||||
|
||||
return ( \IPS\Login::compareHashes( $member->conv_password, $providedHash ) ) ? TRUE : FALSE;
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large.
Load diff
@@ -229,4 +229,32 @@ class _Joomla extends \IPS\convert\Software
|
||||
$libraryClass->setLastKeyValue( $row['id'] );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Process a login
|
||||
*
|
||||
* @param \IPS\Member $member The member
|
||||
* @param string $password Password from form
|
||||
* @return bool
|
||||
*/
|
||||
public function login( $member, $password )
|
||||
{
|
||||
/* Joomla 3 */
|
||||
if( preg_match( '/^\$2[ay]\$(0[4-9]|[1-2][0-9]|3[0-1])\$[a-zA-Z0-9.\/]{53}/', $member->conv_password ) )
|
||||
{
|
||||
require_once \IPS\ROOT_PATH . "/applications/convert/sources/Login/PasswordHash.php";
|
||||
$ph = new \PasswordHash( 8, TRUE );
|
||||
return $ph->CheckPassword( $password, $member->conv_password ) ? TRUE : FALSE;
|
||||
}
|
||||
|
||||
/* Joomla 2 */
|
||||
if ( \IPS\Login::compareHashes( $member->conv_password, md5( $password . $member->misc ) ) )
|
||||
{
|
||||
return TRUE;
|
||||
}
|
||||
else
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -283,10 +283,30 @@ class _Mybb extends \IPS\convert\Software
|
||||
|
||||
/* 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", "f_announce_rebuild" );
|
||||
}
|
||||
|
||||
/**
|
||||
* Fix post data
|
||||
*
|
||||
* @param string 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 );
|
||||
|
||||
/* remove justify, since we don't support it */
|
||||
$post = str_replace( array( '[justify]', '[/justify]' ), '', $post );
|
||||
|
||||
return $post;
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert announcements
|
||||
*
|
||||
@@ -899,7 +919,7 @@ class _Mybb extends \IPS\convert\Software
|
||||
/* Warnings */
|
||||
foreach( $this->db->select( '*', 'warnings', array( "uid=? AND pid=?", $row['uid'], 0 ) ) AS $warning )
|
||||
{
|
||||
$libraryClass->convertWarnLog( array(
|
||||
$warnId = $libraryClass->convertWarnLog( array(
|
||||
'wl_id' => $warning['wid'],
|
||||
'wl_member' => $warning['uid'],
|
||||
'wl_moderator' => $warning['issuedby'],
|
||||
@@ -909,6 +929,17 @@ class _Mybb extends \IPS\convert\Software
|
||||
'wl_note_mods' => $warning['notes'],
|
||||
'wl_expire_date' => $warning['expires'],
|
||||
) );
|
||||
|
||||
/* Add a member history record for this member */
|
||||
$libraryClass->convertMemberHistory( array(
|
||||
'log_id' => 'w' . $warning['wid'],
|
||||
'log_member' => $warning['uid'],
|
||||
'log_by' => $warning['issuedby'],
|
||||
'log_type' => 'warning',
|
||||
'log_data' => array( 'wid' => $warnId ),
|
||||
'log_date' => $warning['dateline']
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
$libraryClass->setLastKeyValue( $row['uid'] );
|
||||
@@ -1078,4 +1109,23 @@ class _Mybb extends \IPS\convert\Software
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Process a login
|
||||
*
|
||||
* @param \IPS\Member $member The member
|
||||
* @param string $password Password from form
|
||||
* @return bool
|
||||
*/
|
||||
public function login( $member, $password )
|
||||
{
|
||||
if ( \IPS\Login::compareHashes( $member->conv_password, md5( md5( $member->misc ) . md5( $password ) ) ) )
|
||||
{
|
||||
return TRUE;
|
||||
}
|
||||
else
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -7,7 +7,6 @@
|
||||
* @package Invision Community
|
||||
* @subpackage Converter
|
||||
* @since 6 December 2016
|
||||
* @note Only redirect scripts are supported right now
|
||||
*/
|
||||
|
||||
namespace IPS\convert\Software\Core;
|
||||
@@ -29,7 +28,7 @@ class _Photopost extends \IPS\convert\Software
|
||||
public static function softwareName()
|
||||
{
|
||||
/* Child classes must override this method */
|
||||
return "Photopost";
|
||||
return "Photopost (8.x)";
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -46,11 +45,242 @@ class _Photopost extends \IPS\convert\Software
|
||||
/**
|
||||
* Content we can convert from this software.
|
||||
*
|
||||
* @return NULL
|
||||
* @return array
|
||||
*/
|
||||
public static function canConvert()
|
||||
{
|
||||
return NULL;
|
||||
return array(
|
||||
'convertGroups' => array(
|
||||
'table' => 'usergroups',
|
||||
'where' => NULL,
|
||||
),
|
||||
'convertMembers' => array(
|
||||
'table' => 'users',
|
||||
'where' => NULL,
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* List of conversion methods that require additional information
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public static function checkConf()
|
||||
{
|
||||
return array(
|
||||
'convertGroups',
|
||||
'convertMembers'
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get More Information
|
||||
*
|
||||
* @param string $method Conversion method
|
||||
* @return array
|
||||
*/
|
||||
public function getMoreInfo( $method )
|
||||
{
|
||||
$return = array();
|
||||
|
||||
switch( $method )
|
||||
{
|
||||
case 'convertGroups':
|
||||
$return['convertGroups'] = array();
|
||||
|
||||
$options = array();
|
||||
$options['none'] = '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( '*', 'usergroups' ) AS $group )
|
||||
{
|
||||
\IPS\Member::loggedIn()->language()->words["map_group_{$group['groupid']}"] = $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();
|
||||
|
||||
\IPS\Member::loggedIn()->language()->words['photo_location_desc'] = \IPS\Member::loggedIn()->language()->addToStack( 'photo_location_nodb_desc' );
|
||||
$return['convertMembers']['photo_location'] = array(
|
||||
'field_class' => 'IPS\\Helpers\\Form\\Text',
|
||||
'field_default' => NULL,
|
||||
'field_required' => TRUE,
|
||||
'field_extra' => array(),
|
||||
'field_hint' => "The path to the folder where avatars are saved (no trailing slash - usually /path_to_photopost/data/avatars):",
|
||||
'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', 'location', 'interests', 'occupation', 'bio' ) AS $field )
|
||||
{
|
||||
\IPS\Member::loggedIn()->language()->words["field_{$field}"] = \IPS\Member::loggedIn()->language()->addToStack( 'pseudo_field', FALSE, array( 'sprintf' => ucwords( $field ) ) );
|
||||
\IPS\Member::loggedIn()->language()->words["field_{$field}_desc"] = \IPS\Member::loggedIn()->language()->addToStack( 'pseudo_field_desc' );
|
||||
$return['convertMembers']["field_{$field}"] = array(
|
||||
'field_class' => 'IPS\\Helpers\\Form\\Radio',
|
||||
'field_default' => 'no_convert',
|
||||
'field_required' => TRUE,
|
||||
'field_extra' => array(
|
||||
'options' => array(
|
||||
'no_convert' => \IPS\Member::loggedIn()->language()->addToStack( 'no_convert' ),
|
||||
'create_field' => \IPS\Member::loggedIn()->language()->addToStack( 'create_field' ),
|
||||
),
|
||||
'userSuppliedInput' => 'create_field'
|
||||
),
|
||||
'field_hint' => NULL
|
||||
);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
return ( isset( $return[ $method ] ) ) ? $return[ $method ] : array();
|
||||
}
|
||||
|
||||
/**
|
||||
* Finish - Adds everything it needs to the queues and clears data store
|
||||
*
|
||||
* @return array Message 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_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' ) );
|
||||
|
||||
return array( "f_search_index_rebuild", "f_clear_caches", "f_signatures_rebuild" );
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert groups
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function convertGroups()
|
||||
{
|
||||
$libraryClass = $this->getLibrary();
|
||||
|
||||
$libraryClass::setKey( 'groupid' );
|
||||
|
||||
foreach( $this->fetch( 'usergroups', 'groupid' ) AS $row )
|
||||
{
|
||||
$info = array(
|
||||
'g_id' => $row['groupid'],
|
||||
'g_name' => $row['groupname']
|
||||
);
|
||||
|
||||
$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' );
|
||||
|
||||
foreach( $this->fetch( 'users', 'userid' ) AS $row )
|
||||
{
|
||||
$birthdayYear = $birthdayMonth = $birthdayDay = NULL;
|
||||
|
||||
/* Is there a birthdate? */
|
||||
if( $row['birthday'] != '0000-00-00' )
|
||||
{
|
||||
list( $birthdayYear, $birthdayMonth, $birthdayDay ) = explode( '-', $row['birthday'] );
|
||||
}
|
||||
|
||||
$info = array(
|
||||
'member_id' => $row['userid'],
|
||||
'email' => $row['email'],
|
||||
'name' => $row['username'],
|
||||
'md5_password' => $row['password'],
|
||||
'member_group_id' => $row['usergroupid'],
|
||||
'joined' => $row['joindate'] ?: NULL,
|
||||
'ip_address' => $row['ipaddress'],
|
||||
'last_visit' => $row['laston'],
|
||||
'last_activity' => $row['laston'],
|
||||
'bday_day' => $birthdayDay,
|
||||
'bday_month' => $birthdayMonth,
|
||||
'bday_year' => $birthdayYear,
|
||||
'signature' => static::fixPostData( $row['signature'] )
|
||||
);
|
||||
|
||||
/* Pseudo Fields */
|
||||
$profileFields = array();
|
||||
foreach( array( 'homepage', 'icq', 'aim', 'yahoo', 'location', 'interests', 'occupation', 'bio' ) AS $pseudo )
|
||||
{
|
||||
/* Are we retaining? */
|
||||
if ( $this->app->_session['more_info']['convertMembers']["field_{$pseudo}"] == 'no_convert' )
|
||||
{
|
||||
/* No, skip */
|
||||
continue;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
/* We don't actually need this, but we need to make sure the field was created */
|
||||
$this->app->getLink( $pseudo, 'core_pfields_data' );
|
||||
}
|
||||
catch( \OutOfRangeException $e )
|
||||
{
|
||||
$libraryClass->convertProfileField( array(
|
||||
'pf_id' => $pseudo,
|
||||
'pf_name' => $this->app->_session['more_info']['convertMembers']["field_{$pseudo}"],
|
||||
'pf_desc' => '',
|
||||
'pf_type' => 'Text',
|
||||
'pf_content' => '[]',
|
||||
'pf_member_hide' => 0,
|
||||
'pf_max_input' => 255,
|
||||
'pf_member_edit' => 1,
|
||||
'pf_show_on_reg' => 0,
|
||||
'pf_admin_only' => 0,
|
||||
) );
|
||||
}
|
||||
|
||||
$profileFields[ $pseudo ] = $row[ $pseudo ];
|
||||
}
|
||||
|
||||
$libraryClass->convertMember( $info, $profileFields, $row['avatar'], rtrim( $this->app->_session['more_info']['convertMembers']['photo_location'], '/' ) );
|
||||
$libraryClass->setLastKeyValue( $row['userid'] );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -28,7 +28,7 @@ class _Phpbb extends \IPS\convert\Software
|
||||
public static function softwareName()
|
||||
{
|
||||
/* Child classes must override this method */
|
||||
return "phpBB 3.1";
|
||||
return "phpBB (3.1.x/3.2.x)";
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -98,6 +98,24 @@ 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 )
|
||||
{
|
||||
if( isset( $rows['convertBanfilters'] ) )
|
||||
{
|
||||
$rows['convertBanfilters2'] = $rows['convertBanfilters'];
|
||||
$rows['convertBanfilters2']['step_method'] = 'convertBanfilters2';
|
||||
$rows['convertBanfilters2']['source_rows'] = $this->countRows( static::canConvert()['convertBanfilters2']['table'], static::canConvert()['convertBanfilters2']['where'] );
|
||||
}
|
||||
|
||||
return $rows;
|
||||
}
|
||||
|
||||
/**
|
||||
* Count Source Rows for a specific step
|
||||
*
|
||||
@@ -310,6 +328,9 @@ class _Phpbb extends \IPS\convert\Software
|
||||
/* Content Counts */
|
||||
\IPS\Task::queue( 'core', 'RecountMemberContent', array( 'app' => $this->app->app_id ), 4, array( 'app' ) );
|
||||
|
||||
/* Attachments */
|
||||
\IPS\Task::queue( 'core', 'RebuildAttachmentThumbnails', array( 'app' => $this->app->app_id ), 1, array( 'app' ) );
|
||||
|
||||
/* First Post Data */
|
||||
\IPS\Task::queue( 'convert', 'RebuildConversationFirstIds', array( 'app' => $this->app->app_id ), 2, array( 'app' ) );
|
||||
|
||||
@@ -698,8 +719,7 @@ class _Phpbb extends \IPS\convert\Software
|
||||
{
|
||||
$userfields = $this->db->select( '*', 'profile_fields_data', array( "user_id=?", $row['user_id'] ) )->first();
|
||||
}
|
||||
catch( \UnderflowException $e )
|
||||
{}
|
||||
catch( \UnderflowException $e ) {}
|
||||
|
||||
foreach( $this->db->select( '*', 'profile_fields' ) AS $field )
|
||||
{
|
||||
@@ -720,6 +740,10 @@ 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;
|
||||
|
||||
/* Finally */
|
||||
$libraryClass->convertMember( $info, $pfields, $filename, $filepath );
|
||||
@@ -946,7 +970,7 @@ class _Phpbb extends \IPS\convert\Software
|
||||
$maps = array();
|
||||
|
||||
/* First one first initial author */
|
||||
$maps[$row['author_id']] = array(
|
||||
$maps[ $row['author_id'] ] = array(
|
||||
'map_user_id' => $row['author_id'],
|
||||
'map_is_starter' => 1,
|
||||
'map_last_topic_reply' => $row['message_time'],
|
||||
@@ -973,13 +997,18 @@ class _Phpbb extends \IPS\convert\Software
|
||||
to a custom folder then they will have a row in privmsgs_to and we will end up resetting map_is_starter to 0 otherwise */
|
||||
if( isset( $maps[ $to['user_id'] ] ) )
|
||||
{
|
||||
if( $to['folder_id'] > 0 )
|
||||
{
|
||||
$maps[ $to['user_id'] ]['map_folder_id'] = $this->_getPmFolder( $to['user_id'], $to['folder_id'] );
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
$maps[ $to['user_id'] ] = array(
|
||||
'map_user_id' => $to['user_id'],
|
||||
'map_is_starter' => 0,
|
||||
'map_last_topic_reply' => $row['message_time']
|
||||
'map_last_topic_reply' => $row['message_time'],
|
||||
'map_folder_id' => ( $to['folder_id'] > 0 ) ? $this->_getPmFolder( $to['user_id'], $to['folder_id'] ) : FALSE
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1045,4 +1074,108 @@ class _Phpbb extends \IPS\convert\Software
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Lookup cache
|
||||
*/
|
||||
protected static $pmFolders = array();
|
||||
|
||||
/**
|
||||
* @brief PhpBB Source Folders
|
||||
*/
|
||||
protected static $phpBbFolders = NULL;
|
||||
|
||||
/**
|
||||
* Get array key for the folder
|
||||
*
|
||||
* @param int $user User ID
|
||||
* @param string $folderId Folder Name
|
||||
* @return boolean
|
||||
*/
|
||||
protected function _getPmFolder( $user, $folderId )
|
||||
{
|
||||
/* Check for cached folder info */
|
||||
if( isset( static::$pmFolders[ $user ][ $folderId ] ) )
|
||||
{
|
||||
return static::$pmFolders[ $user ][ $folderId ];
|
||||
}
|
||||
|
||||
/* Check for cached phpBB data */
|
||||
if( static::$phpBbFolders === NULL )
|
||||
{
|
||||
static::$phpBbFolders = iterator_to_array( $this->db->select( 'folder_id,folder_name', 'privmsgs_folder' )->setKeyField( 'folder_id' )->setValueField( 'folder_name' ) );
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
/* Does the referenced folder exist in PhpBB? */
|
||||
if( !isset( static::$phpBbFolders[ $folderId ] ) )
|
||||
{
|
||||
throw new \OutOfRangeException;
|
||||
}
|
||||
|
||||
$member = \IPS\Member::load( $this->app->getLink( (int) $user, 'core_members' ) );
|
||||
$filters = json_decode( $member->pconversation_filters, TRUE );
|
||||
|
||||
/* No PM Folders or it's a guest */
|
||||
if( $filters === NULL OR !$member->member_id )
|
||||
{
|
||||
throw new \OutOfRangeException;
|
||||
}
|
||||
}
|
||||
catch( \OutOfRangeException $e )
|
||||
{
|
||||
return static::$pmFolders[ $user ][ $folderId ] = FALSE;
|
||||
}
|
||||
|
||||
/* Search PM folders and return match */
|
||||
return static::$pmFolders[ $user ][ $folderId ] = array_search( static::$phpBbFolders[ $folderId ], $filters );
|
||||
}
|
||||
|
||||
/**
|
||||
* Process a login
|
||||
*
|
||||
* @param \IPS\Member $member The member
|
||||
* @param string $password Password from form
|
||||
* @return bool
|
||||
*/
|
||||
public function login( $member, $password )
|
||||
{
|
||||
$password = html_entity_decode( $password );
|
||||
$success = FALSE;
|
||||
$hash = $member->conv_password;
|
||||
|
||||
/* phpBB 3.1 */
|
||||
if( preg_match( '/^\$2[ay]\$(0[4-9]|[1-2][0-9]|3[0-1])\$[a-zA-Z0-9.\/]{53}/', $hash ) )
|
||||
{
|
||||
require_once \IPS\ROOT_PATH . "/applications/convert/sources/Login/PasswordHash.php";
|
||||
$ph = new \PasswordHash( 8, TRUE );
|
||||
$success = $ph->CheckPassword( $password, $member->conv_password ) ? TRUE : FALSE;
|
||||
}
|
||||
|
||||
$hashLibrary = new \IPS\convert\Login\HashCryptPrivate;
|
||||
if ( $success === FALSE )
|
||||
{
|
||||
/* phpBB3 */
|
||||
$single_md5_pass = md5( $password );
|
||||
$itoa64 = './0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz';
|
||||
|
||||
if ( \strlen( $hash ) == 34 )
|
||||
{
|
||||
$success = ( \IPS\Login::compareHashes( $hash, $hashLibrary->hashCryptPrivate( $password, $hash, $itoa64 ) ) ) ? TRUE : FALSE;
|
||||
}
|
||||
else
|
||||
{
|
||||
$success = ( \IPS\Login::compareHashes( $hash, $single_md5_pass ) ) ? TRUE : FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
/* phpBB2 */
|
||||
if ( !$success )
|
||||
{
|
||||
$success = ( \IPS\Login::compareHashes( $hash, $hashLibrary->hashCryptPrivate( $single_md5_pass, $hash, $itoa64 ) ) ) ? TRUE : FALSE ;
|
||||
}
|
||||
|
||||
return $success;
|
||||
}
|
||||
}
|
||||
@@ -28,7 +28,7 @@ class _Punbb extends \IPS\convert\Software
|
||||
public static function softwareName()
|
||||
{
|
||||
/* Child classes must override this method */
|
||||
return "PunBB 1.x";
|
||||
return "PunBB (1.x)";
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -454,4 +454,35 @@ class _Punbb extends \IPS\convert\Software
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Process a login
|
||||
*
|
||||
* @param \IPS\Member $member The member
|
||||
* @param string $password Password from form
|
||||
* @return bool
|
||||
*/
|
||||
public function login( $member, $password )
|
||||
{
|
||||
$success = FALSE;
|
||||
|
||||
if ( mb_strlen( $member->conv_password ) == 40 )
|
||||
{
|
||||
/* Password with salt */
|
||||
$success = \IPS\Login::compareHashes( $member->conv_password, sha1( $member->conv_password_extra . sha1( $password ) ) );
|
||||
|
||||
if ( !$success )
|
||||
{
|
||||
/* No salt */
|
||||
$success = \IPS\Login::compareHashes( $member->conv_password, sha1( $password ) );
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* MD5 */
|
||||
$success = \IPS\Login::compareHashes( $member->conv_password, md5( $password ) );
|
||||
}
|
||||
|
||||
return $success;
|
||||
}
|
||||
}
|
||||
@@ -28,7 +28,7 @@ class _Smf extends \IPS\convert\Software
|
||||
public static function softwareName()
|
||||
{
|
||||
/* Child classes must override this method */
|
||||
return "Simple Machines Forum";
|
||||
return "Simple Machines Forum (2.0.x)";
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -226,7 +226,7 @@ class _Smf extends \IPS\convert\Software
|
||||
'field_class' => 'IPS\\Helpers\\Form\\Radio',
|
||||
'field_default' => 'user_name',
|
||||
'field_required' => TRUE,
|
||||
'field_extra' => array( 'options' => array( 'user_name', 'display_name' ) ),
|
||||
'field_extra' => array( 'options' => array( 'user_name' => 'user_name', 'display_name' => 'display_name' ) ),
|
||||
'field_hint' => NULL,
|
||||
);
|
||||
|
||||
@@ -298,7 +298,7 @@ class _Smf extends \IPS\convert\Software
|
||||
\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 ), 4, array( 'app' ) );
|
||||
\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", "f_rebuild_attachments" );
|
||||
}
|
||||
@@ -318,7 +318,7 @@ class _Smf extends \IPS\convert\Software
|
||||
$post = str_replace( $search, $replace, $post );
|
||||
|
||||
// And img tags
|
||||
$post = preg_replace("#\[img width=(\d+)(?: height=(\d+))?\]([a-zA-Z0-9.:\-/%\?&_]+)\[\/img\]#i", "[img]$3[/img]", $post);
|
||||
$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);
|
||||
@@ -648,7 +648,7 @@ class _Smf extends \IPS\convert\Software
|
||||
'email' => $row['email_address'],
|
||||
'name' => $name,
|
||||
'password' => $row['passwd'],
|
||||
'password_extra' => $row['password_salt'],
|
||||
'password_extra' => $row['member_name'], // We need to keep the original member name for the SMF password hash
|
||||
'member_group_id' => $row['id_group'],
|
||||
'joined' => $row['date_registered'],
|
||||
'ip_address' => $row['member_ip'],
|
||||
@@ -900,4 +900,45 @@ class _Smf extends \IPS\convert\Software
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Process a login
|
||||
*
|
||||
* @param \IPS\Member $member The member
|
||||
* @param string $password Password from form
|
||||
* @return bool
|
||||
*/
|
||||
public function login( $member, $password )
|
||||
{
|
||||
if ( \IPS\Login::compareHashes( $member->conv_password, sha1( mb_strtolower( $member->name ) . html_entity_decode( $password ) ) ) )
|
||||
{
|
||||
return TRUE;
|
||||
}
|
||||
else if ( \IPS\Login::compareHashes( $member->conv_password, sha1( mb_strtolower( $member->name ) . $password ) ) )
|
||||
{
|
||||
return TRUE;
|
||||
}
|
||||
/* In 4.2.6 we save the original members name as the salt so that we don't have one that has been modified in the conversion process */
|
||||
else if ( \IPS\Login::compareHashes( $member->conv_password, sha1( mb_strtolower( $member->conv_password_extra ) . $password ) ) )
|
||||
{
|
||||
return TRUE;
|
||||
}
|
||||
else
|
||||
{
|
||||
require_once \IPS\ROOT_PATH . "/applications/convert/sources/Login/PasswordHash.php";
|
||||
$ph = new \PasswordHash( 8, TRUE );
|
||||
|
||||
if( $ph->CheckPassword( mb_strtolower( $member->name ) . $password, $member->conv_password ) )
|
||||
{
|
||||
return TRUE;
|
||||
}
|
||||
/* In 4.2.6 we save the original members name as the salt so that we don't have one that has been modified in the conversion process */
|
||||
else if ( $ph->CheckPassword( mb_strtolower( $member->conv_password_extra ) . $password, $member->conv_password ) )
|
||||
{
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
@@ -132,6 +132,32 @@ 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 )
|
||||
{
|
||||
$count = $this->countRows( static::canConvert()['convertMembersFollowers']['table'], static::canConvert()['convertMembersFollowers']['where'] );
|
||||
|
||||
if( $count )
|
||||
{
|
||||
$rows['convertMembersFollowers'] = array(
|
||||
'step_method' => 'convertMembersFollowers',
|
||||
'step_title' => 'convert_follows',
|
||||
'ips_rows' => \IPS\Db::i()->select( 'COUNT(*)', 'core_follow', array( 'follow_app=? and follow_area=?', 'core', 'member' ) )->first(),
|
||||
'source_rows' => $count,
|
||||
'per_cycle' => 500,
|
||||
'dependencies' => array( 'convertMembers' ),
|
||||
'link_type' => 'core_follow',
|
||||
);
|
||||
}
|
||||
|
||||
return $rows;
|
||||
}
|
||||
|
||||
/**
|
||||
* Can we convert passwords from this software.
|
||||
@@ -265,6 +291,15 @@ class _UBBthreads extends \IPS\convert\Software
|
||||
'field_hint' => \IPS\Member::loggedIn()->language()->addToStack( 'username_hint' ),
|
||||
);
|
||||
|
||||
$return['convertMembers']['photo_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_ubbthreads_photo_path'),
|
||||
'field_validation' => function( $value ) { if ( !@is_dir( $value ) ) { throw new \DomainException( 'path_invalid' ); } },
|
||||
);
|
||||
|
||||
foreach( array( 'homepage', 'occupation', 'hobbies', 'location', 'icq', 'yahoo', 'aim', 'msn' ) AS $field )
|
||||
{
|
||||
\IPS\Member::loggedIn()->language()->words["field_{$field}"] = \IPS\Member::loggedIn()->language()->addToStack( 'pseudo_field', FALSE, array( 'sprintf' => $field ) );
|
||||
@@ -315,7 +350,7 @@ class _UBBthreads extends \IPS\convert\Software
|
||||
\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 ), 4, array( 'app' ) );
|
||||
\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", "f_rebuild_attachments" );
|
||||
}
|
||||
@@ -584,8 +619,16 @@ class _UBBthreads extends \IPS\convert\Software
|
||||
/* Profile photo */
|
||||
$profilePhotoName = NULL;
|
||||
$profilePhotoData = NULL;
|
||||
$profilePhotoPath = NULL;
|
||||
|
||||
if ( !empty( $row['USER_AVATAR'] ) AND ( $row['USER_AVATAR'] != 'http://' ) )
|
||||
/* Is it a file? */
|
||||
if( !empty( $row['USER_AVATAR'] ) AND mb_substr( $row['USER_AVATAR'], 0, 1 ) == '/' )
|
||||
{
|
||||
$profilePhotoPath = pathinfo( rtrim( $this->app->_session['more_info']['convertMembers']['photo_location'], '/' ) . $row['USER_AVATAR'], PATHINFO_DIRNAME );
|
||||
$profilePhotoName = pathinfo( rtrim( $this->app->_session['more_info']['convertMembers']['photo_location'], '/' ) . $row['USER_AVATAR'], PATHINFO_BASENAME );
|
||||
}
|
||||
/* Or an URL? */
|
||||
elseif ( !empty( $row['USER_AVATAR'] ) AND ( $row['USER_AVATAR'] != 'http://' ) AND mb_substr( $row['USER_AVATAR'], 0, 4 ) )
|
||||
{
|
||||
try
|
||||
{
|
||||
@@ -595,7 +638,7 @@ class _UBBthreads extends \IPS\convert\Software
|
||||
catch( \IPS\Http\Request\Exception $e ) { }
|
||||
}
|
||||
|
||||
$libraryClass->convertMember( $info, $pfields, $profilePhotoName, NULL, $profilePhotoData );
|
||||
$libraryClass->convertMember( $info, $pfields, $profilePhotoName, $profilePhotoPath, $profilePhotoData );
|
||||
$libraryClass->setLastKeyValue( $row['USER_ID'] );
|
||||
}
|
||||
}
|
||||
@@ -609,7 +652,7 @@ class _UBBthreads extends \IPS\convert\Software
|
||||
{
|
||||
$libraryClass = $this->getLibrary();
|
||||
|
||||
foreach ( $this->fetch( 'WATCH_LISTS', 'WATCH_ID', array( 'WATCH_TYPE=?', 'u' ), 'USER_ID ASC, WATCH_ID ASC' ) as $row )
|
||||
foreach ( $this->fetch( 'WATCH_LISTS', 'WATCH_ID', array( 'WATCH_TYPE=?', 'u' ) ) as $row )
|
||||
{
|
||||
$libraryClass->convertFollow( array(
|
||||
'follow_app' => 'core',
|
||||
@@ -769,7 +812,7 @@ class _UBBthreads extends \IPS\convert\Software
|
||||
$data = $this->app->getLink( (int) $matches[1], array( 'members', 'core_members' ) );
|
||||
$item = \IPS\Member::load( $data );
|
||||
|
||||
if( $item->canView() )
|
||||
if( \IPS\Member::loggedIn()->canAccessModule( \IPS\Application\Module::get( 'core', 'members' ) ) )
|
||||
{
|
||||
return $item->url();
|
||||
}
|
||||
@@ -782,4 +825,37 @@ class _UBBthreads extends \IPS\convert\Software
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Process a login
|
||||
*
|
||||
* @param \IPS\Member $member The member
|
||||
* @param string $password Password from form
|
||||
* @return bool
|
||||
*/
|
||||
public function login( $member, $password )
|
||||
{
|
||||
$hash = $member->members_pass_hash;
|
||||
$salt = $member->members_pass_salt;
|
||||
|
||||
if ( \IPS\Login::compareHashes( $hash, md5( $password ) ) )
|
||||
{
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
// Not using md5, UBB salts the password with the password
|
||||
// IPB already md5'd it though, *sigh*
|
||||
if ( \IPS\Login::compareHashes( $hash, md5( md5( $salt ) . crypt( $password, $password ) ) ) )
|
||||
{
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
// Now standard IPB check.
|
||||
if ( \IPS\Login::compareHashes( $hash, md5( md5( $salt ) . md5( $password ) ) ) )
|
||||
{
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
@@ -27,7 +27,7 @@ class _Vanilla extends \IPS\convert\Software
|
||||
public static function softwareName()
|
||||
{
|
||||
/* Child classes must override this method */
|
||||
return "Vanilla 2";
|
||||
return "Vanilla 2 (2.2.x/2.3.x)";
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -118,8 +118,8 @@ class _Vanilla extends \IPS\convert\Software
|
||||
* Resolve the filesystem location of a file from a path stored in the database
|
||||
* There are several different ways Vanilla may store these, including as remote URL's
|
||||
*
|
||||
* @param $location File location retrieved from the database
|
||||
* @param $uploadsPath Configured uploads path
|
||||
* @param string $location File location retrieved from the database
|
||||
* @param string $uploadsPath Configured uploads path
|
||||
* @return \IPS\Http\Url|string|void
|
||||
*/
|
||||
public static function parseMediaLocation( $location, $uploadsPath )
|
||||
@@ -325,7 +325,7 @@ class _Vanilla extends \IPS\convert\Software
|
||||
\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 ), 4, array( 'app' ) );
|
||||
\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", "f_rebuild_attachments" );
|
||||
}
|
||||
@@ -566,4 +566,31 @@ class _Vanilla extends \IPS\convert\Software
|
||||
$libraryClass->setLastKeyValue( $row['MessageID'] );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Process a login
|
||||
*
|
||||
* @param \IPS\Member $member The member
|
||||
* @param string $password Password from form
|
||||
* @return bool
|
||||
*/
|
||||
public function login( $member, $password )
|
||||
{
|
||||
/* Vanilla 2.2 */
|
||||
if( preg_match( '/^\$2[ay]\$(0[4-9]|[1-2][0-9]|3[0-1])\$[a-zA-Z0-9.\/]{53}/', $member->conv_password ) OR mb_substr( $member->conv_password, 0, 3 ) == '$P$' )
|
||||
{
|
||||
require_once \IPS\ROOT_PATH . "/applications/convert/sources/Login/PasswordHash.php";
|
||||
$ph = new \PasswordHash( 8, TRUE );
|
||||
return $ph->CheckPassword( $password, $member->conv_password ) ? TRUE : FALSE;
|
||||
}
|
||||
|
||||
if ( \IPS\Login::compareHashes( $member->conv_password, md5( md5( str_replace( ''', "'", html_entity_decode( $password ) ) ) . $member->misc ) ) )
|
||||
{
|
||||
return TRUE;
|
||||
}
|
||||
else
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -166,6 +166,43 @@ class _Vbulletin extends \IPS\convert\Software
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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 'userchangelog':
|
||||
return $this->db->select( 'count(changeid)', 'userchangelog', array( $this->db->in( 'fieldname', array_keys( static::$changeLogTypes ) ) ) )->first();
|
||||
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' ) )
|
||||
{
|
||||
$this->db->addIndex( 'pm', array(
|
||||
'type' => 'key',
|
||||
'name' => 'parent_id',
|
||||
'columns' => array( 'parentpmid', 'folderid' )
|
||||
) );
|
||||
}
|
||||
|
||||
return parent::countRows( $table, $where, $recache );
|
||||
break;
|
||||
|
||||
default:
|
||||
return parent::countRows( $table, $where, $recache );
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Can we convert passwords from this software.
|
||||
@@ -479,12 +516,15 @@ class _Vbulletin extends \IPS\convert\Software
|
||||
|
||||
/* Content Counts */
|
||||
\IPS\Task::queue( 'core', 'RecountMemberContent', array( 'app' => $this->app->app_id ), 4, array( 'app' ) );
|
||||
|
||||
/* Clubs */
|
||||
\IPS\Task::queue( 'convert', 'RecountClubMembers', array( 'app' => $this->app->app_id ), 2, array( 'app' ) );
|
||||
|
||||
/* 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 ), 4, array( 'app' ) );
|
||||
\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", "f_announce_rebuild" );
|
||||
}
|
||||
@@ -882,7 +922,7 @@ class _Vbulletin extends \IPS\convert\Software
|
||||
/**
|
||||
* @brief Member history type map
|
||||
*/
|
||||
protected $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' => 'member_group_id', 'membergroupids' => 'mgroup_others' );
|
||||
|
||||
/**
|
||||
* Convert member history
|
||||
@@ -892,50 +932,15 @@ class _Vbulletin extends \IPS\convert\Software
|
||||
public function convertMemberHistory()
|
||||
{
|
||||
$libraryClass = $this->getLibrary();
|
||||
|
||||
$libraryClass::setKey( 'changeid' );
|
||||
|
||||
$fixGroups = function( $string )
|
||||
foreach( $this->fetch( 'userchangelog', 'changeid', array( $this->db->in( 'fieldname', array_keys( static::$changeLogTypes ) ) ) ) AS $change )
|
||||
{
|
||||
$groups = explode( ',', $string );
|
||||
$newGroups = array();
|
||||
|
||||
array_walk( $groups, function( &$item, $key ) use ( &$newGroups )
|
||||
{
|
||||
try
|
||||
{
|
||||
$item = $this->app->getLink( $item, 'core_groups' );
|
||||
$newGroups[] = $item;
|
||||
}
|
||||
catch( \OutOfRangeException $e ){}
|
||||
});
|
||||
|
||||
return implode( ',', $newGroups );
|
||||
};
|
||||
|
||||
foreach( $this->fetch( 'userchangelog', 'changeid' ) AS $change )
|
||||
{
|
||||
if( !in_array( $change['fieldname'], array_keys( $this->changeLogTypes ) ) )
|
||||
{
|
||||
$libraryClass->setLastKeyValue( $change['changeid'] );
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Any processing we need to do */
|
||||
switch( $this->changeLogTypes[ $change['fieldname'] ] )
|
||||
{
|
||||
case 'member_group_id':
|
||||
case 'mgroup_others':
|
||||
$change['oldvalue'] = $fixGroups( $change['oldvalue'] );
|
||||
$change['newvalue'] = $fixGroups( $change['newvalue'] );
|
||||
break;
|
||||
}
|
||||
|
||||
$libraryClass->convertMemberHistory( array(
|
||||
'log_id' => $change['changeid'],
|
||||
'log_member' => $change['userid'],
|
||||
'log_by' => $change['adminid'],
|
||||
'log_type' => $this->changeLogTypes[ $change['fieldname'] ],
|
||||
'log_type' => static::$changeLogTypes[ $change['fieldname'] ],
|
||||
'log_data' => array( 'old' => $change['oldvalue'], 'new' => $change['newvalue'] ),
|
||||
'log_date' => $change['change_time']
|
||||
)
|
||||
@@ -1241,7 +1246,7 @@ class _Vbulletin extends \IPS\convert\Software
|
||||
}
|
||||
}
|
||||
|
||||
$libraryClass->convertMember( $info, $profileFields, $filename, $filepath, $filedata );
|
||||
$libraryClass->convertMember( $info, $profileFields, $filename, $filepath );
|
||||
|
||||
/* Any friends need converting to followers? */
|
||||
foreach( $this->db->select( '*', 'userlist', array( "type=? AND friend=? AND userid=?", 'buddy', 'yes', $user['userid'] ) ) AS $follower )
|
||||
@@ -1933,10 +1938,11 @@ class _Vbulletin extends \IPS\convert\Software
|
||||
}
|
||||
|
||||
/* Profile URLs can be in one of 3 formats really...
|
||||
* /member.php/1-name
|
||||
* /members/1-name
|
||||
* /member.php?u=1
|
||||
*/
|
||||
* /member.php/1-name
|
||||
* /members/1-name
|
||||
* /member.php?u=1
|
||||
* /member.php?1-name
|
||||
*/
|
||||
$path = $url->data[ \IPS\Http\Url::COMPONENT_PATH ];
|
||||
if( mb_strpos( $path, 'member.php' ) !== FALSE )
|
||||
{
|
||||
@@ -1944,6 +1950,10 @@ class _Vbulletin extends \IPS\convert\Software
|
||||
{
|
||||
$oldId = \IPS\Request::i()->u;
|
||||
}
|
||||
elseif( preg_match( '#^(\d+)-[^/]+#i', $url->data[ \IPS\Http\Url::COMPONENT_QUERY ], $matches ) )
|
||||
{
|
||||
$oldId = $matches[1];
|
||||
}
|
||||
else
|
||||
{
|
||||
$queryStringPieces = explode( '-', mb_substr( $path, mb_strpos( $path, 'member.php/' ) + mb_strlen( 'member.php/' ) ) );
|
||||
@@ -1971,4 +1981,23 @@ class _Vbulletin extends \IPS\convert\Software
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Process a login
|
||||
*
|
||||
* @param \IPS\Member $member The member
|
||||
* @param string $password Password from form
|
||||
* @return bool
|
||||
*/
|
||||
public static function login( $member, $password )
|
||||
{
|
||||
if ( \IPS\Login::compareHashes( $member->conv_password, md5( md5( str_replace( ''', "'", html_entity_decode( $password ) ) ) . $member->conv_password_extra ) ) )
|
||||
{
|
||||
return TRUE;
|
||||
}
|
||||
else
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -158,6 +158,10 @@ class _Vbulletin5 extends \IPS\convert\Software
|
||||
$where = array( $this->db->in( 'nodeid', $clubs ) );
|
||||
return parent::countRows( $table, $where, $recache );
|
||||
break;
|
||||
|
||||
case 'userchangelog':
|
||||
return $this->db->select( 'count(changeid)', 'userchangelog', array( $this->db->in( 'fieldname', array_keys( static::$changeLogTypes ) ) ) )->first();
|
||||
break;
|
||||
|
||||
default:
|
||||
return parent::countRows( $table, $where, $recache );
|
||||
@@ -464,8 +468,14 @@ class _Vbulletin5 extends \IPS\convert\Software
|
||||
/* Content Counts */
|
||||
\IPS\Task::queue( 'core', 'RecountMemberContent', array( 'app' => $this->app->app_id ), 4, array( 'app' ) );
|
||||
|
||||
/* Clubs */
|
||||
\IPS\Task::queue( 'convert', 'RecountClubMembers', array( 'app' => $this->app->app_id ), 2, array( 'app' ) );
|
||||
|
||||
/* 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" );
|
||||
}
|
||||
@@ -488,6 +498,77 @@ class _Vbulletin5 extends \IPS\convert\Software
|
||||
/* 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 */
|
||||
$matches = array();
|
||||
preg_match_all( "/\[IMG2=JSON](.+?)\[\/IMG2\]/i", $post, $matches );
|
||||
|
||||
if ( count( $matches ) )
|
||||
{
|
||||
foreach( $matches[0] as $k => $v )
|
||||
{
|
||||
try
|
||||
{
|
||||
/* Make sure the JSON value exists */
|
||||
if( !isset( $matches[1][ $k ] ) )
|
||||
{
|
||||
throw new \DomainException;
|
||||
}
|
||||
|
||||
$decoded = json_decode( $matches[1][ $k ], TRUE );
|
||||
|
||||
/* Make sure the JSON is valid and contains src */
|
||||
if( !isset( $decoded['src'] ) OR empty( $decoded['src'] ) )
|
||||
{
|
||||
throw new \DomainException;
|
||||
}
|
||||
|
||||
$post = str_replace( $v, "[img]{$decoded['src']}[/img]", $post );
|
||||
}
|
||||
catch( \DomainException $e )
|
||||
{
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Mentions */
|
||||
$matches = array();
|
||||
preg_match_all( '#\[user(=\"?(\d+)\"?)?\](.+?)\[\/user\]#i', $post, $matches ); // this purposefully matches more than the default vB mention.
|
||||
|
||||
if ( count( $matches ) )
|
||||
{
|
||||
if ( isset( $matches[1] ) )
|
||||
{
|
||||
$mentions = array();
|
||||
foreach( $matches[1] AS $k => $v )
|
||||
{
|
||||
if ( isset( $matches[3][$k] ) )
|
||||
{
|
||||
$name = trim( $matches[3][ $k ], '@' );
|
||||
$mentions[ $name ] = $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' );
|
||||
}
|
||||
|
||||
foreach( $mentions AS $member_name => $member_id )
|
||||
{
|
||||
$maps[ $member_name ] = preg_quote( $maps[ $member_name ], '#' );
|
||||
$memberNameEscaped = preg_quote( $member_name, '#' );
|
||||
|
||||
$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 );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $post;
|
||||
}
|
||||
|
||||
@@ -822,7 +903,7 @@ class _Vbulletin5 extends \IPS\convert\Software
|
||||
/**
|
||||
* @brief Member history type map
|
||||
*/
|
||||
protected $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' => 'member_group_id', 'membergroupids' => 'mgroup_others' );
|
||||
|
||||
/**
|
||||
* Convert member history
|
||||
@@ -832,53 +913,18 @@ class _Vbulletin5 extends \IPS\convert\Software
|
||||
public function convertMemberHistory()
|
||||
{
|
||||
$libraryClass = $this->getLibrary();
|
||||
|
||||
$libraryClass::setKey( 'changeid' );
|
||||
|
||||
$fixGroups = function( $string )
|
||||
foreach( $this->fetch( 'userchangelog', 'changeid', array( $this->db->in( 'fieldname', array_keys( static::$changeLogTypes ) ) ) ) AS $change )
|
||||
{
|
||||
$groups = explode( ',', $string );
|
||||
$newGroups = array();
|
||||
|
||||
array_walk( $groups, function( &$item, $key ) use ( &$newGroups )
|
||||
{
|
||||
try
|
||||
{
|
||||
$item = $this->app->getLink( $item, 'core_groups' );
|
||||
$newGroups[] = $item;
|
||||
}
|
||||
catch( \OutOfRangeException $e ){}
|
||||
});
|
||||
|
||||
return implode( ',', $newGroups );
|
||||
};
|
||||
|
||||
foreach( $this->fetch( 'userchangelog', 'changeid' ) AS $change )
|
||||
{
|
||||
if( !in_array( $change['fieldname'], array_keys( $this->changeLogTypes ) ) )
|
||||
{
|
||||
$libraryClass->setLastKeyValue( $change['changeid'] );
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Any processing we need to do */
|
||||
switch( $this->changeLogTypes[ $change['fieldname'] ] )
|
||||
{
|
||||
case 'member_group_id':
|
||||
case 'mgroup_others':
|
||||
$change['oldvalue'] = $fixGroups( $change['oldvalue'] );
|
||||
$change['newvalue'] = $fixGroups( $change['newvalue'] );
|
||||
break;
|
||||
}
|
||||
|
||||
$libraryClass->convertMemberHistory( array(
|
||||
'log_id' => $change['changeid'],
|
||||
'log_member' => $change['userid'],
|
||||
'log_by' => $change['adminid'],
|
||||
'log_type' => $this->changeLogTypes[ $change['fieldname'] ],
|
||||
'log_type' => static::$changeLogTypes[ $change['fieldname'] ],
|
||||
'log_data' => array( 'old' => $change['oldvalue'], 'new' => $change['newvalue'] ),
|
||||
'log_date' => $change['change_time'],
|
||||
'log_ip_address' => long2ip( $change['ipaddress'] )
|
||||
'log_ip_address' => long2ip( (int) $change['ipaddress'] )
|
||||
)
|
||||
);
|
||||
|
||||
@@ -1221,7 +1267,7 @@ class _Vbulletin5 extends \IPS\convert\Software
|
||||
$libraryClass->convertMemberHistory( array(
|
||||
'log_id' => 'w' . $warn['nodeid'],
|
||||
'log_member' => $warn['infracteduserid'],
|
||||
'log_by' => $warn['userid'],
|
||||
'log_by' => $warn['actionuserid'],
|
||||
'log_type' => 'warning',
|
||||
'log_data' => array( 'wid' => $warnId ),
|
||||
'log_date' => $warn['actiondateline']
|
||||
@@ -1344,18 +1390,19 @@ class _Vbulletin5 extends \IPS\convert\Software
|
||||
'map_user_active' => 1,
|
||||
'map_user_banned' => 0,
|
||||
'map_has_unread' => 0,
|
||||
'map_is_starter' => ( $pm['userid'] == $pm['userid'] ) ? 1 : 0,
|
||||
'map_is_starter' => 1,
|
||||
);
|
||||
|
||||
foreach( $this->db->select( '*', 'node', array( "parentid=?", $pm['nodeid'] ) ) AS $post )
|
||||
|
||||
/* All other maps */
|
||||
foreach( $this->db->select( '*', 'sentto', array( "nodeid=? AND userid!=?", $pm['nodeid'], $pm['userid'] ) ) AS $map )
|
||||
{
|
||||
$maps[ $post['userid'] ] = array(
|
||||
'map_user_id' => $post['userid'],
|
||||
$maps[ $map['userid'] ] = array(
|
||||
'map_user_id' => $map['userid'],
|
||||
'map_topic_id' => $pm['nodeid'],
|
||||
'map_user_active' => 1,
|
||||
'map_user_active' => !$map['deleted'],
|
||||
'map_user_banned' => 0,
|
||||
'map_has_unread' => 0,
|
||||
'map_is_starter' => ( $post['userid'] == $pm['userid'] ) ? 1 : 0,
|
||||
'map_has_unread' => !$map['msgread'],
|
||||
'map_is_starter' => 0
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1880,4 +1927,42 @@ class _Vbulletin5 extends \IPS\convert\Software
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Process a login
|
||||
*
|
||||
* @param \IPS\Member $member The member
|
||||
* @param string $password Password from form
|
||||
* @return bool
|
||||
*/
|
||||
public static function login( $member, $password )
|
||||
{
|
||||
/* If no algorithm is defined, use the legacy handler */
|
||||
if ( \strpos( $member->misc, 'blowfish' ) === FALSE and \strpos( $member->misc, 'legacy' ) === FALSE )
|
||||
{
|
||||
return \IPS\convert\Software\Core\Vbulletin::login( $member, $password );
|
||||
}
|
||||
|
||||
/* Which do we need to use? */
|
||||
$algo = explode( ':', $member->misc );
|
||||
|
||||
switch( $algo[ 0 ] )
|
||||
{
|
||||
case 'blowfish':
|
||||
/* vBulletin uses PasswordHash, however they md5 once the password prior to checking */
|
||||
$md5_once_password = md5( $password );
|
||||
require_once \IPS\ROOT_PATH . "/applications/convert/sources/Login/PasswordHash.php";
|
||||
$ph = new \PasswordHash( $algo[ 1 ], FALSE );
|
||||
return $ph->CheckPassword( $md5_once_password, $member->conv_password );
|
||||
break;
|
||||
|
||||
case 'legacy':
|
||||
/* Legacy Passwords are stored in a format of HASH SALT so we need to explode on the space. */
|
||||
$token = explode( ' ', $member->conv_password );
|
||||
$member->conv_password = $token[0];
|
||||
$member->conv_password_extra = $token[1];
|
||||
return \IPS\convert\Software\Core\Vbulletin::login( $member, $password );
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -231,4 +231,34 @@ class _Wordpress extends \IPS\convert\Software
|
||||
|
||||
return array( "f_search_index_rebuild", "f_clear_caches" );
|
||||
}
|
||||
|
||||
/**
|
||||
* Process a login
|
||||
*
|
||||
* @param \IPS\Member $member The member
|
||||
* @param string $password Password from form
|
||||
* @return bool
|
||||
*/
|
||||
public function login( $member, $password )
|
||||
{
|
||||
$success = FALSE;
|
||||
|
||||
// If the hash is still md5...
|
||||
if ( \strlen( $member->conv_password ) <= 32 )
|
||||
{
|
||||
$success = ( \IPS\Login::compareHashes( $member->conv_password, md5( $password ) ) ) ? TRUE : FALSE;
|
||||
}
|
||||
// New pass hash check
|
||||
else
|
||||
{
|
||||
// Init the pass class
|
||||
require_once \IPS\ROOT_PATH . "/applications/convert/sources/Login/PasswordHash.php";
|
||||
$ph = new \PasswordHash( 8, TRUE );
|
||||
|
||||
// Check it
|
||||
$success = $ph->CheckPassword( $password, $member->conv_password ) ? TRUE : FALSE;
|
||||
}
|
||||
|
||||
return $success;
|
||||
}
|
||||
}
|
||||
@@ -1,7 +1,7 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @brief Converter XenForo 1.x Master Class
|
||||
* @brief Converter XenForo 1.x/2.x Master Class
|
||||
* @author <a href='https://www.invisioncommunity.com'>Invision Power Services, Inc.</a>
|
||||
* @copyright (c) Invision Power Services, Inc.
|
||||
* @package Invision Community
|
||||
@@ -20,6 +20,48 @@ if ( !defined( '\IPS\SUITE_UNIQUE_KEY' ) )
|
||||
|
||||
class _Xenforo extends \IPS\convert\Software
|
||||
{
|
||||
/**
|
||||
* @brief The similarities between XF1 and XF2 are close enough that we can use the same converter
|
||||
*/
|
||||
public static $isLegacy = NULL;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param \IPS\convert\App The application to reference for database and other information.
|
||||
* @param bool 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 XF1 or XF2 */
|
||||
if ( static::$isLegacy === NULL )
|
||||
{
|
||||
$version = $this->db->select( 'MAX(version_id)', 'xf_template', array( "addon_id=?", 'XF' ) )->first();
|
||||
|
||||
if ( $version < 2000010 )
|
||||
{
|
||||
static::$isLegacy = TRUE;
|
||||
}
|
||||
else
|
||||
{
|
||||
static::$isLegacy = FALSE;
|
||||
}
|
||||
}
|
||||
}
|
||||
catch( \Exception $e ) {} # If we can't query, we won't be able to do anything anyway
|
||||
}
|
||||
|
||||
return $return;
|
||||
}
|
||||
|
||||
/**
|
||||
* Software Name
|
||||
*
|
||||
@@ -27,7 +69,7 @@ class _Xenforo extends \IPS\convert\Software
|
||||
*/
|
||||
public static function softwareName()
|
||||
{
|
||||
return "XenForo (1.x)";
|
||||
return "XenForo (1.5.x/2.0.x)";
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -85,10 +127,10 @@ class _Xenforo extends \IPS\convert\Software
|
||||
'where' => NULL
|
||||
),
|
||||
'convertMemberHistory' => array(
|
||||
'table' => 'xf_user_change_log',
|
||||
'table' => ( static::$isLegacy === FALSE OR is_null( static::$isLegacy ) ) ? 'xf_change_log' : 'xf_user_change_log',
|
||||
'where' => NULL
|
||||
),
|
||||
'convertWarnReason' => array(
|
||||
'convertWarnReasons' => array(
|
||||
'table' => 'xf_warning_definition',
|
||||
'where' => NULL
|
||||
),
|
||||
@@ -123,6 +165,34 @@ class _Xenforo extends \IPS\convert\Software
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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 )
|
||||
{
|
||||
/* 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();
|
||||
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();
|
||||
break;
|
||||
|
||||
default:
|
||||
return parent::countRows( $table, $where, $recache );
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Can we convert passwords from this software.
|
||||
*
|
||||
@@ -218,7 +288,7 @@ class _Xenforo extends \IPS\convert\Software
|
||||
|
||||
foreach( $this->db->select( '*', 'xf_user_field' ) AS $field )
|
||||
{
|
||||
\IPS\Member::loggedIn()->language()->words["map_pfield_{$field['field_id']}"] = $this->getPhrase( "user_field_{$field['field_id']}" );
|
||||
\IPS\Member::loggedIn()->language()->words["map_pfield_{$field['field_id']}"] = $this->getPhrase( "user_field_{$field['field_id']}", "user_field_title.{$field['field_id']}" );
|
||||
\IPS\Member::loggedIn()->language()->words["map_pfield_{$field['field_id']}_desc"] = \IPS\Member::loggedIn()->language()->addToStack( 'map_pfield_desc' );
|
||||
|
||||
$return['convertProfileFields']["map_pfield_{$field['field_id']}"] = array(
|
||||
@@ -324,7 +394,7 @@ class _Xenforo extends \IPS\convert\Software
|
||||
continue;
|
||||
}
|
||||
|
||||
$title = $this->getPhrase( 'option_' . $setting );
|
||||
$title = $this->getPhrase( 'option_' . $setting, 'option.' . $setting );
|
||||
|
||||
if ( !$title )
|
||||
{
|
||||
@@ -340,13 +410,15 @@ class _Xenforo extends \IPS\convert\Software
|
||||
/**
|
||||
* Helper to fetch a xenforo phrase
|
||||
*
|
||||
* @param string $title Phrase
|
||||
* @param string $xfOneTitle XF1 Phrase title
|
||||
* @param string $xfTwoTitle XF2 Phrase Title
|
||||
* @return string|null
|
||||
*/
|
||||
protected function getPhrase( $title )
|
||||
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 )
|
||||
@@ -379,6 +451,9 @@ class _Xenforo extends \IPS\convert\Software
|
||||
/* 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' ) );
|
||||
|
||||
/* Rebuild Leaderboard */
|
||||
\IPS\Task::queue( 'core', 'RebuildReputationLeaderboard', array(), 4 );
|
||||
\IPS\Db::i()->delete('core_reputation_leaderboard_history');
|
||||
@@ -395,7 +470,7 @@ class _Xenforo extends \IPS\convert\Software
|
||||
public static function fixPostData( $post )
|
||||
{
|
||||
// run everything through htmlspecialchars to prevent XSS
|
||||
$post = htmlspecialchars( $post, \IPS\HTMLENTITIES | ENT_QUOTES, 'UTF-8', FALSE );
|
||||
$post = htmlspecialchars( $post, ENT_DISALLOWED | ENT_QUOTES, 'UTF-8', FALSE );
|
||||
|
||||
// find YouTube ID's and replace.
|
||||
$post = preg_replace( '#\[media=youtube\](.+?)\[/media\]#i', '[media]http://www.youtube.com/watch?v=$1[/media]', $post );
|
||||
@@ -410,9 +485,9 @@ class _Xenforo extends \IPS\convert\Software
|
||||
$mentions = array();
|
||||
foreach( $matches[1] AS $k => $v )
|
||||
{
|
||||
if ( isset( $matches[2][$k] ) )
|
||||
if ( isset( $matches[2][ $k ] ) )
|
||||
{
|
||||
$name = trim( $matches[2][$k], '@' );
|
||||
$name = trim( $matches[2][ $k ], '@' );
|
||||
$mentions[$name] = $v;
|
||||
}
|
||||
}
|
||||
@@ -422,17 +497,17 @@ class _Xenforo extends \IPS\convert\Software
|
||||
$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[ $member->name ] = $member->member_id;
|
||||
$urls[ $member->name ] = $member->url();
|
||||
$cardUrls[ $member->name ] = $member->url()->setQueryString( 'do', 'hovercard' );
|
||||
}
|
||||
|
||||
foreach( $mentions AS $member_name => $member_id )
|
||||
{
|
||||
$maps[$member_name] = preg_quote( $maps[$member_name], '#' );
|
||||
$member_name = preg_quote( $member_name, '#' );
|
||||
$maps[ $member_name ] = preg_quote( $maps[ $member_name ], '#' );
|
||||
$memberNameEscaped = preg_quote( $member_name, '#' );
|
||||
|
||||
$post = preg_replace( "#\[user={$member_id}\]@?{$member_name}\[\/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 );
|
||||
$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 );
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -530,18 +605,52 @@ class _Xenforo extends \IPS\convert\Software
|
||||
/* 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;
|
||||
|
||||
if ( mb_substr( $row['image_url'], 0, 4 ) == 'http' )
|
||||
$filepathx2 = NULL;
|
||||
$filedatax2 = NULL;
|
||||
$filenamex2 = NULL;
|
||||
|
||||
/* 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'] ) )
|
||||
{
|
||||
$filedatax2 = $images['emoticon_x2'];
|
||||
|
||||
/* We always save the sprites to PNG */
|
||||
$filenamex2 = "{$row['title']}.png";
|
||||
}
|
||||
|
||||
/* We always save the sprites to PNG */
|
||||
$filename = "{$row['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( static::$isLegacy == FALSE AND !empty( $row['image_url_2x'] ) )
|
||||
{
|
||||
$filedata = file_get_contents( $row['image_url_2x'] );
|
||||
$fileurlx2 = explode( '/', $row['image_url_2x'] );
|
||||
$filenamex2 = array_pop( $fileurlx2 );
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
$fileurl = explode( '/', $row['image_url'] );
|
||||
$filename = array_pop( $fileurl );
|
||||
$filepath = rtrim( $this->app->_session['more_info']['convertEmoticons']['emoticon_path'], '/' ) . '/' . implode( '/', $fileurl );
|
||||
|
||||
if( static::$isLegacy == FALSE AND !empty( $row['image_url_2x'] ) )
|
||||
{
|
||||
$fileurlx2 = explode( '/', $row['image_url_2x'] );
|
||||
$filenamex2 = array_pop( $fileurlx2 );
|
||||
$filepathx2 = rtrim( $this->app->_session['more_info']['convertEmoticons']['emoticon_path'], '/' ) . '/' . implode( '/', $fileurlx2 );
|
||||
}
|
||||
}
|
||||
|
||||
/* XenForo allows multiple codes - we don't. */
|
||||
@@ -552,7 +661,7 @@ class _Xenforo extends \IPS\convert\Software
|
||||
try
|
||||
{
|
||||
$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" );
|
||||
$title = $this->getPhrase( "smilie_category_{$category['smilie_category_id']}_title", "smilie_category_title.{$category['smilie_category_id']}" );
|
||||
|
||||
if ( is_null( $title ) )
|
||||
{
|
||||
@@ -579,10 +688,11 @@ class _Xenforo extends \IPS\convert\Software
|
||||
'id' => $row['smilie_id'],
|
||||
'typed' => $code,
|
||||
'filename' => $filename,
|
||||
'filenamex2' => $filenamex2,
|
||||
'emo_position' => $row['display_order'],
|
||||
);
|
||||
|
||||
$libraryClass->convertEmoticon( $info, $set, $this->app->_session['more_info']['convertEmoticons']['keep_existing_emoticons'], $filepath, $filedata );
|
||||
|
||||
$libraryClass->convertEmoticon( $info, $set, $this->app->_session['more_info']['convertEmoticons']['keep_existing_emoticons'], $filepath, $filedata, $filepathx2, $filedatax2 );
|
||||
|
||||
$libraryClass->setLastKeyValue( $row['smilie_id'] );
|
||||
}
|
||||
@@ -603,8 +713,8 @@ class _Xenforo extends \IPS\convert\Software
|
||||
$info['pf_id'] = $row['field_id'];
|
||||
$merge = $this->app->_session['more_info']['convertProfileFields']["map_pfield_{$row['field_id']}"] != 'none' ? $this->app->_session['more_info']['convertProfileFields']["map_pfield_{$row['field_id']}"] : NULL;
|
||||
$info['pf_type'] = $this->_fieldMap( $row['field_type'] );
|
||||
$info['pf_name'] = $this->getPhrase( "user_field_{$row['field_id']}" );
|
||||
$info['pf_desc'] = $this->getPhrase( "user_field_{$row['field_id']}_desc" );
|
||||
$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_not_null'] = $row['required'];
|
||||
$info['pf_member_hide'] = ( $row['viewable_profile'] > 0 ) ? 0 : 1;
|
||||
@@ -734,7 +844,7 @@ class _Xenforo extends \IPS\convert\Software
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function convertWarnReason()
|
||||
public function convertWarnReasons()
|
||||
{
|
||||
$libraryClass = $this->getLibrary();
|
||||
|
||||
@@ -742,7 +852,7 @@ class _Xenforo extends \IPS\convert\Software
|
||||
|
||||
foreach( $this->fetch( 'xf_warning_definition', 'warning_definition_id' ) AS $row )
|
||||
{
|
||||
$title = $this->getPhrase( "warning_definition_{$row['warning_definition_id']}_title" );
|
||||
$title = $this->getPhrase( "warning_definition_{$row['warning_definition_id']}_title", "warning_title.{$row['warning_definition_id']}" );
|
||||
$remove = ( $row['expiry_type'] == 'never' ) ? 0 : $row['expiry_default'];
|
||||
|
||||
switch( $row['expiry_type'] )
|
||||
@@ -777,7 +887,7 @@ class _Xenforo extends \IPS\convert\Software
|
||||
/**
|
||||
* @brief Member history type map
|
||||
*/
|
||||
protected $changeLogTypes = array( 'username' => 'display_name', 'email' => 'email_change', 'user_group_id' => 'member_group_id', 'secondar_group_ids' => 'mgroup_others' );
|
||||
protected static $changeLogTypes = array( 'username' => 'display_name', 'email' => 'email_change', 'user_group_id' => 'member_group_id', 'secondary_group_ids' => 'mgroup_others' );
|
||||
|
||||
/**
|
||||
* Convert member history
|
||||
@@ -790,47 +900,27 @@ class _Xenforo extends \IPS\convert\Software
|
||||
|
||||
$libraryClass::setKey( 'log_id' );
|
||||
|
||||
$fixGroups = function( $string )
|
||||
$userField = 'user_id';
|
||||
$table = 'xf_user_change_log';
|
||||
|
||||
if( ( static::$isLegacy === FALSE OR is_null( static::$isLegacy ) ) )
|
||||
{
|
||||
$groups = explode( ',', $string );
|
||||
$newGroups = array();
|
||||
|
||||
array_walk( $groups, function( &$item, $key ) use ( &$newGroups )
|
||||
{
|
||||
try
|
||||
{
|
||||
$item = $this->app->getLink( $item, 'core_groups' );
|
||||
$newGroups[] = $item;
|
||||
}
|
||||
catch( \OutOfRangeException $e ){}
|
||||
});
|
||||
|
||||
return implode( ',', $newGroups );
|
||||
};
|
||||
|
||||
foreach( $this->fetch( 'xf_user_change_log', 'log_id' ) AS $change )
|
||||
$table = 'xf_change_log';
|
||||
$userField = 'content_id';
|
||||
$where = array( 'content_type=? AND ' . $this->db->in( 'field', array_keys( static::$changeLogTypes ) ), 'user' );
|
||||
}
|
||||
else
|
||||
{
|
||||
if( !in_array( $change['field'], array_keys( $this->changeLogTypes ) ) )
|
||||
{
|
||||
$libraryClass->setLastKeyValue( $change['log_id'] );
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Any processing we need to do */
|
||||
switch( $this->changeLogTypes[ $change['field'] ] )
|
||||
{
|
||||
case 'member_group_id':
|
||||
case 'mgroup_others':
|
||||
$change['old_value'] = $fixGroups( $change['old_value'] );
|
||||
$change['new_value'] = $fixGroups( $change['new_value'] );
|
||||
break;
|
||||
}
|
||||
$where = array( $this->db->in( 'field', array_keys( static::$changeLogTypes ) ) );
|
||||
}
|
||||
|
||||
foreach( $this->fetch( $table, 'log_id', $where ) AS $change )
|
||||
{
|
||||
$libraryClass->convertMemberHistory( array(
|
||||
'log_id' => $change['log_id'],
|
||||
'log_member' => $change['user_id'],
|
||||
'log_by' => ( $change['edit_user_id'] !== $change['user_id'] ) ? $change['edit_user_id'] : null,
|
||||
'log_type' => $this->changeLogTypes[ $change['field'] ],
|
||||
'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']
|
||||
)
|
||||
@@ -886,8 +976,8 @@ class _Xenforo extends \IPS\convert\Software
|
||||
catch( \UnderflowException $e )
|
||||
{
|
||||
/* Ut oh... do something random. */
|
||||
$hash = md5( uniqid() );
|
||||
$salt = md5( uniqid() );
|
||||
$hash = md5( mt_rand() );
|
||||
$salt = md5( mt_rand() );
|
||||
}
|
||||
|
||||
/* IP Address */
|
||||
@@ -1415,4 +1505,103 @@ class _Xenforo extends \IPS\convert\Software
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Process a login
|
||||
*
|
||||
* @param \IPS\Member $member The member
|
||||
* @param string $password Password from form
|
||||
* @return bool
|
||||
*/
|
||||
public function login( $member, $password )
|
||||
{
|
||||
$password = html_entity_decode( $password );
|
||||
|
||||
// XF 1.2
|
||||
require_once \IPS\ROOT_PATH . "/applications/convert/sources/Login/PasswordHash.php";
|
||||
$ph = new \PasswordHash( 10, TRUE );
|
||||
|
||||
if ( $ph->CheckPassword( $password, $member->conv_password ) )
|
||||
{
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
// XF 1.1
|
||||
if ( extension_loaded( 'hash' ) )
|
||||
{
|
||||
$hashedPassword = hash( 'sha256', hash( 'sha256', $password ) . $member->misc );
|
||||
}
|
||||
else
|
||||
{
|
||||
$hashedPassword = sha1( sha1( $password ) . $member->misc );
|
||||
}
|
||||
|
||||
if ( \IPS\Login::compareHashes( $member->conv_password, $hashedPassword ) )
|
||||
{
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
// 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