ORIENT/plugins/janvince/smallcontactform/models/Message.php

541 lines
19 KiB
PHP

<?php namespace JanVince\SmallContactForm\Models;
use Str;
use Model;
use URL;
use October\Rain\Router\Helper as RouterHelper;
use Cms\Classes\Page as CmsPage;
use Cms\Classes\Theme;
use JanVince\SmallContactForm\Models\Settings;
use Log;
use Validator;
use Mail;
use Request;
use Carbon\Carbon;
use View;
use App;
use System\Models\MailTemplate;
use System\Classes\MailManager;
use Twig;
use Input;
use System\Models\File;
class Message extends Model
{
use \October\Rain\Database\Traits\Validation;
public $table = 'janvince_smallcontactform_messages';
public $implement = ['@RainLab.Translate.Behaviors.TranslatableModel'];
public $timestamps = true;
public $rules = [];
public $translatable = [];
protected $guarded = [];
protected $jsonable = ['form_data'];
public $attachMany = [
'uploads' => 'System\Models\File',
];
/**
* Scope new messages only
*/
public function scopeIsNew($query)
{
return $query->where('new_message', '=', 1);
}
/**
* Scope read messages only
*/
public function scopeIsRead($query)
{
return $query->where('new_message', '=', 0);
}
public function storeFormData($data, $formAlias, $formDescription){
if(Settings::getTranslated('privacy_disable_messages_saving')) {
return;
}
$output = [];
$name_field_value = NULL;
$email_field_value = NULL;
$message_field_value = NULL;
$formFields = Settings::getTranslated('form_fields');
$uploads = [];
foreach($data as $key => $value) {
// skip helpers
if(substr($key, 0, 1) == '_'){
continue;
}
// skip reCaptcha
if($key == 'g-recaptcha-response'){
continue;
}
// skip non-defined fields
// store uploaded file -- currently only one file is supported
$fieldDefined = null;
$fieldUpload = null;
foreach( $formFields as $field) {
if( $field['name'] == $key) {
$fieldDefined = true;
if($field['type'] == 'file') {
$fieldUpload = true;
if(!empty(Input::file($key))) {
$file = new File;
$file->data = (Input::file($key));
$file->is_public = true;
$file->save();
$uploads[] = $file;
}
}
}
}
// skip uploads
if($fieldUpload){
continue;
}
if( !$fieldDefined ) {
Log::warning('SMALL CONTACT FORM WARNING: Found a non-defined field in sent data! Field name: ' . e($key) . ' and value: ' . e($value['value']) );
continue;
}
$output[$key] = e($value['value']);
// if email field is assigned in autoreply, save it separatelly
if(empty($email_field_value) and $key == Settings::getTranslated('autoreply_email_field')){
$email_field_value = e($value['value']);
}
// if name field is assigned in autoreply, save it separatelly
if(empty($name_field_value) and $key == Settings::getTranslated('autoreply_name_field')){
$name_field_value = e($value['value']);
}
// if message is assigned in autoreply, save it separatelly
if(empty($message_field_value) and $key == Settings::getTranslated('autoreply_message_field')){
$message_field_value = e($value['value']);
}
}
$this->form_data = $output;
$this->name = $name_field_value;
$this->email = $email_field_value;
$this->message = $message_field_value;
$this->remote_ip = Request::ip();
$this->form_alias = $formAlias;
$this->form_description = $formDescription;
$this->url = url()->full();
$this->save();
// Add files
if($uploads) {
foreach($uploads as $upload) {
$this->uploads()->add($upload);
}
}
return $this;
}
/**
* Build and send autoreply message
*/
public function sendAutoreplyEmail($postData, $componentProperties = [], $formAlias, $formDescription, $messageObject){
if(!Settings::getTranslated('allow_autoreply')) {
return;
}
if (!empty($componentProperties['disable_autoreply'])) {
return;
}
if(!Settings::getTranslated('autoreply_email_field')) {
Log::error('SMALL CONTACT FORM ERROR: Contact form data have no email to send autoreply message!');
return;
}
/**
* Extract and test email field value
*/
$sendTo = '';
foreach($postData as $key => $field) {
if($key == Settings::getTranslated('autoreply_email_field')){
$sendTo = $field['value'];
}
}
$validator = Validator::make(['email' => $sendTo], ['email' => 'required|email']);
if($validator->fails()){
Log::error('SMALL CONTACT FORM ERROR: Email to send autoreply is not valid!' . PHP_EOL . ' Data: '. json_encode($postData) );
return;
}
if( Settings::getTranslated('allow_email_queue') ){
$method = 'queue';
} else {
$method = 'send';
}
$output = [];
$outputFull = [];
$formFields = Settings::getTranslated('form_fields');
foreach($formFields as $field) {
if(!empty($field['type'] and $field['type'] == 'file')) {
continue;
}
$fieldValue = null;
if( !empty( $postData[ $field['name'] ]['value'] ) ) {
$fieldValue = e( html_entity_decode( $postData[ $field['name'] ]['value'] ) );
} else {
$fieldValue = null;
}
if( !empty( $field['name'] ) ) {
$outputFull[ $field['name'] ] = array_merge( $field, [ 'value' => $fieldValue ] );
}
$output[ $field['name'] ] = $fieldValue;
}
$output['form_description'] = $formDescription;
$output['form_alias'] = $formAlias;
$template = Settings::getTranslatedTemplates('en', App::getLocale(), 'autoreply');
if( Settings::getTranslated('email_template') ){
if(View::exists(Settings::getTranslated('email_template')) OR !empty( MailTemplate::listAllTemplates()[Settings::getTranslated('email_template')] ) ) {
$template = Settings::getTranslated('email_template');
} else {
Log::error('SMALL CONTACT FORM: Missing defined email template: ' . Settings::getTranslated('email_template') . '. Default template will be used!');
}
}
/**
* Override email template by component property
* Language specific template has priority (override non language specific)
*/
if ( !empty($componentProperties['autoreply_template']) and !empty( MailTemplate::listAllTemplates()[ $componentProperties['autoreply_template'] ] ) ) {
$template = $componentProperties['autoreply_template'];
} elseif ( !empty($componentProperties['autoreply_template']) and empty( MailTemplate::listAllTemplates()[ $componentProperties['autoreply_template'] ] ) ) {
Log::error('SMALL CONTACT FORM: Missing defined email template: ' . $componentProperties['autoreply_template'] . '. ' . $template . ' template will be used!');
}
if ( !empty($componentProperties[ ('autoreply_template_'.App::getLocale())]) and !empty( MailTemplate::listAllTemplates()[ $componentProperties[ ('autoreply_template_'.App::getLocale())] ] ) ) {
$template = $componentProperties[('autoreply_template_'.App::getLocale())];
} elseif ( !empty($componentProperties[ ('autoreply_template_'.App::getLocale())]) and empty( MailTemplate::listAllTemplates()[ $componentProperties[ ('autoreply_template_'.App::getLocale())] ] ) ) {
Log::error('SMALL CONTACT FORM: Missing defined email template: ' . $componentProperties[ ('autoreply_template_'.App::getLocale())] . '. ' . $template . ' template will be used!');
}
if(!empty($messageObject->uploads))
{
$uploads = $messageObject->uploads;
}
else
{
$uploads = [];
}
Mail::{$method}($template, ['messageObject' => $messageObject, 'uploads' => $uploads, 'fields' => $output, 'fieldsDetails' => $outputFull, 'url' => url()->full()], function($message) use($sendTo, $componentProperties, $output){
$message->to($sendTo);
if (!empty($componentProperties['autoreply_subject'])) {
$message->subject(Twig::parse($componentProperties['autoreply_subject'],['fields' => $output]));
\App::forgetInstance('parse.twig');
\App::forgetInstance('twig.environment');
} elseif (Settings::getTranslated('email_subject')) {
$message->subject(Twig::parse(Settings::getTranslated('email_subject'), ['fields' => $output]));
\App::forgetInstance('parse.twig');
\App::forgetInstance('twig.environment');
}
/**
* From address
* Component's property can override this
*/
$fromAddress = null;
$fromAddressName = null;
if( Settings::getTranslated('email_address_from') ) {
$fromAddress = Settings::getTranslated('email_address_from');
$fromAddressName = Settings::getTranslated('email_address_from_name');
}
if( !empty($componentProperties['autoreply_address_from']) ) {
$fromAddress = $componentProperties['autoreply_address_from'];
}
if( !empty($componentProperties['autoreply_address_from_name']) ) {
$fromAddressName = $componentProperties['autoreply_address_from_name'];
}
if( !empty($componentProperties[ ('autoreply_address_from_name_'.App::getLocale()) ]) ) {
$fromAddressName = $componentProperties[ ('autoreply_address_from_name_'.App::getLocale()) ];
}
$validator = Validator::make(['email' => $fromAddress], ['email' => 'required|email']);
if($validator->fails()){
Log::error('SMALL CONTACT FORM ERROR: Autoreply email address is invalid (' .$fromAddress. ')! System email address and name will be used.');
} else {
$message->from($fromAddress, $fromAddressName);
}
/**
* Reply To address
* Component's property can override this
*/
$replyToAddress = null;
if( Settings::getTranslated('email_address_replyto') ) {
$replyToAddress = Settings::getTranslated('email_address_replyto');
}
if( !empty($componentProperties['autoreply_address_replyto']) ) {
$replyToAddress = $componentProperties['autoreply_address_replyto'];
}
if( $replyToAddress ) {
$validator = Validator::make(['email' => $replyToAddress], ['email' => 'required|email']);
if($validator->fails()){
Log::error('SMALL CONTACT FORM ERROR: Autoreply Reply To email address is invalid (' .$replyToAddress. ')! No Reply To header will be added.');
} else {
$message->replyTo($replyToAddress);
}
}
});
}
/**
* Build and send notification message
*/
public function sendNotificationEmail($postData, $componentProperties = [], $formAlias, $formDescription, $messageObject){
if(!Settings::getTranslated('allow_notifications')) {
return;
}
if(!empty($componentProperties['disable_notifications'])) {
return;
}
$sendTo = (!empty($componentProperties['notification_address_to']) ? $componentProperties['notification_address_to'] : Settings::getTranslated('notification_address_to') );
$sendToAddresses = explode(',', $sendTo);
$sendToAddressesValidated = [];
foreach($sendToAddresses as $sendToAddress) {
$validator = Validator::make(['email' => trim($sendToAddress)], ['email' => 'required|email']);
if($validator->fails()){
Log::error('SMALL CONTACT FORM ERROR: Notification email address (' .trim($sendToAddress). ') is invalid! No notification will be delivered!');
} else {
$sendToAddressesValidated[] = trim($sendToAddress);
}
}
if( !count($sendToAddressesValidated) ) {
return;
}
if( Settings::getTranslated('allow_email_queue') ){
$method = 'queue';
} else {
$method = 'send';
}
$output = [];
$outputFull = [];
$formFields = Settings::getTranslated('form_fields');
$replyToAddress = null;
$replyToName = null;
foreach($formFields as $field) {
if(!empty($field['type'] and $field['type'] == 'file')) {
continue;
}
$fieldValue = null;
if( !empty( $postData[ $field['name'] ]['value'] ) ) {
$fieldValue = e( html_entity_decode( $postData[ $field['name'] ]['value'] ) );
} else {
$fieldValue = null;
}
if( !empty( $field['name'] ) ) {
$outputFull[ $field['name'] ] = array_merge( $field, [ 'value' => $fieldValue ] );
}
// If email field is assigned, prepare for replyTo
if(empty($replyToAddress) and $field['name'] == Settings::getTranslated('autoreply_email_field') and isset($postData[$field['name']]['value'])){
$replyToAddress = e( $postData[$field['name']]['value'] );
}
// If name field is assigned, prepare for fromAddress
if(empty($replyToName) and $field['name'] == Settings::getTranslated('autoreply_name_field') and isset($postData[$field['name']]['value'])){
$replyToName = e( $postData[$field['name']]['value'] );
}
$output[ $field['name'] ] = $fieldValue;
}
$output['form_description'] = $formDescription;
$output['form_alias'] = $formAlias;
$template = Settings::getTranslatedTemplates('en', App::getLocale(), 'notification');
if( Settings::getTranslated('notification_template') ){
if(View::exists(Settings::getTranslated('notification_template')) OR !empty( MailTemplate::listAllTemplates()[Settings::getTranslated('notification_template')] ) ) {
$template = Settings::getTranslated('notification_template');
} else {
Log::error('SMALL CONTACT FORM: Missing defined email template: ' . Settings::getTranslated('notification_template') . '. Default template will be used!');
}
}
/**
* Override email template by component property
* Language specific template has priority (override non language specific)
*/
if ( !empty($componentProperties['notification_template']) and !empty( MailTemplate::listAllTemplates()[ $componentProperties['notification_template'] ] ) ) {
$template = $componentProperties['notification_template'];
} elseif ( !empty($componentProperties['notification_template']) and empty( MailTemplate::listAllTemplates()[ $componentProperties['notification_template'] ] ) ) {
Log::error('SMALL CONTACT FORM: Missing defined email template: ' . $componentProperties['notification_template'] . '. ' . $template . ' template will be used!');
}
if ( !empty($componentProperties[ ('notification_template_'.App::getLocale())]) and !empty( MailTemplate::listAllTemplates()[ $componentProperties[ ('notification_template_'.App::getLocale())] ] ) ) {
$template = $componentProperties[('notification_template_'.App::getLocale())];
} elseif ( !empty($componentProperties[ ('notification_template_'.App::getLocale())]) and empty( MailTemplate::listAllTemplates()[ $componentProperties[ ('notification_template_'.App::getLocale())] ] ) ) {
Log::error('SMALL CONTACT FORM: Missing defined email template: ' . $componentProperties[ ('notification_template_'.App::getLocale())] . '. ' . $template . ' template will be used!');
}
if(!empty($messageObject->uploads))
{
$uploads = $messageObject->uploads;
}
else
{
$uploads = [];
}
Mail::{$method}($template, ['messageObject' => $messageObject, 'uploads' => $uploads, 'fields' => $output, 'fieldsDetails' => $outputFull, 'url' => url()->full()], function($message) use($sendToAddressesValidated, $replyToAddress, $replyToName, $componentProperties, $output){
if( count($sendToAddressesValidated)>1 ) {
foreach($sendToAddressesValidated as $address) {
$message->bcc($address);
}
} elseif( !empty($sendToAddressesValidated[0]) ) {
$message->to($sendToAddressesValidated[0]);
} else {
return;
}
if (!empty($componentProperties['notification_subject'])) {
$message->subject(Twig::parse($componentProperties['notification_subject'], ['fields' => $output]));
\App::forgetInstance('parse.twig');
\App::forgetInstance('twig.environment');
}
/**
* Set Reply to address and also set From address if requested
*/
if ( !empty($replyToAddress) ) {
$validator = Validator::make(['email' => $replyToAddress], ['email' => 'required|email']);
if($validator->fails()){
Log::error('SMALL CONTACT FORM ERROR: Notification replyTo address is not valid (' .$replyToAddress. ')! Reply to address will not be used.');
return;
}
$message->replyTo($replyToAddress, $replyToName);
// Force From field if requested
if ( Settings::getTranslated('notification_address_from_form') ) {
$message->from($replyToAddress, $replyToName);
}
}
/**
* Set From address if defined in component property
*/
if ( !empty($componentProperties['notification_address_from'])) {
if (!empty($componentProperties['notification_address_from_name'])) {
$fromAddressName = $componentProperties['notification_address_from_name'];
} else {
$fromAddressName = null;
}
$message->from($componentProperties['notification_address_from'], $fromAddressName);
}
});
}
/**
* Test how many times was given IP address used this day
* @return int
*/
public function testIPAddress($ip){
$today = Carbon::today();
$count = Message::whereDate('created_at', '=', $today->toDateString())
->where('remote_ip', '=', $ip)
->count();
return $count;
}
}