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

Freegle / Iznik / 11495

09 May 2026 07:35AM UTC coverage: 69.06% (-3.8%) from 72.847%
11495

Pull #408

circleci

edwh
docs(migration): mark restartproject and repaircafewales as migrated (PR #408)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Pull Request #408: feat(batch): migrate check_cgas, visualise, tn_sync + dry-run improvements

9127 of 10554 branches covered (86.48%)

Branch coverage included in aggregate %.

507 of 663 new or added lines in 16 files covered. (76.47%)

11902 existing lines in 138 files now uncovered.

101630 of 149824 relevant lines covered (67.83%)

19.56 hits per line

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

82.18
/iznik-batch/app/Services/RepairCafeWalesService.php
1
<?php
2

3
namespace App\Services;
4

5
use App\Models\Location;
6
use App\Models\Group;
7
use ICal\ICal;
8
use Illuminate\Support\Facades\Log;
9

10
class RepairCafeWalesService
11
{
12
    private const DAYS_AHEAD = 31;
13
    private const POSTCODE   = '/([Gg][Ii][Rr] 0[Aa]{2})|((([A-Za-z][0-9]{1,2})|(([A-Za-z][A-Ha-hJ-Yj-y][0-9]{1,2})|(([A-Za-z][0-9][A-Za-z])|([A-Za-z][A-Ha-hJ-Yj-y][0-9][A-Za-z]?))))\s?[0-9][A-Za-z]{2})/mi';
14

15
    public function __construct(private CommunityEventService $events) {}
5✔
16

NEW
17
    protected function icalUrl(): string
×
18
    {
NEW
19
        return 'https://repaircafewales.org/events/list/?ical=1';
×
20
    }
21

22
    public function sync(bool $dryRun = false): array
5✔
23
    {
24
        $added         = 0;
5✔
25
        $updated       = 0;
5✔
26
        $deleted       = 0;
5✔
27
        $now           = date('Y-m-d');
5✔
28
        $rangeEnd      = date('Y-m-d 23:59:59', strtotime('+' . self::DAYS_AHEAD . ' days'));
5✔
29
        $externalsSeen = [];
5✔
30

31
        try {
32
            $ical = new ICal(options: [
5✔
33
                'defaultSpan'                 => 2,
5✔
34
                'defaultTimeZone'             => 'UTC',
5✔
35
                'disableCharacterReplacement' => false,
5✔
36
                'filterDaysAfter'             => self::DAYS_AHEAD,
5✔
37
                'filterDaysBefore'            => 0,
5✔
38
                'skipRecurrence'              => false,
5✔
39
            ]);
5✔
40
            $ical->initUrl($this->icalUrl());
5✔
NEW
41
        } catch (\Exception $e) {
×
NEW
42
            Log::error('RepairCafeWales: failed to fetch iCal feed', ['error' => $e->getMessage()]);
×
NEW
43
            return ['added' => $added, 'updated' => $updated, 'deleted' => $deleted];
×
44
        }
45

46
        $icalEvents = $ical->eventsFromRange($now . ' 00:00:00', $rangeEnd);
5✔
47

48
        if (empty($icalEvents)) {
5✔
49
            Log::warning('RepairCafeWales: no events in feed');
1✔
50
        }
51

52
        foreach ($icalEvents as $event) {
5✔
53
            $externalId            = $event->uid;
4✔
54
            $externalsSeen[$externalId] = true;
4✔
55

56
            $title       = $event->summary ?? '';
4✔
57
            $description = $event->description ?? '';
4✔
58
            $location    = $event->location ?? '';
4✔
59
            $url         = $event->url ?? null;
4✔
60

61
            $start = $ical->iCalDateToDateTime($event->dtstart_array[3])->format('Y-m-d H:i:s');
4✔
62
            $end   = $ical->iCalDateToDateTime($event->dtend_array[3])->format('Y-m-d H:i:s');
4✔
63

64
            if (!preg_match(self::POSTCODE, $location, $matches)) {
4✔
65
                Log::debug('RepairCafeWales: no postcode in location', ['location' => $location]);
1✔
66
                continue;
1✔
67
            }
68

69
            $postcode = strtoupper(trim($matches[0]));
3✔
70
            $locRow = Location::getByName($postcode);
3✔
71

72
            if (!$locRow) {
3✔
NEW
73
                Log::debug('RepairCafeWales: postcode not found', ['postcode' => $postcode]);
×
NEW
74
                continue;
×
75
            }
76

77
            $groupIds = Location::groupsNear((float) $locRow->lat, (float) $locRow->lng, 15);
3✔
78

79
            if (empty($groupIds)) {
3✔
NEW
80
                Log::debug('RepairCafeWales: no groups near postcode', ['postcode' => $postcode]);
×
NEW
81
                continue;
×
82
            }
83

84
            $freegleGroup = Group::find($groupIds[0]);
3✔
85
            if (!$freegleGroup) {
3✔
NEW
86
                continue;
×
87
            }
88

89
            if (!$freegleGroup->getSetting('communityevents', 1)) {
3✔
NEW
90
                Log::debug('RepairCafeWales: communityevents disabled', ['group' => $freegleGroup->nameshort]);
×
NEW
91
                continue;
×
92
            }
93

94
            $existing = $this->events->findByExternalId($externalId);
3✔
95

96
            if ($existing) {
3✔
97
                if ($dryRun) {
1✔
NEW
98
                    Log::debug('RepairCafeWales: dry run — would update', ['external_id' => $externalId]);
×
NEW
99
                    $updated++;
×
NEW
100
                    continue;
×
101
                }
102

103
                $pendingFlag = $existing->title !== $title ||
1✔
104
                               $existing->location !== $location ||
1✔
105
                               $existing->description !== $description;
1✔
106

107
                $updateData = [
1✔
108
                    'title'       => $title,
1✔
109
                    'location'    => $location,
1✔
110
                    'description' => $description,
1✔
111
                    'contacturl'  => $url,
1✔
112
                ];
1✔
113

114
                if ($pendingFlag && !$existing->pending) {
1✔
115
                    $updateData['pending'] = 1;
1✔
116
                }
117

118
                $this->events->updateEvent($existing->id, $updateData);
1✔
119
                $this->events->removeDates($existing->id);
1✔
120
                $this->events->addDate($existing->id, $start, $end);
1✔
121
                $updated++;
1✔
122
            } else {
123
                if ($dryRun) {
2✔
124
                    Log::debug('RepairCafeWales: dry run — would create', ['external_id' => $externalId]);
1✔
125
                    $added++;
1✔
126
                    continue;
1✔
127
                }
128

129
                $eid = $this->events->createEvent(
1✔
130
                    null,
1✔
131
                    $title,
1✔
132
                    $location,
1✔
133
                    null,
1✔
134
                    null,
1✔
135
                    null,
1✔
136
                    $url,
1✔
137
                    $description,
1✔
138
                    $externalId
1✔
139
                );
1✔
140

141
                $this->events->addGroup($eid, $groupIds[0]);
1✔
142
                $this->events->addDate($eid, $start, $end);
1✔
143
                $added++;
1✔
144
            }
145
        }
146

147
        $existings = $this->events->getUpcomingByExternalIdSubstring('repaircafewales', $now);
5✔
148
        foreach ($existings as $e) {
5✔
149
            if (!array_key_exists($e->externalid, $externalsSeen)) {
3✔
150
                if ($dryRun) {
1✔
NEW
151
                    Log::debug('RepairCafeWales: dry run — would delete', ['external_id' => $e->externalid]);
×
NEW
152
                    $deleted++;
×
NEW
153
                    continue;
×
154
                }
155
                $this->events->markDeleted($e->id);
1✔
156
                $deleted++;
1✔
157
            }
158
        }
159

160
        return ['added' => $added, 'updated' => $updated, 'deleted' => $deleted];
5✔
161
    }
162
}
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