diff --git a/application/config/google_calendar.php b/application/config/google_calendar.php new file mode 100644 index 0000000..fe8329b --- /dev/null +++ b/application/config/google_calendar.php @@ -0,0 +1,5 @@ + $_POST['is_beauty'], 'is_barber' => $_POST['is_barber'], 'service_category_id' => $_POST['service_category_id'], - 'is_active' => $_POST['is_active'] + 'is_active' => $_POST['is_active'], + 'google_calendar_id' => isset($_POST['google_calendar_id']) ? $_POST['google_calendar_id'] : '' ); $this->Service_model->updateWorker($_POST['worker_id'], $workerArray); $this->Log_model->addLog('workers', $data['currentUser']->username.' módosította a(z) '.$_POST['worker_name'].' nevű dolgozót ('.implode(',',$workerArray).')', $data['currentUser']->username); diff --git a/application/controllers/Pages.php b/application/controllers/Pages.php index 1bdbf1b..a7a02ce 100755 --- a/application/controllers/Pages.php +++ b/application/controllers/Pages.php @@ -437,7 +437,29 @@ class Pages extends CI_Controller { } } } - + + // Google Calendar: create events for worker and owner + $this->load->library('GoogleCalendar'); + $this->config->load('google_calendar'); + $newBooking = $this->Service_model->getBookingByToken($manageToken); + if($newBooking){ + $gcalServiceNames = implode(', ', array_map(function($s){ return $s->service_name_no; }, $serviceArray)); + $gcalTitle = $worker->worker_name . ' — ' . $gcalServiceNames . ' — ' . $bookingArray['guest_name']; + $gcalDescription = 'Guest: ' . $bookingArray['guest_name'] . "\nPhone: " . $bookingArray['guest_phone'] . "\nEmail: " . $bookingArray['guest_email']; + $gcalStart = $bookingArray['booking_date'] . 'T' . $bookingArray['booking_start_time']; + $gcalEnd = $bookingArray['booking_date'] . 'T' . $bookingArray['booking_finish_time']; + $workerEventId = null; + $ownerEventId = null; + if(!empty($worker->google_calendar_id)){ + $workerEventId = $this->googlecalendar->createEvent($worker->google_calendar_id, $gcalTitle, $gcalDescription, $gcalStart, $gcalEnd); + } + $evelinCalId = $this->config->item('gcal_evelin_calendar_id'); + if(!empty($evelinCalId)){ + $ownerEventId = $this->googlecalendar->createEvent($evelinCalId, $gcalTitle, $gcalDescription, $gcalStart, $gcalEnd); + } + $this->Service_model->updateBookingCalEvents($newBooking->booking_id, $workerEventId, $ownerEventId); + } + $content = ''; switch($_POST['lang']){ @@ -832,6 +854,32 @@ class Pages extends CI_Controller { if(is_object($sel)) $serviceArray[] = $sel; } + // Google Calendar: delete old events, create new ones + $this->load->library('GoogleCalendar'); + $this->config->load('google_calendar'); + $evelinCalId = $this->config->item('gcal_evelin_calendar_id'); + $oldWorker = $this->Service_model->getWorkerById($booking->worker_id); + if(!empty($booking->gcal_event_id_worker) && !empty($oldWorker->google_calendar_id)){ + $this->googlecalendar->deleteEvent($oldWorker->google_calendar_id, $booking->gcal_event_id_worker); + } + if(!empty($booking->gcal_event_id_owner) && !empty($evelinCalId)){ + $this->googlecalendar->deleteEvent($evelinCalId, $booking->gcal_event_id_owner); + } + $gcalServiceNames = implode(', ', array_map(function($s){ return $s->service_name_no; }, $serviceArray)); + $gcalTitle = $worker->worker_name . ' — ' . $gcalServiceNames . ' — ' . $booking->guest_name; + $gcalDescription = 'Guest: ' . $booking->guest_name . "\nPhone: " . $booking->guest_phone . "\nEmail: " . $booking->guest_email; + $gcalStart = $newBookingDate . 'T' . $newStartTime; + $gcalEnd = $newBookingDate . 'T' . $finishTime; + $newWorkerEventId = null; + $newOwnerEventId = null; + if(!empty($worker->google_calendar_id)){ + $newWorkerEventId = $this->googlecalendar->createEvent($worker->google_calendar_id, $gcalTitle, $gcalDescription, $gcalStart, $gcalEnd); + } + if(!empty($evelinCalId)){ + $newOwnerEventId = $this->googlecalendar->createEvent($evelinCalId, $gcalTitle, $gcalDescription, $gcalStart, $gcalEnd); + } + $this->Service_model->updateBookingCalEvents($booking->booking_id, $newWorkerEventId, $newOwnerEventId); + $manageLink = SITEURL.$lang.'/manage-booking/'.$token; $totalServicePrice = 0; foreach($serviceArray as $s){ $totalServicePrice += $s->service_price; } @@ -941,6 +989,17 @@ class Pages extends CI_Controller { )); $this->User_model->sendEmail($emailArray, $lang, ''); + // Google Calendar: delete events on cancellation + $this->load->library('GoogleCalendar'); + $this->config->load('google_calendar'); + if(!empty($booking->gcal_event_id_worker) && !empty($worker->google_calendar_id)){ + $this->googlecalendar->deleteEvent($worker->google_calendar_id, $booking->gcal_event_id_worker); + } + $evelinCalId = $this->config->item('gcal_evelin_calendar_id'); + if(!empty($booking->gcal_event_id_owner) && !empty($evelinCalId)){ + $this->googlecalendar->deleteEvent($evelinCalId, $booking->gcal_event_id_owner); + } + $this->Service_model->deleteBooking($booking->booking_id); $data['selectedLang'] = $lang; diff --git a/application/libraries/GoogleCalendar.php b/application/libraries/GoogleCalendar.php new file mode 100644 index 0000000..2b70d9c --- /dev/null +++ b/application/libraries/GoogleCalendar.php @@ -0,0 +1,85 @@ +config->load('google_calendar'); + $serviceAccountPath = $CI->config->item('gcal_service_account_path'); + + if (!file_exists($serviceAccountPath)) { + return; + } + + try { + $client = new Google_Client(); + $client->setAuthConfig($serviceAccountPath); + $client->setScopes([Google_Service_Calendar::CALENDAR]); + $this->service = new Google_Service_Calendar($client); + } catch (Exception $e) { + // Silently fail — calendar errors must never break the booking flow + } + } + + /** + * Create a calendar event. + * @return string|null The new event ID, or null on failure. + */ + public function createEvent($calendarId, $title, $description, $startDatetime, $endDatetime) { + if (!$this->service || empty($calendarId)) return null; + try { + $event = new Google_Service_Calendar_Event([ + 'summary' => $title, + 'description' => $description, + 'start' => ['dateTime' => $startDatetime, 'timeZone' => 'Europe/Oslo'], + 'end' => ['dateTime' => $endDatetime, 'timeZone' => 'Europe/Oslo'], + ]); + $result = $this->service->events->insert($calendarId, $event); + return $result->getId(); + } catch (Exception $e) { + return null; + } + } + + /** + * Update an existing calendar event. + * @return string|null The event ID, or null on failure. + */ + public function updateEvent($calendarId, $eventId, $title, $description, $startDatetime, $endDatetime) { + if (!$this->service || empty($calendarId) || empty($eventId)) return null; + try { + $event = $this->service->events->get($calendarId, $eventId); + $event->setSummary($title); + $event->setDescription($description); + $event->setStart(new Google_Service_Calendar_EventDateTime([ + 'dateTime' => $startDatetime, + 'timeZone' => 'Europe/Oslo', + ])); + $event->setEnd(new Google_Service_Calendar_EventDateTime([ + 'dateTime' => $endDatetime, + 'timeZone' => 'Europe/Oslo', + ])); + $result = $this->service->events->update($calendarId, $eventId, $event); + return $result->getId(); + } catch (Exception $e) { + return null; + } + } + + /** + * Delete a calendar event. Silently skips if not found. + */ + public function deleteEvent($calendarId, $eventId) { + if (!$this->service || empty($calendarId) || empty($eventId)) return; + try { + $this->service->events->delete($calendarId, $eventId); + } catch (Exception $e) { + // Silently skip — event may already be gone + } + } +} diff --git a/application/models/Service_model.php b/application/models/Service_model.php index 009c5c7..a31667d 100755 --- a/application/models/Service_model.php +++ b/application/models/Service_model.php @@ -561,6 +561,11 @@ class Service_model extends CI_Model { $query = $this->db->query('SELECT * FROM bookings WHERE manage_token = "'.$this->db->escape_str($token).'" LIMIT 1;'); return $query->num_rows() > 0 ? $query->result()[0] : false; } + + public function updateBookingCalEvents($booking_id, $worker_event_id, $owner_event_id){ + $this->load->database(); + $this->db->query("UPDATE bookings SET gcal_event_id_worker = '".$this->db->escape_str($worker_event_id)."', gcal_event_id_owner = '".$this->db->escape_str($owner_event_id)."' WHERE booking_id = '".$this->db->escape_str($booking_id)."';"); + } public function getWorkerSchedule($worker_id) { return $this->db diff --git a/application/models/User_model.php b/application/models/User_model.php index 5ea5102..a7b5f96 100755 --- a/application/models/User_model.php +++ b/application/models/User_model.php @@ -138,7 +138,7 @@ class User_model extends CI_Model { if(!empty($addressList)){ foreach($addressList as $addressListItem){ // Instantiation and passing `true` enables exceptions - $mail = new PHPMailer(false); + $mail = new PHPMailer(true); $mail->SMTPDebug = false; $mail->do_debug = 1; try { @@ -188,6 +188,7 @@ class User_model extends CI_Model { } catch (Exception $e) { //header('location:'.base_url().'manage-applicants/?email-sent=false&error='.$mail->ErrorInfo); + log_message('error', 'sendEmail FAILED: ' . $mail->ErrorInfo); echo "Üzenetküldési hiba. Mailer Error: {$mail->ErrorInfo}"; } diff --git a/application/views/admin/includes/update-worker-form.php b/application/views/admin/includes/update-worker-form.php index 51cbd8f..4203956 100755 --- a/application/views/admin/includes/update-worker-form.php +++ b/application/views/admin/includes/update-worker-form.php @@ -52,6 +52,10 @@ +
+ + +
Mégsem diff --git a/composer.json b/composer.json index 01e65f4..cedd523 100755 --- a/composer.json +++ b/composer.json @@ -11,7 +11,9 @@ "source": "https://github.com/bcit-ci/CodeIgniter" }, "require": { - "php": ">=5.3.7" + "php": ">=5.3.7", + "google/apiclient": "^2.0", + "phpmailer/phpmailer": "^6.0" }, "suggest": { "paragonie/random_compat": "Provides better randomness in PHP 5.x"