Version 4.3.0
This commit is contained in:
1 parent
96997ddd8e
commit
fe1acf984a
1349 files changed
+116159
-67711
No files matched your search
@@ -0,0 +1,162 @@
|
||||
<?php
|
||||
/**
|
||||
* @brief automaticmoderation Task
|
||||
* @author <a href='https://www.invisioncommunity.com'>Invision Power Services, Inc.</a>
|
||||
* @copyright (c) Invision Power Services, Inc.
|
||||
* @license https://www.invisioncommunity.com/legal/standards/
|
||||
* @package Invision Community
|
||||
* @since 08 Dec 2017
|
||||
*/
|
||||
|
||||
namespace IPS\core\tasks;
|
||||
|
||||
/* 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;
|
||||
}
|
||||
|
||||
/**
|
||||
* automaticmoderation Task
|
||||
*/
|
||||
class _automaticmoderation extends \IPS\Task
|
||||
{
|
||||
/**
|
||||
* Execute
|
||||
*
|
||||
* If ran successfully, should return anything worth logging. Only log something
|
||||
* worth mentioning (don't log "task ran successfully"). Return NULL (actual NULL, not '' or 0) to not log (which will be most cases).
|
||||
* If an error occurs which means the task could not finish running, throw an \IPS\Task\Exception - do not log an error as a normal log.
|
||||
* Tasks should execute within the time of a normal HTTP request.
|
||||
*
|
||||
* @return mixed Message to log or NULL
|
||||
* @throws \IPS\Task\Exception
|
||||
*/
|
||||
public function execute()
|
||||
{
|
||||
if ( ! \IPS\Settings::i()->automoderation_enabled )
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
foreach( \IPS\Db::i()->select( '*', 'core_automatic_moderation_pending', NULL, 'pending_added ASC', array( 0, 50 ) ) as $pending )
|
||||
{
|
||||
/* Check report exists still */
|
||||
try
|
||||
{
|
||||
$report = \IPS\core\Reports\Report::load( $pending['pending_report_id'] );
|
||||
}
|
||||
catch( \OutofRangeException $e )
|
||||
{
|
||||
/* Report is missing */
|
||||
\IPS\Db::i()->delete( 'core_automatic_moderation_pending', array( 'pending_report_id=?', $pending['pending_report_id'] ) );
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Check object exists still */
|
||||
$className = $pending['pending_object_class'];
|
||||
|
||||
try
|
||||
{
|
||||
$object = $className::load( $pending['pending_object_id'] );
|
||||
}
|
||||
catch( \OutofRangeException $e )
|
||||
{
|
||||
/* Object no longer exists */
|
||||
\IPS\Db::i()->delete( 'core_automatic_moderation_pending', array( 'pending_object_class=? and pending_object_id=?', $pending['pending_object_class'], $pending['pending_object_id'] ) );
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Check rule exists still */
|
||||
try
|
||||
{
|
||||
$rule = \IPS\core\Reports\Rules::load( $pending['pending_rule_id'] );
|
||||
}
|
||||
catch( \OutofRangeException $e )
|
||||
{
|
||||
/* Rule no longer exists */
|
||||
\IPS\Db::i()->delete( 'core_automatic_moderation_pending', array( 'pending_rule_id=?', $pending['pending_rule_id'] ) );
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Right, that's all sorted so process the bad boy */
|
||||
$hidden = FALSE;
|
||||
try
|
||||
{
|
||||
if ( $object instanceof \IPS\Content\Comment )
|
||||
{
|
||||
$item = $object->item();
|
||||
if ( $item and $item::$firstCommentRequired and $object->isFirst() )
|
||||
{
|
||||
/* Hide the item, not the object */
|
||||
$item->hide( FALSE, 'automaticmoderation_hide_reason' );
|
||||
$hidden = TRUE;
|
||||
}
|
||||
}
|
||||
}
|
||||
catch( \Exception $e ) { }
|
||||
|
||||
if ( $hidden === FALSE )
|
||||
{
|
||||
$object->hide( FALSE, 'automaticmoderation_hide_reason' );
|
||||
}
|
||||
|
||||
/* Remove from the pending queue */
|
||||
\IPS\Db::i()->delete( 'core_automatic_moderation_pending', array( 'pending_object_class=? and pending_object_id=?', $pending['pending_object_class'], $pending['pending_object_id'] ) );
|
||||
|
||||
/* Send notification to mods */
|
||||
$moderators = array( 'm' => array(), 'g' => array() );
|
||||
foreach ( \IPS\Db::i()->select( '*', 'core_moderators' ) as $mod )
|
||||
{
|
||||
$canView = FALSE;
|
||||
if ( $mod['perms'] == '*' )
|
||||
{
|
||||
$canView = TRUE;
|
||||
}
|
||||
if ( $canView === FALSE )
|
||||
{
|
||||
$perms = json_decode( $mod['perms'], TRUE );
|
||||
|
||||
if ( isset( $perms['can_view_reports'] ) AND $perms['can_view_reports'] === TRUE )
|
||||
{
|
||||
$canView = TRUE;
|
||||
}
|
||||
}
|
||||
if ( $canView === TRUE )
|
||||
{
|
||||
$moderators[ $mod['type'] ][] = $mod['id'];
|
||||
}
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
$latestReport = \IPS\Db::i()->select( '*', 'core_rc_reports', array( 'rid=?', $report->id ), 'date_reported DESC' )->first();
|
||||
$notification = new \IPS\Notification( \IPS\Application::load('core'), 'automatic_moderation', $report, array( $report, $latestReport, $object ) );
|
||||
foreach ( \IPS\Db::i()->select( '*', 'core_members', ( count( $moderators['m'] ) ? \IPS\Db::i()->in( 'member_id', $moderators['m'] ) . ' OR ' : '' ) . \IPS\Db::i()->in( 'member_group_id', $moderators['g'] ) . ' OR ' . \IPS\Db::i()->findInSet( 'mgroup_others', $moderators['g'] ) ) as $member )
|
||||
{
|
||||
$notification->recipients->attach( \IPS\Member::constructFromData( $member ) );
|
||||
}
|
||||
|
||||
$notification->send();
|
||||
}
|
||||
catch( \Exception $e ) { }
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Cleanup
|
||||
*
|
||||
* If your task takes longer than 15 minutes to run, this method
|
||||
* will be called before execute(). Use it to clean up anything which
|
||||
* may not have been done
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function cleanup()
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
@@ -33,6 +33,19 @@ class _cleanup extends \IPS\Task
|
||||
/* Delete old password / security answer reset requests */
|
||||
\IPS\Db::i()->delete( 'core_validating', array( '( lost_pass=1 OR forgot_security=1 ) AND email_sent < ?', \IPS\DateTime::create()->sub( new \DateInterval( 'P1D' ) )->getTimestamp() ) );
|
||||
|
||||
/* Delete cancelled registration members */
|
||||
foreach( \IPS\Db::i()->select( 'member_id', 'core_validating', array( 'do_not_delete=0 and reg_cancelled > 0 and reg_cancelled < ?', time() - 86400 ) ) as $id )
|
||||
{
|
||||
try
|
||||
{
|
||||
\IPS\Member::load( $id )->delete();
|
||||
}
|
||||
catch ( \OutOfRangeException $e )
|
||||
{
|
||||
\IPS\Db::i()->delete( 'core_validating', array( 'member_id=?', $id ) );
|
||||
}
|
||||
}
|
||||
|
||||
/* Delete old validating members */
|
||||
if ( \IPS\Settings::i()->validate_day_prune )
|
||||
{
|
||||
@@ -93,12 +106,6 @@ class _cleanup extends \IPS\Task
|
||||
\IPS\Db::i()->delete( 'core_error_logs', array( 'log_date < ?', \IPS\DateTime::create()->sub( new \DateInterval( 'P' . \IPS\Settings::i()->prune_log_error . 'D' ) )->getTimestamp() ) );
|
||||
}
|
||||
|
||||
/* ...and system logs */
|
||||
if( \IPS\Settings::i()->prune_log_system )
|
||||
{
|
||||
\IPS\Log::pruneLogs( \IPS\Settings::i()->prune_log_system );
|
||||
}
|
||||
|
||||
/* ...and spam service logs */
|
||||
if( \IPS\Settings::i()->prune_log_spam )
|
||||
{
|
||||
@@ -185,21 +192,11 @@ class _cleanup extends \IPS\Task
|
||||
}
|
||||
|
||||
/* Delete any incompleted accounts (for example, someone has clicked "Sign in with Twitter" and never provided a username or email */
|
||||
foreach ( new \IPS\Patterns\ActiveRecordIterator( \IPS\Db::i()->select( '*', 'core_members', array( array( '(name=? OR email=?)', '', '' ), array( 'joined<? AND last_visit=0 AND ipsconnect_id=0', \IPS\DateTime::create()->sub( new \DateInterval( 'PT1H' ) )->getTimestamp() ) ) ), 'IPS\Member' ) as $incompleteMember )
|
||||
foreach ( new \IPS\Patterns\ActiveRecordIterator( \IPS\Db::i()->select( '*', 'core_members', array( array( '(name=? OR email=?)', '', '' ), array( 'joined<? AND last_visit=0', \IPS\DateTime::create()->sub( new \DateInterval( 'PT1H' ) )->getTimestamp() ) ) ), 'IPS\Member' ) as $incompleteMember )
|
||||
{
|
||||
$incompleteMember->delete();
|
||||
}
|
||||
|
||||
/* Prune search index */
|
||||
if ( \IPS\Settings::i()->search_index_timeframe )
|
||||
{
|
||||
try
|
||||
{
|
||||
\IPS\Content\Search\Index::i()->prune( \IPS\DateTime::create()->sub( new \DateInterval( 'P' . \IPS\Settings::i()->search_index_timeframe . 'D' ) ) );
|
||||
}
|
||||
catch ( \UnexpectedValueException $e ) { }
|
||||
}
|
||||
|
||||
/* Remove widgets */
|
||||
if ( \IPS\Application::appIsEnabled('cms') )
|
||||
{
|
||||
@@ -222,6 +219,11 @@ class _cleanup extends \IPS\Task
|
||||
|
||||
/* Close open polls that need closing */
|
||||
\IPS\Db::i()->update( 'core_polls', array( 'poll_closed' => 1 ), array( 'poll_closed=? AND poll_close_date>? AND poll_close_date<?', 0, -1, time() ) );
|
||||
|
||||
/* Delete expired oAuth Authorization Codes */
|
||||
\IPS\Db::i()->delete( 'core_oauth_server_authorization_codes', array( 'expires<?', time() ) );
|
||||
\IPS\Db::i()->delete( 'core_oauth_server_access_tokens', array( 'refresh_token_expires<?', time() ) );
|
||||
\IPS\Db::i()->delete( 'core_oauth_authorize_prompts', array( 'timestamp<?', ( time() - 300 ) ) );
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@@ -44,7 +44,8 @@ class _clearsessions extends \IPS\Task
|
||||
}
|
||||
|
||||
\IPS\Db::i()->delete( 'core_sys_cp_sessions', array( 'session_running_time<?', ( time() - $timeout ) ) );
|
||||
\IPS\Session\Front::clearSessions( $timeout );
|
||||
$class = \IPS\Session\Store::i();
|
||||
$class::clearSessions( $timeout );
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@@ -1,90 +0,0 @@
|
||||
<?php
|
||||
/**
|
||||
* @brief Reattempt queued IPS Connect requests
|
||||
* @author <a href='https://www.invisioncommunity.com'>Invision Power Services, Inc.</a>
|
||||
* @copyright (c) Invision Power Services, Inc.
|
||||
* @license https://www.invisioncommunity.com/legal/standards/
|
||||
* @package Invision Community
|
||||
* @since 3 Dec 2013
|
||||
*/
|
||||
|
||||
namespace IPS\core\tasks;
|
||||
|
||||
/* 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;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reattempt queued IPS Connect requests
|
||||
*/
|
||||
class _connect extends \IPS\Task
|
||||
{
|
||||
/**
|
||||
* Execute
|
||||
*
|
||||
* @return mixed Message to log or NULL
|
||||
* @throws \RuntimeException
|
||||
*/
|
||||
public function execute()
|
||||
{
|
||||
/* Get the next request */
|
||||
try
|
||||
{
|
||||
$request = \IPS\Db::i()->select( 'q.*, s.*', array( 'core_ipsconnect_queue', 'q' ), array( 's.slave_enabled=?', 1 ), 'q.id asc', array( 0, 1 ) )
|
||||
->join( array( 'core_ipsconnect_slaves', 's' ), "s.slave_id=q.slave_id" )
|
||||
->first();
|
||||
|
||||
/* Try to process request again */
|
||||
try
|
||||
{
|
||||
parse_str( $request['request_url'], $variables );
|
||||
|
||||
$response = \IPS\Http\Url::external( $request['slave_url'] )
|
||||
->setQueryString( $variables )
|
||||
->request()
|
||||
->get();
|
||||
|
||||
if( $response->httpResponseCode !== NULL AND $response->httpResponseCode > 200 )
|
||||
{
|
||||
/* Update fail count */
|
||||
\IPS\Db::i()->update( 'core_ipsconnect_queue', 'fail_count=fail_count+1', array( 'id=?', $request['id'] ) );
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
$response = $response->decodeJson();
|
||||
|
||||
/* If this is a registered slave but the slave is telling us Connect is disabled, remove it */
|
||||
if( isset( $response['status'] ) AND $response['status'] == 'DISABLED' )
|
||||
{
|
||||
\IPS\Db::i()->update( 'core_ipsconnect_slaves', array( 'slave_enabled' => 0 ), array( 'slave_id=?', $request['slave_id'] ) );
|
||||
\IPS\Db::i()->update( 'core_sys_conf_settings', array( 'conf_value' => \IPS\Db::i()->select( 'COUNT(*)', 'core_ipsconnect_slaves', array( 'slave_enabled=?', 1 ) )->first() ), array( 'conf_key=?', 'connect_slaves' ) );
|
||||
unset( \IPS\Data\Store::i()->settings );
|
||||
}
|
||||
|
||||
/* If we are here, request succeeded - remove from queue */
|
||||
\IPS\Db::i()->delete( 'core_ipsconnect_queue', array( 'id=?', $request['id'] ) );
|
||||
return NULL;
|
||||
}
|
||||
catch( \RuntimeException $e )
|
||||
{
|
||||
/* Update fail count */
|
||||
\IPS\Db::i()->update( 'core_ipsconnect_queue', 'fail_count=fail_count+1', array( 'id=?', $request['id'] ) );
|
||||
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
catch( \UnderflowException $e )
|
||||
{
|
||||
/* There are none left - disable task */
|
||||
\IPS\Db::i()->update( 'core_tasks', array( 'enabled' => 0 ), "`key`='connect'" );
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
@@ -47,9 +47,18 @@ class _deletecontent extends \IPS\Task
|
||||
|
||||
foreach( new \IPS\Patterns\ActiveRecordIterator( \IPS\Db::i()->select( '*', 'core_deletion_log', array( "dellog_deleted_date<?", $timeago->getTimestamp() ) ), 'IPS\core\DeletionLog' ) AS $log )
|
||||
{
|
||||
$class = $log->content_class;
|
||||
$content = $class::load( $log->content_id );
|
||||
$content->delete();
|
||||
try
|
||||
{
|
||||
$class = $log->content_class;
|
||||
if ( class_exists ( $class ) )
|
||||
{
|
||||
$content = $class::load( $log->content_id );
|
||||
$content->delete();
|
||||
}
|
||||
}
|
||||
/* If the content is gone already, don't let an uncaught exception bubble up...just remove the deletion log orphaned entry */
|
||||
catch( \OutOfRangeException $e ){}
|
||||
|
||||
$log->delete();
|
||||
}
|
||||
|
||||
|
||||
@@ -40,7 +40,7 @@ class _digest extends \IPS\Task
|
||||
$frequency = $frequencies[ array_rand( $frequencies ) ];
|
||||
|
||||
/* Grab some members to send digests to. */
|
||||
$members = \IPS\Db::i()->select( 'follow_member_id, follow_notify_sent', 'core_follow', array( 'follow_notify_do=1 AND follow_visible=1 AND follow_notify_freq = ? AND follow_notify_sent < ?', $frequency, ( $frequency == 'daily' ) ? time() - 86400 : time() - 604800 ), 'follow_notify_sent ASC', array( 0, 50 ), NULL, NULL, \IPS\Db::SELECT_DISTINCT );
|
||||
$members = \IPS\Db::i()->select( 'follow_member_id, follow_notify_sent', 'core_follow', array( 'follow_notify_do=1 AND follow_notify_freq = ? AND follow_notify_sent < ?', $frequency, ( $frequency == 'daily' ) ? time() - 86400 : time() - 604800 ), 'follow_notify_sent ASC', array( 0, 50 ), NULL, NULL, \IPS\Db::SELECT_DISTINCT );
|
||||
|
||||
if( !count( $members ) )
|
||||
{
|
||||
@@ -55,7 +55,7 @@ class _digest extends \IPS\Task
|
||||
}
|
||||
|
||||
/* Fetch the member's follows so we can build their digest */
|
||||
$follows = \IPS\Db::i()->select( '*', 'core_follow', array( 'follow_notify_do=1 AND follow_notify_freq=? AND follow_visible=1 AND follow_notify_sent < ? AND ' . \IPS\Db::i()->in( 'follow_member_id', $memberIDs ), $frequency, time() - 86400 ), 'follow_notify_sent ASC, follow_app ASC, follow_area ASC' );
|
||||
$follows = \IPS\Db::i()->select( '*', 'core_follow', array( 'follow_notify_do=1 AND follow_notify_freq=? AND follow_notify_sent < ? AND ' . \IPS\Db::i()->in( 'follow_member_id', $memberIDs ), $frequency, time() - 86400 ), 'follow_notify_sent ASC, follow_app ASC, follow_area ASC' );
|
||||
|
||||
$groupedFollows = array();
|
||||
foreach( $follows as $follow )
|
||||
|
||||
@@ -54,6 +54,13 @@ class _leaderboard extends \IPS\Task
|
||||
else
|
||||
{
|
||||
$startDate = new \IPS\DateTime( 'yesterday midnight', $timezone );
|
||||
|
||||
/* Do we need to run this task at all? If we don't have any records in core_reputation_index we can skip this task */
|
||||
$existing = \IPS\Db::i()->select( 'count(*)', 'core_reputation_index' )->first();
|
||||
if ( !$existing )
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
$yesterdayEnd = new \IPS\DateTime( 'today midnight', $timezone );
|
||||
@@ -65,19 +72,20 @@ class _leaderboard extends \IPS\Task
|
||||
for( $i = 0; $i < $difference; $i++ )
|
||||
{
|
||||
$position = 0;
|
||||
|
||||
foreach( \IPS\Db::i()->select( 'core_reputation_index.member_received as member, SUM(rep_rating) as rep', 'core_reputation_index', array( 'member_received > 0 AND rep_date BETWEEN ? and ?', $startDate->getTimeStamp(), $yesterdayEnd->getTimeStamp() ), 'rep DESC', 4, 'member' )->setKeyField('member')->setValueField('rep') as $member => $rep )
|
||||
|
||||
/* As this can run multiple times, and the unique constraint is member_id, position, it is possible to end up with multiple members with the same positon */
|
||||
$date = $startDate->setTime( 12, 0 )->getTimeStamp();
|
||||
\IPS\Db::i()->delete( 'core_reputation_leaderboard_history', array( 'leader_date BETWEEN ? and ?', $date - 4, $date ) );
|
||||
|
||||
foreach( \IPS\Db::i()->select( 'core_reputation_index.member_received as member, SUM(rep_rating) as rep', 'core_reputation_index', array( 'member_received > 0 AND rep_date BETWEEN ? and ?', $startDate->setTime( 0, 0, 1 )->getTimeStamp(), $startDate->setTime( 23, 59, 59 )->getTimeStamp() ), 'rep DESC', 4, 'member' )->setKeyField('member')->setValueField('rep') as $member => $rep )
|
||||
{
|
||||
$date = $startDate->setTime( 12, 0 )->getTimeStamp();
|
||||
$position++;
|
||||
|
||||
/* As this can run multiple times, and the unique constraint is member_id, position, it is possible to end up with multiple members with the same positon */
|
||||
\IPS\Db::i()->delete( 'core_reputation_leaderboard_history', array( 'leader_date=? and leader_position=?', $date, $position ) );
|
||||
|
||||
if ( $member and $rep )
|
||||
{
|
||||
$date = $startDate->setTime( 12, 0 )->getTimeStamp();
|
||||
$position++;
|
||||
|
||||
\IPS\Db::i()->replace( 'core_reputation_leaderboard_history', array(
|
||||
'leader_date' => $startDate->setTime( 12, 0 )->getTimeStamp(),
|
||||
'leader_date' => $date,
|
||||
'leader_member_id' => $member,
|
||||
'leader_position' => $position,
|
||||
'leader_rep_total' => $rep
|
||||
@@ -85,13 +93,18 @@ class _leaderboard extends \IPS\Task
|
||||
}
|
||||
}
|
||||
|
||||
/* If there are no entries, date is not defined correctly as midday */
|
||||
if ( ! $position )
|
||||
{
|
||||
$date = $startDate->setTime( 12, 0 )->getTimeStamp();
|
||||
}
|
||||
|
||||
/* Fill in the blanks */
|
||||
if ( $position and $position < 5 )
|
||||
{
|
||||
while( $position < 4 )
|
||||
{
|
||||
$position++;
|
||||
\IPS\Db::i()->delete( 'core_reputation_leaderboard_history', array( 'leader_date=? and leader_position=?', $date - $position, $position ) );
|
||||
|
||||
\IPS\Db::i()->replace( 'core_reputation_leaderboard_history', array(
|
||||
'leader_date' => $date - $position,
|
||||
|
||||
@@ -43,8 +43,9 @@ class _onlineusers extends \IPS\Task
|
||||
|
||||
try
|
||||
{
|
||||
$onlineGuests = \IPS\Db::i()->select( 'COUNT(*)', 'core_sessions', array( 'member_id=? OR member_id IS NULL', 0 ) )->first();
|
||||
$onlineMembers = \IPS\Db::i()->select( 'COUNT(*)', 'core_sessions', array( 'member_id>?', 0 ), NULL, NULL, 'member_id' )->first();
|
||||
/* @todo Right now, users excluded from the online user list would not be counted if using REDIS - Matt has said to leave it with him */
|
||||
$onlineGuests = \IPS\Session\Store::i()->getOnlineUsers( \IPS\Session\Store::ONLINE_GUESTS | \IPS\Session\Store::ONLINE_COUNT_ONLY );
|
||||
$onlineMembers = \IPS\Session\Store::i()->getOnlineUsers( \IPS\Session\Store::ONLINE_MEMBERS | \IPS\Session\Store::ONLINE_COUNT_ONLY, 'desc', NULL, NULL, TRUE );
|
||||
}
|
||||
catch( \UnderflowException $e) {}
|
||||
|
||||
|
||||
@@ -29,22 +29,36 @@ class _profilesync extends \IPS\Task
|
||||
*/
|
||||
public function execute()
|
||||
{
|
||||
$services = \IPS\core\ProfileSync\ProfileSyncAbstract::services();
|
||||
if ( !empty( $services ) )
|
||||
$totalToSync = \IPS\Db::i()->select( 'count(*)', 'core_members', array( "temp_ban=0 AND profilesync_lastsync > 0" ) )->first();
|
||||
|
||||
if( !$totalToSync )
|
||||
{
|
||||
$where = array( 'profilesync IS NOT NULL' );
|
||||
|
||||
/* Exclude banned users */
|
||||
$where[] = array( 'temp_ban=?', 0 );
|
||||
|
||||
foreach ( \IPS\Db::i()->select( '*', 'core_members', $where, 'profilesync_lastsync ASC', 25 ) as $row )
|
||||
{
|
||||
foreach ( $services as $class )
|
||||
{
|
||||
$obj = new $class( \IPS\Member::constructFromData( $row ) );
|
||||
$obj->sync();
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* The task runs once per hour and looks for all accounts that haven't been synced in 12+ hours, so we want to set a hard limit that
|
||||
will allow all accounts to be processed in a 12 hour period if resources permit */
|
||||
$accounts = ceil( $totalToSync / 12 );
|
||||
}
|
||||
|
||||
$this->runUntilTimeout( function()
|
||||
{
|
||||
try
|
||||
{
|
||||
$member = \IPS\Db::i()->select( '*', 'core_members', array( "temp_ban=0 AND profilesync_lastsync > 0 AND profilesync_lastsync < ?", ( time() - ( 60 * 60 * 12 ) ) ), 'profilesync_lastsync ASC', 1 )->first();
|
||||
}
|
||||
catch ( \UnderflowException $e )
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
$member = \IPS\Member::constructFromData( $member );
|
||||
$member->profileSync();
|
||||
|
||||
return TRUE;
|
||||
}, $accounts );
|
||||
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,64 @@
|
||||
<?php
|
||||
/**
|
||||
* @brief prunesearchindex Task
|
||||
* @author <a href='https://www.invisioncommunity.com'>Invision Power Services, Inc.</a>
|
||||
* @copyright (c) Invision Power Services, Inc.
|
||||
* @license https://www.invisioncommunity.com/legal/standards/
|
||||
* @package Invision Community
|
||||
* @since 07 Sep 2017
|
||||
*/
|
||||
|
||||
namespace IPS\core\tasks;
|
||||
|
||||
/* 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;
|
||||
}
|
||||
|
||||
/**
|
||||
* prunesearchindex Task
|
||||
*/
|
||||
class _prunesearchindex extends \IPS\Task
|
||||
{
|
||||
/**
|
||||
* Execute
|
||||
*
|
||||
* If ran successfully, should return anything worth logging. Only log something
|
||||
* worth mentioning (don't log "task ran successfully"). Return NULL (actual NULL, not '' or 0) to not log (which will be most cases).
|
||||
* If an error occurs which means the task could not finish running, throw an \IPS\Task\Exception - do not log an error as a normal log.
|
||||
* Tasks should execute within the time of a normal HTTP request.
|
||||
*
|
||||
* @return mixed Message to log or NULL
|
||||
* @throws \IPS\Task\Exception
|
||||
*/
|
||||
public function execute()
|
||||
{
|
||||
/* Prune search index */
|
||||
if ( \IPS\Settings::i()->search_method == 'mysql' and \IPS\Settings::i()->search_index_timeframe )
|
||||
{
|
||||
try
|
||||
{
|
||||
\IPS\Content\Search\Index::i()->prune( \IPS\DateTime::create()->sub( new \DateInterval( 'P' . \IPS\Settings::i()->search_index_timeframe . 'D' ) ) );
|
||||
}
|
||||
catch ( \UnexpectedValueException $e ) { }
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Cleanup
|
||||
*
|
||||
* If your task takes longer than 15 minutes to run, this method
|
||||
* will be called before execute(). Use it to clean up anything which
|
||||
* may not have been done
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function cleanup()
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,59 @@
|
||||
<?php
|
||||
/**
|
||||
* @brief prunesystemlogs Task
|
||||
* @author <a href='https://www.invisioncommunity.com'>Invision Power Services, Inc.</a>
|
||||
* @copyright (c) Invision Power Services, Inc.
|
||||
* @license https://www.invisioncommunity.com/legal/standards/
|
||||
* @package Invision Community
|
||||
* @since 07 Sep 2017
|
||||
*/
|
||||
|
||||
namespace IPS\core\tasks;
|
||||
|
||||
/* 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;
|
||||
}
|
||||
|
||||
/**
|
||||
* prunesystemlogs Task
|
||||
*/
|
||||
class _prunesystemlogs extends \IPS\Task
|
||||
{
|
||||
/**
|
||||
* Execute
|
||||
*
|
||||
* If ran successfully, should return anything worth logging. Only log something
|
||||
* worth mentioning (don't log "task ran successfully"). Return NULL (actual NULL, not '' or 0) to not log (which will be most cases).
|
||||
* If an error occurs which means the task could not finish running, throw an \IPS\Task\Exception - do not log an error as a normal log.
|
||||
* Tasks should execute within the time of a normal HTTP request.
|
||||
*
|
||||
* @return mixed Message to log or NULL
|
||||
* @throws \IPS\Task\Exception
|
||||
*/
|
||||
public function execute()
|
||||
{
|
||||
if( \IPS\Settings::i()->prune_log_system )
|
||||
{
|
||||
\IPS\Log::pruneLogs( \IPS\Settings::i()->prune_log_system );
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Cleanup
|
||||
*
|
||||
* If your task takes longer than 15 minutes to run, this method
|
||||
* will be called before execute(). Use it to clean up anything which
|
||||
* may not have been done
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function cleanup()
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
@@ -36,6 +36,7 @@ class _sitemapgenerator extends \IPS\Task
|
||||
}
|
||||
catch( \Exception $e )
|
||||
{
|
||||
\IPS\Log::log( $e, 'sitemap_generator' );
|
||||
return $e->getMessage();
|
||||
}
|
||||
|
||||
|
||||
@@ -22,6 +22,11 @@ if ( !defined( '\IPS\SUITE_UNIQUE_KEY' ) )
|
||||
*/
|
||||
class _updatecheck extends \IPS\Task
|
||||
{
|
||||
/**
|
||||
* @brief Type to send to update server
|
||||
*/
|
||||
public $type = 'task';
|
||||
|
||||
/**
|
||||
* Execute
|
||||
*
|
||||
@@ -29,6 +34,9 @@ class _updatecheck extends \IPS\Task
|
||||
*/
|
||||
public function execute()
|
||||
{
|
||||
/* Refresh stored license data */
|
||||
\IPS\IPS::licenseKey( TRUE );
|
||||
|
||||
$fails = array();
|
||||
|
||||
/* Do IPS apps */
|
||||
@@ -41,7 +49,7 @@ class _updatecheck extends \IPS\Task
|
||||
}
|
||||
}
|
||||
$version = min( $versions );
|
||||
$url = \IPS\Http\Url::ips('updateCheck');
|
||||
$url = \IPS\Http\Url::ips('updateCheck')->setQueryString( array( 'type' => $this->type, 'key' => \IPS\Settings::i()->ipb_reg_number ) );
|
||||
if ( \IPS\USE_DEVELOPMENT_BUILDS )
|
||||
{
|
||||
$url = $url->setQueryString( 'development', 1 );
|
||||
|
||||
@@ -0,0 +1,286 @@
|
||||
<?php
|
||||
/**
|
||||
* @brief usagereporting Task
|
||||
* @author <a href='https://www.invisioncommunity.com'>Invision Power Services, Inc.</a>
|
||||
* @copyright (c) Invision Power Services, Inc.
|
||||
* @license https://www.invisioncommunity.com/legal/standards/
|
||||
* @package Invision Community
|
||||
* @since 27 Dec 2017
|
||||
*/
|
||||
|
||||
namespace IPS\core\tasks;
|
||||
|
||||
/* 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;
|
||||
}
|
||||
|
||||
/**
|
||||
* usagereporting Task
|
||||
*/
|
||||
class _usagereporting extends \IPS\Task
|
||||
{
|
||||
/**
|
||||
* Execute
|
||||
*
|
||||
* If ran successfully, should return anything worth logging. Only log something
|
||||
* worth mentioning (don't log "task ran successfully"). Return NULL (actual NULL, not '' or 0) to not log (which will be most cases).
|
||||
* If an error occurs which means the task could not finish running, throw an \IPS\Task\Exception - do not log an error as a normal log.
|
||||
* Tasks should execute within the time of a normal HTTP request.
|
||||
*
|
||||
* @return mixed Message to log or NULL
|
||||
* @throws \IPS\Task\Exception
|
||||
*/
|
||||
public function execute()
|
||||
{
|
||||
/* Check usage reporting is enabled */
|
||||
if ( !\IPS\Settings::i()->usage_reporting )
|
||||
{
|
||||
\IPS\Db::i()->update( 'core_tasks', array( 'enabled' => 0 ), array( '`key`=?', 'usagereporting' ) );
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Check this isn't a test install */
|
||||
$licenseData = \IPS\IPS::licenseKey();
|
||||
if ( \IPS\IN_DEV or !$licenseData or mb_substr( $licenseData['key'], -12 ) === '-TESTINSTALL' )
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Send the report */
|
||||
try
|
||||
{
|
||||
$response = \IPS\Http\Url::external('https://invisionpowerdiagnostics.com/usage')->request()->post( $this->buildReport() );
|
||||
|
||||
/* If the server has asked us to stop sending reports, then turn it off */
|
||||
if ( $response->httpResponseCode == 410 )
|
||||
{
|
||||
\IPS\Settings::i()->changeValues( array( 'usage_reporting' => 0 ) );
|
||||
\IPS\Db::i()->update( 'core_tasks', array( 'enabled' => 0 ), array( '`key`=?', 'usagereporting' ) );
|
||||
}
|
||||
}
|
||||
catch ( \IPS\Http\Url\Exception $e ) { }
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create report
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
final protected function buildReport()
|
||||
{
|
||||
/* Identifier which allows us to keep separate reports from this community
|
||||
from other reports (so we can see how communities change things as they grow) but
|
||||
does NOT allow us to identify which community is sending the report */
|
||||
$report = array( 'anonymized_id' => md5( \IPS\Settings::i()->base_url . \IPS\Settings::i()->site_secret_key ) );
|
||||
|
||||
/* Community data */
|
||||
$licenseData = \IPS\IPS::licenseKey(); // this is just to know if it is *active* and if it is CiC - we don't actually send the license key
|
||||
$report['community'] = array(
|
||||
'version' => \IPS\Application::load('core')->version,
|
||||
'installed' => date( 'Y-m-d', \IPS\Settings::i()->board_start ),
|
||||
'active_license'=> $licenseData ? ( (bool) $licenseData['active'] ) : FALSE,
|
||||
'cloud' => $licenseData ? ( (bool) $licenseData['cloud'] ) : FALSE,
|
||||
);
|
||||
|
||||
/* Server Data */
|
||||
$report['server'] = array(
|
||||
'php_version' => PHP_VERSION_ID,
|
||||
'php_extensions' => get_loaded_extensions(),
|
||||
'mysql_version' => \IPS\Db::i()->server_version,
|
||||
'os' => PHP_OS,
|
||||
);
|
||||
|
||||
/* Apps */
|
||||
$report['apps'] = array();
|
||||
foreach ( \IPS\Application::applications() as $app )
|
||||
{
|
||||
if ( $app->enabled )
|
||||
{
|
||||
$report['apps'][ $app->directory ] = $app->long_version;
|
||||
}
|
||||
}
|
||||
|
||||
/* Plugins */
|
||||
$report['plugins'] = array();
|
||||
foreach ( \IPS\Plugin::plugins() as $plugin )
|
||||
{
|
||||
if ( $plugin->enabled )
|
||||
{
|
||||
$report['plugins'][ $plugin->location ] = $plugin->version_long;
|
||||
}
|
||||
}
|
||||
|
||||
/* Themes */
|
||||
$report['themes'] = array();
|
||||
foreach ( \IPS\Theme::themes() as $theme )
|
||||
{
|
||||
$settings = array();
|
||||
foreach ( $theme->settings as $k => $v )
|
||||
{
|
||||
if ( in_array( $k, array( 'responsive', 'rounded_photos', 'social_links', 'sidebar_position', 'sidebar_responsive', 'enable_fluid_width', 'fluid_width_size', 'js_incclude', 'ajax_pagination', 'cm_store_view', 'body_font', 'headline_font' ) ) )
|
||||
{
|
||||
$settings[ $k ] = $v;
|
||||
}
|
||||
}
|
||||
|
||||
$report['themes'][] = array(
|
||||
'customised' => \IPS\Db::i()->select( 'COUNT(*)', 'core_theme_templates', array( 'template_set_id=?', $theme->id ) )->first(),
|
||||
'settings' => $settings,
|
||||
);
|
||||
}
|
||||
|
||||
/* Languages */
|
||||
$report['languages'] = array();
|
||||
foreach ( \IPS\Lang::languages() as $lang )
|
||||
{
|
||||
$localeDot = \strpos( $lang->short, '.' );
|
||||
$langKey = $localeDot ? \substr( $lang->short, 0, $localeDot ) : $lang->short;
|
||||
|
||||
if ( !isset( $report['languages'][ $langKey ] ) )
|
||||
{
|
||||
$report['languages'][ $langKey ] = 0;
|
||||
}
|
||||
$report['languages'][ $langKey ]++;
|
||||
}
|
||||
|
||||
/* Settings */
|
||||
foreach ( \IPS\Db::i()->select( array( 'conf_key', 'conf_value', 'conf_default', 'conf_app', 'conf_report' ), 'core_sys_conf_settings', 'conf_report IS NOT NULL' ) as $row )
|
||||
{
|
||||
if ( in_array( $row['conf_app'], \IPS\Application::$ipsApps ) and \IPS\Application::appIsEnabled( $row['conf_app'] ) )
|
||||
{
|
||||
if ( $row['conf_report'] == 'full' )
|
||||
{
|
||||
$report['settings'][ $row['conf_key'] ] = $row['conf_value'];
|
||||
}
|
||||
else
|
||||
{
|
||||
$report['settings'][ $row['conf_key'] ] = ( $row['conf_value'] != $row['conf_default'] );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Database counts */
|
||||
foreach ( \IPS\Application::$ipsApps as $app )
|
||||
{
|
||||
if ( \IPS\Application::appIsEnabled( $app ) and file_exists( \IPS\ROOT_PATH . "/applications/{$app}/data/schema.json" ) )
|
||||
{
|
||||
foreach ( json_decode( file_get_contents( \IPS\ROOT_PATH . "/applications/{$app}/data/schema.json" ), TRUE ) as $table => $data )
|
||||
{
|
||||
if ( isset( $data['reporting'] ) and $data['reporting'] === 'count' )
|
||||
{
|
||||
$report['tables'][ $table ] = \IPS\Db::i()->select( 'COUNT(*)', $table )->first();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* File storage configurations */
|
||||
$report['files'] = array( 'amazon' => 0, 'database' => 0, 'filesystem' => 0, 'ftp' => 0, 'other' => 0 );
|
||||
foreach ( \IPS\Application::allExtensions( 'core', 'FileStorage', FALSE ) as $k => $v )
|
||||
{
|
||||
try
|
||||
{
|
||||
$class = \strtolower( \substr( get_class( \IPS\File::getClass( $k ) ), 9 ) );
|
||||
|
||||
if ( isset( $report['files'][ $class ] ) )
|
||||
{
|
||||
$report['files'][ $class ]++;
|
||||
}
|
||||
else
|
||||
{
|
||||
$report['files']['other']++;
|
||||
}
|
||||
}
|
||||
catch ( \Exception $e ) { }
|
||||
}
|
||||
|
||||
/* Login methods */
|
||||
$loginMethods = array(
|
||||
'IPS\Login\Handler\Standard' => 'standard',
|
||||
'IPS\Login\Handler\OAuth2\Facebook' => 'facebook',
|
||||
'IPS\Login\Handler\OAuth2\Google' => 'google',
|
||||
'IPS\Login\Handler\OAuth2\LinkedIn' => 'linkedin',
|
||||
'IPS\Login\Handler\OAuth2\Microsoft' => 'microsoft',
|
||||
'IPS\Login\Handler\OAuth1\Twitter' => 'twitter',
|
||||
'IPS\Login\Handler\OAuth2\Invision' => 'invision',
|
||||
'IPS\Login\Handler\OAuth2\Wordpress' => 'wordpress',
|
||||
'IPS\Login\Handler\OAuth2\Custom' => 'oauth',
|
||||
'IPS\Login\Handler\ExternalDatabase' => 'external',
|
||||
'IPS\Login\Handler\LDAP' => 'ldap',
|
||||
);
|
||||
foreach ( $loginMethods as $k => $v )
|
||||
{
|
||||
$report['login'][ $v ] = 0;
|
||||
}
|
||||
$report['login']['other'] = 0;
|
||||
foreach ( \IPS\Login::methods() as $method )
|
||||
{
|
||||
$class = get_class( $method );
|
||||
if ( array_key_exists( $class, $loginMethods ) )
|
||||
{
|
||||
$report['login'][ $loginMethods[ $class ] ]++;
|
||||
}
|
||||
else
|
||||
{
|
||||
$report['login']['other']++;
|
||||
}
|
||||
}
|
||||
|
||||
/* Payment methods */
|
||||
$report['paymethods'] = array();
|
||||
if ( \IPS\Application::appIsEnabled('nexus') )
|
||||
{
|
||||
$report['paymethods'] = array( 'authorizenet_aim' => 0, 'authorizenet_dpm' => 0, 'manual' => 0, 'paypal_standard' => 0, 'paypal_pro' => 0, 'stripe_card' => 0, 'stripe_native' => 0, 'stripe_alipay' => 0, 'stripe_amex' => 0, 'stripe_bancontact' => 0, 'stripe_giropay' => 0, 'stripe_ideal' => 0, 'stripe_sofort' => 0, 'test' => 0, 'twocheckout' => 0, 'other' => 0 );
|
||||
foreach ( \IPS\nexus\Gateway::roots() as $gateway )
|
||||
{
|
||||
$class = \strtolower( \substr( get_class( $gateway ), 18 ) );
|
||||
$settings = json_decode( $gateway->settings, TRUE );
|
||||
|
||||
if ( $class === 'authorizenet' )
|
||||
{
|
||||
$class = ( $settings['method'] === 'AIM' ) ? 'authorizenet_aim' : 'authorizenet_dpm';
|
||||
}
|
||||
elseif ( $class === 'paypal' )
|
||||
{
|
||||
$class = ( $settings['type'] === 'paypal' ) ? 'paypal_standard' : 'paypal_pro';
|
||||
}
|
||||
elseif ( $class === 'stripe' )
|
||||
{
|
||||
$class = 'stripe_' . $settings['type'];
|
||||
}
|
||||
|
||||
|
||||
if ( array_key_exists( $class, $report['paymethods'] ) )
|
||||
{
|
||||
$report['paymethods'][ $class ]++;
|
||||
}
|
||||
else
|
||||
{
|
||||
$report['paymethods']['other']++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Return */
|
||||
return $report;
|
||||
}
|
||||
|
||||
/**
|
||||
* Cleanup
|
||||
*
|
||||
* If your task takes longer than 15 minutes to run, this method
|
||||
* will be called before execute(). Use it to clean up anything which
|
||||
* may not have been done
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function cleanup()
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,90 @@
|
||||
<?php
|
||||
/**
|
||||
* @brief User agent statistics task
|
||||
* @author <a href='https://www.invisioncommunity.com'>Invision Power Services, Inc.</a>
|
||||
* @copyright (c) Invision Power Services, Inc.
|
||||
* @license https://www.invisioncommunity.com/legal/standards/
|
||||
* @package Invision Community
|
||||
* @since 10 Jan 2018
|
||||
*/
|
||||
|
||||
namespace IPS\core\tasks;
|
||||
|
||||
/* 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;
|
||||
}
|
||||
|
||||
/**
|
||||
* User agent statistics task
|
||||
*/
|
||||
class _userAgentStatistics extends \IPS\Task
|
||||
{
|
||||
/**
|
||||
* Execute
|
||||
*
|
||||
* If ran successfully, should return anything worth logging. Only log something
|
||||
* worth mentioning (don't log "task ran successfully"). Return NULL (actual NULL, not '' or 0) to not log (which will be most cases).
|
||||
* If an error occurs which means the task could not finish running, throw an \IPS\Task\Exception - do not log an error as a normal log.
|
||||
* Tasks should execute within the time of a normal HTTP request.
|
||||
*
|
||||
* @return mixed Message to log or NULL
|
||||
* @throws \IPS\Task\Exception
|
||||
*/
|
||||
public function execute()
|
||||
{
|
||||
$desktops = 0;
|
||||
$tablets = 0;
|
||||
$mobiles = 0;
|
||||
$consoles = 0;
|
||||
|
||||
foreach( \IPS\Session\Store::i()->getOnlineUsers( \IPS\Session\Store::ONLINE_MEMBERS, 'desc', NULL, NULL, TRUE, TRUE ) as $row )
|
||||
{
|
||||
$userAgent = \IPS\Http\Useragent::parse( $row['browser'] );
|
||||
|
||||
if( in_array( $userAgent->platform, array( 'iPhone', 'Windows Phone OS', 'BlackBerry', 'Android', 'Tizen' ) ) )
|
||||
{
|
||||
$mobiles++;
|
||||
}
|
||||
elseif( in_array( $userAgent->platform, array( 'iPad / iPod Touch', 'Kindle', 'Kindle Fire', 'Playbook' ) ) )
|
||||
{
|
||||
$tablets++;
|
||||
}
|
||||
elseif( in_array( $userAgent->platform, array( 'Nintendo 3DS', 'New Nintendo 3DS', 'Nintendo Wii', 'Nintendo WiiU', 'PlayStation 3', 'PlayStation 4', 'PlayStation Vita', 'Xbox 360', 'Xbox One' ) ) )
|
||||
{
|
||||
$consoles++;
|
||||
}
|
||||
else
|
||||
{
|
||||
$desktops++;
|
||||
}
|
||||
}
|
||||
|
||||
\IPS\Db::i()->insert( 'core_statistics', array(
|
||||
'type' => 'devices',
|
||||
'value_1' => $mobiles,
|
||||
'value_2' => $tablets,
|
||||
'value_3' => $consoles,
|
||||
'value_4' => $desktops,
|
||||
'time' => time()
|
||||
) );
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Cleanup
|
||||
*
|
||||
* If your task takes longer than 15 minutes to run, this method
|
||||
* will be called before execute(). Use it to clean up anything which
|
||||
* may not have been done
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function cleanup()
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
@@ -38,52 +38,96 @@ class _viewupdates extends \IPS\Task
|
||||
$this->runUntilTimeout(function(){
|
||||
try
|
||||
{
|
||||
$result = \IPS\Db::i()->select( 'classname, id, COUNT(*) AS count', 'core_view_updates', NULL, NULL, 20, array( 'classname', 'id' ) );
|
||||
|
||||
/* If there's no more, break the loop and stop */
|
||||
if( !count( $result ) )
|
||||
$database = \IPS\Db::i()->select( 'classname, id, COUNT(*) AS count', 'core_view_updates', NULL, NULL, 20, array( 'classname', 'id' ), NULL, \IPS\Db::SELECT_FROM_WRITE_SERVER );
|
||||
$redis = array();
|
||||
|
||||
/* Database results first */
|
||||
foreach( $database as $row )
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
foreach( $result as $row )
|
||||
{
|
||||
$class = $row['classname'];
|
||||
if ( class_exists( $class ) and in_array( 'IPS\Content\Views', class_implements( $class ) ) AND isset( $class::$databaseColumnMap['views'] ) )
|
||||
try
|
||||
{
|
||||
try
|
||||
{
|
||||
\IPS\Db::i()->update(
|
||||
$class::$databaseTable,
|
||||
"`{$class::$databasePrefix}{$class::$databaseColumnMap['views']}`=`{$class::$databasePrefix}{$class::$databaseColumnMap['views']}`+{$row['count']}",
|
||||
array( "{$class::$databasePrefix}{$class::$databaseColumnId}=?", $row['id'] )
|
||||
);
|
||||
}
|
||||
catch( \IPS\Db\Exception $e )
|
||||
{
|
||||
/* Table to update no longer exists */
|
||||
if( $e->getCode() == 1146 )
|
||||
{
|
||||
\IPS\Db::i()->delete( 'core_view_updates', array( 'classname=?', $row['classname'] ) );
|
||||
}
|
||||
|
||||
throw $e;
|
||||
}
|
||||
$this->update( $row['classname'], $row['id'], $row['count'] );
|
||||
}
|
||||
|
||||
catch( \OutOfRangeException $e )
|
||||
{
|
||||
\IPS\Db::i()->delete( 'core_view_updates', array( 'classname=?', $row['classname'] ) );
|
||||
}
|
||||
|
||||
\IPS\Db::i()->delete( 'core_view_updates', array( 'classname=? AND id=?', $row['classname'], $row['id'] ) );
|
||||
}
|
||||
}
|
||||
catch ( \UnderflowException $e ) { }
|
||||
|
||||
/* Now try redis */
|
||||
if ( \IPS\REDIS_ENABLED and \IPS\CACHE_METHOD == 'Redis' and \IPS\CACHE_CONFIG )
|
||||
{
|
||||
try
|
||||
{
|
||||
$redis = \IPS\Redis::i()->zRevRangeByScore( 'topic_views', '+inf', '-inf', array('withscores' => TRUE, 'limit' => array( 0, 20 ) ) );
|
||||
|
||||
/* If we're here we just ran some, so we can return true to see if there are any more to run */
|
||||
foreach( $redis as $data => $count )
|
||||
{
|
||||
list( $class, $id ) = explode( '__', $data );
|
||||
|
||||
try
|
||||
{
|
||||
$this->update( $class, $id, intval( $count ) );
|
||||
}
|
||||
catch( \OutOfRangeException $e ) { }
|
||||
|
||||
\IPS\Redis::i()->zRem( 'topic_views', $data );
|
||||
}
|
||||
}
|
||||
catch( \Exception $e ) { }
|
||||
}
|
||||
|
||||
/* Go for another go? */
|
||||
if ( count( $database ) or count( $redis ) )
|
||||
{
|
||||
return TRUE;
|
||||
}
|
||||
catch ( \UnderflowException $e )
|
||||
else
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the row
|
||||
*
|
||||
* @param string $class Class to update
|
||||
* @param int $id ID of item
|
||||
* @param int $count Count to update
|
||||
* @throws \OutOfRangeException When table to update no longer exists
|
||||
*/
|
||||
protected function update( $class, $id, $count )
|
||||
{
|
||||
if ( class_exists( $class ) and in_array( 'IPS\Content\Views', class_implements( $class ) ) AND isset( $class::$databaseColumnMap['views'] ) )
|
||||
{
|
||||
try
|
||||
{
|
||||
\IPS\Db::i()->update(
|
||||
$class::$databaseTable,
|
||||
"`{$class::$databasePrefix}{$class::$databaseColumnMap['views']}`=`{$class::$databasePrefix}{$class::$databaseColumnMap['views']}`+{$count}",
|
||||
array( "{$class::$databasePrefix}{$class::$databaseColumnId}=?", $id )
|
||||
);
|
||||
|
||||
\IPS\Content\Search\Index::i()->updateViewCounts( $class, $id, $count );
|
||||
}
|
||||
catch( \IPS\Db\Exception $e )
|
||||
{
|
||||
/* Table to update no longer exists */
|
||||
if( $e->getCode() == 1146 )
|
||||
{
|
||||
throw new \OutOfRangeException;
|
||||
}
|
||||
|
||||
throw $e;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Cleanup
|
||||
*
|
||||
|
||||
Reference in new issue
Block a user