@param ServerRequestInterface $request
@param Tree                   $tree

@return ResponseInterface
541559
public function addChildAction(ServerRequestInterface $request, Tree $tree): ResponseInterface
    {
        $xref = $request->get('xref', '');

        $individual = Individual::getInstance($xref, $tree);

        Auth::checkIndividualAccess($individual, true);

        $PEDI = $request->get('PEDI', '');

        $this->glevels = $request->get('glevels', []);
        $this->tag     = $request->get('tag', []);
        $this->text    = $request->get('text', []);
        $this->islink  = $request->get('islink', []);

        // Create a family
        if ($individual->sex() === 'F') {
            $gedcom = "0 @@ FAM\n1 WIFE @" . $individual->xref() . '@';
        } else {
            $gedcom = "0 @@ FAM\n1 HUSB @" . $individual->xref() . '@';
        }
        $family = $tree->createFamily($gedcom);

        // Link the parent to the family
        $individual->createFact('1 FAMS @' . $family->xref() . '@', true);

        // Create a child
        $this->splitSource(); // separate SOUR record from the rest

        $gedcom = '0 @@ INDI';
        $gedcom .= $this->addNewName($request, $tree);
        $gedcom .= $this->addNewSex($request);
        $gedcom .= "\n" . GedcomCodePedi::createNewFamcPedi($PEDI, $family->xref());
        if (preg_match_all('/([A-Z0-9_]+)/', $tree->getPreference('QUICK_REQUIRED_FACTS'), $matches)) {
            foreach ($matches[1] as $match) {
                $gedcom .= $this->addNewFact($request, $tree, $match);
            }
        }
        if ((bool) $request->get('SOUR_INDI')) {
            $gedcom = $this->handleUpdates($gedcom);
        } else {
            $gedcom = $this->updateRest($gedcom);
        }

        $child = $tree->createIndividual($gedcom);

        // Link the family to the child
        $family->createFact('1 CHIL @' . $child->xref() . '@', true);

        if ($request->get('goto') === 'new') {
            return redirect($child->url());
        }

        return redirect($individual->url());
    }
491786
public function editName(ServerRequestInterface $request, Tree $tree): ResponseInterface
    {
        $fact_id = $request->get('fact_id', '');
        $xref    = $request->get('xref', '');

        $individual = Individual::getInstance($xref, $tree);

        Auth::checkIndividualAccess($individual, true);

        // Find the fact to edit
        foreach ($individual->facts() as $fact) {
            if ($fact->id() === $fact_id && $fact->canEdit()) {
                return $this->viewResponse('edit/new-individual', [
                    'tree'       => $tree,
                    'title'      => I18N::translate('Edit the name'),
                    'nextaction' => 'update',
                    'individual' => $individual,
                    'family'     => null,
                    'name_fact'  => $fact,
                    'famtag'     => '',
                    'gender'     => $individual->sex(),
                ]);
            }
        }

        throw new NotFoundHttpException();
    }
528126
public function messageAction(ServerRequestInterface $request, Tree $tree, UserInterface $user): ResponseInterface
    {
        $body    = $request->get('body', '');
        $subject = $request->get('subject', '');
        $to      = $request->get('to', '');
        $url     = $request->get('url', '');

        $to_user = $this->user_service->findByUserName($to);
        $ip      = $request->getClientIp() ?? '127.0.0.1';

        if ($to_user === null || $to_user->getPreference('contactmethod') === 'none') {
            throw new AccessDeniedHttpException('Invalid contact user id');
        }

        if ($body === '' || $subject === '') {
            return redirect(route('message', [
                'body'    => $body,
                'subject' => $subject,
                'to'      => $to,
                'tree'    => $tree,
                'url'     => $url,
            ]));
        }

        if ($this->deliverMessage($tree, $user, $to_user, $subject, $body, $url, $ip)) {
            FlashMessages::addMessage(I18N::translate('The message was successfully sent to %s.', e($to_user->realName())), 'success');

            $url = $url ?: route('tree-page', ['ged' => $tree->name()]);

            return redirect($url);
        }

        FlashMessages::addMessage(I18N::translate('The message was not sent.'), 'danger');

        $redirect_url = route('contact', [
            'body'    => $body,
            'subject' => $subject,
            'to'      => $to,
            'url'     => $url,
        ]);

        return redirect($redirect_url);
    }
