(C) Moorfields Eye Hospital NHS Foundation Trust, 2008-2011 (C) OpenEyes Foundation, 2011-2013 This file is part of OpenEyes. OpenEyes is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. OpenEyes is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenEyes in a file titled COPYING. If not, see .
Author: OpenEyes (info@openeyes.org.uk)
 /**
  * Update the worklist display order for the current user based on the submitted ids.
  */
 public function actionManualUpdateDisplayOrder()
 {
     $worklist_ids = @$_POST['item_ids'] ? explode(',', $_POST['item_ids']) : array();
     if (!$this->manager->setWorklistDisplayOrderForUser(Yii::app()->user, $worklist_ids)) {
         OELog::log(print_r($this->manager->getErrors(), true));
         throw new Exception('Unable to save new display order for worklists');
     }
     $this->redirect('/worklist/manual');
 }
Exemple #2
0
 /**
  * Override to allow us to have classes defined outside of core that store the data in a different way
  *
  * @param array $attributes
  * @return CActiveRecord
  */
 protected function instantiate($attributes)
 {
     if (isset($attributes['patient_measurement_id'])) {
         if ($pm = PatientMeasurement::model()->findByPk($attributes['patient_measurement_id'])) {
             $origin = $pm->originReference;
             if ($origin && $origin->event) {
                 $api = Yii::app()->moduleAPI->getForEventId($origin->event_id);
                 if ($api) {
                     OELog::log("we have an api");
                     return $api->getMeasurementClassForEventId($origin->event_id);
                 }
             }
         }
     }
     return parent::instantiate($attributes);
 }
 /**
  * @param $id
  *
  * @throws \CHttpException
  * @throws \Exception
  */
 public function actionAddComment($id)
 {
     $element = $this->getMessageElement();
     if (count($element->comments)) {
         throw new \CHttpException(409, 'Only one comment allowed per message.');
     }
     $comment = new OphCoMessaging_Message_Comment();
     \OELog::log(print_r($_POST, true));
     $comment->comment_text = @$_POST['OEModule_OphCoMessaging_models_OphCoMessaging_Message_Comment']['comment_text'];
     $comment->element_id = $element->id;
     if (!$comment->validate()) {
         $this->show_comment_form = true;
         $this->action = new \CInlineAction($this, 'view');
         $errors = array('Comment' => array());
         foreach ($comment->getErrors() as $err) {
             $errors['Comment'] = array_values($err);
         }
         $this->render('view', array('errors' => $errors, 'comment' => $comment));
     } else {
         $transaction = \Yii::app()->db->beginTransaction();
         try {
             $element->marked_as_read = true;
             $element->save();
             $comment->save();
             $transaction->commit();
             \Yii::app()->user->setFlash('success', 'Comment added to record');
         } catch (\Exception $e) {
             $transaction->rollback();
             throw $e;
         }
         $this->redirectAfterAction();
     }
 }
 /**
  * Save the event for this controller - will create or update the event, create and update the elements, delete any
  * elements that are no longer required. Note that $data is provided for the purposes of any extensions to this
  * behaviour that might be required.
  *
  * @param $data
  * @return bool
  * @throws Exception
  */
 public function saveEvent($data)
 {
     if (!$this->event->isNewRecord) {
         // this is an edit, so need to work out what we are deleting
         $oe_ids = array();
         foreach ($this->open_elements as $o_e) {
             if ($o_e->id) {
                 if (isset($oe_ids[get_class($o_e)])) {
                     $oe_ids[get_class($o_e)][] = $o_e->id;
                 } else {
                     $oe_ids[get_class($o_e)] = array($o_e->id);
                 }
             }
         }
         // delete any elements that are no longer required for the event
         foreach ($this->event->getElements() as $curr_element) {
             if (!isset($oe_ids[get_class($curr_element)]) || !in_array($curr_element->id, $oe_ids[get_class($curr_element)])) {
                 $curr_element->delete();
             }
         }
     } else {
         if (!$this->event->save()) {
             OELog::log("Failed to create new event for episode_id={$this->episode->id}, event_type_id=" . $this->event_type->id);
             throw new Exception('Unable to save event.');
         }
         OELog::log("Created new event for episode_id={$this->episode->id}, event_type_id=" . $this->event_type->id);
     }
     foreach ($this->open_elements as $element) {
         $element->event_id = $this->event->id;
         // No need to validate as it has already been validated and the event id was just generated.
         if (!$element->save(false)) {
             throw new Exception('Unable to save element ' . get_class($element) . '.');
         }
     }
     // ensure any complex data is saved to the elements
     $this->saveEventComplexAttributesFromData($data);
     // update the information attribute on the event
     $this->updateEventInfo();
     return true;
 }
 /**
  * Logs out the current user and redirect to homepage.
  */
 public function actionLogout()
 {
     $user = Yii::app()->session['user'];
     $user->audit('logout', 'logout');
     OELog::log("User {$user->username} logged out");
     Yii::app()->user->logout();
     $this->redirect(Yii::app()->homeUrl);
 }
