user()->uri)->get(); return view('subscription.index', compact('subs')); } public function create() { return view('subscription.create'); } public function store(Request $request) { /* validate the submission */ $data = $request->validate([ 'source' => 'required|url', 'displayname' => 'nullable|string|max:255', 'color' => 'nullable|regex:/^#[0-9A-Fa-f]{6}$/', 'refreshrate' => 'nullable|string|max:10', ]); /* normalize hard to check against this url */ $source = rtrim(trim($data['source']), '/'); /* set the principal URI */ $principalUri = $request->user()->uri; /* check for existing subscriptions */ $already = Subscription::query() ->where('principaluri', $principalUri) ->where('source', $source) ->exists(); if ($already) { return Redirect::route('calendar.index')->with('toast', [ 'message' => __('You are already subscribed to that calendar.'), 'type' => 'info', ]); } $sub = DB::transaction(function () use ($data, $principalUri, $source) { /* create the calendarsubscriptions record */ $sub = Subscription::create([ 'uri' => (string) Str::uuid(), 'principaluri' => $principalUri, 'source' => $source, 'displayname' => $data['displayname'] ?: $source, 'calendarcolor' => $data['color'] ?? '#1a1a1a', 'refreshrate' => 'P1D', 'lastmodified' => now()->timestamp, ]); // create new empty calendar container $calId = Calendar::create([ 'synctoken' => 1, 'components' => 'VEVENT', ])->id; // create mirror calendarinstance row (description can be user-editable, not relied on) CalendarInstance::create([ 'calendarid' => $calId, 'principaluri' => $principalUri, 'uri' => (string) Str::uuid(), 'displayname' => $sub->displayname, 'description' => 'Remote feed: '.$source, // informational only 'calendarcolor' => $sub->calendarcolor, 'timezone' => config('app.timezone', 'UTC'), ]); // meta entry CalendarMeta::updateOrCreate( ['calendar_id' => $calId], [ 'subscription_id' => $sub->id, 'title' => $sub->displayname, 'color' => $sub->calendarcolor, 'color_fg' => contrast_text_color($sub->calendarcolor), 'is_shared' => true, 'is_remote' => true, ] ); return $sub; }); // sync immediately so events appear without waiting for the */10 dispatcher SyncSubscription::dispatch($sub)->afterCommit(); return Redirect::route('calendar.index')->with('toast', [ 'message' => __('Subscription added! Syncing events now...'), 'type' => 'success', ]); } public function edit(Subscription $subscription) { $this->authorize('update', $subscription); return view('subscription.edit', ['subscription' => $subscription]); } public function update(Request $request, Subscription $subscription) { $this->authorize('update', $subscription); $data = $request->validate([ 'displayname' => 'nullable|string|max:255', 'calendarcolor' => 'nullable|regex:/^#[0-9A-Fa-f]{6}$/', 'refreshrate' => 'nullable|string|max:10', 'striptodos' => 'sometimes|boolean', 'stripalarms' => 'sometimes|boolean', 'stripattachments' => 'sometimes|boolean', ]); // update calendarsubscriptions record $subscription->update($data); // update corresponding calendar_meta record $subscription->meta()->updateOrCreate( [], // no “where” clause → look at subscription_id FK [ 'title' => $subscription->displayname, 'color' => $subscription->calendarcolor ?? '#1a1a1a', 'color_fg' => contrast_text_color( $subscription->calendarcolor ?? '#1a1a1a' ), 'updated_at'=> now(), ] ); return back()->with('toast', __('Subscription updated!')); } public function destroy(Subscription $subscription) { $this->authorize('delete', $subscription); $subscription->delete(); return back()->with('toast', __('Subscription removed!')); } }