766014
public function postAdminDeleteAction(ServerRequestInterface $request, Tree $tree): ResponseInterface
    {
        $block_id = (int) $request->get('block_id');

        DB::table('block_setting')->where('block_id', '=', $block_id)->delete();

        DB::table('block')->where('block_id', '=', $block_id)->delete();

        $url = route('module', [
            'module' => $this->name(),
            'action' => 'Admin',
            'ged'    => $tree->name(),
        ]);

        return redirect($url);
    }
41401
public function linkMediaToSource(ServerRequestInterface $request, Tree $tree): ResponseInterface
    {
        $xref = $request->get('xref', '');

        $media = Media::getInstance($xref, $tree);

        return response(view('modals/link-media-to-source', [
            'media' => $media,
            'tree'  => $tree,
        ]));
    }
1290106
public function getAddMediaAction(ServerRequestInterface $request, Tree $tree): ResponseInterface
    {
        $xref = $request->get('xref', '');

        $media = Media::getInstance($xref, $tree);

        if ($media === null) {
            throw new MediaNotFoundException();
        }

        $options = $this->mediaOptions($media);

        $title = I18N::translate('Add %s to the clippings cart', $media->fullName());

        return $this->viewResponse('modules/clippings/add-options', [
            'options' => $options,
            'default' => key($options),
            'record'  => $media,
            'title'   => $title,
            'tree'    => $tree,
        ]);
    }
1224381
public function exportClient(ServerRequestInterface $request, Tree $tree): ResponseInterface
    {
        // Validate user parameters
        $convert          = (bool) $request->get('convert');
        $zip              = (bool) $request->get('zip');
        $media            = (bool) $request->get('media');
        $media_path       = $request->get('media-path', '');
        $privatize_export = $request->get('privatize_export', '');

        $access_levels = [
            'gedadmin' => Auth::PRIV_NONE,
            'user'     => Auth::PRIV_USER,
            'visitor'  => Auth::PRIV_PRIVATE,
            'none'     => Auth::PRIV_HIDE,
        ];

        $access_level = $access_levels[$privatize_export];
        $encoding     = $convert ? 'ANSI' : 'UTF-8';

        // What to call the downloaded file
        $download_filename = $tree->name();
        if (strtolower(substr($download_filename, -4, 4)) !== '.ged') {
            $download_filename .= '.ged';
        }

        if ($zip || $media) {
            // Export the GEDCOM to an in-memory stream.
            $tmp_stream = tmpfile();
            FunctionsExport::exportGedcom($tree, $tmp_stream, $access_level, $media_path, $encoding);
            rewind($tmp_stream);

            // Create a new/empty .ZIP file
            $temp_zip_file  = tempnam(sys_get_temp_dir(), 'webtrees-zip-');
            $zip_filesystem = new Filesystem(new ZipArchiveAdapter($temp_zip_file));
            $zip_filesystem->writeStream($download_filename, $tmp_stream);

            if ($media) {
                $rows = DB::table('media')
                    ->where('m_file', '=', $tree->id())
                    ->get();

                $path = $tree->getPreference('MEDIA_DIRECTORY');

                foreach ($rows as $row) {
                    $record = Media::getInstance($row->m_id, $tree, $row->m_gedcom);
                    if ($record->canShow()) {
                        foreach ($record->mediaFiles() as $media_file) {
                            if (file_exists($media_file->getServerFilename())) {
                                $fp = fopen($media_file->getServerFilename(), 'rb');
                                $zip_filesystem->writeStream($path . $media_file->filename(), $fp);
                                fclose($fp);
                            }
                        }
                    }
                }
            }

            // The ZipArchiveAdapter may or may not close the stream.
            if (is_resource($tmp_stream)) {
                fclose($tmp_stream);
            }

            // Need to force-close the filesystem
            unset($zip_filesystem);

            // Use a stream, so that we do not have to load the entire file into memory.
            $stream   = app(StreamFactoryInterface::class)->createStreamFromFile($temp_zip_file);
            $filename = addcslashes($download_filename, '"') . '.zip';

            return response()
                ->withBody($stream)
                ->withHeader('Content-Type', 'application/zip')
                ->withHeader('Content-Disposition', 'attachment; filename="' . $filename . '"');
        }

        $resource = fopen('php://temp', 'wb+');
        FunctionsExport::exportGedcom($tree, $resource, $access_level, $media_path, $encoding);
        rewind($resource);

        $charset = $convert ? 'ISO-8859-1' : 'UTF-8';

        /** @var StreamFactoryInterface $response_factory */
        $stream_factory = app(StreamFactoryInterface::class);

        $stream = $stream_factory->createStreamFromStream($resource);

        /** @var ResponseFactoryInterface $response_factory */
        $response_factory = app(ResponseFactoryInterface::class);

        return $response_factory->createResponse()
            ->withBody($stream)
            ->withHeader('Content-Type', 'text/x-gedcom; charset=' . $charset)
            ->withHeader('Content-Disposition', 'attachment; filename="' . addcslashes($download_filename, '"') . '"');
    }
