• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

ericfortmeyer / activity-log / 20521974594

26 Dec 2025 11:53AM UTC coverage: 43.123% (-6.0%) from 49.13%
20521974594

push

github

web-flow
feat: add webhook for deployments (#63)

Signed-off-by: Eric Fortmeyer <e.fortmeyer01@gmail.com>

11 of 128 new or added lines in 13 files covered. (8.59%)

1 existing line in 1 file now uncovered.

348 of 807 relevant lines covered (43.12%)

1.33 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

0.0
/src/Http/RequestProcessors/EmailReportForMonth.php
1
<?php
2

3
declare(strict_types=1);
4

5
namespace EricFortmeyer\ActivityLog\Http\RequestProcessors;
6

7
use EricFortmeyer\ActivityLog\{
8
    CreditHours,
9
    TimeEntry,
10
    EmailConfig,
11
    MonthFilters,
12
    RemarksForMonth,
13
    EmailReport
14
};
15
use EricFortmeyer\ActivityLog\UserInterface\Contexts\TimeEntriesContext;
16
use EricFortmeyer\ActivityLog\Services\{
17
    TimeEntryService,
18
    RemarksForMonthService,
19
    CreditHoursService,
20
    TemplateBinder,
21
};
22
use EricFortmeyer\ActivityLog\UserInterface\Contexts\EmailReportContext;
23
use EricFortmeyer\ActivityLog\UserInterface\Contexts\ServerErrorContext;
24
use EricFortmeyer\ActivityLog\Utils\Hasher;
25
use Phpolar\Model\Model;
26
use Phpolar\Phpolar\Auth\Authorize;
27
use Phpolar\PurePhp\HtmlSafeContext;
28
use Phpolar\Storage\NotFound;
29

30
final class EmailReportForMonth extends AbstractTenantBasedRequestProcessor
31
{
32
    public function __construct(
33
        private readonly string $appVersion,
34
        private readonly EmailConfig $mailConfig,
35
        private readonly TimeEntryService $timeEntryService,
36
        private readonly RemarksForMonthService $remarksService,
37
        private readonly CreditHoursService $creditHoursService,
38
        private readonly TemplateBinder $templateEngine,
39
        readonly Hasher $hasher,
40
    ) {
41
        parent::__construct($hasher);
×
42
    }
43

44
    #[Authorize]
45
    public function process(
46
        #[Model] EmailReport $emailReport = new EmailReport(),
47
        #[Model] MonthFilters $monthFilters = new MonthFilters(),
48
    ): string {
49
        $month = $emailReport->month;
×
50
        $year = $emailReport->year;
×
51
        $timeEntries = $this->timeEntryService->getAllByMonth(
×
52
            month: $month,
×
53
            year: $year,
×
54
            tenantId: $this->getTenantId(),
×
55
        );
×
56
        $remarks = $this->remarksService->get(RemarksForMonth::getIdFromMonth(
×
57
            month: $month,
×
58
            year: $year,
×
59
            tenantId: $this->getTenantId(),
×
60
        ));
×
61
        $creditHours = $this->creditHoursService->get(CreditHours::getIdFromMonth(
×
62
            month: $month,
×
63
            year: $year,
×
64
            tenantId: $this->getTenantId(),
×
65
        ));
×
66
        $currentEntry = new TimeEntry();
×
67
        TimeEntry::setUninitializedValues(
×
68
            $currentEntry,
×
69
            $month,
×
70
            $year,
×
71
        );
×
72

73
        if ($emailReport->isValid() === true) {
×
74
            $success = mail(
×
75
                to: $emailReport->mailTo,
×
76
                subject: $emailReport->getSubject($this->user),
×
77
                message: $this->templateEngine->apply(
×
78
                    "email-report",
×
79
                    new EmailReportContext(
×
80
                        emailReport: $emailReport,
×
81
                        timeEntries: $timeEntries,
×
82
                        currentEntry: $currentEntry,
×
83
                        filters: $monthFilters,
×
84
                        remarks: $remarks,
×
85
                        creditHours: $creditHours,
×
86
                    ),
×
87
                ),
×
88
                additional_headers: $this->mailConfig->headers,
×
89
            );
×
90

91
            if ($success === false) {
×
92
                $error = error_get_last();
×
93
                if ($error !== null) {
×
94
                    ["message" => $message] = $error;
×
95
                    return $this->templateEngine->apply(
×
96
                        "500",
×
97
                        new HtmlSafeContext(
×
98
                            new ServerErrorContext(
×
99
                                message: $message,
×
100
                            ),
×
101
                        ),
×
102
                    );
×
103
                }
104
            }
105

106
            $emailReport->isPosted();
×
107
        }
108

109

110
        return $this->templateEngine->apply(
×
111
            "index",
×
112
            $this->getContext(
×
113
                currentEntry: $currentEntry,
×
114
                timeEntries: $timeEntries,
×
115
                monthFilters: $monthFilters,
×
116
                remarks: $remarks,
×
117
                creditHours: $creditHours,
×
118
            )
×
119
        );
×
120
    }
121

122
    /**
123
     * @param TimeEntry[] $timeEntries
124
     */
125
    private function getContext(
126
        TimeEntry $currentEntry,
127
        array $timeEntries,
128
        MonthFilters $monthFilters,
129
        RemarksForMonth| NotFound $remarks,
130
        CreditHours|NotFound $creditHours,
131
    ): TimeEntriesContext {
132
        return match (true) {
×
133
            $remarks instanceof NotFound && $creditHours instanceof NotFound =>
×
134
            new TimeEntriesContext(
×
NEW
135
                appVersion: $this->appVersion,
×
136
                currentEntry: $currentEntry,
×
137
                timeEntries: $timeEntries,
×
138
                tenantId: $this->getTenantId(),
×
139
                filters: $monthFilters,
×
140
                user: $this->user
×
141
            ),
×
142
            $creditHours instanceof CreditHours && $remarks instanceof NotFound =>
×
143
            new TimeEntriesContext(
×
NEW
144
                appVersion: $this->appVersion,
×
145
                currentEntry: $currentEntry,
×
146
                timeEntries: $timeEntries,
×
147
                tenantId: $this->getTenantId(),
×
148
                filters: $monthFilters,
×
149
                creditHours: $creditHours,
×
150
                user: $this->user
×
151
            ),
×
152
            $creditHours instanceof CreditHours && $remarks instanceof RemarksForMonth =>
×
153
            new TimeEntriesContext(
×
NEW
154
                appVersion: $this->appVersion,
×
155
                currentEntry: $currentEntry,
×
156
                timeEntries: $timeEntries,
×
157
                tenantId: $this->getTenantId(),
×
158
                filters: $monthFilters,
×
159
                remarks: $remarks,
×
160
                creditHours: $creditHours,
×
161
                user: $this->user,
×
162
            ),
×
163
            $remarks instanceof RemarksForMonth && $creditHours instanceof NotFound =>
×
164
            new TimeEntriesContext(
×
NEW
165
                appVersion: $this->appVersion,
×
166
                currentEntry: $currentEntry,
×
167
                timeEntries: $timeEntries,
×
168
                tenantId: $this->getTenantId(),
×
169
                filters: $monthFilters,
×
170
                remarks: $remarks,
×
171
                user: $this->user
×
172
            ),
×
173
            default =>
×
174
            new TimeEntriesContext(
×
NEW
175
                appVersion: $this->appVersion,
×
176
                currentEntry: $currentEntry,
×
177
                user: $this->user,
×
178
                tenantId: $this->getTenantId(),
×
179
            )
×
180
        };
×
181
    }
182
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc