diff --git a/application/controllers/jobs/AmpelMail.php b/application/controllers/jobs/AmpelMail.php
new file mode 100644
index 000000000..f77122735
--- /dev/null
+++ b/application/controllers/jobs/AmpelMail.php
@@ -0,0 +1,214 @@
+input->is_cli_request())
+ {
+ $cli = true;
+ }
+ else
+ {
+ $this->output->set_status_header(403, 'Jobs must be run from the CLI');
+ echo "Jobs must be run from the CLI";
+ exit;
+ }
+
+ // Load models
+ $this->load->model('content/Ampel_model', 'AmpelModel');
+ $this->load->model('person/Person_model', 'PersonModel');
+
+ // Load helpers
+ $this->load->helper('sancho');
+ }
+
+ /**
+ * Main function index as help
+ *
+ * @return void
+ */
+ public function index()
+ {
+ $result = "The following are the available command line interface commands\n\n";
+ $result .= "php index.ci.php jobs/AmpelMail generateAmpelMail";
+
+ echo $result. PHP_EOL;
+ }
+
+ /**
+ * Generates mail content for new and overdue Ampeln, which
+ * 1. are not confirmed by the user yet and
+ * 2. are marked to be sent by email
+ * Ampel is new when inserted within the last 7 days before the cronjob runs (as cronjob runs weekly)
+ * Ampel is overdue when the cronjob runs after the deadline date.
+ * @return void
+ */
+ public function generateAmpelMail()
+ {
+ // Get all notifications, that are not expired, not before vorlaufzeit AND email is true
+ $result_active_ampeln = $this->AmpelModel->active(true);
+
+ // Stores users, description, deadline and system-link of notifications
+ $new_ampel_data_arr = array(); // data of new notifications that are not confirmed
+ $overdue_ampel_data_arr = array(); // data of overdue notifications that are not confirmed
+
+ if (hasData($result_active_ampeln))
+ {
+ $ampel_arr = $result_active_ampeln->retval;
+
+ // Loop through ampeln
+ foreach ($ampel_arr as $ampel)
+ {
+ $ampel_id = $ampel->ampel_id;
+ $now = date_create(date('Y-m-d'));
+ $deadline = date_create($ampel->deadline);
+ $insert_date = date_create($ampel->insertamum);
+ $qry_all_ampel_user = $ampel->benutzer_select; // sql select to get all user who get this ampel
+ $new = false;
+ $overdue = false;
+
+ // get all user, who get this ampel
+ $result_ampel_user = $this->AmpelModel->execBenutzerSelect($qry_all_ampel_user);
+
+ if (hasData($result_ampel_user))
+ {
+ $ampel_user_arr = $result_ampel_user->retval;
+
+ // loop through all user, who get this ampel
+ foreach ($ampel_user_arr as $ampel_user)
+ {
+ $uid = $ampel_user->uid;
+
+ // break if ampel was almost confirmed by the user
+ if($this->AmpelModel->isConfirmed($ampel_id, $uid)) break;
+
+ // check if ampel is new (inserted within last week, as cronjob will run every week)
+ if ($now->diff($insert_date)->days <= 7) $new = true;
+
+ //check if ampel is overdue
+ if ($now > $deadline) $overdue = true;
+
+ // if ampel is new
+ if ($new)
+ {
+ $html_text = '
'. strtoupper($ampel->kurzbz). '
';
+
+ // create template-specific data array of new notifications
+ // if uid already exists in the array, only the html text will be added to the existing html text
+ $new_ampel_data_arr =
+ $this->_getAmpelContentData($uid, $html_text, $new_ampel_data_arr);
+ }
+
+ // if ampel is overdue
+ if ($overdue)
+ {
+ $html_text = '
+ '. strtoupper($ampel->kurzbz). '
+
+ Die Deadline für die Bestätigung war am
+ '. date_format($deadline, 'Y-m-d'). '
+
+
';
+
+ // create template-specific data array of overdue notifications
+ // if uid already exists in the array, only the html text will be added to the existing html text
+ $overdue_ampel_data_arr =
+ $this->_getAmpelContentData($uid, $html_text, $overdue_ampel_data_arr);
+ }
+ }
+ }
+ elseif (isError($result_ampel_user))
+ {
+ show_error($result_ampel_user->error);
+ }
+ }
+ }
+ elseif (isError($result_active_ampeln))
+ {
+ show_error($result_active_ampeln->error);
+ }
+
+ // Send mails for new ampeln merged by user
+ foreach ($new_ampel_data_arr as $new_ampel_data)
+ {
+ sendMail(
+ 'Sancho_Content_AmpelNeu',
+ $new_ampel_data,
+ $new_ampel_data['uid']. '@'. DOMAIN,
+ 'Du hast eine neue Ampel!',
+ 'sancho_header_neue_nachrichten_in_ampelsystem.jpg'
+ );
+ };
+ // Send mails for overdue ampeln merged by user
+ foreach ($overdue_ampel_data_arr as $overdue_ampel_data)
+ {
+ sendMail(
+ 'Sancho_Content_AmpelUeberfaellig',
+ $overdue_ampel_data,
+ $overdue_ampel_data['uid']. '@'. DOMAIN,
+ 'Bestätige bitte Deine Ampel!',
+ 'sancho_header_ampel_overdue.jpg'
+ );
+ };
+ }
+
+ // ------------------------------------------------------------------------
+ // Private methods
+ /**
+ * Returns associative array with data as needed in the ampel content templates.
+ * @param string $uid UID, needed to merge user.
+ * @param string $html_text Specific HTML Content to be set initially for a user or to add if user exists.
+ * @param array $ampel_data_arr Array with ampeln.
+ * @return array
+ */
+ private function _getAmpelContentData($uid, $html_text, $ampel_data_arr)
+ {
+ $firstName = $this->PersonModel->getByUid($uid)->retval[0]->vorname;
+
+ // check if user already exists in the array
+ $key_position = array_search($uid, array_column($ampel_data_arr, 'uid'));
+
+ // If user already exists in the array, add only new ampel data to users ampel list
+ if ($key_position !== false)
+ {
+ $ampel_data_arr[$key_position]['ampel_list'] .= $html_text;
+ }
+ // If user does not exist, create new user and push all data needed
+ else
+ {
+ $ampel_data_arr[] = array(
+ 'uid' => $uid,
+ 'firstName' => $firstName,
+ 'ampel_list' => $html_text,
+ 'link' => self::CIS_AMPELVERWALTUNG_URL
+ );
+ }
+ return $ampel_data_arr;
+ }
+}
diff --git a/application/helpers/sancho_helper.php b/application/helpers/sancho_helper.php
new file mode 100644
index 000000000..210c5115b
--- /dev/null
+++ b/application/helpers/sancho_helper.php
@@ -0,0 +1,93 @@
+load->library('email');
+ $ci->load->library('MailLib');
+
+ $sanchoHeader_img = 'skin/images/sancho/'. $headerImg;
+ $sanchoFooter_img = 'skin/images/sancho/sancho_footer.jpg';
+
+ // Embed sancho header and footer image
+ // reset important to ensure embedding of images when called in a loop
+ $ci->email->clear(true); // clear vars and attachments
+ $ci->email->attach($sanchoHeader_img);
+ $ci->email->attach($sanchoFooter_img);
+ $cid_header = $ci->email->attachment_cid($sanchoHeader_img); // sets unique content id for embedding
+ $cid_footer = $ci->email->attachment_cid($sanchoFooter_img); // sets unique content id for embedding
+
+ // Set specific mail content into specific content template
+ $content = _parseMailContent($vorlage_kurzbz, $vorlage_data);
+
+ // overall main content data array
+ $layout = array(
+ 'CID_header' => $cid_header,
+ 'CID_footer' => $cid_footer,
+ 'content' => $content
+ );
+
+ // Set overall main content into the sancho mail template
+ $body = _parseMailContent('Sancho_Mail_Template', $layout);
+
+ // Send mail
+ $ci->maillib->send('sancho@'. DOMAIN, $to, $subject, $body);
+}
+
+/**
+ * Replace variables in the mail content template with specific mail content data.
+ * @param string $vorlage_kurzbz Name of the template for specific mail content.
+ * @param array $vorlage_data Associative array with specific mail content varibales
+ * to be replaced in the content template.
+ * @return string
+ */
+function _parseMailContent($vorlage_kurzbz, $vorlage_data)
+{
+ $ci =& get_instance();
+ $ci->load->library('VorlageLib');
+
+ $result = $ci->vorlagelib->getVorlagetextByVorlage($vorlage_kurzbz);
+
+ if (isSuccess($result))
+ {
+ // If the text and the subject of the template are not empty
+ if (is_array($result->retval) && count($result->retval) > 0 &&
+ !empty($result->retval[0]->text))
+ {
+ // Parses template text
+ $parsedText = $ci->vorlagelib->parseVorlagetext($result->retval[0]->text, $vorlage_data);
+
+ return $parsedText;
+ }
+ }
+}
diff --git a/application/models/content/Ampel_model.php b/application/models/content/Ampel_model.php
index 84109e17b..e569755df 100644
--- a/application/models/content/Ampel_model.php
+++ b/application/models/content/Ampel_model.php
@@ -1,7 +1,6 @@
dbTable = 'public.tbl_ampel';
$this->pk = 'ampel_id';
}
+
+ /**
+ * Returns all active Ampeln, that are actually:
+ * 1. not after the deadline date
+ * 2. not before the vorlaufszeit
+ * @param bool $email If true, then only ampeln are retrieved that are marked to be sent by mail.
+ * @return array Returns array of objects.
+ */
+ public function active($email = false)
+ {
+ $parametersArray = null;
+ $query = '
+ SELECT *
+ FROM public.tbl_ampel
+ WHERE';
+
+ if ($email === true)
+ {
+ $parametersArray['email'] = $email;
+ $query .= ' email = ? AND';
+ }
+
+ $query .= '
+ (NOW()<(deadline+(verfallszeit || \' days\')::interval)::date)
+ OR (verfallszeit IS NULL AND NOW() < deadline)
+ AND (NOW()>(deadline-(vorlaufzeit || \' days\')::interval)::date)
+ OR (vorlaufzeit IS NULL AND NOW() > deadline)';
+
+ $query .= ' ORDER BY deadline DESC';
+
+ return $this->execQuery($query, $parametersArray);
+ }
+
+ /**
+ * Returns all Ampel-receiver of a specific Ampel.
+ * @param string $benutzer_select SQL Statement which defines the Ampel-receiver.
+ * @return array Returns array of objects with property 'uid'.
+ */
+ public function execBenutzerSelect($benutzer_select)
+ {
+ if (isset($benutzer_select) && !empty(trim($benutzer_select)))
+ {
+ return $this->execQuery($benutzer_select);
+ }
+ }
+
+ /**
+ * Checks if Ampel was confirmed by the user.
+ * @param int $ampel_id Ampel-ID
+ * @param string $uid UID
+ * @return bool
+ */
+ public function isConfirmed($ampel_id, $uid)
+ {
+ $result = null;
+ $query = '
+ SELECT 1
+ FROM public.tbl_ampel_benutzer_bestaetigt
+ WHERE ampel_id = ?
+ AND uid = ?';
+
+ if (isset($ampel_id, $uid))
+ {
+ $result = $this->execQuery($query, array($ampel_id, $uid));
+ }
+
+ if ($result)
+ {
+ if (count($result->retval) > 0)
+ {
+ return true;
+ }
+ else
+ {
+ return false;
+ }
+ }
+ else
+ return $result; //will contain the error-msg from execQuery
+ }
}
diff --git a/skin/images/sancho/sancho_header_TEMPLATE.jpg b/skin/images/sancho/sancho_header_TEMPLATE.jpg
deleted file mode 100644
index c237afb96..000000000
Binary files a/skin/images/sancho/sancho_header_TEMPLATE.jpg and /dev/null differ
diff --git a/skin/images/sancho/sancho_header_TEMPLATE.xcf b/skin/images/sancho/sancho_header_TEMPLATE.xcf
new file mode 100644
index 000000000..8334fd0c1
Binary files /dev/null and b/skin/images/sancho/sancho_header_TEMPLATE.xcf differ
diff --git a/skin/images/sancho/sancho_header_ampel_overdue.jpg b/skin/images/sancho/sancho_header_ampel_overdue.jpg
new file mode 100644
index 000000000..84bdad785
Binary files /dev/null and b/skin/images/sancho/sancho_header_ampel_overdue.jpg differ
diff --git a/skin/images/sancho/sancho_header_deadline_ampel_overdue.jpg b/skin/images/sancho/sancho_header_deadline_ampel_overdue.jpg
deleted file mode 100644
index 662afab92..000000000
Binary files a/skin/images/sancho/sancho_header_deadline_ampel_overdue.jpg and /dev/null differ
diff --git a/skin/images/sancho/sancho_header_du_hast_neue_nachrichten.jpg b/skin/images/sancho/sancho_header_du_hast_neue_nachrichten.jpg
new file mode 100644
index 000000000..2bc1657f9
Binary files /dev/null and b/skin/images/sancho/sancho_header_du_hast_neue_nachrichten.jpg differ
diff --git a/skin/images/sancho/sancho_header_ich_habe_neue_nachrichten_fuer_dich.jpg b/skin/images/sancho/sancho_header_ich_habe_neue_nachrichten_fuer_dich.jpg
new file mode 100644
index 000000000..edafa54ce
Binary files /dev/null and b/skin/images/sancho/sancho_header_ich_habe_neue_nachrichten_fuer_dich.jpg differ
diff --git a/skin/images/sancho/sancho_header_ich_habe_neue_nachrichten_fuer_sie.jpg b/skin/images/sancho/sancho_header_ich_habe_neue_nachrichten_fuer_sie.jpg
deleted file mode 100644
index dc7f49361..000000000
Binary files a/skin/images/sancho/sancho_header_ich_habe_neue_nachrichten_fuer_sie.jpg and /dev/null differ
diff --git a/skin/images/sancho/sancho_header_neue_nachrichten_in_ampelsystem.jpg b/skin/images/sancho/sancho_header_neue_nachrichten_in_ampelsystem.jpg
index a47bb7c0e..e9d23ebc8 100644
Binary files a/skin/images/sancho/sancho_header_neue_nachrichten_in_ampelsystem.jpg and b/skin/images/sancho/sancho_header_neue_nachrichten_in_ampelsystem.jpg differ
diff --git a/skin/images/sancho/sancho_header_sie_haben_neue_nachrichten.jpg b/skin/images/sancho/sancho_header_sie_haben_neue_nachrichten.jpg
deleted file mode 100644
index e5e7962b6..000000000
Binary files a/skin/images/sancho/sancho_header_sie_haben_neue_nachrichten.jpg and /dev/null differ