687011
public function places(ServerRequestInterface $request, Tree $tree): ResponseInterface
    {
        $search  = $request->get('search', '');
        $replace = $request->get('replace', '');

        if ($search !== '' && $replace !== '') {
            $changes = $this->changePlacesPreview($tree, $search, $replace);
        } else {
            $changes = [];
        }

        /* I18N: Renumber the records in a family tree */
        $title = I18N::translate('Update place names') . ' — ' . e($tree->title());

        return $this->viewResponse('admin/trees-places', [
            'changes' => $changes,
            'replace' => $replace,
            'search'  => $search,
            'title'   => $title,
        ]);
    }
312861
public function step(ServerRequestInterface $request, ?Tree $tree): ResponseInterface
    {
        $step = $request->getQueryParams()['step'] ?? self::STEP_CHECK;

        switch ($step) {
            case self::STEP_CHECK:
                return $this->wizardStepCheck();

            case self::STEP_PREPARE:
                return $this->wizardStepPrepare();

            case self::STEP_PENDING:
                return $this->wizardStepPending();

            case self::STEP_EXPORT:
                if ($tree === null) {
                    throw new RuntimeException('Exporting a non-existant tree?');
                }

                return $this->wizardStepExport($tree);

            case self::STEP_DOWNLOAD:
                return $this->wizardStepDownload();

            case self::STEP_UNZIP:
                return $this->wizardStepUnzip();

            case self::STEP_COPY:
                return $this->wizardStepCopy();

            case self::STEP_CLEANUP:
                return $this->wizardStepCleanup();
        }

        throw new NotFoundHttpException();
    }
1304069
public function addSpouse(ServerRequestInterface $request, Tree $tree): ResponseInterface
    {
        $xref = $request->get('xref', '');

        $individual = Individual::getInstance($xref, $tree);

        Auth::checkIndividualAccess($individual, true);

        if ($individual->sex() === 'F') {
            $title  = $individual->fullName() . ' - ' . I18N::translate('Add a husband');
            $famtag = 'HUSB';
            $gender = 'M';
        } else {
            $title  = $individual->fullName() . ' - ' . I18N::translate('Add a wife');
            $famtag = 'WIFE';
            $gender = 'F';
        }

        return $this->viewResponse('edit/new-individual', [
            'tree'       => $tree,
            'title'      => $title,
            'nextaction' => 'add_spouse_to_individual_action',
            'individual' => $individual,
            'family'     => null,
            'name_fact'  => null,
            'famtag'     => $famtag,
            'gender'     => $gender,
        ]);
    }
