165 lines
5.0 KiB
PHP
165 lines
5.0 KiB
PHP
<?php
|
||
|
||
namespace App\Http\Controllers;
|
||
|
||
use Illuminate\Http\Request;
|
||
use Illuminate\Support\Str;
|
||
use Carbon\Carbon;
|
||
use Illuminate\Support\Facades\DB;
|
||
use App\Models\Calendar;
|
||
use App\Models\Event;
|
||
use App\Models\EventMeta;
|
||
|
||
class EventController extends Controller
|
||
{
|
||
public function create(Calendar $calendar)
|
||
{
|
||
$this->authorize('update', $calendar);
|
||
return view('events.form', ['calendar' => $calendar, 'event' => new Event]);
|
||
}
|
||
|
||
/**
|
||
* insert VEVENT into Sabre’s calendarobjects + meta row
|
||
*/
|
||
public function store(Request $req, Calendar $calendar)
|
||
{
|
||
$this->authorize('update', $calendar);
|
||
|
||
$data = $req->validate([
|
||
'title' => 'required|string|max:200',
|
||
'start_at' => 'required|date',
|
||
'end_at' => 'required|date|after:start_at',
|
||
'description' => 'nullable|string',
|
||
'location' => 'nullable|string',
|
||
'all_day' => 'sometimes|boolean',
|
||
'category' => 'nullable|string|max:50',
|
||
]);
|
||
|
||
// prepare payload
|
||
$uid = Str::uuid() . '@' . parse_url(config('app.url'), PHP_URL_HOST);
|
||
$start = new Carbon($data['start_at'], $calendar->timezone);
|
||
$end = new Carbon($data['end_at'], $calendar->timezone);
|
||
|
||
// prepare strings
|
||
$description = $data['description'] ?? '';
|
||
$location = $data['location'] ?? '';
|
||
$description = str_replace("\n", '\\n', $description);
|
||
$location = str_replace("\n", '\\n', $location);
|
||
|
||
|
||
/* build minimal iCalendar payload */
|
||
$ical = <<<ICS
|
||
BEGIN:VCALENDAR
|
||
VERSION:2.0
|
||
PRODID:-//Kithkin//Laravel CalDAV//EN
|
||
BEGIN:VEVENT
|
||
UID:$uid
|
||
DTSTAMP:{$start->utc()->format('Ymd\\THis\\Z')}
|
||
DTSTART:{$start->format('Ymd\\THis')}
|
||
DTEND:{$end->format('Ymd\\THis')}
|
||
SUMMARY:{$data['title']}
|
||
DESCRIPTION:$description
|
||
LOCATION:$location
|
||
END:VEVENT
|
||
END:VCALENDAR
|
||
|
||
ICS;
|
||
|
||
$event = Event::create([
|
||
'calendarid' => $calendar->id,
|
||
'uri' => Str::uuid() . '.ics',
|
||
'lastmodified' => time(),
|
||
'etag' => md5($ical),
|
||
'size' => strlen($ical),
|
||
'componenttype' => 'VEVENT',
|
||
'uid' => $uid,
|
||
'calendardata' => $ical,
|
||
]);
|
||
|
||
$event->meta()->create([
|
||
'title' => $data['title'],
|
||
'description' => $data['description'] ?? null,
|
||
'location' => $data['location'] ?? null,
|
||
'all_day' => $data['all_day'] ?? false,
|
||
'category' => $data['category'] ?? null,
|
||
'start_at' => $start,
|
||
'end_at' => $end,
|
||
]);
|
||
|
||
return redirect()->route('calendars.show', $calendar);
|
||
}
|
||
|
||
public function edit(Calendar $calendar, Event $event)
|
||
{
|
||
$this->authorize('update', $calendar);
|
||
return view('events.form', compact('calendar', 'event'));
|
||
}
|
||
|
||
/**
|
||
* update vevent + meta
|
||
*/
|
||
public function update(Request $req, Calendar $calendar, Event $event)
|
||
{
|
||
$this->authorize('update', $calendar);
|
||
|
||
$data = $req->validate([
|
||
'title' => 'required|string|max:200',
|
||
'start_at' => 'required|date',
|
||
'end_at' => 'required|date|after:start_at',
|
||
'description' => 'nullable|string',
|
||
'location' => 'nullable|string',
|
||
'category' => 'nullable|string|max:50',
|
||
]);
|
||
|
||
// rebuild the icalendar payload
|
||
$tz = $calendar->timezone;
|
||
$start = new \Carbon\Carbon($data['start_at'], $tz);
|
||
$end = new \Carbon\Carbon($data['end_at'], $tz);
|
||
|
||
// prepare strings
|
||
$description = $data['description'] ?? '';
|
||
$location = $data['location'] ?? '';
|
||
$description = str_replace("\n", '\\n', $description);
|
||
$location = str_replace("\n", '\\n', $location);
|
||
|
||
// note: keep the UID stable (CalDAV relies on it!)
|
||
$uid = $event->uid;
|
||
|
||
$ical = <<<ICS
|
||
BEGIN:VCALENDAR
|
||
VERSION:2.0
|
||
PRODID:-//Kithkin//Laravel CalDAV//EN
|
||
BEGIN:VEVENT
|
||
UID:$uid
|
||
DTSTAMP:{$start->utc()->format('Ymd\\THis\\Z')}
|
||
DTSTART;TZID={$tz}:{$start->format('Ymd\\THis')}
|
||
DTEND;TZID={$tz}:{$end->format('Ymd\\THis')}
|
||
SUMMARY:{$data['title']}
|
||
DESCRIPTION:$description
|
||
LOCATION:$location
|
||
END:VEVENT
|
||
END:VCALENDAR
|
||
|
||
ICS;
|
||
|
||
// persist changes
|
||
$event->update([
|
||
'calendardata' => $ical,
|
||
'etag' => md5($ical),
|
||
'lastmodified' => time(),
|
||
]);
|
||
|
||
$event->meta()->updateOrCreate([], [
|
||
'title' => $data['title'],
|
||
'description' => $data['description'] ?? null,
|
||
'location' => $data['location'] ?? null,
|
||
'all_day' => $data['all_day'] ?? false,
|
||
'category' => $data['category'] ?? null,
|
||
'start_at' => $start,
|
||
'end_at' => $end,
|
||
]);
|
||
|
||
return redirect()->route('calendars.show', $calendar);
|
||
}
|
||
}
|