ready !== null ) { return $this->ready; } $read = new ResourceCapacityRepository();$definitions = array( 'calendar_connections' => array( 'id' => 'bigint unsigned', 'provider' => 'varchar(20)', 'owner_user_id' => 'bigint unsigned', 'staff_id' => 'bigint unsigned', 'authority' => 'varchar(20)', 'timezone' => 'varchar(64)', 'calendars' => 'longtext', 'credential' => 'longtext', 'enabled' => 'tinyint unsigned', 'consent_revision' => 'bigint unsigned', 'revision' => 'bigint unsigned', 'sync_revision' => 'bigint unsigned', 'coverage_start' => 'datetime', 'coverage_end' => 'datetime', 'last_attempt' => 'datetime', 'last_success' => 'datetime', 'next_attempt' => 'datetime', 'error_code' => 'varchar(32)', 'created_at' => 'datetime' ), 'calendar_busy' => array( 'id' => 'bigint unsigned', 'connection_id' => 'bigint unsigned', 'calendar_digest' => 'char(64)', 'start_utc' => 'datetime', 'end_utc' => 'datetime', 'sync_revision' => 'bigint unsigned' ), 'calendar_oauth_states' => array( 'token_hash' => 'char(64)', 'user_id' => 'bigint unsigned', 'staff_id' => 'bigint unsigned', 'provider' => 'varchar(20)', 'purpose' => 'varchar(20)', 'state_payload' => 'longtext', 'expires_at' => 'datetime' ) ); if ( ! OptionalStoreSchema::present( $read, 'abientot_calendar_inbound_schema_version', '1', $definitions, array( 'calendar_connections' => array( array( 'id' ) ), 'calendar_busy' => array( array( 'id' ) ), 'calendar_oauth_states' => array( array( 'token_hash' ) ) ) ) ) { $this->ready = false; return false; } global $wpdb; foreach ( $definitions as$table => $columns ) { $engine = Db::rows( $wpdb->suppress_errors( true ), $wpdb->get_results( $wpdb->prepare( 'SELECT ENGINE FROM information_schema.TABLES WHERE TABLE_SCHEMA=DATABASE() AND TABLE_NAME=%s', $read->table( $table ) ), ARRAY_A ), 'retained_capacity_storage_unavailable' ); if ( strtoupper( (string) ( $engine[0]['ENGINE'] ?? '' ) ) !== 'INNODB' ) { throw new \RuntimeException( 'calendar_retained_engine' ); } foreach ( Db::rows( $wpdb->suppress_errors( true ), $wpdb->get_results( $wpdb->prepare( 'SHOW COLUMNS FROM %i', $read->table( $table ) ), ARRAY_A ), 'retained_capacity_storage_unavailable' )as$column ) { $nullable = $table === 'calendar_connections' && in_array( $column['Field'], array( 'coverage_start', 'coverage_end', 'last_attempt', 'last_success', 'next_attempt' ), true ); if ( isset( $columns[ $column['Field'] ] ) && ( $column['Null'] === 'YES' ) !== $nullable ) { throw new \RuntimeException( 'calendar_retained_nullability' ); } } } $this->ready = true; return true; } public function available( int $staffId, string $startUtc, string $endUtc ): bool { if ( $staffId < 1 || ! self::valid( $startUtc ) || ! self::valid( $endUtc ) || $startUtc >= $endUtc ) { throw new \DomainException( 'calendar_interval' ); } if ( ! $this->present() ) { return true; } global $wpdb; $read = new ResourceCapacityRepository(); $connections = Db::rows( $wpdb->suppress_errors( true ), $wpdb->get_results( $wpdb->prepare( 'SELECT id,provider,consent_revision,revision,sync_revision,coverage_start,coverage_end,last_success,error_code FROM %i WHERE staff_id=%d AND enabled=1', $read->table( 'calendar_connections' ), $staffId ), ARRAY_A ), 'retained_capacity_storage_unavailable' ); foreach ( $connections as$row ) { $success = is_string( $row['last_success'] ) && self::valid( $row['last_success'] ) ? strtotime( $row['last_success'] . ' UTC' ) : false; if ( ! in_array( $row['provider'], array( 'google', 'outlook' ), true ) || (int) $row['consent_revision'] !== 1 || (int) $row['sync_revision'] < 1 || $row['error_code'] !== '' || $success === false || time() - $success > 900 || $success - time() > 60 || ! is_string( $row['coverage_start'] ) || ! self::valid( $row['coverage_start'] ) || ! is_string( $row['coverage_end'] ) || ! self::valid( $row['coverage_end'] ) || $row['coverage_start'] > $startUtc || $row['coverage_end'] < $endUtc ) { return false; } $busy = Db::rows( $wpdb->suppress_errors( true ), $wpdb->get_results( $wpdb->prepare( 'SELECT start_utc,end_utc,sync_revision FROM %i WHERE connection_id=%d AND start_utc<%s AND end_utc>%s', $read->table( 'calendar_busy' ), (int) $row['id'], $endUtc, $startUtc ), ARRAY_A ), 'retained_capacity_storage_unavailable' ); foreach ( $busy as$interval ) { if ( ! self::valid( $interval['start_utc'] ) || ! self::valid( $interval['end_utc'] ) || $interval['start_utc'] >= $interval['end_utc'] || (int) $interval['sync_revision'] !== (int) $row['sync_revision'] ) { return false; } return false; } } return true; } private static function valid( string $stamp ): bool { $date = \DateTimeImmutable::createFromFormat( '!Y-m-d H:i:s', $stamp, new \DateTimeZone( 'UTC' ) ); return $date !== false && $date->format( 'Y-m-d H:i:s' ) === $stamp; } }