answer( $name, $event_id, $event_name ); } /** * Work out the answer. * * @param string|null $name Person's name. * @param int|null $event_id Event ID. * @param string|null $event_name Event title. * @return array */ private function answer( ?string $name, ?int $event_id, ?string $event_name ): array { $check = $this->guard( 'etn_manage_organizer', 'etn_manage_event' ); if ( $check ) { return $check; } try { if ( ( null !== $event_id && $event_id > 0 ) || '' !== trim( (string) $event_name ) ) { return $this->on_event( $event_id, $event_name ); } if ( '' !== trim( (string) $name ) ) { return $this->one_person( trim( (string) $name ) ); } return $this->overview(); } catch ( \Throwable $e ) { Log::error( static::class . ' error', [ 'error' => $e->getMessage() ] ); return [ 'error' => 'Could not read ' . $this->role() . 's: ' . $e->getMessage() ]; } } /** * How many there are, and who is on the most events. * * @return array */ private function overview(): array { $people = $this->query->people( $this->role() ); // Keep only current people. Events can still list a user who lost the role or was deleted. $counts = array_intersect_key( $this->events_per_person(), $people ); arsort( $counts ); $busiest = []; foreach ( array_slice( $counts, 0, self::LIST_LIMIT, true ) as $id => $events ) { $busiest[] = $this->card( $people[ $id ] ) + [ 'events' => $events ]; } $on_events = count( $counts ); return [ 'status' => 'ok', 'total' => count( $people ), 'on_an_event' => $on_events, 'not_on_an_event' => count( $people ) - $on_events, 'busiest' => $busiest, 'definitions' => [ 'total' => 'Every user with the ' . $this->role() . ' role.', 'busiest' => 'Up to ' . self::LIST_LIMIT . ' ' . $this->role() . 's on the most events, drafts included.', ], 'page' => $this->people_page(), ]; } /** * One person, found by name. * * @param string $name Name, or part of it. * @return array */ private function one_person( string $name ): array { $people = $this->query->people( $this->role() ); $matches = $this->find_people( $people, $name ); if ( empty( $matches ) ) { return $this->not_found( 'No ' . $this->role() . " is called \"{$name}\".", $this->people_page() ); } if ( count( $matches ) > 1 ) { return [ 'status' => 'needs_clarification', 'reason' => 'More than one ' . $this->role() . " matches \"{$name}\".", 'matches' => array_map( fn( $p ) => $this->card( $p ), array_slice( $matches, 0, self::LIST_LIMIT ) ), 'say' => 'Do not pick one. Read out the names and ask which one they mean. Then call this tool again with that full name.', 'page' => $this->people_page(), ]; } $person = $matches[0]; $event_ids = []; foreach ( $this->query->event_people( $this->role() ) as $event => $ids ) { if ( in_array( $person['id'], $ids, true ) ) { $event_ids[] = $event; } } $events = $this->query->events_info( $event_ids ); $today = current_time( 'Y-m-d' ); $upcoming = array_filter( $events, static fn( $e ) => 'publish' === $e['post_status'] && $e['end_date'] >= $today ); $result = [ 'status' => 'ok', 'person' => $this->card( $person ) + [ 'email' => $person['email'], 'groups' => array_values( $this->query->group_names( $person['groups'] ) ), ], 'events' => [ 'total' => count( $events ), 'upcoming' => count( $upcoming ), 'latest' => array_map( static fn( $e ) => [ 'title' => $e['title'], 'start_date' => $e['start_date'], 'post_status' => $e['post_status'], ], array_values( array_slice( $events, 0, self::LIST_LIMIT ) ) ), ], 'today' => $today, 'page' => $this->people_page(), ]; if ( 'speaker' === $this->role() ) { $result['sessions'] = $this->sessions_of( $person['id'] ); } return $result; } /** * Everyone on one event. * * @param int|null $event_id Event ID. * @param string|null $event_name Event title. * @return array */ private function on_event( ?int $event_id, ?string $event_name ): array { list( $event_id, $title, $stop ) = $this->resolve_event( $event_id, $event_name, $this->page( __( 'Events', 'aisentic' ), '/events' ) ); if ( null !== $stop ) { return $stop; } $people = $this->query->people( $this->role() ); $ids = $this->query->event_people( $this->role() )[ $event_id ] ?? []; $list = []; foreach ( $ids as $id ) { if ( isset( $people[ $id ] ) ) { $list[] = $this->card( $people[ $id ] ); } } return [ 'status' => 'ok', 'event' => $title, 'total' => count( $list ), 'people' => array_slice( $list, 0, self::LIST_LIMIT * 2 ), 'say' => empty( $list ) ? 'Say this event has no ' . $this->role() . 's set. Do not say the site has none.' : '', 'page' => $this->event_page( $event_id, $title ), ]; } /** * How many events each person is on. * * @return array User ID => events. */ private function events_per_person(): array { $counts = []; foreach ( $this->query->event_people( $this->role() ) as $ids ) { foreach ( $ids as $id ) { $counts[ $id ] = ( $counts[ $id ] ?? 0 ) + 1; } } return $counts; } /** * The sessions one speaker gives, latest schedule first. * * @param int $person_id User ID. * @return array{total:int,latest:array} */ private function sessions_of( int $person_id ): array { $sessions = []; foreach ( $this->query->schedules() as $schedule ) { foreach ( $schedule['sessions'] as $session ) { if ( in_array( $person_id, $session['speakers'], true ) ) { $sessions[] = [ 'topic' => $session['topic'], 'schedule' => $schedule['title'], 'date' => $schedule['date'], 'start' => $session['start'], 'end' => $session['end'], ]; } } } return [ 'total' => count( $sessions ), 'latest' => array_slice( $sessions, 0, self::LIST_LIMIT ), ]; } /** * People whose name matches. An exact name wins over a partial one. * * @param array $people All people. * @param string $name Name, or part of it. * @return array */ private function find_people( array $people, string $name ): array { $exact = array_filter( $people, static fn( $p ) => 0 === strcasecmp( trim( $p['name'] ), $name ) ); if ( ! empty( $exact ) ) { return array_values( $exact ); } return array_values( array_filter( $people, static fn( $p ) => false !== mb_stripos( $p['name'], $name ) ) ); } /** * The few fields worth saying about a person. * * @param array $person One entry of people(). * @return array{name:string,designation:string,company:string} */ private function card( array $person ): array { return [ 'name' => $person['name'], 'designation' => $person['designation'], 'company' => $person['company'], ]; } }