Exemple #6
0
 /**
  * Mailer:mail is intended as a more robust simple replacement for php mail(),
  * @param array $to address eg array('*****@*****.**'=>'OpenEyes')
  * @param string $subject
  * @param string $body
  * @param array $from address eg array('*****@*****.**'=>'OpenEyes')
  * @return bool mail sent without error
  */
 public static function mail($to, $subject, $body, $from)
 {
     try {
         $message = Yii::app()->mailer->newMessage();
         $message->setSubject($subject);
         $message->setFrom($from);
         $message->setTo($to);
         $message->setBody($body);
         Yii::app()->mailer->sendMessage($message);
     } catch (Exception $Exception) {
         OELog::logException($Exception);
         return false;
     }
     return true;
 }
Exemple #7
0
 /**
  * @param $resource_type
  * @param $id
  */
 public function actionUpdate($resource_type, $id)
 {
     if (!in_array($resource_type, static::$resources)) {
         $this->sendErrorResponse(404, "Unrecognised Resource type {$resource_type}");
     }
     if (!$id) {
         $this->sendResponse(404, 'External Resource ID required');
     }
     $resource_model = $this->getResourceModel($resource_type);
     $body = \Yii::app()->request->rawBody;
     try {
         $resource = $resource_model::fromXml(static::$version, $body, array('update_only' => $this->getUpdateOnly(), 'partial_record' => $this->getPartialRecord()));
         if ($resource->errors) {
             $this->sendErrorResponse(400, $resource->errors);
         }
         $resource->id = $id;
         if (!($internal_id = $resource->save())) {
             if ($resource->errors && !$resource->warn_errors) {
                 $this->sendErrorResponse(400, $resource->errors);
             } else {
                 // no internal id indicates we didn't get a resource
                 $response = array('Message' => $resource_type . ' not created');
                 // map errors to warnings if this is the case
                 if ($resource->errors) {
                     $response['Warnings'] = $resource->errors;
                 }
                 // success in that we are happy for there to have been no action taken
                 $this->sendSuccessResponse(200, $response);
             }
         }
         $response = array('Id' => $internal_id);
         if ($resource->isNewResource) {
             $status_code = 201;
             $response['Message'] = $resource_type . ' created.';
         } else {
             $status_code = 200;
             $response['Message'] = $resource_type . ' updated.';
         }
         if ($resource->warnings) {
             $response['Warnings'] = $resource->warnings;
         }
         $this->sendSuccessResponse($status_code, $response);
     } catch (\Exception $e) {
         if (YII_DEBUG) {
             $errors = $resource->errors;
             $errors[] = $e->getMessage();
             \OELog::log(print_r($errors));
         } else {
             $errors = array('Could not save resource');
         }
         $this->sendErrorResponse(500, $errors);
     }
 }
