<commit_before><?php
/**
 * Rules Engine: The brains behind this whole operation
 *
 * @package BadgeOS
 * @subpackage Achievements
 * @author Credly, LLC
 * @license http://www.gnu.org/licenses/agpl.txt GNU AGPL v3.0
 * @link https://credly.com
 */

/**
 * Check if user should earn an achievement, and award it if so.
 *
 * @since  1.0.0
 * @param  integer $achievement_id The given achievement ID to possibly award
 * @param  integer $user_id        The given user's ID
 * @param  string $trigger         The trigger
 * @param  integer $site_id        The triggered site id
 * @param  array $args             The triggered args
 * @return void
 */
function badgeos_maybe_award_achievement_to_user( $achievement_id = 0, $user_id = 0, $this_trigger = '', $site_id = '', $args = array() ) {

	// Set to current site id
	if ( ! $site_id )
		$site_id = get_current_blog_id();

	// Grab current user ID if one isn't specified
	if ( ! $user_id )
		$user_id = wp_get_current_user()->ID;

	// If the user does not have access to this achievement, bail here
	if ( ! badgeos_user_has_access_to_achievement( $user_id, $achievement_id, $this_trigger, $site_id, $args ) )
		return false;

	// If the user has completed the achievement, award it
	if ( badgeos_check_achievement_completion_for_user( $achievement_id, $user_id, $this_trigger, $site_id, $args ) )
		badgeos_award_achievement_to_user( $achievement_id, $user_id, $this_trigger, $site_id, $args );
}

/**
 * Check if user has completed an achievement
 *
 * @since  1.0.0
 * @param  integer $achievement_id The given achievement ID to verify
 * @param  integer $user_id        The given user's ID
 * @param  string  $trigger        The trigger
 * @param  integer $site_id        The triggered site id
 * @param  array   $args           The triggered args
 * @return bool                    True if user has completed achievement, false otherwise
 */
function badgeos_check_achievement_completion_for_user( $achievement_id = 0, $user_id = 0, $this_trigger = '', $site_id = '', $args = array() ) {

	// Assume the user has completed the achievement
	$return = true;

	// Set to current site id
	if ( ! $site_id )
		$site_id = get_current_blog_id();

	// If the user has not already earned the achievement...
	if ( ! badgeos_get_user_achievements( array( 'user_id' => absint( $user_id ), 'achievement_id' => absint( $achievement_id ), 'since' => 1 + badgeos_achievement_last_user_activity( $achievement_id, $user_id ) ) ) ) {

		// Grab our required achievements for this achievement
		$required_achievements = badgeos_get_required_achievements_for_achievement( $achievement_id );

		// If we have requirements, loop through each and make sure they've been completed
		if ( is_array( $required_achievements ) && ! empty( $required_achievements ) ) {
			foreach ( $required_achievements as $requirement ) {
				// Has the user already earned the requirement?
				if ( ! badgeos_get_user_achievements( array( 'user_id' => $user_id, 'achievement_id' => $requirement->ID, 'since' => badgeos_achievement_last_user_activity( $achievement_id, $user_id ) ) ) ) {
					$return = false;
					break;
				}
			}
		}
	}

	// Available filter to support custom earning rules
	return apply_filters( 'user_deserves_achievement', $return, $user_id, $achievement_id, $this_trigger, $site_id, $args );

}

/**
 * Check if user meets the points requirement for a given achievement
 *
 * @since  1.0.0
 * @param  bool    $return         The current status of whether or not the user deserves this achievement
 * @param  integer $user_id        The given user's ID
 * @param  integer $achievement_id The given achievement's post ID
 * @return bool                    Our possibly updated earning status
 */