102773
public function calendar(ServerRequestInterface $request, Tree $tree): ResponseInterface
    {
        $CALENDAR_FORMAT = $tree->getPreference('CALENDAR_FORMAT');

        $cal      = $request->getQueryParams()['cal'] ?? '';
        $day      = $request->getQueryParams()['day'] ?? '';
        $month    = $request->getQueryParams()['month'] ?? '';
        $year     = $request->getQueryParams()['year'] ?? '';
        $view     = $request->getQueryParams()['view'] ?? 'day';
        $filterev = $request->getQueryParams()['filterev'] ?? 'BIRT-MARR-DEAT';
        $filterof = $request->getQueryParams()['filterof'] ?? 'all';
        $filtersx = $request->getQueryParams()['filtersx'] ?? '';

        if ($cal . $day . $month . $year === '') {
            // No date specified? Use the most likely calendar
            $cal = $this->localization_service->calendar()->gedcomCalendarEscape();
        }

        // Create a CalendarDate from the parameters

        // We cannot display new-style/old-style years, so convert to new style
        if (preg_match('/^(\d\d)\d\d\/(\d\d)$/', $year, $match)) {
            $year = $match[1] . $match[2];
        }

        // advanced-year "year range"
        if (preg_match('/^(\d+)-(\d+)$/', $year, $match)) {
            if (strlen($match[1]) > strlen($match[2])) {
                $match[2] = substr($match[1], 0, strlen($match[1]) - strlen($match[2])) . $match[2];
            }
            $ged_date = new Date("FROM {$cal} {$match[1]} TO {$cal} {$match[2]}");
            $view     = 'year';
        } elseif (preg_match('/^(\d+)(\?+)$/', $year, $match)) {
            // advanced-year "decade/century wildcard"
            $y1       = $match[1] . str_replace('?', '0', $match[2]);
            $y2       = $match[1] . str_replace('?', '9', $match[2]);
            $ged_date = new Date("FROM {$cal} {$y1} TO {$cal} {$y2}");
            $view     = 'year';
        } else {
            if ($year < 0) {
                $year = (-$year) . ' B.C.';
            } // need BC to parse date
            $ged_date = new Date("{$cal} {$day} {$month} {$year}");
        }
        $cal_date = $ged_date->minimumDate();

        // Fill in any missing bits with todays date
        $today = $cal_date->today();
        if ($cal_date->day === 0) {
            $cal_date->day = $today->day;
        }
        if ($cal_date->month === 0) {
            $cal_date->month = $today->month;
        }
        if ($cal_date->year === 0) {
            $cal_date->year = $today->year;
        }

        $cal_date->setJdFromYmd();

        // Extract values from date
        $days_in_month = $cal_date->daysInMonth();
        $days_in_week  = $cal_date->daysInWeek();

        // Invalid dates? Go to monthly view, where they'll be found.
        if ($cal_date->day > $days_in_month && $view === 'day') {
            $view = 'month';
        }

        /** @var Fact[]|Fact[][] $found_facts */
        $found_facts = [];

        switch ($view) {
            case 'day':
                $found_facts = $this->applyFilter($this->calendar_service->getAnniversaryEvents($cal_date->minimumJulianDay(), $filterev, $tree), $filterof, $filtersx);
                break;
            case 'month':
                $cal_date->day = 0;
                $cal_date->setJdFromYmd();
                // Make a separate list for each day. Unspecified/invalid days go in day 0.
                for ($d = 0; $d <= $days_in_month; ++$d) {
                    $found_facts[$d] = [];
                }
                // Fetch events for each day
                $jds = range($cal_date->minimumJulianDay(), $cal_date->maximumJulianDay());

                foreach ($jds as $jd) {
                    foreach ($this->applyFilter($this->calendar_service->getAnniversaryEvents($jd, $filterev, $tree), $filterof, $filtersx) as $fact) {
                        $tmp = $fact->date()->minimumDate();
                        if ($tmp->day >= 1 && $tmp->day <= $tmp->daysInMonth()) {
                            // If the day is valid (for its own calendar), display it in the
                            // anniversary day (for the display calendar).
                            $found_facts[$jd - $cal_date->minimumJulianDay() + 1][] = $fact;
                        } else {
                            // Otherwise, display it in the "Day not set" box.
                            $found_facts[0][] = $fact;
                        }
                    }
                }
                break;
            case 'year':
                $cal_date->month = 0;
                $cal_date->setJdFromYmd();
                $found_facts = $this->applyFilter($this->calendar_service->getCalendarEvents($ged_date->minimumJulianDay(), $ged_date->maximumJulianDay(), explode('-', $filterev), $tree), $filterof, $filtersx);
                // Eliminate duplicates (e.g. BET JUL 1900 AND SEP 1900 will appear twice in 1900)
                $found_facts = array_unique($found_facts);
                break;
        }

        // Group the facts by family/individual
        $indis     = [];
        $fams      = [];
        $cal_facts = [];

        switch ($view) {
            case 'year':
            case 'day':
                foreach ($found_facts as $fact) {
                    $record = $fact->record();
                    $xref   = $record->xref();
                    if ($record instanceof Individual) {
                        if (empty($indis[$xref])) {
                            $indis[$xref] = $this->calendarFactText($fact, true);
                        } else {
                            $indis[$xref] .= '<br>' . $this->calendarFactText($fact, true);
                        }
                    } elseif ($record instanceof Family) {
                        if (empty($indis[$xref])) {
                            $fams[$xref] = $this->calendarFactText($fact, true);
                        } else {
                            $fams[$xref] .= '<br>' . $this->calendarFactText($fact, true);
                        }
                    }
                }
                break;
            case 'month':
                foreach ($found_facts as $d => $facts) {
                    $cal_facts[$d] = [];
                    foreach ($facts as $fact) {
                        $xref = $fact->record()->xref();
                        if (empty($cal_facts[$d][$xref])) {
                            $cal_facts[$d][$xref] = $this->calendarFactText($fact, false);
                        } else {
                            $cal_facts[$d][$xref] .= '<br>' . $this->calendarFactText($fact, false);
                        }
                    }
                }
                break;
        }

        ob_start();

        switch ($view) {
            case 'year':
            case 'day':
                echo '<table class="w-100"><tr>';
                echo '<td class="descriptionbox center"><i class="icon-indis"></i>', I18N::translate('Individuals'), '</td>';
                echo '<td class="descriptionbox center"><i class="icon-cfamily"></i>', I18N::translate('Families'), '</td>';
                echo '</tr><tr>';
                echo '<td class="optionbox wrap">';

                $content = $this->calendarListText($indis, '<li>', '</li>', $tree);
                if ($content) {
                    echo '<ul>', $content, '</ul>';
                }

                echo '</td>';
                echo '<td class="optionbox wrap">';

                $content = $this->calendarListText($fams, '<li>', '</li>', $tree);
                if ($content) {
                    echo '<ul>', $content, '</ul>';
                }

                echo '</td>';
                echo '</tr><tr>';
                echo '<td class="descriptionbox">', I18N::translate('Total individuals: %s', I18N::number(count($indis))), '</td>';
                echo '<td class="descriptionbox">', I18N::translate('Total families: %s', I18N::number(count($fams))), '</td>';
                echo '</tr></table>';

                break;
            case 'month':
                // We use JD%7 = 0/Mon…6/Sun. Standard definitions use 0/Sun…6/Sat.
                $week_start    = (I18N::firstDay() + 6) % 7;
                $weekend_start = ($this->localization_service->weekendStart() + 6) % 7;
                $weekend_end   = ($this->localization_service->weekendEnd() + 6) % 7;
                // The french  calendar has a 10-day week, which starts on primidi
                if ($days_in_week === 10) {
                    $week_start    = 0;
                    $weekend_start = -1;
                    $weekend_end   = -1;
                }
                echo '<table class="w-100"><thead><tr>';
                for ($week_day = 0; $week_day < $days_in_week; ++$week_day) {
                    $day_name = $cal_date->dayNames(($week_day + $week_start) % $days_in_week);
                    if ($week_day == $weekend_start || $week_day == $weekend_end) {
                        echo '<th class="descriptionbox weekend" width="' . (100 / $days_in_week) . '%">', $day_name, '</th>';
                    } else {
                        echo '<th class="descriptionbox" width="' . (100 / $days_in_week) . '%">', $day_name, '</th>';
                    }
                }
                echo '</tr>';
                echo '</thead>';
                echo '<tbody>';
                // Print days 1 to n of the month, but extend to cover "empty" days before/after the month to make whole weeks.
                // e.g. instead of 1 -> 30 (=30 days), we might have -1 -> 33 (=35 days)
                $start_d = 1 - ($cal_date->minimumJulianDay() - $week_start) % $days_in_week;
                $end_d   = $days_in_month + ($days_in_week - ($cal_date->maximumJulianDay() - $week_start + 1) % $days_in_week) % $days_in_week;
                // Make sure that there is an empty box for any leap/missing days
                if ($start_d === 1 && $end_d === $days_in_month && count($found_facts[0]) > 0) {
                    $end_d += $days_in_week;
                }
                for ($d = $start_d; $d <= $end_d; ++$d) {
                    if (($d + $cal_date->minimumJulianDay() - $week_start) % $days_in_week === 1) {
                        echo '<tr>';
                    }
                    echo '<td class="optionbox wrap">';
                    if ($d < 1 || $d > $days_in_month) {
                        if (count($cal_facts[0]) > 0) {
                            echo '<span class="cal_day">', I18N::translate('Day not set'), '</span><br style="clear: both;">';
                            echo '<div class="details1" style="height: 180px; overflow: auto;">';
                            echo $this->calendarListText($cal_facts[0], '', '', $tree);
                            echo '</div>';
                            $cal_facts[0] = [];
                        }
                    } else {
                        // Format the day number using the calendar
                        $tmp   = new Date($cal_date->format("%@ {$d} %O %E"));
                        $d_fmt = $tmp->minimumDate()->format('%j');
                        if ($d === $today->day && $cal_date->month === $today->month) {
                            echo '<span class="cal_day current_day">', $d_fmt, '</span>';
                        } else {
                            echo '<span class="cal_day">', $d_fmt, '</span>';
                        }
                        // Show a converted date
                        foreach (explode('_and_', $CALENDAR_FORMAT) as $convcal) {
                            switch ($convcal) {
                                case 'french':
                                    $alt_date = new FrenchDate($cal_date->minimumJulianDay() + $d - 1);
                                    break;
                                case 'gregorian':
                                    $alt_date = new GregorianDate($cal_date->minimumJulianDay() + $d - 1);
                                    break;
                                case 'jewish':
                                    $alt_date = new JewishDate($cal_date->minimumJulianDay() + $d - 1);
                                    break;
                                case 'julian':
                                    $alt_date = new JulianDate($cal_date->minimumJulianDay() + $d - 1);
                                    break;
                                case 'hijri':
                                    $alt_date = new HijriDate($cal_date->minimumJulianDay() + $d - 1);
                                    break;
                                case 'jalali':
                                    $alt_date = new JalaliDate($cal_date->minimumJulianDay() + $d - 1);
                                    break;
                                case 'none':
                                default:
                                    $alt_date = $cal_date;
                                    break;
                            }
                            if (get_class($alt_date) !== get_class($cal_date) && $alt_date->inValidRange()) {
                                echo '<span class="rtl_cal_day">' . $alt_date->format('%j %M') . '</span>';
                                // Just show the first conversion
                                break;
                            }
                        }
                        echo '<br style="clear: both;"><div class="details1" style="height: 180px; overflow: auto;">';
                        echo $this->calendarListText($cal_facts[$d], '', '', $tree);
                        echo '</div>';
                    }
                    echo '</td>';
                    if (($d + $cal_date->minimumJulianDay() - $week_start) % $days_in_week === 0) {
                        echo '</tr>';
                    }
                }
                echo '</tbody>';
                echo '</table>';
                break;
        }

        $html = ob_get_clean();

        return response($html);
    }
