Skip to content

Commit 1ddf772

Browse files
authored
Merge pull request #3295 from codeeu/dev
Dev
2 parents e7d223f + e3b07ed commit 1ddf772

File tree

1 file changed

+185
-0
lines changed

1 file changed

+185
-0
lines changed
Lines changed: 185 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,185 @@
1+
<?php
2+
3+
namespace App\Console\Commands;
4+
5+
use App\ResourceItem;
6+
use Carbon\Carbon;
7+
use Illuminate\Console\Command;
8+
9+
/**
10+
* Training resources report for https://codeweek.eu/training and related Learn & Teach resources.
11+
*
12+
* Training page: static list of MOOC modules (not in DB). Download links go directly to S3,
13+
* so download counts, geography, and top-downloaded are not available unless S3 logs are used
14+
* or a tracking redirect is implemented.
15+
*/
16+
class TrainingResourcesReport extends Command
17+
{
18+
/** Code4Europe project start – used for "added since" baseline (configurable). */
19+
private const CODE4EUROPE_START = '2024-06-01';
20+
21+
/** Number of static training modules on /training (from resources/views/static/training/index.blade.php). */
22+
private const STATIC_TRAINING_MODULES_COUNT = 22;
23+
24+
protected $signature = 'training:report
25+
{--format=text : Output format: text or json }
26+
{--baseline= : Override baseline date (Y-m-d) for "added since" }
27+
{--learn-teach-only : Only output Learn & Teach resource counts (baseline + total now) }';
28+
29+
protected $description = 'Training resources report: counts (static training modules + Learn & Teach resources), baseline vs total. Download/geography/top10 require tracking or S3 logs.';
30+
31+
public function handle(): int
32+
{
33+
$format = $this->option('format');
34+
$learnTeachOnly = $this->option('learn-teach-only');
35+
$baseline = $this->option('baseline') ? Carbon::parse($this->option('baseline')) : Carbon::parse(self::CODE4EUROPE_START);
36+
37+
if ($learnTeachOnly) {
38+
$stats = $this->learnTeachResourcesStats($baseline);
39+
if ($format === 'json') {
40+
$this->line(json_encode([
41+
'learn_teach_resources' => $stats,
42+
'generated_at' => now()->toIso8601String(),
43+
], JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES));
44+
return self::SUCCESS;
45+
}
46+
$this->line('Learn & Teach Resources (https://codeweek.eu/resources/learn-and-teach)');
47+
$this->line('Baseline date (project start): ' . $stats['baseline_date']);
48+
$this->line('Total resources now: ' . $stats['total_resources_now']);
49+
$this->line('Added since baseline: ' . $stats['added_since_baseline']);
50+
return self::SUCCESS;
51+
}
52+
53+
$report = [
54+
'generated_at' => now()->toIso8601String(),
55+
'report_period_downloads' => 'June/Sept 2024 – Jan 2026 (requested). Download data not collected by application.',
56+
'training_page' => $this->trainingPageStats(),
57+
'learn_teach_resources' => $this->learnTeachResourcesStats($baseline),
58+
'downloads' => $this->downloadsSection(),
59+
'geographical_distribution' => $this->geographySection(),
60+
'downloads_over_time' => $this->downloadsOverTimeSection(),
61+
'top_10_downloaded' => $this->top10Section(),
62+
'notes' => $this->notes(),
63+
];
64+
65+
if ($format === 'json') {
66+
$this->line(json_encode($report, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES));
67+
return self::SUCCESS;
68+
}
69+
70+
$this->printTextReport($report, $baseline);
71+
return self::SUCCESS;
72+
}
73+
74+
private function trainingPageStats(): array
75+
{
76+
return [
77+
'url' => 'https://codeweek.eu/training',
78+
'total_training_modules_now' => self::STATIC_TRAINING_MODULES_COUNT,
79+
'added_since_code4europe_baseline' => null,
80+
'note' => 'The /training page is static: modules are hardcoded in resources/views/static/training/index.blade.php. There is no DB record of when each module was added, so "added since baseline" is not available. Total count is fixed (22 modules).',
81+
];
82+
}
83+
84+
private function learnTeachResourcesStats(Carbon $baseline): array
85+
{
86+
$total = ResourceItem::query()->where('active', true)->count();
87+
$addedSince = ResourceItem::query()
88+
->where('active', true)
89+
->where('created_at', '>=', $baseline->copy()->startOfDay())
90+
->count();
91+
92+
return [
93+
'total_resources_now' => $total,
94+
'added_since_baseline' => $addedSince,
95+
'baseline_date' => $baseline->format('Y-m-d'),
96+
'note' => 'Learn & Teach resources at /resources/learn-and-teach (ResourceItem). Not the same as the static /training modules; both are "training-related" content.',
97+
];
98+
}
99+
100+
private function downloadsSection(): array
101+
{
102+
return [
103+
'total_downloads' => null,
104+
'downloads_june_sept_2024_to_jan_2026' => null,
105+
'note' => 'Training module "Download video script" and similar links point directly to S3. The application does not track clicks or downloads. To get numbers: (1) use S3 access logs for the codeweek-s3/docs/training bucket/path, or (2) add a redirect route that logs (resource/module, date, optional country) then redirects to the S3 URL.',
106+
];
107+
}
108+
109+
private function geographySection(): array
110+
{
111+
return [
112+
'top_by_country' => null,
113+
'note' => 'Geographical distribution is not tracked. To report by country: add server-side logging when users access training pages or use a download redirect that records country (e.g. from GeoIP or Accept-Language).',
114+
];
115+
}
116+
117+
private function downloadsOverTimeSection(): array
118+
{
119+
return [
120+
'downloads_over_time' => null,
121+
'peak_periods' => null,
122+
'note' => 'Not available without download tracking (or S3 log analysis).',
123+
];
124+
}
125+
126+
private function top10Section(): array
127+
{
128+
return [
129+
'top_10_downloaded_resources' => null,
130+
'note' => 'Not available without download tracking. Training modules are static (no resource_id in DB for each module); tracking would need to record by module slug or URL.',
131+
];
132+
}
133+
134+
private function notes(): array
135+
{
136+
return [
137+
'training_vs_resources' => 'The Training page (/training) lists static MOOC modules. The Learn & Teach page (/resources/learn-and-teach) lists ResourceItem records. Both can be considered "training resources" for reporting.',
138+
'code4europe_baseline' => 'Baseline for "added since" uses ' . self::CODE4EUROPE_START . '. Override with --baseline=YYYY-MM-DD.',
139+
'implementing_tracking' => 'To enable download and geography metrics: add a migration for training_downloads (e.g. module_slug, downloaded_at, country_code), replace direct S3 links with /training/download?module=... that logs and redirects, and optionally log page views for /training and each module.',
140+
];
141+
}
142+
143+
private function printTextReport(array $report, Carbon $baseline): void
144+
{
145+
$this->line('=== Training resources report ===');
146+
$this->line('Generated: ' . $report['generated_at']);
147+
$this->line('');
148+
149+
$this->line('--- Training page (https://codeweek.eu/training) ---');
150+
$this->line('Total training modules (static list): ' . $report['training_page']['total_training_modules_now']);
151+
$this->line('Added since Code4Europe baseline: not stored (static content)');
152+
$this->line($report['training_page']['note']);
153+
$this->line('');
154+
155+
$this->line('--- Learn & Teach resources (ResourceItem) ---');
156+
$this->line('Total resources now: ' . $report['learn_teach_resources']['total_resources_now']);
157+
$this->line('Added since baseline (' . $baseline->format('Y-m-d') . '): ' . $report['learn_teach_resources']['added_since_baseline']);
158+
$this->line($report['learn_teach_resources']['note']);
159+
$this->line('');
160+
161+
$this->line('--- Downloads ---');
162+
$this->line('Total number: not tracked (links go to S3).');
163+
$this->line('June/Sept 2024 – Jan 2026: not tracked.');
164+
$this->line($report['downloads']['note']);
165+
$this->line('');
166+
167+
$this->line('--- Geographical distribution / engagement ---');
168+
$this->line('Top by country: not tracked.');
169+
$this->line($report['geographical_distribution']['note']);
170+
$this->line('');
171+
172+
$this->line('--- Downloads over time / peaks ---');
173+
$this->line($report['downloads_over_time']['note']);
174+
$this->line('');
175+
176+
$this->line('--- Top 10 downloaded training resources ---');
177+
$this->line($report['top_10_downloaded']['note']);
178+
$this->line('');
179+
180+
$this->line('--- Notes ---');
181+
foreach ($report['notes'] as $key => $text) {
182+
$this->line($key . ': ' . $text);
183+
}
184+
}
185+
}

0 commit comments

Comments
 (0)