function badgeos_user_meets_points_requirement( $return = false, $user_id = 0, $achievement_id = 0 ) {

	// First, see if the achievement requires a minimum amount of points
	if ( 'points' == get_post_meta( $achievement_id, '_badgeos_earned_by', true ) ) {

		// Grab our user's points and see if they at least as many as required
		$user_points     = absint( badgeos_get_users_points( $user_id ) );
		$points_required = absint( get_post_meta( $achievement_id, '_badgeos_points_required', true ) );
		$last_activity   = badgeos_achievement_last_user_activity( $achievement_id );

		if ( $user_points >= $points_required )
			$return = true;
		else
			$return = false;

		// If the user just earned the badge, though, don't let them earn it again
		// This prevents an infinite loop if the badge has no maximum earnings limit
		if ( $last_activity >= time('-2 seconds') )
			$return = false;
	}

	// Return our eligibility status
	return $return;
}
add_filter( 'user_deserves_achievement', 'badgeos_user_meets_points_requirement', 10, 3 );

/**
 * Award an achievement to a user
 *
 * @since  1.0.0
 * @param  integer $achievement_id The given achievement ID to award
 * @param  integer $user_id        The given user's ID
 * @param  string $trigger         The trigger
 * @param  integer $site_id        The triggered site id
 * @param  array $args             The triggered args
 * @return void
 */
function badgeos_award_achievement_to_user( $achievement_id = 0, $user_id = 0, $this_trigger = '', $site_id = '', $args = array() ) {

	global $wp_filters, $wp_version;

	// Sanity Check: ensure we're working with an achievement post
	if ( ! badgeos_is_achievement( $achievement_id ) )
		return false;

	// Use the current user ID if none specified
	if ( $user_id == 0 )
		$user_id = wp_get_current_user()->ID;

	// Get the current site ID none specified
	if ( ! $site_id )
		$site_id = get_current_blog_id();

	// Setup our achievement object
	$achievement_object = badgeos_build_achievement_object( $achievement_id );

	// Update user's earned achievements
	badgeos_update_user_achievements( array( 'user_id' => $user_id, 'new_achievements' => array( $achievement_object ) ) );

	// Log the earning of the award
	badgeos_post_log_entry( $achievement_id, $user_id );

	// Available hook for unlocking any achievement of this achievement type
	do_action( 'badgeos_unlock_' . $achievement_object->post_type, $user_id, $achievement_id, $this_trigger, $site_id, $args );

	// Patch for WordPress to support recursive actions, specifically for badgeos_award_achievement
	// Because global iteration is fun, assuming we can get this fixed for WordPress 3.9
	$is_recursed_filter = ( 'badgeos_award_achievement' == current_filter() && version_compare( $wp_version, '3.9', '<' ) );
	$current_key = null;

	// Get current position
	if ( $is_recursed_filter ) {
		$current_key = key( $wp_filters[ 'badgeos_award_achievement' ] );
	}

	// Available hook to do other things with each awarded achievement
	do_action( 'badgeos_award_achievement', $user_id, $achievement_id, $this_trigger, $site_id, $args );

	if ( $is_recursed_filter ) {
		reset( $wp_filters[ 'badgeos_award_achievement' ] );

		while ( key( $wp_filters[ 'badgeos_award_achievement' ] ) !== $current_key ) {
			next( $wp_filters[ 'badgeos_award_achievement' ] );
		}
	}

}

/**
 * Revoke an achievement from a user
 *
 * @since  1.0.0
 * @param  integer $achievement_id The given achievement's post ID
 * @param  integer $user_id        The given user's ID
 * @return void
 */
function badgeos_revoke_achievement_from_user( $achievement_id = 0, $user_id = 0 ) {

	// Use the current user's ID if none specified
	if ( ! $user_id )
		$user_id = wp_get_current_user()->ID;

	// Grab the user's earned achievements
	$earned_achievements = badgeos_get_user_achievements( array( 'user_id' => $user_id ) );

	// Loop through each achievement and drop the achievement we're revoking
	foreach ( $earned_achievements as $key => $achievement ) {
		if ( $achievement->ID == $achievement_id ) {

			// Drop the achievement from our earnings
			unset( $earned_achievements[$key] );

			// Re-key our array
			$earned_achievements = array_values( $earned_achievements );<commit_msg>Correct $wp_filters references to $wp_filter<commit_after><?php
/**
 * Rules Engine: The brains behind this whole operation
 *
 * @package BadgeOS
 * @subpackage Achievements
 * @author Credly, LLC
 * @license http://www.gnu.org/licenses/agpl.txt GNU AGPL v3.0
 * @link https://credly.com
 */

/**
 * Check if user should earn an achievement, and award it if so.
 *
 * @since  1.0.0
 * @param  integer $achievement_id The given achievement ID to possibly award
 * @param  integer $user_id        The given user's ID
 * @param  string $trigger         The trigger
 * @param  integer $site_id        The triggered site id
 * @param  array $args             The triggered args
 * @return void
 */
function badgeos_maybe_award_achievement_to_user( $achievement_id = 0, $user_id = 0, $this_trigger = '', $site_id = '', $args = array() ) {

	// Set to current site id
	if ( ! $site_id )
		$site_id = get_current_blog_id();

	// Grab current user ID if one isn't specified
	if ( ! $user_id )
		$user_id = wp_get_current_user()->ID;

	// If the user does not have access to this achievement, bail here
	if ( ! badgeos_user_has_access_to_achievement( $user_id, $achievement_id, $this_trigger, $site_id, $args ) )
		return false;

	// If the user has completed the achievement, award it
	if ( badgeos_check_achievement_completion_for_user( $achievement_id, $user_id, $this_trigger, $site_id, $args ) )
		badgeos_award_achievement_to_user( $achievement_id, $user_id, $this_trigger, $site_id, $args );
}

/**
 * Check if user has completed an achievement
 *
 * @since  1.0.0
 * @param  integer $achievement_id The given achievement ID to verify
 * @param  integer $user_id        The given user's ID
 * @param  string  $trigger        The trigger
 * @param  integer $site_id        The triggered site id
 * @param  array   $args           The triggered args
 * @return bool                    True if user has completed achievement, false otherwise
 */
function badgeos_check_achievement_completion_for_user( $achievement_id = 0, $user_id = 0, $this_trigger = '', $site_id = '', $args = array() ) {

	// Assume the user has completed the achievement
	$return = true;

	// Set to current site id
	if ( ! $site_id )
		$site_id = get_current_blog_id();

	// If the user has not already earned the achievement...
	if ( ! badgeos_get_user_achievements( array( 'user_id' => absint( $user_id ), 'achievement_id' => absint( $achievement_id ), 'since' => 1 + badgeos_achievement_last_user_activity( $achievement_id, $user_id ) ) ) ) {

		// Grab our required achievements for this achievement
		$required_achievements = badgeos_get_required_achievements_for_achievement( $achievement_id );

		// If we have requirements, loop through each and make sure they've been completed
		if ( is_array( $required_achievements ) && ! empty( $required_achievements ) ) {
			foreach ( $required_achievements as $requirement ) {
				// Has the user already earned the requirement?
				if ( ! badgeos_get_user_achievements( array( 'user_id' => $user_id, 'achievement_id' => $requirement->ID, 'since' => badgeos_achievement_last_user_activity( $achievement_id, $user_id ) ) ) ) {
					$return = false;
					break;
				}
			}
		}
	}

	// Available filter to support custom earning rules
	return apply_filters( 'user_deserves_achievement', $return, $user_id, $achievement_id, $this_trigger, $site_id, $args );

}

/**
 * Check if user meets the points requirement for a given achievement
 *
 * @since  1.0.0
 * @param  bool    $return         The current status of whether or not the user deserves this achievement
 * @param  integer $user_id        The given user's ID
 * @param  integer $achievement_id The given achievement's post ID
 * @return bool                    Our possibly updated earning status
 */
function badgeos_user_meets_points_requirement( $return = false, $user_id = 0, $achievement_id = 0 ) {

	// First, see if the achievement requires a minimum amount of points
	if ( 'points' == get_post_meta( $achievement_id, '_badgeos_earned_by', true ) ) {

		// Grab our user's points and see if they at least as many as required
		$user_points     = absint( badgeos_get_users_points( $user_id ) );
		$points_required = absint( get_post_meta( $achievement_id, '_badgeos_points_required', true ) );
		$last_activity   = badgeos_achievement_last_user_activity( $achievement_id );

		if ( $user_points >= $points_required )
			$return = true;
		else
			$return = false;

		// If the user just earned the badge, though, don't let them earn it again
		// This prevents an infinite loop if the badge has no maximum earnings limit
		if ( $last_activity >= time('-2 seconds') )
			$return = false;
	}

	// Return our eligibility status
	return $return;
}
add_filter( 'user_deserves_achievement', 'badgeos_user_meets_points_requirement', 10, 3 );

/**
 * Award an achievement to a user
 *
 * @since  1.0.0
 * @param  integer $achievement_id The given achievement ID to award
 * @param  integer $user_id        The given user's ID
 * @param  string $trigger         The trigger
 * @param  integer $site_id        The triggered site id
 * @param  array $args             The triggered args
 * @return void
 */
function badgeos_award_achievement_to_user( $achievement_id = 0, $user_id = 0, $this_trigger = '', $site_id = '', $args = array() ) {

	global $wp_filter, $wp_version;

	// Sanity Check: ensure we're working with an achievement post
	if ( ! badgeos_is_achievement( $achievement_id ) )
		return false;

	// Use the current user ID if none specified
	if ( $user_id == 0 )
		$user_id = wp_get_current_user()->ID;

	// Get the current site ID none specified
	if ( ! $site_id )
		$site_id = get_current_blog_id();

	// Setup our achievement object
	$achievement_object = badgeos_build_achievement_object( $achievement_id );

	// Update user's earned achievements
	badgeos_update_user_achievements( array( 'user_id' => $user_id, 'new_achievements' => array( $achievement_object ) ) );

	// Log the earning of the award
	badgeos_post_log_entry( $achievement_id, $user_id );

	// Available hook for unlocking any achievement of this achievement type
	do_action( 'badgeos_unlock_' . $achievement_object->post_type, $user_id, $achievement_id, $this_trigger, $site_id, $args );

	// Patch for WordPress to support recursive actions, specifically for badgeos_award_achievement
	// Because global iteration is fun, assuming we can get this fixed for WordPress 3.9
	$is_recursed_filter = ( 'badgeos_award_achievement' == current_filter() && version_compare( $wp_version, '3.9', '<' ) );
	$current_key = null;

	// Get current position
	if ( $is_recursed_filter ) {
		$current_key = key( $wp_filter[ 'badgeos_award_achievement' ] );
	}

	// Available hook to do other things with each awarded achievement
	do_action( 'badgeos_award_achievement', $user_id, $achievement_id, $this_trigger, $site_id, $args );

	if ( $is_recursed_filter ) {
		reset( $wp_filter[ 'badgeos_award_achievement' ] );

		while ( key( $wp_filter[ 'badgeos_award_achievement' ] ) !== $current_key ) {
			next( $wp_filter[ 'badgeos_award_achievement' ] );
		}
	}

}

/**
 * Revoke an achievement from a user
 *
 * @since  1.0.0
 * @param  integer $achievement_id The given achievement's post ID
 * @param  integer $user_id        The given user's ID
 * @return void
 */
function badgeos_revoke_achievement_from_user( $achievement_id = 0, $user_id = 0 ) {

	// Use the current user's ID if none specified
	if ( ! $user_id )
		$user_id = wp_get_current_user()->ID;

	// Grab the user's earned achievements
	$earned_achievements = badgeos_get_user_achievements( array( 'user_id' => $user_id ) );

	// Loop through each achievement and drop the achievement we're revoking
	foreach ( $earned_achievements as $key => $achievement ) {
		if ( $achievement->ID == $achievement_id ) {

			// Drop the achievement from our earnings
			unset( $earned_achievements[$key] );

			// Re-key our array
			$earned_achievements = array_values( $earned_achievements );
{'fraction_non_alphanumeric': 0.10585133098945254, 'fraction_numerical': 0.004645906579608237, 'mean_word_length': 3.9027393044013543, 'pattern_counts': {'":': 0, '<': 7, '<?xml version=': 0, '>': 39, 'https://': 2, 'lorem ipsum': 0, 'www.': 2, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '4521121', 'n_tokens_mistral': 5486, 'n_tokens_neox': 5164, 'n_words': 1546}