522262
public function contactAction(ServerRequestInterface $request, Tree $tree): ResponseInterface
    {
        $body       = $request->get('body', '');
        $from_email = $request->get('from_email', '');
        $from_name  = $request->get('from_name', '');
        $subject    = $request->get('subject', '');
        $to         = $request->get('to', '');
        $url        = $request->get('url', '');
        $ip         = $request->getClientIp() ?? '127.0.0.1';

        $to_user = $this->user_service->findByUserName($to);

        if ($to_user === null) {
            throw new NotFoundHttpException();
        }

        if (!in_array($to_user, $this->validContacts($tree), false)) {
            throw new AccessDeniedHttpException('Invalid contact user id');
        }

        $errors = $body === '' || $subject === '' || $from_email === '' || $from_name === '';

        if (!preg_match('/^[^@]+@([^@]+)$/', $from_email, $match) || !checkdnsrr($match[1])) {
            FlashMessages::addMessage(I18N::translate('Please enter a valid email address.'), 'danger');
            $errors = true;
        }

        if (preg_match('/(?!' . preg_quote(WT_BASE_URL, '/') . ')(((?:ftp|http|https):\/\/)[a-zA-Z0-9.-]+)/', $subject . $body, $match)) {
            FlashMessages::addMessage(I18N::translate('You are not allowed to send messages that contain external links.') . ' ' . /* I18N: e.g. ‘You should delete the “http://” from “http://www.example.com” and try again.’ */
                I18N::translate('You should delete the “%1$s” from “%2$s” and try again.', $match[2], $match[1]), 'danger');
            $errors = true;
        }

        if ($errors) {
            return redirect(route('contact', [
                'body'       => $body,
                'from_email' => $from_email,
                'from_name'  => $from_name,
                'subject'    => $subject,
                'to'         => $to,
                'tree'       => $tree,
                'url'        => $url,
            ]));
        }

        $sender = new GuestUser($from_email, $from_name);

        if ($this->deliverMessage($tree, $sender, $to_user, $subject, $body, $url, $ip)) {
            FlashMessages::addMessage(I18N::translate('The message was successfully sent to %s.', e($to_user->realName())), 'success');

            $url = $url ?: route('tree-page', ['ged' => $tree->name()]);

            return redirect($url);
        }

        FlashMessages::addMessage(I18N::translate('The message was not sent.'), 'danger');

        $redirect_url = route('contact', [
            'body'       => $body,
            'from_email' => $from_email,
            'from_name'  => $from_name,
            'subject'    => $subject,
            'to'         => $to,
            'url'        => $url,
        ]);

        return redirect($redirect_url);
    }
