Index: admin_templates/forms/form_edit_emails.tpl =================================================================== --- admin_templates/forms/form_edit_emails.tpl (revision 13756) +++ admin_templates/forms/form_edit_emails.tpl (working copy) @@ -60,6 +60,7 @@ + @@ -97,6 +98,8 @@ for (var $i = 0; $i < $fields.length; $i++) { get_control($field_mask, $fields[$i]).disabled = !$enabled; } + + get_control($field_mask, 'ProcessUnmatchedEmails', undefined, '_cb').disabled = !$enabled; } reflectFromFields(); Index: admin_templates/submissions/submission_view.tpl =================================================================== --- admin_templates/submissions/submission_view.tpl (revision 13756) +++ admin_templates/submissions/submission_view.tpl (working copy) @@ -109,6 +109,23 @@ + + + + + + + + + + @@ -130,6 +147,11 @@ + + + + + @@ -163,4 +185,35 @@
+ + class="" onchange="update_checkbox(this, document.getElementById(''));" onclick=""> + + +
+ + + + \ No newline at end of file Index: install/english.lang =================================================================== --- install/english.lang (revision 13789) +++ install/english.lang (working copy) @@ -520,6 +520,7 @@ TWF4aW11bSBudW1iZXIgb2YgU2VjdGlvbnMgb24gSXRlbSBjYW4gYmUgYWRkZWQgdG8= Q3VzdG9tIE1lbnUgSWNvbiAoaWUuIGltZy9tZW51X3Byb2R1Y3RzLmdpZik= TWVudSBTdGF0dXM= + TWVyZ2UgdG8gU3VibWlzc2lvbg== TWVzc2FnZQ== TWVzc2FnZSBCb2R5 UGxhaW4gVGV4dCBWZXJzaW9u @@ -566,6 +567,7 @@ UHJpbWFyeQ== UHJpbWFyeSBMYW5ndWFnZSBQaHJhc2U= T3JkZXI= + Q29udmVydCB1bm1hdGNoZWQgZS1tYWlscyBpbnRvIG5ldyBzdWJtaXNzaW9ucw== UXVhbnRpdHk= UmF0aW5n UmVjaXBpZW50J3MgQWRkcmVzcw== Index: install/install_schema.sql =================================================================== --- install/install_schema.sql (revision 13780) +++ install/install_schema.sql (working copy) @@ -1105,11 +1105,13 @@ LogStatus tinyint(3) unsigned NOT NULL DEFAULT '2', LastUpdatedOn int(10) unsigned DEFAULT NULL, Notes text, + MessageId varchar(255) DEFAULT NULL, PRIMARY KEY (FormSubmissionId), KEY FormId (FormId), KEY SubmissionTime (SubmissionTime), KEY LogStatus (LogStatus), - KEY LastUpdatedOn (LastUpdatedOn) + KEY LastUpdatedOn (LastUpdatedOn), + KEY MessageId (MessageId) ); CREATE TABLE SubmissionLog ( @@ -1162,6 +1164,7 @@ RequireLogin tinyint(4) NOT NULL DEFAULT '0', UseSecurityImage tinyint(4) NOT NULL DEFAULT '0', EnableEmailCommunication tinyint(4) NOT NULL DEFAULT '0', + ProcessUnmatchedEmails tinyint(4) NOT NULL DEFAULT '0', ReplyFromName varchar(255) NOT NULL DEFAULT '', ReplyFromEmail varchar(255) NOT NULL DEFAULT '', ReplyCc varchar(255) NOT NULL DEFAULT '', @@ -1179,7 +1182,8 @@ PRIMARY KEY (FormId), KEY UseSecurityImage (UseSecurityImage), KEY RequireLogin (RequireLogin), - KEY EnableEmailCommunication (EnableEmailCommunication) + KEY EnableEmailCommunication (EnableEmailCommunication), + KEY ProcessUnmatchedEmails (ProcessUnmatchedEmails) ); CREATE TABLE Semaphores ( Index: install/upgrades.sql =================================================================== --- install/upgrades.sql (revision 13789) +++ install/upgrades.sql (working copy) @@ -1922,3 +1922,12 @@ UPDATE ConfigurationValues SET DisplayOrder = DisplayOrder - 0.01 WHERE ModuleOwner = 'In-Portal' AND `Section` = 'in-portal:configure_categories' AND DisplayOrder > 10.07; + +# ===== v 5.1.0 ===== +ALTER TABLE Forms + ADD ProcessUnmatchedEmails TINYINT NOT NULL DEFAULT '0' AFTER EnableEmailCommunication, + ADD INDEX (ProcessUnmatchedEmails); + +ALTER TABLE FormSubmissions + ADD MessageId VARCHAR(255) NULL DEFAULT NULL AFTER Notes, + ADD INDEX (MessageId); \ No newline at end of file Index: units/forms/form_submissions/form_submissions_config.php =================================================================== --- units/forms/form_submissions/form_submissions_config.php (revision 13756) +++ units/forms/form_submissions/form_submissions_config.php (working copy) @@ -133,8 +133,20 @@ 'LastUpdatedOn' => Array ('type' => 'int', 'formatter' => 'kDateFormatter', 'default' => NULL), 'Notes' => Array ('type' => 'string', 'default' => NULL), + 'MessageId' => Array ('type' => 'string', 'max_len' => 255, 'default' => NULL), ), - 'VirtualFields' => Array( + 'VirtualFields' => Array ( + 'MergeToSubmission' => Array ( + 'type' => 'int', + 'formatter' => 'kOptionsFormatter', 'options' => Array (), + 'default' => NULL + ), + + 'IsMergeToSubmission' => Array ( + 'type' => 'int', + 'formatter' => 'kOptionsFormatter', 'options' => Array (1 => 'la_Yes', 0 => 'la_No'), 'use_phrases' => 1, + 'default' => 0 + ), ), 'CalculatedFields' => Array( ), Index: units/forms/form_submissions/form_submissions_eh.php =================================================================== --- units/forms/form_submissions/form_submissions_eh.php (revision 13756) +++ units/forms/form_submissions/form_submissions_eh.php (working copy) @@ -238,6 +238,21 @@ } /** + * Checks, that target submission was selected for merging + * + * @param kEvent $event + */ + function OnBeforeItemUpdate(&$event) + { + parent::OnBeforeItemUpdate($event); + + $object =& $event->getObject(); + /* @var $object kDBItem */ + + $object->setRequired('MergeToSubmission', $object->GetDBField('IsMergeToSubmission')); + } + + /** * Passes form_id, when using "Prev"/"Next" toolbar buttons * * @param kEvent $event @@ -265,4 +280,159 @@ $event->SetRedirectParam('pass', 'm,form,formsubs'); } } + + /** + * Fills merge-to dropdown + * + * @param kEvent $event + */ + function OnAfterItemLoad(&$event) + { + parent::OnAfterItemLoad($event); + + $object =& $event->getObject(); + /* @var $object kDBItem */ + + $form_id = $object->GetDBField('FormId'); + $email_field = $this->getFieldByRole($form_id, EMAIL_COMMUNICATION_ROLE_EMAIL); + + if (!$email_field) { + return ; + } + + $sql = 'SELECT * + FROM ' . $this->Application->getUnitOption($event->Prefix, 'TableName') . ' + WHERE (FormId = ' . $form_id . ') AND (' . $email_field . ' = ' . $this->Conn->qstr( $object->GetDBField($email_field) ) . ')'; + $submissions = $this->Conn->Query($sql, 'FormSubmissionId'); + + // remove this submission + unset($submissions[ $object->GetID() ]); + + if (!$submissions) { + return ; + } + + $options = Array (); + + $name_field = $this->getFieldByRole($form_id, EMAIL_COMMUNICATION_ROLE_NAME); + $subject_field = $this->getFieldByRole($form_id, EMAIL_COMMUNICATION_ROLE_SUBJECT); + + $language =& $this->Application->recallObject('lang.current'); + /* @var $language kDBItem */ + + $date_format = $language->GetDBField('DateFormat'); + + foreach ($submissions as $submission_id => $submission_data) { + $option_title = ''; // SenderName (email@address.com) - Subject (06/29/2010) + + if ($name_field) { + $option_title = $submission_data[$name_field] . ' (' . $submission_data[$email_field] . ') - '; + } + else { + $option_title = $submission_data[$email_field] . ' - '; + } + + if ($subject_field) { + $option_title .= $submission_data[$subject_field] . ' (' . adodb_date($date_format, $submission_data['SubmissionTime']) . ')'; + } + else { + $option_title .= adodb_date($date_format, $submission_data['SubmissionTime']); + } + + $options[$submission_id] = $option_title; + } + + $field_options = $object->GetFieldOptions('MergeToSubmission'); + $field_options['options'] = $options; + $object->SetFieldOptions('MergeToSubmission', $field_options); + } + + /** + * Returns submission field name based on given role + * + * @param int $form_id + * @param string $role + * @return string + */ + function getFieldByRole($form_id, $role) + { + static $cache = Array (); + + if (!array_key_exists($form_id, $cache)) { + $id_field = $this->Application->getUnitOption('formflds', 'IDField'); + $table_name = $this->Application->getUnitOption('formflds', 'TableName'); + + $sql = 'SELECT ' . $id_field . ', EmailCommunicationRole + FROM ' . $table_name . ' + WHERE FormId = ' . $form_id . ' AND EmailCommunicationRole <> 0'; + $cache[$form_id] = $this->Conn->GetCol($sql, 'EmailCommunicationRole'); + } + + // get field name by role + return array_key_exists($role, $cache[$form_id]) ? 'fld_' . $cache[$form_id][$role] : false; + } + + /** + * Performs submission merge + * + * @param kEvent $event + */ + function OnUpdate(&$event) + { + parent::OnUpdate($event); + + if ($event->status == erSUCCESS) { + $object =& $event->getObject(); + /* @var $object kDBItem */ + + $merge_to = $object->GetDBField('MergeToSubmission'); + + if (!$merge_to) { + return ; + } + + $form_id = $object->GetDBField('FormId'); + + $sql = 'SELECT * + FROM ' . TABLE_PREFIX . 'Forms + WHERE FormId = ' . $form_id; + $form_info = $this->Conn->GetRow($sql); + + $reply =& $this->Application->recallObject('submission-log.merge', null, Array ('skip_autoload' => true)); + /* @var $reply kDBItem */ + + $email_field = $this->getFieldByRole($form_id, EMAIL_COMMUNICATION_ROLE_EMAIL); + $subject_field = $this->getFieldByRole($form_id, EMAIL_COMMUNICATION_ROLE_SUBJECT); + $body_field = $this->getFieldByRole($form_id, EMAIL_COMMUNICATION_ROLE_BODY); + + $reply->SetDBField('FormSubmissionId', $merge_to); + + if ($email_field) { + $reply->SetDBField('FromEmail', $object->GetDBField($email_field)); + } + + $reply->SetDBField('ToEmail', $form_info['ReplyFromEmail']); + + if ($subject_field) { + $reply->SetDBField('Subject', $object->GetDBField($subject_field)); + } + + if ($body_field) { + $reply->SetDBField('Message', $object->GetDBField($body_field)); + } + + $reply->SetDBField('SentOn_date', $object->GetDBField('SubmissionTime')); + $reply->SetDBField('SentOn_time', $object->GetDBField('SubmissionTime')); + $reply->SetDBField('MessageId', $object->GetDBField('MessageId')); + $reply->SetDBField('SentStatus', SUBMISSION_LOG_SENT); + + // as if emails was really received via mailbox + $this->Application->SetVar('client_mode', 1); + + if ($reply->Create()) { + // delete submission, since it was merged + $object->Delete(); + } + } + } } \ No newline at end of file Index: units/forms/forms/forms_config.php =================================================================== --- units/forms/forms/forms_config.php (revision 13756) +++ units/forms/forms/forms_config.php (working copy) @@ -151,6 +151,11 @@ 'formatter' => 'kOptionsFormatter', 'options' => Array (1 => 'la_Yes', 0 => 'la_No'), 'use_phrases' => 1, 'not_null' => 1, 'default' => 0 ), + 'ProcessUnmatchedEmails' => Array ( + 'type' => 'int', + 'formatter' => 'kOptionsFormatter', 'options' => Array (1 => 'la_Yes', 0 => 'la_No'), 'use_phrases' => 1, + 'not_null' => 1, 'default' => 0 + ), 'ReplyFromName' => Array ('type' => 'string', 'max_len' => 255, 'not_null' => 1, 'default' => ''), 'ReplyFromEmail' => Array ('type' => 'string', 'max_len' => 255, 'not_null' => 1, 'default' => ''), 'ReplyCc' => Array ('type' => 'string', 'max_len' => 255, 'not_null' => 1, 'default' => ''), Index: units/forms/forms/forms_eh.php =================================================================== --- units/forms/forms/forms_eh.php (revision 13756) +++ units/forms/forms/forms_eh.php (working copy) @@ -388,6 +388,7 @@ Array ( 'recipient_email' => $recipient_email, 'bounce_mode' => $bounce_mode, + 'form_info' => $form_info, ) ); } @@ -459,6 +460,63 @@ if (!preg_match('/^(.*) #verify(.*)$/', $fields_hash['Subject'], $regs)) { // incorrect subject, no verification code + $form_info = $params['form_info']; + + if ($form_info['ProcessUnmatchedEmails']) { + // it's requested to convert unmatched emails to new submissions + $form_id = $form_info['FormId']; + $this->Application->SetVar('form_id', $form_id); + + $sql = 'SELECT ' . $this->Application->getUnitOption('formsubs', 'IDField') . ' + FROM ' . $this->Application->getUnitOption('formsubs', 'TableName') . ' + WHERE MessageId = ' . $this->Conn->qstr($fields_hash['MessageId']); + $found = $this->Conn->GetOne($sql); + + if ($found) { + // don't process same message twice + return false; + } + + $sql = 'SELECT * + FROM ' . TABLE_PREFIX . 'FormFields + WHERE (FormId = ' . $form_info['FormId'] . ') AND (EmailCommunicationRole > 0)'; + $form_fields = $this->Conn->Query($sql, 'EmailCommunicationRole'); + + // what roles are filled from what fields + $role_mapping = Array ( + EMAIL_COMMUNICATION_ROLE_EMAIL => 'FromEmail', + EMAIL_COMMUNICATION_ROLE_NAME => 'FromName', + EMAIL_COMMUNICATION_ROLE_SUBJECT => 'Subject', + EMAIL_COMMUNICATION_ROLE_BODY => 'Message', + ); + + $submission_fields = Array (); + + foreach ($role_mapping as $role => $email_field) { + if (array_key_exists($role, $form_fields)) { + $submission_fields[ 'fld_' . $form_fields[$role]['FormFieldId'] ] = $fields_hash[$email_field]; + } + } + + if ($submission_fields) { + // remove object, because it's linked to single form upon creation forever + $this->Application->removeObject('formsubs.-item'); + + $form_submission =& $this->Application->recallObject('formsubs.-item', null, Array ('skip_autoload' => true)); + /* @var $form_submission kDBItem */ + + // in case that other non-role mapped fields are required + $form_submission->IgnoreValidation = true; + $form_submission->SetDBFieldsFromHash($submission_fields); + $form_submission->SetDBField('FormId', $form_id); + $form_submission->SetDBField('MessageId', $fields_hash['MessageId']); + $form_submission->SetDBField('SubmissionTime_date', adodb_mktime()); + $form_submission->SetDBField('SubmissionTime_time', adodb_mktime()); + + return $form_submission->Create(); + } + } + return false; } Index: units/forms/submission_log/submission_log_eh.php =================================================================== --- units/forms/submission_log/submission_log_eh.php (revision 13756) +++ units/forms/submission_log/submission_log_eh.php (working copy) @@ -486,7 +486,7 @@ $now = adodb_mktime(); $sent_status = $object->GetDBField('SentStatus'); - if (($sent_status == SUBMISSION_LOG_SENT) && ($sent_status != $object->GetOriginalField('SentStatus'))) { + if (($event->Special != 'merge') && ($sent_status == SUBMISSION_LOG_SENT) && ($sent_status != $object->GetOriginalField('SentStatus'))) { // sent status was set $object->SetDBField('SentOn_date', $now); $object->SetDBField('SentOn_time', $now);