746 lines
30 KiB
PHP
746 lines
30 KiB
PHP
<?php
|
|
|
|
use PHPMailer\PHPMailer\PHPMailer;
|
|
use PHPMailer\PHPMailer\Exception;
|
|
|
|
/**
|
|
* Description of UserController
|
|
*
|
|
* @author fronk
|
|
*/
|
|
class UserController extends mfBaseController
|
|
{
|
|
private $me;
|
|
|
|
protected function init($request = null)
|
|
{
|
|
$this->needlogin = true;
|
|
$me = new User();
|
|
$me->loadMe(true);
|
|
$this->me = $me;
|
|
$this->layout()->set("me", $me);
|
|
|
|
if (!$me->isAdmin() && ($this->action != "" || $request != null)) $this->redirect("Dashboard");
|
|
if ($_SERVER['REQUEST_METHOD'] === 'POST') $this->postData = json_decode(file_get_contents('php://input'), true);
|
|
}
|
|
|
|
protected function indexAction($request)
|
|
{
|
|
if (!$this->isAdmin()) {
|
|
throw new Exception("Forbidden", 403);
|
|
}
|
|
|
|
Helper::renderVue($this, "User", "Benutzer", [
|
|
"IS_ADMIN" => $this->me->isAdmin(),
|
|
"USERS" => array_map(fn($user) => [
|
|
"username" => $user->username,
|
|
"name" => $user->name,
|
|
"address" => ($user->address->company) ? $user->address->company : $user->address->getFullName(),
|
|
"email" => $user->email,
|
|
"mobile" => $user->mobile,
|
|
"twofactor" => [1 => 'Mail', 2 => 'SMS'][$user->twofactor] ?? 'N/A',
|
|
"isAdmin" => $user->isAdmin(),
|
|
"isTechnician" => $user->is("Technician"),
|
|
"isActive" => $user->active,
|
|
"id" => $user->id
|
|
], UserModel::getAll()),
|
|
"ADD_URL" => self::getUrl("User", "Form"),
|
|
"EDIT_URL" => self::getUrl("User", "Form"),
|
|
"IMPERSONATE_URL" => self::getUrl("User", "impersonate"),
|
|
"SEND_LOGIN_EMAIL_URL" => self::getUrl("User", "sendLoginEmail"),
|
|
]);
|
|
}
|
|
|
|
protected function formAction() {
|
|
if (!$this->isAdmin()) $this->redirect("Dashboard");
|
|
|
|
$id = $this->request->id;
|
|
$user = ($id && is_numeric($id) && $id > 0) ? new User($id) : new User();
|
|
if ($user->id) {
|
|
$pageTitle = "Benutzer bearbeiten: " . $user->name;
|
|
} else {
|
|
$user->id = null;
|
|
$user->permissions = (object)['data' => []];
|
|
$pageTitle = "Benutzer erstellen";
|
|
}
|
|
|
|
if ($user->id && !$user->id) throw new Exception("User not found.", 404);
|
|
|
|
$flags = $user->id ? $this->getFlags($user) : [];
|
|
|
|
$userData = array_merge(
|
|
$user->toArray(),
|
|
$flags,
|
|
['permissions' => (array)$user->permissions->data]
|
|
);
|
|
|
|
$lookups = [
|
|
"addresses" => array_map(fn($addr) => ['value' => $addr->id, 'text' => $addr->company ?: $addr->getFullName()], AddressModel::getAll()),
|
|
"networks" => array_map(fn($net) => ['value' => $net->id, 'text' => $net->name], NetworkModel::getAll()),
|
|
"consentProjects" => array_map(fn($proj) => ['value' => $proj->id, 'text' => $proj->name], ConstructionConsentProject::getAll()),
|
|
"permissionTemplates" => UserPermissionTemplateModel::getAll([], null, 0, ['key' => 'name', 'order' => 'asc']),
|
|
"users" => array_map(fn($u) => ['value' => $u->id, 'text' => $u->name], UserModel::search(['active' => 1])),
|
|
];
|
|
|
|
Helper::renderVue($this, "UserEdit", $pageTitle, [
|
|
"USER_DATA" => $userData,
|
|
"LOOKUPS" => $lookups,
|
|
"PERMISSIONS_CONFIG" => TT_USER_PERMISSION,
|
|
"SAVE_URL" => self::getUrl("User", "save"),
|
|
"API_KEY_URL" => self::getUrl("User", "generateApikey"),
|
|
]);
|
|
}
|
|
|
|
private function getFlags(User $user): array {
|
|
$flags = [
|
|
'preorder_networks' => $user->getFlag("preorder_networks")->value(),
|
|
'constructionconsent_projects' => $user->getFlag("constructionConsent_projects")->value(),
|
|
'employee_number' => $user->getFlag("employee_number")->value(),
|
|
'project_api_key' => $user->getFlag("project_api_key")->value(),
|
|
'vodia_identity_domain' => $user->getFlag("vodia_identity_domain")->value(),
|
|
'vodia_identity_username' => $user->getFlag("vodia_identity_username")->value(),
|
|
'vodia_identity_default' => $user->getFlag("vodia_identity_default")->value(),
|
|
];
|
|
|
|
$jsonKeys = ['preorder_networks', 'constructionconsent_projects'];
|
|
|
|
foreach ($flags as $key => &$value)
|
|
if (in_array($key, $jsonKeys) && $value) $value = json_decode($value, true);
|
|
return $flags;
|
|
}
|
|
|
|
|
|
protected function getUserDataForTemplateAction() {
|
|
$id = $this->request->id;
|
|
if (!$id) self::sendError("User ID is required.");
|
|
$user = new User($id);
|
|
if (!$user->id) self::sendError("User not found.");
|
|
|
|
$preorderNetworks = $user->getFlag("preorder_networks")->value();
|
|
$consentProjects = $user->getFlag("constructionConsent_projects")->value();
|
|
|
|
self::returnJson([
|
|
'permissions' => (array)$user->permissions->data,
|
|
'preorder_networks' => $preorderNetworks ? json_decode($preorderNetworks, true) : [],
|
|
'constructionconsent_projects' => $consentProjects ? json_decode($consentProjects, true) : [],
|
|
'vodia_identity_domain' => $user->getFlag("vodia_identity_domain")->value(),
|
|
'vodia_identity_default' => $user->getFlag("vodia_identity_default")->value(),
|
|
]);
|
|
}
|
|
|
|
protected function managePermissionTemplatesAction() {
|
|
Helper::renderVue($this, "UserPermissionTemplate", "Berechtigungsvorlagen", ["PERMISSIONS_CONFIG" => TT_USER_PERMISSION]);
|
|
}
|
|
|
|
protected function getPermissionTemplatesAction() {
|
|
self::returnJson(array_map(
|
|
function ($perm) {
|
|
$perm = (array)$perm;
|
|
$perm['permissions'] = json_decode($perm['permissions'], true) ?: [];
|
|
return $perm;
|
|
}, UserPermissionTemplateModel::getAll([], null, 0, ['key' => 'name', 'order' => 'asc'])
|
|
));
|
|
}
|
|
|
|
protected function savePermissionTemplateAction() {
|
|
if (empty($this->postData['name'])) self::sendError("Template name is required.");
|
|
|
|
$data = [
|
|
'name' => $this->postData['name'],
|
|
'permissions' => json_encode($this->postData['permissions'] ?? []),
|
|
];
|
|
|
|
if (empty($this->postData['id'])) {
|
|
$data += ['createBy' => $this->user->id, 'create' => time()];
|
|
$id = UserPermissionTemplateModel::create($data);
|
|
self::returnJson(['success' => true, 'message' => 'Vorlage erstellt.', 'id' => $id]);
|
|
}
|
|
|
|
$template = UserPermissionTemplateModel::get($this->postData['id']);
|
|
$data += [
|
|
'id' => $this->postData['id'],
|
|
'create' => $template->create,
|
|
'createBy' => $template->createBy,
|
|
];
|
|
|
|
UserPermissionTemplateModel::update($data);
|
|
self::returnJson(['success' => true, 'message' => 'Vorlage gespeichert.']);
|
|
}
|
|
|
|
protected function deletePermissionTemplateAction() {
|
|
$post = json_decode(file_get_contents('php://input'), true);
|
|
if (empty($post['id'])) self::sendError("Template ID is required.");
|
|
UserPermissionTemplateModel::delete($post['id']);
|
|
self::returnJson(['success' => true, 'message' => 'Vorlage gelöscht.']);
|
|
}
|
|
|
|
|
|
|
|
protected function generateApikeyAction($request) {
|
|
if (!$this->isAdmin()) $this->redirect("Dashboard");
|
|
|
|
$id = $request['id'];
|
|
if (!is_numeric($id) || $id < 1) {
|
|
$this->layout()->setFlash("User nicht gefunden.", "error");
|
|
$this->redirect("User");
|
|
}
|
|
|
|
$user = new User($id);
|
|
if (!$user->id) {
|
|
$this->layout()->setFlash("User nicht gefunden.", "error");
|
|
$this->redirect("User");
|
|
}
|
|
|
|
$user->apikey = $user->createApiKey();
|
|
$user->save();
|
|
|
|
self::returnJson(['success' => true]);
|
|
}
|
|
|
|
protected function saveAction() {
|
|
$r = $this->request;
|
|
$id = $r->id;
|
|
|
|
if (!$this->isAdmin()) {
|
|
$id = $this->me->id;
|
|
$request['username'] = $this->me->username;
|
|
unset($r->address_id);
|
|
}
|
|
|
|
if (!$id && !$r->username) self::redirect('User');
|
|
|
|
$user = new User($id);
|
|
if ($this->isAdmin() && !$r->id) {
|
|
$tu = new User();
|
|
$tu->loadByUsername($r->username);
|
|
if ($tu->id) {
|
|
$this->layout()->setFlash("Benutzer mit diesem Benutzername bereits vorhanden!", "error");
|
|
$this->redirect("User");
|
|
}
|
|
}
|
|
|
|
$user->active = $r->active === "true" ? 1 : 0;
|
|
|
|
if (!$user->permissions) $user->permissions = new WorkerPermission();
|
|
if ($r->username) $user->username = $r->username;
|
|
if ($r->name) $user->name = $r->name;
|
|
if ($r->email) $user->email = $r->email;
|
|
if ($r->mobile) $user->mobile = $r->mobile;
|
|
else $user->mobile = NULL;
|
|
|
|
if ($this->isAdmin()) {
|
|
if ($r->address_id) {
|
|
$user->address_id = intval($r->address_id);
|
|
$address = new Address($user->address_id);
|
|
if (!$address->id) {
|
|
throw new Exception("Unbekannte Firma/Person");
|
|
}
|
|
} else {
|
|
$user->address_id = null;
|
|
}
|
|
|
|
$user->twofactorrequired = ($r->twofactorrequired == "true") ? 1 : 0;
|
|
}
|
|
|
|
if ($r->password) {
|
|
if ($r->password === $r->password2) {
|
|
$user->password = mfLoginController::generatePasswordHash($r->password);
|
|
} else {
|
|
$this->layout()->setFlash("Passwörter stimmen nicht überein!", "error");
|
|
}
|
|
}
|
|
|
|
$user->edit_by = $this->me->id;
|
|
if (!$id) {
|
|
$user->create_by = $this->me->id;
|
|
}
|
|
|
|
$id = $user->save();
|
|
|
|
if ($this->isAdmin()) {
|
|
$user->permissions->admin = ($r->admin == "true" || $user->id == 1) ? "true" : "false";
|
|
$user->permissions->employee = ($r->employee == "true") ? "true" : "false";
|
|
$user->permissions->technician = ($r->technician == "true") ? "true" : "false";
|
|
$user->permissions->preorderfront = ($r->preorderfront == "true") ? "true" : "false";
|
|
$user->permissions->preorderlogistics = ($r->preorderlogistics == "true") ? "true" : "false";
|
|
$user->permissions->preorderaddressreporting = ($r->preorderaddressreporting == "true") ? "true" : "false";
|
|
$user->permissions->preorderreadonly = ($r->preorderreadonly == "true") ? "true" : "false";
|
|
|
|
$canPermissions = [
|
|
'Building', 'Pipework', 'Linework', 'Patching', 'Filestore',
|
|
'Cpeprovisioning', 'Cpeshipping', 'Voipnumbering', 'Preorder',
|
|
'Preorderpricing', 'PreorderpricingReadonly', 'Preorderbilling',
|
|
'PreorderbillingReadonly', 'Order', 'Billing', 'Fibu', 'Statistics',
|
|
'WarehouseAdmin', 'WarehouseEShop', 'WarehouseUser', 'ADBExtended',
|
|
'AssetAdmin', 'RMLAdmin', 'RMLCompany'
|
|
];
|
|
|
|
foreach ($canPermissions as $perm) {
|
|
$user->permissions->{"can" . $perm} = "false";
|
|
}
|
|
|
|
if ($r->get("can") && is_array($r->can)) {
|
|
foreach ($r->can as $key => $can) {
|
|
if ($can) {
|
|
$user->permissions->{"can" . $key} = "true";
|
|
}
|
|
}
|
|
}
|
|
|
|
$user->permissions->save();
|
|
|
|
function handleWorkerFlag(User $user, $request, string $flagName, $requestKey, $permissionCheck = null) {
|
|
$flag = new WorkerFlag($user->id, $flagName);
|
|
$value = $request->$requestKey;
|
|
|
|
if ($value && (!$permissionCheck || $user->permissions->$permissionCheck === "true")) {
|
|
$flag->value(is_array($value) ? json_encode($value) : $value);
|
|
$flag->save();
|
|
return true;
|
|
}
|
|
|
|
$flag->delete();
|
|
return false;
|
|
}
|
|
|
|
$preorderNetworks = handleWorkerFlag($user, $r, "preorder_networks", "preorder_networks");
|
|
if ($preorderNetworks) {
|
|
$user->permissions->canPreorder = "true";
|
|
$user->permissions->save();
|
|
}
|
|
|
|
handleWorkerFlag($user, $r, "constructionConsent_projects", "constructionconsent_projects");
|
|
handleWorkerFlag($user, $r, "employee_number", "employee_number", "employee");
|
|
handleWorkerFlag($user, $r, "project_api_key", "project_api_key");
|
|
handleWorkerFlag($user, $r, "vodia_identity_domain", "vodia_identity_domain");
|
|
handleWorkerFlag($user, $r, "vodia_identity_username", "vodia_identity_username");
|
|
handleWorkerFlag($user, $r, "vodia_identity_default", "vodia_identity_default");
|
|
}
|
|
|
|
$this->layout()->setFlash("Benutzer gespeichert.", "success");
|
|
self::redirect('User');
|
|
}
|
|
|
|
protected function pwchangeAction($request)
|
|
{
|
|
$me = new User();
|
|
$me->loadMe();
|
|
|
|
$pw1 = $request['password'];
|
|
$pw2 = $request['password2'];
|
|
|
|
if (!$pw1 == $pw2) {
|
|
throw new Exception("Passwords don't match! Password change aborted.");
|
|
}
|
|
|
|
if (strlen($pw1) < 8) {
|
|
throw new Exception("Passwords must be 8 characters minimum!");
|
|
}
|
|
|
|
if ($pw1 == "12345678" || $pw1 == "123456789" || $pw1 == "password" || $pw1 == "passwort") {
|
|
throw new Exception("Be a little more creative with your password please...");
|
|
}
|
|
|
|
$me->password = mfLoginController::generatePasswordHash($pw1);
|
|
$me->save();
|
|
$this->redirect("Dashboard");
|
|
}
|
|
|
|
|
|
public function getUsers()
|
|
{
|
|
$users = array();
|
|
$res = $this->db()->select(MFUSERTABLE, '*', '1=1 ORDER BY username');
|
|
if ($this->db()->num_rows($res)) {
|
|
while ($data = $this->db()->fetch_object($res)) {
|
|
$users[$data->id] = new User($data);
|
|
}
|
|
}
|
|
return $users;
|
|
}
|
|
|
|
private function isAdmin()
|
|
{
|
|
$me = new User();
|
|
$this->layout->set("me", $me);
|
|
$me->loadMe();
|
|
|
|
return $me->isAdmin();
|
|
}
|
|
|
|
protected function apiAction() {
|
|
$do = $this->request->do;
|
|
$data = [];
|
|
|
|
$me = new User();
|
|
$me->loadMe();
|
|
|
|
$return = false;
|
|
|
|
switch($do) {
|
|
case "sse":
|
|
$me->is(["Admin"]) && $return = $this->startSuperexpertApi();
|
|
break;
|
|
case "ese":
|
|
$me->is(["Admin"]) && $return = $this->extendSuperexpertApi();
|
|
break;
|
|
case "endse":
|
|
$me->is(["Admin"]) && $return = $this->endSuperexpertApi();
|
|
break;
|
|
case "getVodiaIdentity":
|
|
$return = $this->getVodiaIdentityApi();
|
|
break;
|
|
case "setVodiaIdentity":
|
|
$return = $this->setVodiaIdentityApi();
|
|
break;
|
|
case "getVodiaCall":
|
|
$return = $this->getVodiaCallApi();
|
|
break;
|
|
default:
|
|
$return = false;
|
|
}
|
|
|
|
if(!is_array($return) || !count($return)) {
|
|
$data = ["status" => "error"];
|
|
$this->returnJson($data);
|
|
}
|
|
$data['status'] = "OK";
|
|
$data['result'] = $return;
|
|
$this->returnJson($data);
|
|
}
|
|
|
|
private function getVodiaIdentityApi() {
|
|
if(!ENABLE_VODIA_IDENTITY_SWITCHER) {
|
|
return ["enabled" => false];
|
|
}
|
|
|
|
$me = new User();
|
|
$me->loadMe();
|
|
|
|
$vodia = new Vodia_Api(VODIA_API_URL, VODIA_API_ADMIN_USER, VODIA_API_ADMIN_PASS);
|
|
|
|
$domain = $me->getFlag("vodia_identity_domain")->value();
|
|
$username = $me->getFlag("vodia_identity_username")->value();
|
|
$default = $me->getFlag("vodia_identity_default")->value();
|
|
|
|
|
|
if(!$domain || !$username || !$default) {
|
|
return ["enabled" => false];
|
|
}
|
|
|
|
$current = $vodia->getUsersetting($domain, $username, "ani");
|
|
if($current) {
|
|
if(str_replace(" ", "", $current) == str_replace(" ", "", $default)) {
|
|
$current = $default;
|
|
}
|
|
} else {
|
|
$current = $default;
|
|
}
|
|
|
|
return [
|
|
"enabled" => true,
|
|
"domain" => $domain,
|
|
"username" => $username,
|
|
"default" => $default,
|
|
"default_number" => str_replace(" ", "", $default),
|
|
"current" => $current,
|
|
"identities" => VODIA_OUTBOUND_IDENTITIES,
|
|
];
|
|
}
|
|
|
|
private function setVodiaIdentityApi() {
|
|
if(!ENABLE_VODIA_IDENTITY_SWITCHER) {
|
|
return ["enabled" => false];
|
|
}
|
|
|
|
$number = $this->request->number;
|
|
if(!$number) {
|
|
return false;
|
|
}
|
|
|
|
// expects number to start with +
|
|
if(!substr($number, 0, 1) == "+") {
|
|
return false;
|
|
}
|
|
|
|
$me = new User();
|
|
$me->loadMe();
|
|
|
|
$domain = $me->getFlag("vodia_identity_domain")->value();
|
|
$username = $me->getFlag("vodia_identity_username")->value();
|
|
|
|
if(!$domain || !$username) {
|
|
return ["enabled" => false];
|
|
}
|
|
|
|
$vodia = new Vodia_Api(VODIA_API_URL, VODIA_API_ADMIN_USER, VODIA_API_ADMIN_PASS);
|
|
|
|
if(!$vodia->setUsersettings($domain, $username, ["ani" => $number])) {
|
|
return false;
|
|
}
|
|
|
|
return ["enabled" => true, "number" => $number];
|
|
|
|
}
|
|
|
|
private function getVodiaCallApi() {
|
|
if(!ENABLE_VODIA_IDENTITY_SWITCHER) {
|
|
return ["enabled" => false];
|
|
}
|
|
|
|
$domain = $this->me->getFlag("vodia_identity_domain")->value();
|
|
$username = $this->me->getFlag("vodia_identity_username")->value();
|
|
|
|
if(!$domain || !$username) {
|
|
return ["enabled" => false];
|
|
}
|
|
|
|
$vodia = new Vodia_Api(VODIA_API_URL, VODIA_API_ADMIN_USER, VODIA_API_ADMIN_PASS);
|
|
|
|
$calls = $vodia->getActiveCalls($domain, $username);
|
|
if(!$calls) {
|
|
return ["enabled" => true, "calls" => []];
|
|
}
|
|
|
|
$from = null;
|
|
foreach($calls as $call) {
|
|
if(isset($call['from'])) {
|
|
$from = $call['from'];
|
|
if(preg_match('/<sip:([^@]+)@/', $from, $m)) {
|
|
$from = $m[1];
|
|
} elseif(preg_match('/<([^>]+)>/', $from, $m)) {
|
|
$from = $m[1];
|
|
} else {
|
|
$from = str_replace('"', '', $from);
|
|
}
|
|
break; // only return the first call's from number
|
|
}
|
|
}
|
|
|
|
return ["enabled" => true, "number" => $from];
|
|
|
|
}
|
|
|
|
private function startSuperexpertApi() {
|
|
$me = new User();
|
|
$me->loadMe();
|
|
|
|
if($me->superexpertEnabled() ) {
|
|
// superexpert mode started already
|
|
return false;
|
|
}
|
|
|
|
$me->superexpertStart(1800);
|
|
|
|
return ["valid_to" => $me->getFlag("superexpert_lock_date")->value()];
|
|
}
|
|
|
|
private function extendSuperexpertApi() {
|
|
$me = new User();
|
|
$me->loadMe();
|
|
|
|
if(!$me->superexpertEnabled() ) {
|
|
// superexpert mode must be started already
|
|
$this->log->debug("se not started");
|
|
return false;
|
|
}
|
|
$this->log->debug("ese");
|
|
$me->superexpertExtend(1800);
|
|
|
|
return ["valid_to" => $me->getFlag("superexpert_lock_date")->value()];
|
|
}
|
|
|
|
private function endSuperexpertApi() {
|
|
$me = new User();
|
|
$me->loadMe();
|
|
|
|
if($me->superexpertEnabled() ) {
|
|
$me->superexpertStop();
|
|
}
|
|
|
|
|
|
return ["valid_to" => null];
|
|
}
|
|
|
|
protected function getByIdAction() {
|
|
$id = $this->request->id;
|
|
$user = new User($id);
|
|
$this->returnJson($user->toArray());
|
|
}
|
|
|
|
protected function impersonateAction() {
|
|
if(!$this->me->isAdmin() || $this->me->address_id != 1) {
|
|
header("HTTP/1.1 403 Forbidden");
|
|
exit;
|
|
}
|
|
|
|
if($this->request->unimpersonate) {
|
|
unset($_SESSION[MFAPPNAME.'_impersonate']);
|
|
$this->redirect("User");
|
|
}
|
|
|
|
if(!$this->request->username || strlen($this->request->username) < 3) {
|
|
header("HTTP/1.1 500 Internal Server Error");
|
|
exit;
|
|
}
|
|
|
|
$_SESSION[MFAPPNAME.'_impersonate'] = $this->request->username;
|
|
$this->redirect("Dashboard");
|
|
}
|
|
|
|
protected function sendLoginEmailAction()
|
|
{
|
|
$id = $this->request->id;
|
|
if (!$id || !is_numeric($id)) {
|
|
self::sendError("Benutzer-ID fehlt oder ist ungültig.");
|
|
}
|
|
|
|
$user = new User($id);
|
|
if (!$user->id || !$user->email) {
|
|
self::sendError("Benutzer nicht gefunden oder keine E-Mail-Adresse hinterlegt.");
|
|
}
|
|
|
|
$userFullName = htmlspecialchars($user->name);
|
|
$userUsername = htmlspecialchars($user->username);
|
|
$firstName = htmlspecialchars(explode(' ', $user->name)[0]);
|
|
|
|
$subject = "Ihr Zugang zu TheTOOL by XINON, {$firstName}!";
|
|
|
|
$logoToolPath = LIBDIR . '/../public/assets/images/the-tool-logo.png';
|
|
$logoXinonPath = LIBDIR . '/../public/assets/images/xinon-full.png';
|
|
|
|
$logoToolTag = file_exists($logoToolPath) ? '<img src="cid:logo_thetool" alt="TheTOOL Logo" style="max-height: 40px; border: 0;">' : '';
|
|
$logoXinonTag = file_exists($logoXinonPath) ? '<img src="cid:logo_xinon" alt="XINON Logo" style="max-height: 40px; border: 0;">' : '';
|
|
|
|
$currentYear = date("Y");
|
|
$xinonBlue = '#005384';
|
|
$loginLink = 'https://thetool.xinon.at';
|
|
$passwordResetLink = 'https://thetool.xinon.at/UserPasswordReset/forgotPassword';
|
|
|
|
$html = <<<HTML
|
|
<!DOCTYPE html>
|
|
<html lang="de">
|
|
<head>
|
|
<meta charset="UTF-8">
|
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
<title>{$subject}</title>
|
|
<style>
|
|
body { margin: 0; padding: 0; -webkit-text-size-adjust: 100%; -ms-text-size-adjust: 100%; }
|
|
table, td { border-collapse: collapse; mso-table-lspace: 0pt; mso-table-rspace: 0pt; }
|
|
img { border: 0; height: auto; line-height: 100%; outline: none; text-decoration: none; -ms-interpolation-mode: bicubic; }
|
|
p { display: block; margin: 13px 0; }
|
|
</style>
|
|
</head>
|
|
<body style="margin: 0; padding: 0; background-color: #f3f4f6;">
|
|
<table role="presentation" border="0" cellpadding="0" cellspacing="0" width="100%" style="background-color: #f3f4f6;">
|
|
<tr>
|
|
<td style="padding: 20px 10px;">
|
|
<table align="center" border="0" cellpadding="0" cellspacing="0" role="presentation" style="width: 100%; max-width: 600px;">
|
|
<tr>
|
|
<td>
|
|
<table align="center" border="0" cellpadding="0" cellspacing="0" role="presentation" style="background-color: #ffffff; width: 100%; border-radius: 8px; box-shadow: 0 4px 10px rgba(0,0,0,0.1); border-top: 5px solid {$xinonBlue};">
|
|
<tr>
|
|
<td align="center" style="padding: 25px 20px; border-bottom: 1px solid #eeeeee;">
|
|
<table role="presentation" border="0" cellpadding="0" cellspacing="0" width="100%">
|
|
<tr>
|
|
<td align="left" width="50%" style="text-align: left; padding-left: 10px;">{$logoToolTag}</td>
|
|
<td align="right" width="50%" style="text-align: right; padding-right: 10px;">{$logoXinonTag}</td>
|
|
</tr>
|
|
</table>
|
|
</td>
|
|
</tr>
|
|
<tr>
|
|
<td style="padding: 30px 40px 35px 40px;">
|
|
<h1 style="font-family: Arial, sans-serif; font-size: 28px; font-weight: bold; color: #111827; margin: 0 0 16px 0;">Willkommen an Bord, {$firstName}!</h1>
|
|
<p style="font-family: Arial, sans-serif; font-size: 16px; color: #4b5563; margin: 0 0 24px;">Wir freuen uns, Sie im Team zu haben. Ihr Zugang zu <strong>einer smarteren Arbeitsweise</strong> ist freigeschaltet.</p>
|
|
|
|
<p style="font-family: Arial, sans-serif; font-size: 16px; color: #4b5563;">Ihr persönlicher Benutzername lautet:</p>
|
|
<table role="presentation" border="0" cellpadding="0" cellspacing="0" width="100%">
|
|
<tr>
|
|
<td style="background-color: #f3f4f6; border-radius: 5px; padding: 12px 15px; font-family: monospace, sans-serif; font-size: 18px; color: #111827; text-align: center; border: 1px solid #e5e7eb;">
|
|
{$userUsername}
|
|
</td>
|
|
</tr>
|
|
</table>
|
|
|
|
<p style="font-family: Arial, sans-serif; font-size: 16px; color: #4b5563; margin-top: 30px; text-align: center;">Um zu starten, legen Sie bitte Ihr <strong>persönliches Passwort</strong> fest.</p>
|
|
|
|
<table role="presentation" border="0" cellpadding="0" cellspacing="0" width="100%">
|
|
<tr>
|
|
<td align="center" style="padding: 15px 0 25px 0;">
|
|
<a href="{$passwordResetLink}" target="_blank" style="font-family: Arial, sans-serif; font-size: 18px; font-weight: bold; color: #ffffff; text-decoration: none; background-color: {$xinonBlue}; padding: 15px 30px; border-radius: 8px; display: inline-block;">Passwort erstmalig setzen</a>
|
|
</td>
|
|
</tr>
|
|
</table>
|
|
|
|
<table role="presentation" border="0" cellpadding="0" cellspacing="0" width="100%">
|
|
<tr>
|
|
<td align="center" style="border-top: 1px solid #eeeeee; padding-top: 25px;">
|
|
<p style="font-family: Arial, sans-serif; font-size: 14px; color: #6b7280; margin: 0;">Oder besitzen Sie bereits ein Passwort?</p>
|
|
<a href="{$loginLink}" target="_blank" style="font-family: Arial, sans-serif; font-size: 14px; color: {$xinonBlue}; text-decoration: underline;">Direkt zur Login-Seite</a>
|
|
</td>
|
|
</tr>
|
|
</table>
|
|
</td>
|
|
</tr>
|
|
<tr>
|
|
<td style="padding: 20px 40px; text-align: center; font-size: 12px; color: #6b7280; border-top: 1px solid #eeeeee; background-color: #fafafa; border-bottom-left-radius: 8px; border-bottom-right-radius: 8px;">
|
|
<p style="font-family: Arial, sans-serif; margin: 0;">
|
|
© {$currentYear} XINON GmbH | <a href="https://xinon.at/impressum/" target="_blank" style="color: {$xinonBlue}; text-decoration: none;">Impressum</a>
|
|
</p>
|
|
</td>
|
|
</tr>
|
|
</table>
|
|
</td>
|
|
</tr>
|
|
</table>
|
|
</td>
|
|
</tr>
|
|
</table>
|
|
</body>
|
|
</html>
|
|
HTML;
|
|
|
|
$altBody = "Willkommen an Bord, {$firstName}!\n\n" .
|
|
"Wir freuen uns, Sie im Team zu haben. Ihr Zugang zu einer smarteren Arbeitsweise ist freigeschaltet.\n\n" .
|
|
"Ihr persönlicher Benutzername lautet: {$userUsername}\n\n" .
|
|
"Um zu starten, legen Sie bitte Ihr persönliches Passwort fest. Besuchen Sie dazu folgende Seite:\n" .
|
|
"{$passwordResetLink}\n\n" .
|
|
"Oder besitzen Sie bereits ein Passwort? Hier geht es direkt zum Login:\n" .
|
|
"{$loginLink}\n\n" .
|
|
"© {$currentYear} XINON GmbH | Impressum: https://xinon.at/impressum/";
|
|
|
|
$mail = new PHPMailer(true);
|
|
try {
|
|
$mail->isSMTP();
|
|
$mail->Host = TT_PIPEWORK_SMTP_HOST;
|
|
$mail->SMTPAuth = true;
|
|
$mail->Username = TT_PIPEWORK_SMTP_USER;
|
|
$mail->Password = TT_PIPEWORK_SMTP_PASS;
|
|
$mail->CharSet = PHPMailer::CHARSET_UTF8;
|
|
$mail->Encoding = 'base64';
|
|
$mail->SMTPSecure = PHPMailer::ENCRYPTION_STARTTLS;
|
|
$mail->Port = 587;
|
|
|
|
if (file_exists($logoToolPath)) $mail->addEmbeddedImage($logoToolPath, 'logo_thetool');
|
|
if (file_exists($logoXinonPath)) $mail->addEmbeddedImage($logoXinonPath, 'logo_xinon');
|
|
|
|
$mail->setFrom('thetool@xinon.at', 'TheTOOL by XINON');
|
|
$mail->addReplyTo('office@xinon.at', 'XINON Office');
|
|
$mail->addAddress($user->email, $user->name);
|
|
|
|
$mail->isHTML(true);
|
|
$mail->Subject = $subject;
|
|
$mail->Body = $html;
|
|
$mail->AltBody = $altBody;
|
|
|
|
$mail->send();
|
|
self::returnJson(['success' => true, 'message' => 'Willkommens-E-Mail wurde erfolgreich an ' . htmlspecialchars($user->email) . ' gesendet.']);
|
|
|
|
} catch (Exception $e) {
|
|
error_log("Mailer Error in sendLoginEmailAction for user ID {$id}: " . $mail->ErrorInfo);
|
|
self::sendError("E-Mail konnte nicht gesendet werden. Bitte kontaktieren Sie den Support.");
|
|
}
|
|
}
|
|
}
|