Exemple #8
0
 /**
  * add an episode to the patient for the given Firm
  *
  * @param $firm
  * @return Episode
  * @throws Exception
  */
 public function addEpisode($firm)
 {
     $episode = new Episode();
     $episode->patient_id = $this->id;
     if ($firm->getSubspecialtyID()) {
         $episode->firm_id = $firm->id;
     } else {
         $episode->support_services = true;
     }
     $episode->start_date = date("Y-m-d H:i:s");
     if (!$episode->save()) {
         OELog::log("Unable to create new episode for patient_id={$episode->patient_id}, firm_id={$episode->firm_id}, start_date='{$episode->start_date}'");
         throw new Exception('Unable to create create episode: ' . print_r($episode->getErrors(), true));
     }
     OELog::log("New episode created for patient_id={$episode->patient_id}, firm_id={$episode->firm_id}, start_date='{$episode->start_date}'");
     $episode->audit('episode', 'create');
     Yii::app()->event->dispatch('episode_after_create', array('episode' => $episode));
     return $episode;
 }
Exemple #9
0
 public static function add($target, $action, $data = null, $log_message = null, $properties = array())
 {
     if (!($_target = AuditType::model()->find('name=?', array($target)))) {
         $_target = new AuditType();
         $_target->name = $target;
         if (!$_target->save()) {
             throw new Exception("Unable to save audit target: " . print_r($_target->getErrors(), true));
         }
     }
     if (!($_action = AuditAction::model()->find('name=?', array($action)))) {
         $_action = new AuditAction();
         $_action->name = $action;
         if (!$_action->save()) {
             throw new Exception("Unable to save audit action: " . print_r($_action->getErrors(), true));
         }
     }
     $audit = new Audit();
     $audit->type_id = $_target->id;
     $audit->action_id = $_action->id;
     $audit->data = $data;
     if (!isset($properties['user_id'])) {
         if (Yii::app()->session['user']) {
             $properties['user_id'] = Yii::app()->session['user']->id;
         }
     }
     if (isset($properties['module'])) {
         if ($et = EventType::model()->find('class_name=?', array($properties['module']))) {
             $properties['event_type_id'] = $et->id;
         } else {
             if (!($module = AuditModule::model()->find('name=?', array($properties['module'])))) {
                 $module = new AuditModule();
                 $module->name = $properties['module'];
                 if (!$module->save()) {
                     throw new Exception("Unable to create audit_module: " . print_r($module->getErrors(), true));
                 }
             }
             $properties['module_id'] = $module->id;
         }
         unset($properties['module']);
     }
     if (isset($properties['model'])) {
         if (!($model = AuditModel::model()->find('name=?', array($properties['model'])))) {
             $model = new AuditModel();
             $model->name = $properties['model'];
             if (!$model->save()) {
                 throw new Exception("Unable to save audit_model: " . print_r($model->getErrors(), true));
             }
         }
         $properties['model_id'] = $model->id;
         unset($properties['model']);
     }
     foreach ($properties as $key => $value) {
         $audit->{$key} = $value;
     }
     if (!$audit->save()) {
         throw new Exception("Failed to save audit entry: " . print_r($audit->getErrors(), true));
     }
     if (isset($properties['user_id'])) {
         $username = User::model()->findByPk($properties['user_id'])->username;
     }
     $log_message && OELog::log($log_message, @$username);
     return $audit;
 }
 /**
  * Authenticates a user.
  *
  * Uses either BASIC or LDAP authentication. BASIC authenticates against
  * the openeyes DB. LDAP uses whichever LDAP is specified in the params.php
  * config file.
  *
  * @return boolean whether authentication succeeds.
  * @throws
  */
 public function authenticate($force = false)
 {
     if (!in_array(Yii::app()->params['ldap_method'], array('native', 'zend'))) {
         throw new Exception('Unsupported LDAP authentication method: ' . Yii::app()->params['ldap_method'] . ', please use native or zend.');
     }
     Yii::app()->event->dispatch('user_before_login', array('username' => $this->username));
     /**
      * Usernames are case sensitive
      */
     $user = User::model()->find('username = ?', array($this->username));
     if ($user === null) {
         Audit::add('login', 'login-failed', null, "User not found in local database: {$this->username}");
         $this->errorCode = self::ERROR_USERNAME_INVALID;
         return false;
     } elseif (!$force && $user->active != 1) {
         $user->audit('login', 'login-failed', null, "User not active and so cannot login: {$this->username}");
         $this->errorCode = self::ERROR_USER_INACTIVE;
         return false;
     } elseif (!$force && !Yii::app()->getAuthManager()->checkAccess('OprnLogin', $user->id)) {
         $user->audit('login', 'login-failed', "User has not been assigned OprnLogin and so cannot login: {$this->username}", true);
         $this->errorCode = self::ERROR_USER_INACTIVE;
         return false;
     }
     if (in_array($user->username, Yii::app()->params['local_users'])) {
         Yii::app()->params['auth_source'] = 'BASIC';
     }
     $this->password = utf8_decode($this->password);
     /**
      * Here we diverge depending on the authentication source.
      */
     if (Yii::app()->params['auth_source'] == 'LDAP') {
         /**
          * Required for LDAP authentication
          */
         if (Yii::app()->params['ldap_method'] == 'zend') {
             Yii::import('application.vendors.*');
             require_once 'Zend/Ldap.php';
             /**
              * Check with LDAP for authentication
              */
             $options = array('host' => Yii::app()->params['ldap_server'], 'port' => Yii::app()->params['ldap_port'], 'username' => Yii::app()->params['ldap_admin_dn'], 'password' => Yii::app()->params['ldap_password'], 'baseDn' => Yii::app()->params['ldap_admin_dn'], 'useStartTls' => false);
             $ldap = $this->getLdap($options);
             /**
              * Try and bind to the login details provided. This indicates if
              * the user is in LDAP.
              */
             try {
                 $ldap->bind("cn=" . $this->username . "," . Yii::app()->params['ldap_dn'], $this->password);
             } catch (Exception $e) {
                 /**
                  * User not authenticated via LDAP
                  */
                 $audit = new Audit();
                 $audit->action = "login-failed";
                 $audit->target_type = "login";
                 $audit->user_id = $user->id;
                 $audit->data = "Login failed for user {$this->username}: LDAP authentication failed: " . $e->getMessage() . ": " . $this->username;
                 $audit->save();
                 OELog::log("Login failed for user {$this->username}: LDAP authentication failed: " . $e->getMessage(), $this->username);
                 $this->errorCode = self::ERROR_USERNAME_INVALID;
                 return false;
             }
             /**
              * User is in LDAP, get their details.
              */
             $info = $ldap->getEntry("cn=" . $this->username . "," . Yii::app()->params['ldap_dn'], array('givenname', 'sn', 'mail'));
         } else {
             if (!($link = ldap_connect(Yii::app()->params['ldap_server']))) {
                 throw new Exception('Unable to connect to LDAP server.');
             }
             ldap_set_option($link, LDAP_OPT_NETWORK_TIMEOUT, Yii::app()->params['ldap_native_timeout']);
             if (!@ldap_bind($link, "cn={$this->username}," . Yii::app()->params['ldap_dn'], $this->password)) {
                 $audit = new Audit();
                 $audit->action = "login-failed";
                 $audit->target_type = "login";
                 $audit->user_id = $user->id;
                 $audit->data = "Login failed for user {$this->username}: LDAP authentication failed: " . ldap_error($link);
                 $audit->save();
                 OELog::log("Login failed for user {$this->username}: LDAP authentication failed: " . ldap_error($link));
                 $this->errorCode = self::ERROR_USERNAME_INVALID;
                 return false;
             }
             $attempts = isset(Yii::app()->params['ldap_info_retries']) ? Yii::app()->params['ldap_info_retries'] : 1;
             for ($i = 0; $i < $attempts; $i++) {
                 if ($i > 0 && isset(Yii::app()->params['ldap_info_retry_delay'])) {
                     sleep(Yii::app()->params['ldap_info_retry_delay']);
                 }
                 $sr = ldap_search($link, "cn={$this->username}," . Yii::app()->params['ldap_dn'], "cn={$this->username}");
                 $info = ldap_get_entries($link, $sr);
                 if (isset($info[0])) {
                     break;
                 }
             }
             if (!isset($info[0])) {
                 throw new Exception("Failed to retrieve ldap info for user {$user->username}: " . ldap_error($link) . " [" . print_r($info, true) . "]");
             }
             $info = $info[0];
         }
         /**
          * Update user db record with details from LDAP.
          */
         if (Yii::app()->params['ldap_update_name']) {
             if (isset($info['givenname'][0])) {
                 $user->first_name = $info['givenname'][0];
             }
             if (isset($info['sn'][0])) {
                 $user->last_name = $info['sn'][0];
             }
         }
         if (Yii::app()->params['ldap_update_email']) {
             if (isset($info['mail'][0])) {
                 $user->email = $info['mail'][0];
             }
         }
         if (!$user->save()) {
             $user->audit('login', 'login-failed', null, "Login failed for user {$this->username}: unable to update user with details from LDAP: " . print_r($user->getErrors(), true));
             throw new SystemException('Unable to update user with details from LDAP: ' . print_r($user->getErrors(), true));
         }
     } elseif (Yii::app()->params['auth_source'] == 'BASIC') {
         if (!$force && !$user->validatePassword($this->password)) {
             $this->errorCode = self::ERROR_PASSWORD_INVALID;
             $user->audit('login', 'login-failed', null, "Login failed for user {$this->username}: invalid password");
             return false;
         }
     } else {
         /**
          * Unknown auth_source, error
          */
         $user->audit('login', 'login-failed', null, "Login failed for user {$this->username}: unknown auth source: " . Yii::app()->params['auth_source']);
         throw new SystemException('Unknown auth_source: ' . Yii::app()->params['auth_source']);
     }
     $this->_id = $user->id;
     $this->username = $user->username;
     $this->errorCode = self::ERROR_NONE;
     // Get all the user's firms and put them in a session
     $app = Yii::app();
     $firms = array();
     foreach ($user->getAvailableFirms() as $firm) {
         $firms[$firm->id] = $this->firmString($firm);
     }
     if (!count($firms)) {
         $user->audit('login', 'login-failed', null, "Login failed for user {$this->username}: user has no firm rights and cannot use the system");
         throw new Exception('User has no firm rights and cannot use the system.');
     }
     natcasesort($firms);
     $app->session['user'] = $user;
     $app->session['firms'] = $firms;
     reset($firms);
     // Select firm
     if ($user->last_firm_id) {
         $app->session['selected_firm_id'] = $user->last_firm_id;
     } elseif (count($user->firms)) {
         // Set the firm to one the user is associated with
         $userFirms = $user->firms;
         $app->session['selected_firm_id'] = $userFirms[0]->id;
     } else {
         // The user doesn't have firms of their own to select from so we select
         // one arbitrarily
         $app->session['selected_firm_id'] = key($firms);
     }
     // Select site
     if ($user->last_site_id) {
         $app->session['selected_site_id'] = $user->last_site_id;
     } elseif ($default_site = Site::model()->getDefaultSite()) {
         $app->session['selected_site_id'] = $default_site->id;
     } else {
         throw new CException('Cannot find default site');
     }
     $user->audit('login', 'login-successful', null, "User " . strtoupper($this->username) . " logged in");
     return true;
 }
 /**
  * @param \Event $event
  * @param \User $user
  * @param $signature_file_id
  * @return bool
  * @throws \CDbException
  * @throws \Exception
  */
 public function removeConsentSignature(\Event $event, \User $user, $signature_file_id)
 {
     if ($element = $this->getConsentSignatureElementForEvent($event)) {
         if ($element->signature_file_id == $signature_file_id) {
             $transaction = $this->startTransaction();
             try {
                 $element->signature_file_id = null;
                 $element->save();
                 $this->updateEventInfo($event);
                 $event->audit('event', 'cvi-consent-removed', null, 'CVI Consent Signature Removed', array('user_id' => $user->id));
                 $transaction->commit();
                 return true;
             } catch (\Exception $e) {
                 \OELog::log($e->getMessage());
                 $transaction->rollback();
                 return false;
             }
         }
     }
     return false;
 }
 /**
  * Update the Worklist Definition Mapping Attribute order.
  *
  * @param $id
  */
 public function actionDefinitionMappingSort($id)
 {
     $definition = $this->getWorklistDefinition($id);
     $mapping_ids = @$_POST['item_ids'] ?: array();
     if (count($mapping_ids)) {
         if (!$this->manager->setWorklistDefinitionMappingDisplayOrder($definition, $mapping_ids)) {
             OELog::log(print_r($this->manager->getErrors(), true));
             $this->flashMessage('error', 'Could not reorder mappings');
         } else {
             $this->flashMessage('success', 'Mappings re-ordered');
         }
     }
     $this->redirect('/worklistAdmin/definitionMappings/' . $id);
 }
 /**
  * @param CController $controller
  * @param array       $template_data
  * @param int         $eye_id
  * @param User        $notify_user
  *
  * @throws Exception
  *
  * @return bool
  */
 private function processEventForEye(CController $controller, array $template_data, $eye_id, User $notify_user = null)
 {
     $eye_name = $this->getEyeNameById($eye_id);
     $template_data += $this->getSideSpecificTemplateData($eye_name);
     $attachments = array();
     $attach_size = 0;
     if ($app_file = $this->createAndSavePdfForSide($controller, $template_data, $eye_name)) {
         $attachments[] = $app_file;
         $attach_size += $app_file->size;
     }
     if ($ec = $this->getElement('Element_OphCoTherapyapplication_ExceptionalCircumstances')) {
         foreach ($ec->{"{$eye_name}_filecollections"} as $fc) {
             $attachments[] = $fc->getZipFile();
             $attach_size += $fc->getZipFile()->size;
         }
     }
     $service_info = $this->getServiceInfo();
     $link_to_attachments = $attach_size > Helper::convertToBytes(Yii::app()->params['OphCoTherapyapplication_email_size_limit']);
     $template_data['link_to_attachments'] = $link_to_attachments;
     $email_text = $this->generateEmailForSide($controller, $template_data, $eye_name);
     $message = Yii::app()->mailer->newMessage();
     if ($template_data['compliant']) {
         $recipient_type = 'Compliant';
         $message->setSubject(Yii::app()->params['OphCoTherapyapplication_compliant_email_subject']);
     } else {
         $recipient_type = 'Non-compliant';
         $message->setSubject(Yii::app()->params['OphCoTherapyapplication_noncompliant_email_subject']);
     }
     $recipient_type = $template_data['compliant'] ? 'Compliant' : 'Non-compliant';
     try {
         $recipients = $this->getEmailRecipients($service_info, $recipient_type);
     } catch (Exception $e) {
         Yii::app()->user->setFlash('error', $e->getMessage());
         $controller->redirect('/OphCoTherapyapplication/default/view/' . $this->event->id);
     }
     $email_recipients = array();
     foreach ($recipients as $recipient) {
         if (!$recipient->isAllowed()) {
             throw new Exception("Recipient email address {$recipient->recipient_email} is not in the list of allowed domains");
         }
         $email_recipients[$recipient->recipient_email] = $recipient->recipient_name;
     }
     $message->setFrom(Yii::app()->params['OphCoTherapyapplication_sender_email']);
     $message->setTo($email_recipients);
     if ($notify_user && $notify_user->email) {
         $cc = true;
         if (Yii::app()->params['restrict_email_domains']) {
             $domain = preg_replace('/^.*?@/', '', $notify_user->email);
             if (!in_array($domain, Yii::app()->params['restrict_email_domains'])) {
                 Yii::app()->user->setFlash('warning.warning', 'You will not receive a copy of the submission because your email address ' . $notify_user->email . ' is not on a secure domain');
                 $cc = false;
             }
         }
         if ($cc) {
             $message->setCc($notify_user->email);
         }
     }
     $message->setBody($email_text);
     if (!$link_to_attachments) {
         foreach ($attachments as $att) {
             $message->attach(Swift_Attachment::fromPath($att->getPath())->setFilename($att->name));
         }
     }
     if (Yii::app()->mailer->sendMessage($message)) {
         $email = new OphCoTherapyapplication_Email();
         $email->event_id = $this->event->id;
         $email->eye_id = $eye_id;
         $email->email_text = $email_text;
         if (!$email->save()) {
             throw new Exception('Unable to save email: ' . print_r($email->getErrors(), true));
         }
         $email->addAttachments($attachments);
         $this->event->audit('therapy-application', 'submit');
         $this->event->info = self::STATUS_SENT;
         if (!$this->event->save()) {
             throw new Exception('Unable to save event: ' . print_r($this->event->getErrors(), true));
         }
         return true;
     } else {
         OELog::log("Failed to send email for therapy application event_id '{$this->event->id}', eye_id '{$eye_id}'");
         // clean up
         if ($app_file) {
             $app_file->delete();
         }
         return false;
     }
 }
 public function confirmLetterPrinted($confirmto = null, $confirmdate = null)
 {
     // admin users can set confirmto and confirm up to a specific point, steamrollering whatever else is in there
     if (!is_null($confirmto)) {
         if (!($dls = $this->date_letter_sent)) {
             $dls = new OphTrOperationbooking_Operation_Date_Letter_Sent();
             $dls->element_id = $this->id;
         }
         if ($confirmto == self::LETTER_GP) {
             $dls->date_invitation_letter_sent = Helper::convertNHS2MySQL($confirmdate);
             $dls->date_1st_reminder_letter_sent = Helper::convertNHS2MySQL($confirmdate);
             $dls->date_2nd_reminder_letter_sent = Helper::convertNHS2MySQL($confirmdate);
             $dls->date_gp_letter_sent = Helper::convertNHS2MySQL($confirmdate);
         }
         if ($confirmto == self::LETTER_INVITE) {
             $dls->date_invitation_letter_sent = Helper::convertNHS2MySQL($confirmdate);
             $dls->date_1st_reminder_letter_sent = null;
             $dls->date_2nd_reminder_letter_sent = null;
             $dls->date_gp_letter_sent = null;
         }
         if ($confirmto == self::LETTER_REMINDER_1) {
             $dls->date_invitation_letter_sent = Helper::convertNHS2MySQL($confirmdate);
             $dls->date_1st_reminder_letter_sent = Helper::convertNHS2MySQL($confirmdate);
             $dls->date_2nd_reminder_letter_sent = null;
             $dls->date_gp_letter_sent = null;
         }
         if ($confirmto == self::LETTER_REMINDER_2) {
             $dls->date_invitation_letter_sent = Helper::convertNHS2MySQL($confirmdate);
             $dls->date_1st_reminder_letter_sent = Helper::convertNHS2MySQL($confirmdate);
             $dls->date_2nd_reminder_letter_sent = Helper::convertNHS2MySQL($confirmdate);
             $dls->date_gp_letter_sent = null;
         }
         if ($confirmto == 'noletters') {
             $dls->date_invitation_letter_sent = null;
             $dls->date_1st_reminder_letter_sent = null;
             $dls->date_2nd_reminder_letter_sent = null;
             $dls->date_gp_letter_sent = null;
         }
         if (!$dls->save()) {
             throw new Exception('Unable to save date letter sent: ' . print_r($dls->getErrors(), true));
         }
         OELog::log("Letter print confirmed, datelettersent={$dls->id} confirmdate='{$confirmdate}'");
         // Only confirm if letter is actually due
     } elseif ($this->getDueLetter() !== $this->getLastLetter()) {
         if ($dls = $this->date_letter_sent) {
             if ($dls->date_invitation_letter_sent == null) {
                 $dls->date_invitation_letter_sent = date('Y-m-d H:i:s');
             } elseif ($dls->date_1st_reminder_letter_sent == null) {
                 $dls->date_1st_reminder_letter_sent = date('Y-m-d H:i:s');
             } elseif ($dls->date_2nd_reminder_letter_sent == null) {
                 $dls->date_2nd_reminder_letter_sent = date('Y-m-d H:i:s');
             } elseif ($dls->date_gp_letter_sent == null) {
                 $dls->date_gp_letter_sent = date('Y-m-d H:i:s');
             } elseif ($dls->date_scheduling_letter_sent == null) {
                 $dls->date_scheduling_letter_sent = date('Y-m-d H:i:s');
             }
             if (!$dls->save()) {
                 throw new SystemException("Unable to update date_letter_sent record {$dls->id}: " . print_r($dls->getErrors(), true));
             }
             OELog::log("Letter print confirmed, datelettersent={$dls->id}");
         } else {
             $dls = new OphTrOperationbooking_Operation_Date_Letter_Sent();
             $dls->element_id = $this->id;
             $dls->date_invitation_letter_sent = date('Y-m-d H:i:s');
             if (!$dls->save()) {
                 throw new SystemException('Unable to save new date_letter_sent record: ' . print_r($dls->getErrors(), true));
             }
             OELog::log("Letter print confirmed, datelettersent={$dls->id}");
         }
     }
 }
 public function cancel($reason, $cancellation_comment, $reschedule = false)
 {
     $this->booking_cancellation_date = date('Y-m-d H:i:s');
     $this->cancellation_reason_id = $reason->id;
     $this->cancellation_comment = $cancellation_comment;
     $this->cancellation_user_id = Yii::app()->session['user']->id;
     if (!$this->save()) {
         throw new Exception('Unable to save booking: ' . print_r($this->getErrors(), true));
     }
     OELog::log("Booking cancelled: {$this->id}");
     if (!$reschedule) {
         if (!$this->operation->event->addIssue('Operation requires scheduling')) {
             throw new Exception('Unable to add event issue: ' . print_r($this->operation->event->getErrors(), true));
         }
         if (Yii::app()->params['urgent_booking_notify_hours'] && Yii::app()->params['urgent_booking_notify_email']) {
             if (strtotime($this->session->date) <= strtotime(date('Y-m-d')) + Yii::app()->params['urgent_booking_notify_hours'] * 3600) {
                 if (!is_array(Yii::app()->params['urgent_booking_notify_email'])) {
                     $targets = array(Yii::app()->params['urgent_booking_notify_email']);
                 } else {
                     $targets = Yii::app()->params['urgent_booking_notify_email'];
                 }
                 foreach ($targets as $email) {
                     if (!Mailer::mail($email, '[OpenEyes] Urgent cancellation made', "A cancellation was made with a TCI date within the next 24 hours.\n\nDisorder: " . $this->operation->getDisorderText() . "\n\nPlease see: http://" . @$_SERVER['SERVER_NAME'] . "/transport\n\nIf you need any assistance you can reply to this email and one of the OpenEyes support personnel will respond.", 'From: ' . Yii::app()->params['urgent_booking_notify_email_from'] . "\r\n")) {
                     }
                     Yii::app()->user->setFlash('warning.email-failure', 'E-mail Failure. Failed to send one or more urgent booking notification E-mails.');
                 }
             }
         }
         $this->audit('booking', 'cancel');
         $this->operation->event->episode->episode_status_id = 3;
         if (!$this->operation->event->episode->save()) {
             throw new Exception('Unable to update episode status for episode: ' . print_r($operation->event->episode->getErrors(), true));
         }
         // we've just cancelled a booking and updated the element_operation status to 'needs rescheduling'
         // any time we do that we need to add a new record to date_letter_sent
         $date_letter_sent = new OphTrOperationbooking_Operation_Date_Letter_Sent();
         $date_letter_sent->element_id = $this->element_id;
         if (!$date_letter_sent->save()) {
             throw new Exception('Unable to save date_letter_sent: ' . print_r($date_letter_sent->getErrors(), true));
         }
     }
 }