507086
public function getListAction(ServerRequestInterface $request, Tree $tree, UserInterface $user): ResponseInterface
    {
        Auth::checkComponentAccess($this, 'list', $tree, $user);
      
        $listController = new BranchesController(app(ModuleService::class));
        return $listController->list($request, $tree, $user);
    }
478158
public function place(ServerRequestInterface $request, Tree $tree): ResponseInterface
    {
        $query = $request->get('query', '');
        $data  = [];

        foreach ($this->search_service->searchPlaces($tree, $query) as $place) {
            $data[] = ['value' => $place->gedcomName()];
        }

        if (empty($data) && $tree->getPreference('GEONAMES_ACCOUNT')) {
            // No place found? Use an external gazetteer
            $url =
                'http://api.geonames.org/searchJSON' .
                '?name_startsWith=' . urlencode($query) .
                '&lang=' . WT_LOCALE .
                '&fcode=CMTY&fcode=ADM4&fcode=PPL&fcode=PPLA&fcode=PPLC' .
                '&style=full' .
                '&username=' . $tree->getPreference('GEONAMES_ACCOUNT');

            // try to use curl when file_get_contents not allowed
            if (ini_get('allow_url_fopen')) {
                $json = file_get_contents($url);
            } elseif (function_exists('curl_init')) {
                $ch = curl_init();
                curl_setopt($ch, CURLOPT_URL, $url);
                curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
                $json = curl_exec($ch);
                curl_close($ch);
            } else {
                return response([]);
            }

            $places = json_decode($json, true);
            if (isset($places['geonames']) && is_array($places['geonames'])) {
                foreach ($places['geonames'] as $k => $place) {
                    $data[] = ['value' => $place['name'] . ', ' . $place['adminName2'] . ', ' . $place['adminName1'] . ', ' . $place['countryName']];
                }
            }
        }

        return response($data);
    }
565146
public function show(ServerRequestInterface $request, Tree $tree): ResponseInterface
    {
        $xref   = $request->get('xref', '');
        $record = GedcomRecord::getInstance($xref, $tree);

        Auth::checkRecordAccess($record);

        if ($this->hasCustomPage($record)) {
            return redirect($record->url());
        }

        return $this->viewResponse('gedcom-record-page', [
            'facts'         => $record->facts(),
            'families'      => $record->linkedFamilies($record::RECORD_TYPE),
            'individuals'   => $record->linkedIndividuals($record::RECORD_TYPE),
            'meta_robots'   => 'index,follow',
            'notes'         => $record->linkedNotes($record::RECORD_TYPE),
            'media_objects' => $record->linkedMedia($record::RECORD_TYPE),
            'record'        => $record,
            'sources'       => $record->linkedSources($record::RECORD_TYPE),
            'title'         => $record->fullName(),
        ]);
    }
1086915
public function create(ServerRequestInterface $request): ResponseInterface
    {
        $tree_name  = $request->get('tree_name', '');
        $tree_title = $request->get('tree_title', '');

        // We use the tree name as a file name, so no directory separators allowed.
        $tree_name = basename($tree_name);

        if (Tree::findByName($tree_name)) {
            FlashMessages::addMessage(I18N::translate('The family tree “%s” already exists.', e($tree_name)), 'danger');

            $url = route('admin-trees');
        } else {
            $tree = Tree::create($tree_name, $tree_title);
            FlashMessages::addMessage(I18N::translate('The family tree “%s” has been created.', e($tree->name())), 'success');

            $url = route('admin-trees', ['ged' => $tree->name()]);
        }

        return redirect($url);
    }
220681
public function treePageBlock(ServerRequestInterface $request, Tree $tree): ResponseInterface
    {
        $block_id = $request->get('block_id');

        $block_id = (int) DB::table('block')
            ->where('block_id', '=', $block_id)
            ->where('gedcom_id', '=', $tree->id())
            ->value('block_id');

        $module = $this->getBlockModule($tree, $block_id);

        $html = view('layouts/ajax', [
            'content' => $module->getBlock($tree, $block_id, 'gedcom'),
        ]);

        return response($html);
    }