Example #1
1
/**
 * Send email an email with attachements 
 * @param $files - array of files to send
 *      ex: array(
 *              "my_image.png" => array(
 *                  "path" => "/home/datawrapper/my_image.png",
 *                  "format" => "image/png"
 *              )
 *          )
 *
 */
function dw_send_mail_attachment($to, $from, $subject, $body, $files)
{
    $random_hash = md5(date('r', time()));
    // $random_hash = md5(date('r', time()));
    $random_hash = '-----=' . md5(uniqid(mt_rand()));
    // headers
    $headers = 'From: ' . $from . "\n";
    // $headers .= 'Return-Path: <'.$email_reply.'>'."\n";
    $headers .= 'MIME-Version: 1.0' . "\n";
    $headers .= 'Content-Type: multipart/mixed; boundary="' . $random_hash . '"';
    // message
    $message = 'This is a multi-part message in MIME format.' . "\n\n";
    $message .= '--' . $random_hash . "\n";
    $message .= 'Content-Type: text/plain; charset="iso-8859-1"' . "\n";
    $message .= 'Content-Transfer-Encoding: 8bit' . "\n\n";
    $message .= $body . "\n\n";
    // attached files
    foreach ($files as $fn => $file) {
        $path = $file["path"];
        $format = $file["format"];
        $attachment = chunk_split(base64_encode(file_get_contents($path)));
        $message .= '--' . $random_hash . "\n";
        $message .= 'Content-Type: ' . $format . '; name="' . $fn . '"' . "\n";
        $message .= 'Content-Transfer-Encoding: base64' . "\n";
        $message .= 'Content-Disposition:attachement; filename="' . $fn . '"' . "\n\n";
        $message .= $attachment . "\n";
    }
    DatawrapperHooks::execute(DatawrapperHooks::SEND_EMAIL, $to, $subject, $message, $headers);
}
Example #2
0
    public function exportImage($job)
    {
        // since this job is run outside of a session we need
        // to manually set the language to the one of the
        // user who created the job (otherwise the mail won't
        // be translated right)
        global $__l10n;
        $__l10n->loadMessages($job->getUser()->getLanguage());
        $chart = $job->getChart();
        $params = $job->getParameter();
        $format = $params['format'];
        $imgFile = ROOT_PATH . 'charts/exports/' . $chart->getId() . '-' . $params['ratio'] . '.' . $format;
        // execute hook provided by phantomjs plugin
        // this calls phantomjs with the provided arguments
        $res = DatawrapperHooks::execute('phantomjs_exec', ROOT_PATH . 'plugins/' . $this->getName() . '/export_chart.js', $chart->getPublicUrl(), $imgFile, $params['ratio']);
        if (empty($res[0])) {
            $job->setStatus('done');
            // now send email to the user who is waiting for the image!
            dw_send_mail_attachment($job->getUser()->getEmail(), 'noreply@' . $GLOBALS['dw_config']['domain'], __('The image of your chart is ready', $this->getName()), vksprintf(__('Hello,

Here is the requested static image of your chart "%title$s" on %domain$s.

All the best,
Datawrapper', $this->getName()), array('title' => $chart->getTitle(), 'domain' => $GLOBALS['dw_config']['domain'])), array(basename($imgFile) => array('path' => $imgFile, 'format' => "image/{$format}")));
        } else {
            // error message received, send log email
            dw_send_error_mail(sprintf('Image export of chart [%s] failed!', $chart->getId()), print_r($job->toArray()) . "\n\nError:\n" . $res[0]);
            $job->setStatus('failed');
            $job->setFailReason($res[0]);
        }
        $job->save();
    }
 function header_nav_hook(&$headlinks, $part)
 {
     $links = DatawrapperHooks::execute('header_nav_' . $part);
     if (!empty($links)) {
         foreach ($links as $link) {
             $headlinks[] = $link;
         }
     }
 }
Example #4
0
 public function exportStaticPng($job)
 {
     $chart = $job->getChart();
     $params = $job->getParameter();
     $static_path = ROOT_PATH . 'charts/static/' . $chart->getId() . '/';
     // execute hook provided by phantomjs plugin
     // this calls phantomjs with the provided arguments
     $res = DatawrapperHooks::execute('phantomjs_exec', ROOT_PATH . 'plugins/' . $this->getName() . '/gen_static_fallback.js', 'http://' . $GLOBALS['dw_config']['domain'] . '/chart/' . $chart->getId() . '/', $static_path, $params['width'], $params['height']);
     if (empty($res[0])) {
         $job->setStatus('done');
         // upload to CDN if possible
         DatawrapperHooks::execute(DatawrapperHooks::PUBLISH_FILES, array(array($static_path . 'static.html', $chart->getId() . '/static.html', 'text/html'), array($static_path . 'static.png', $chart->getId() . '/static.png', 'image/png')));
     } else {
         // error message received, send log email
         dw_send_error_mail(sprintf('Generation of static fallback for chart [%s] failed', $chart->getId()), print_r($job->toArray()) . "\n\nError:\n" . $res[0]);
         $job->setStatus('failed');
         $job->setFailReason($res[0]);
     }
     $job->save();
 }
Example #5
0
<?php

/*
 * UPLOAD STEP
 */
$app->get('/chart/:id/upload', function ($id) use($app) {
    disable_cache($app);
    check_chart_writable($id, function ($user, $chart) use($app) {
        $datasets = DatawrapperHooks::execute(DatawrapperHooks::GET_DEMO_DATASETS);
        $groups = array();
        foreach ($datasets as $ds) {
            if (!isset($groups[$ds['type']])) {
                $groups[$ds['type']] = array('type' => $ds['type'], 'datasets' => array());
            }
            $groups[$ds['type']]['datasets'][] = $ds;
        }
        $page = array('title' => $chart->getID() . ' :: ' . __('Upload Data'), 'chartData' => $chart->loadData(), 'chart' => $chart, 'datasets' => $groups);
        add_header_vars($page, 'chart');
        add_editor_nav($page, 1);
        $res = $app->response();
        $res['Cache-Control'] = 'max-age=0';
        $app->render('chart/upload.twig', $page);
    });
});
Example #6
0
<?php

/*
 * Generic hook script
 */
define('ROOT_PATH', dirname(dirname(__FILE__)) . '/');
define('NO_SLIM', 1);
define('NO_SESSION', 1);
define('DATAWRAPPER_VERSION', json_decode(file_get_contents(ROOT_PATH . 'package.json'), true)['version']);
require_once ROOT_PATH . 'lib/bootstrap.php';
date_default_timezone_set('Europe/Berlin');
$hook = $argv[1];
if (!empty($hook)) {
    if (DatawrapperHooks::hookRegistered($hook)) {
        DatawrapperHooks::execute($hook, isset($argv[2]) ? $argv[2] : null, isset($argv[3]) ? $argv[3] : null, isset($argv[4]) ? $argv[4] : null);
    } else {
        print "no callback registered under the name " . $hook . "\n";
    }
}
Example #7
0
<?php

require_once ROOT_PATH . 'lib/utils/themes.php';
require_once ROOT_PATH . 'vendor/jsmin/jsmin.php';
/*
 * PUBLISH STEP - shows progress of publishing action and thumbnail generation
 * forwards to /chart/:id/finish
 */
$app->get('/chart/:id/publish', function ($id) use($app) {
    disable_cache($app);
    check_chart_writable($id, function ($user, $chart) use($app) {
        $cfg = $GLOBALS['dw_config'];
        $page = array('title' => $chart->getID() . ' :: ' . __('Publish'), 'chartData' => $chart->loadData(), 'chart' => $chart, 'visualizations' => DatawrapperVisualization::all(), 'vis' => DatawrapperVisualization::get($chart->getType()), 'chartUrl' => $chart->getPublicUrl(), 'chartUrlLocal' => '/chart/' . $chart->getID() . '/preview', 'themes' => DatawrapperTheme::all(), 'exportStaticImage' => !empty($cfg['phantomjs']), 'chartActions' => DatawrapperHooks::execute(DatawrapperHooks::GET_CHART_ACTIONS, $chart), 'estExportTime' => ceil(JobQuery::create()->estimatedTime('export_image') / 60));
        add_header_vars($page, 'chart', 'chart-editor/publish.css');
        add_editor_nav($page, 4);
        if ($user->isAbleToPublish() && ($chart->getLastEditStep() == 3 || $app->request()->get('republish') == 1)) {
            // actual publish process
            $chart->publish();
            $page['chartUrl'] = $chart->getPublicUrl();
            // generate thumbnails
            $page['publish'] = true;
            $page['republish'] = $app->request()->get('republish') == 1;
        }
        $app->render('chart/publish.twig', $page);
    });
});
Example #8
0
 public function redirectPreviousVersions()
 {
     $current_target = $this->getCDNPath();
     $redirect_html = '<html><head><meta http-equiv="REFRESH" content="0; url=/' . $current_target . '"></head></html>';
     $redirect_file = chart_publish_directory() . 'static/' . $this->getID() . '/redirect.html';
     file_put_contents($redirect_file, $redirect_html);
     $files = array();
     for ($v = 0; $v < $this->getPublicVersion(); $v++) {
         $files[] = array($redirect_file, $this->getCDNPath($v) . 'index.html', 'text/html');
     }
     DatawrapperHooks::execute(DatawrapperHooks::PUBLISH_FILES, $files);
 }
Example #9
0
 }
 if ($currUser->isAdmin() && !empty($data->role)) {
     // Only sysadmin can set a sysadmin role
     if ($data->role == "sysadmin") {
         if (!$currUser->isSysAdmin()) {
             error(403, 'Permission denied');
             return;
         }
     }
     $user->SetRole($data->role);
 }
 $user->setLanguage(DatawrapperSession::getLanguage());
 $user->setActivateToken(hash_hmac('sha256', $data->email . '/' . time(), DW_TOKEN_SALT));
 $user->save();
 $result = $user->toArray();
 DatawrapperHooks::execute(DatawrapperHooks::USER_SIGNUP, $user);
 // send an email
 $name = $data->email;
 $domain = $GLOBALS['dw_config']['domain'];
 $protocol = !empty($_SERVER['HTTPS']) ? "https" : "http";
 if ($invitation) {
     // send account invitation link
     $invitationLink = $protocol . '://' . $domain . '/account/invite/' . $user->getActivateToken();
     include ROOT_PATH . 'lib/templates/invitation-email.php';
     dw_send_support_email($data->email, sprintf(__('You have been invited to Datawrapper on %s'), $domain), $invitation_mail, array('name' => $user->guessName(), 'invitation_link' => $invitationLink));
 } else {
     // send account activation link
     $activationLink = $protocol . '://' . $domain . '/account/activate/' . $user->getActivateToken();
     include ROOT_PATH . 'lib/templates/activation-email.php';
     dw_send_support_email($data->email, __('Datawrapper: Please activate your email address'), $activation_mail, array('name' => $user->guessName(), 'activation_link' => $activationLink));
     // we don't need to annoy the user with a login form now,
Example #10
0
        } else {
            return error('unknown-organization', 'Organization not found');
        }
    });
});
/*
 * remove user from organization
 */
$app->delete('/organizations/:id/users/:uid', function ($org_id, $user_id) use($app) {
    if_is_admin(function () use($app, $org_id, $user_id) {
        $org = OrganizationQuery::create()->findPk($org_id);
        $user = UserQuery::create()->findPk($user_id);
        if ($org && $user) {
            $org->removeUser($user);
            $org->save();
            DatawrapperHooks::execute(DatawrapperHooks::USER_ORGANIZATION_REMOVE, $org, $user);
            ok();
        } else {
            return error('unknown-organization-or-user', 'Organization or user not found');
        }
    });
});
/*
 * toggle plugin permissions of organization
 */
$app->put('/organizations/:id/plugins/:op/:plugin_id', function ($org_id, $op, $plugin_id) use($app) {
    if_is_admin(function () use($app, $org_id, $op, $plugin_id) {
        $org = OrganizationQuery::create()->findPk($org_id);
        $plugin = PluginQuery::create()->findPk($plugin_id);
        if (!$org) {
            return error('unknown-organization', 'Organization not found');
Example #11
0
function add_header_vars(&$page, $active = null)
{
    // define the header links
    global $app;
    $config = $GLOBALS['dw_config'];
    if (!isset($active)) {
        $active = explode('/', $app->request()->getResourceUri());
        $active = $active[1];
    }
    $user = DatawrapperSession::getUser();
    $headlinks = array();
    if ($user->isLoggedIn() || empty($config['prevent_guest_charts'])) {
        $headlinks[] = array('url' => '/chart/create', 'id' => 'chart', 'title' => __('Create Chart'), 'icon' => 'pencil');
    }
    if ($user->isLoggedIn() && $user->hasCharts()) {
        $headlinks[] = array('url' => '/mycharts/', 'id' => 'mycharts', 'title' => __('My Charts'), 'icon' => 'signal');
    } else {
        $headlinks[] = array('url' => '/gallery/', 'id' => 'gallery', 'title' => __('Gallery'), 'icon' => 'signal');
    }
    if (isset($config['navigation'])) {
        foreach ($config['navigation'] as $item) {
            $link = array('url' => str_replace('%lang%', substr(DatawrapperSession::getLanguage(), 0, 2), $item['url']), 'id' => $item['id'], 'title' => __($item['title']));
            if (!empty($item['icon'])) {
                $link['icon'] = $item['icon'];
            }
            $headlinks[] = $link;
        }
    }
    // language dropdown
    if (!empty($config['languages'])) {
        $langDropdown = array('url' => '', 'id' => 'lang', 'dropdown' => array(), 'title' => __('Language'), 'icon' => 'font');
        foreach ($config['languages'] as $lang) {
            $langDropdown['dropdown'][] = array('url' => '#lang-' . $lang['id'], 'title' => $lang['title']);
        }
        if (count($langDropdown['dropdown']) > 1) {
            $headlinks[] = $langDropdown;
        }
    }
    if ($user->isLoggedIn()) {
        $shortenedMail = $user->getEmail();
        $shortenedMail = strlen($shortenedMail) > 18 ? substr($shortenedMail, 0, 9) . '...' . substr($shortenedMail, strlen($shortenedMail) - 9) : $shortenedMail;
        $headlinks[] = array('url' => '#user', 'id' => 'user', 'title' => $shortenedMail, 'icon' => 'user', 'dropdown' => array(array('url' => '/account/settings', 'icon' => 'wrench', 'title' => __('Settings')), array('url' => '#logout', 'icon' => 'off', 'title' => __('Logout'))));
        if ($user->isAdmin()) {
            $headlinks[] = array('url' => '/admin', 'id' => 'admin', 'icon' => 'fire', 'title' => __('Admin'));
        }
    } else {
        $headlinks[] = array('url' => '#login', 'id' => 'login', 'title' => __('Login / Sign Up'), 'icon' => 'user');
    }
    foreach ($headlinks as $i => $link) {
        $headlinks[$i]['active'] = $headlinks[$i]['id'] == $active;
    }
    $page['headlinks'] = $headlinks;
    $page['user'] = DatawrapperSession::getUser();
    $page['language'] = substr(DatawrapperSession::getLanguage(), 0, 2);
    $page['locale'] = DatawrapperSession::getLanguage();
    $page['DW_DOMAIN'] = $config['domain'];
    $page['DW_VERSION'] = DATAWRAPPER_VERSION;
    $page['DW_CHART_CACHE_DOMAIN'] = $config['chart_domain'];
    $page['ADMIN_EMAIL'] = $config['email']['admin'];
    $page['config'] = $config;
    $page['invert_navbar'] = substr($config['domain'], -4) == '.pro';
    $uri = $app->request()->getResourceUri();
    $plugin_assets = DatawrapperHooks::execute(DatawrapperHooks::GET_PLUGIN_ASSETS, $uri);
    if (!empty($plugin_assets)) {
        $plugin_js_files = array();
        $plugin_css_files = array();
        foreach ($plugin_assets as $files) {
            if (!is_array($files)) {
                $files = array($files);
            }
            foreach ($files as $file) {
                if (substr($file, -3) == '.js') {
                    $plugin_js_files[] = $file;
                }
                if (substr($file, -4) == '.css') {
                    $plugin_css_files[] = $file;
                }
            }
        }
        $page['plugin_js'] = $plugin_js_files;
        $page['plugin_css'] = $plugin_css_files;
    }
    if (isset($config['piwik'])) {
        $page['PIWIK_URL'] = $config['piwik']['url'];
        $page['PIWIK_IDSITE'] = $config['piwik']['idSite'];
        if (isset($config['piwik']['idSiteNoCharts'])) {
            $page['PIWIK_IDSITE_NO_CHARTS'] = $config['piwik']['idSiteNoCharts'];
        }
    }
    if ($config['debug']) {
        if (file_exists('../.git')) {
            // parse git branch
            $head = file_get_contents('../.git/HEAD');
            $parts = explode("/", $head);
            $page['BRANCH'] = ' (' . trim($parts[count($parts) - 1]) . ')';
        }
    }
}
Example #12
0
<?php

/*
 * UPLOAD STEP
 */
$app->get('/chart/:id/upload', function ($id) use($app) {
    disable_cache($app);
    check_chart_writable($id, function ($user, $chart) use($app) {
        $page = array('title' => $chart->getID() . ' :: ' . __('Upload Data'), 'chartData' => $chart->loadData(), 'chart' => $chart, 'datasets' => DatawrapperHooks::execute(DatawrapperHooks::GET_DEMO_DATASETS));
        add_header_vars($page, 'chart');
        add_editor_nav($page, 1);
        $res = $app->response();
        $res['Cache-Control'] = 'max-age=0';
        $app->render('chart/upload.twig', $page);
    });
});
Example #13
0
    if ($invitation) {
        // send account invitation link
        $invitationLink = $protocol . '://' . $domain . '/account/invite/' . $user->getActivateToken();
        include ROOT_PATH . 'lib/templates/invitation-email.php';
        dw_send_support_email($data->email, sprintf(__('You have been invited to Datawrapper on %s'), $domain), $invitation_mail, array('name' => $user->guessName(), 'invitation_link' => $invitationLink));
    } else {
        // send account activation link
        $activationLink = $protocol . '://' . $domain . '/account/activate/' . $user->getActivateToken();
        include ROOT_PATH . 'lib/templates/activation-email.php';
        dw_send_support_email($data->email, __('Datawrapper: Please activate your email address'), $activation_mail, array('name' => $user->guessName(), 'activation_link' => $activationLink));
        // we don't need to annoy the user with a login form now,
        // so just log in..
        DatawrapperSession::login($user);
    }
    $welcome_msg = __("Hello %name%,\n\nWelcome to your new Datawrapper account.\n\nCheers,\nDatawrapper");
    DatawrapperHooks::execute(DatawrapperHooks::NOTIFY_USER, $user, __('Welcome to Datawrapper!'), str_replace('%name%', $user->guessName(), $welcome_msg));
    ok($result);
});
/*
 * update user profile
 * @needs admin or existing user
 */
$app->put('/users/:id', function ($user_id) use($app) {
    $payload = json_decode($app->request()->getBody());
    $curUser = DatawrapperSession::getUser();
    if ($curUser->isLoggedIn()) {
        if ($user_id == 'current' || $curUser->getId() === intval($user_id)) {
            $user = $curUser;
        } else {
            if ($curUser->isAdmin()) {
                $user = UserQuery::create()->findPK($user_id);
Example #14
0
<?php

if (DatawrapperHooks::hookRegistered(DatawrapperHooks::GET_ADMIN_PAGES)) {
    // pull admin pages from plugins
    $__dw_admin_pages = DatawrapperHooks::execute(DatawrapperHooks::GET_ADMIN_PAGES);
    // order admin pages by index "order"
    usort($__dw_admin_pages, function ($a, $b) {
        return (isset($a['order']) ? $a['order'] : 9999) - (isset($b['order']) ? $b['order'] : 9999);
    });
    foreach ($__dw_admin_pages as $admin_page) {
        $app->map('/admin' . $admin_page['url'], function () use($app, $admin_page, $__dw_admin_pages) {
            disable_cache($app);
            $user = DatawrapperSession::getUser();
            if ($user->isAdmin()) {
                $page_vars = array('title' => $admin_page['title'], 'adminmenu' => array(), 'adminactive' => $admin_page['url']);
                // add admin pages to menu
                foreach ($__dw_admin_pages as $adm_pg) {
                    $page_vars['adminmenu'][$adm_pg['url']] = $adm_pg['title'];
                }
                add_header_vars($page_vars, 'admin');
                call_user_func_array($admin_page['controller'], array($app, $page_vars));
            } else {
                $app->notFound();
            }
        })->via('GET', 'POST');
    }
}
Example #15
0
        // we don't want to send it too often in order to prevent
        // mail spam coming from our server
        $r = ActionQuery::create()->filterByUser($user)->filterByKey('resend-activation')->find();
        if (count($r) > 2) {
            error('avoid-spam', str_replace('%ADMINEMAIL%', $GLOBALS['dw_config']['email']['admin'], __('You already resent the activation mail three times, now. Please <a href="mailto:%ADMINEMAIL%">contact an administrator</a> to proceed with your account activation.')));
            return false;
        }
        // remember that we send the email
        Action::logAction($user, 'resend-activation', $token);
        // send email with activation key
        $name = $user->getEmail();
        $domain = $GLOBALS['dw_config']['domain'];
        $activationLink = 'http://' . $domain . '/account/activate/' . $token;
        $from = 'activate@' . $domain;
        include '../../lib/templates/activation-email.php';
        DatawrapperHooks::execute(DatawrapperHooks::SEND_EMAIL, $user->getEmail(), 'Datawrapper Email Activation', $activation_mail, 'From: ' . $from);
        ok(__('The activation email has been send to your email address, again.'));
    } else {
        error('token-empty', __('You\'re account is probably already activated.'));
    }
});
/*
 * endpoint for validating an invitation. The user sends his new password
 */
$app->post('/account/invitation/:token', function ($token) use($app) {
    $data = json_decode($app->request()->getBody());
    if (!empty($token)) {
        $users = UserQuery::create()->filterByActivateToken($token)->find();
        if (count($users) != 1) {
            error("token-invalid", _("This activation token is invalid. Your email address is probably already activated."));
        } elseif (empty($data->pwd1)) {
Example #16
0
<?php

/*
 * UPLOAD STEP
 */
$app->get('/chart/:id/upload', function ($id) use($app) {
    disable_cache($app);
    check_chart_writable($id, function ($user, $chart) use($app) {
        $page = array('chartData' => $chart->loadData(), 'chart' => $chart, 'datasets' => DatawrapperHooks::execute(DatawrapperHooks::GET_DEMO_DATASETS));
        add_header_vars($page, 'chart');
        add_editor_nav($page, 1);
        $res = $app->response();
        $res['Cache-Control'] = 'max-age=0';
        $app->render('chart-upload.twig', $page);
    });
});
Example #17
0
         Action::logAction($curUser, 'change-password', array('user' => $user->getId()));
     } else {
         Action::logAction($curUser, 'change-password-failed', array('user' => $user->getId(), 'reason' => 'old password is wrong'));
         $errors[] = __('The password could not be changed because your old password was not entered correctly.');
     }
 }
 if (!empty($payload->email) && $payload->email != $user->getEmail()) {
     if (check_email($payload->email) || $curUser->isAdmin()) {
         if (!email_exists($payload->email)) {
             if ($curUser->isAdmin()) {
                 $user->setEmail($payload->email);
             } else {
                 // non-admins need to confirm new emails addresses
                 $token = hash_hmac('sha256', $user->getEmail() . '/' . $payload->email . '/' . time(), DW_TOKEN_SALT);
                 $token_link = get_current_protocol() . '://' . $GLOBALS['dw_config']['domain'] . '/account/profile?token=' . $token;
                 DatawrapperHooks::execute(DatawrapperHooks::SEND_CHANGE_EMAIL_EMAIL, $payload->email, $user->guessName(), $user->getEmail(), $token_link);
                 // log action for later confirmation
                 Action::logAction($curUser, 'email-change-request', array('old-email' => $user->getEmail(), 'new-email' => $payload->email, 'token' => $token));
                 $messages[] = __('To complete the change of your email address, you need to confirm that you have access to it. Therefor we sent an email with the confirmation link to your new address. Your new email will be set right after you clicked that link.');
             }
         } else {
             $errors[] = sprintf(__('The email address <b>%s</b> already exists.'), $payload->email);
         }
     } else {
         $errors[] = sprintf(__('The email address <b>%s</b> is invalid.'), $payload->email);
     }
 }
 if (!empty($payload->name)) {
     $user->setName($payload->name);
 }
 if ($curUser->isAdmin() && !empty($payload->role)) {
Example #18
0
        $page = array('email' => $user->getEmail(), 'auth_salt' => DW_AUTH_SALT);
        add_header_vars($page, 'about', 'account/invite.css');
        $app->render('account/invite.twig', $page);
    });
});
/*
 * store new password, clear invitation token and login
 */
$app->post('/account/invite/:token', function ($token) use($app) {
    _checkInviteTokenAndExec($token, function ($user) use($app) {
        $data = json_decode($app->request()->getBody());
        $user->setPwd($data->pwd);
        $user->setActivateToken('');
        $user->save();
        // notify plugins about the newly activated user
        DatawrapperHooks::execute(DatawrapperHooks::USER_ACTIVATED, $user);
        DatawrapperSession::login($user);
        print json_encode(array('result' => 'ok'));
    });
});
function _checkInviteTokenAndExec($token, $func)
{
    if (!empty($token)) {
        $user = UserQuery::create()->findOneByActivateToken($token);
        if ($user && $user->getRole() != 'pending') {
            $func($user);
        } else {
            // this is not a valid token!
            $page['alert'] = array('type' => 'error', 'message' => __('The invitation token is invalid.'));
            global $app;
            $app->redirect('/');
Example #19
0
function get_chart_content($chart, $user, $published = false, $debug = false)
{
    $theme_css = array();
    $theme_js = array();
    $next_theme_id = $chart->getTheme();
    $locale = DatawrapperSession::getLanguage();
    while (!empty($next_theme_id)) {
        $theme = DatawrapperTheme::get($next_theme_id);
        $theme_js[] = $theme['__static_path'] . $next_theme_id . '.js';
        if ($theme['hasStyles']) {
            $theme_css[] = $theme['__static_path'] . $next_theme_id . '.css';
        }
        $next_theme_id = $theme['extends'];
    }
    $abs = 'http://' . $GLOBALS['dw_config']['domain'];
    $debug = $GLOBALS['dw_config']['debug'] == true || $debug;
    if ($published && !$debug) {
        $base_js = array('//assets-datawrapper.s3.amazonaws.com/globalize.min.js', '//cdnjs.cloudflare.com/ajax/libs/underscore.js/1.4.2/underscore-min.js', '//cdnjs.cloudflare.com/ajax/libs/jquery/1.9.1/jquery.min.js');
        if (substr($locale, 0, 2) != 'en') {
            $base_js[] = '//assets-datawrapper.s3.amazonaws.com/cultures/globalize.culture.' . str_replace('_', '-', $locale) . '.js';
        }
    } else {
        // use local assets
        $base_js = array($abs . '/static/vendor/globalize/globalize.min.js', $abs . '/static/vendor/underscore/underscore-min.js', $abs . '/static/vendor/jquery/jquery-1.9.1' . ($debug ? '' : '.min') . '.js');
        if (substr($locale, 0, 2) != 'en') {
            $base_js[] = $abs . '/static/vendor/globalize/cultures/globalize.culture.' . str_replace('_', '-', $locale) . '.js';
        }
    }
    $vis_js = array();
    $vis_css = array();
    $next_vis_id = $chart->getType();
    $vis_libs = array();
    $vis_locale = array();
    // visualizations may define localized strings, e.g. "other"
    while (!empty($next_vis_id)) {
        $vis = DatawrapperVisualization::get($next_vis_id);
        $vjs = array();
        if (!empty($vis['libraries'])) {
            foreach ($vis['libraries'] as $url) {
                // at first we check if the library lives in ./lib of the vis module
                if (file_exists(ROOT_PATH . 'www/' . $vis['__static_path'] . $url)) {
                    $vis_libs[] = $vis['__static_path'] . $url;
                } else {
                    if (file_exists(ROOT_PATH . 'www/static/vendor/' . $url)) {
                        $vis_libs[] = '/static/vendor/' . $url;
                    }
                }
            }
        }
        if (!empty($vis['locale']) && is_array($vis['locale'])) {
            foreach ($vis['locale'] as $term => $translations) {
                if (!isset($vis_locale[$term])) {
                    $vis_locale[$term] = $translations;
                }
            }
        }
        $vjs[] = $vis['__static_path'] . $vis['id'] . '.js';
        $vis_js = array_merge($vis_js, array_reverse($vjs));
        if ($vis['hasCSS']) {
            $vis_css[] = $vis['__static_path'] . $vis['id'] . '.css';
        }
        $next_vis_id = !empty($vis['extends']) ? $vis['extends'] : null;
    }
    $styles = array_merge($vis_css, array_reverse($theme_css));
    $the_vis = DatawrapperVisualization::get($chart->getType());
    $the_vis['locale'] = $vis_locale;
    $the_theme = DatawrapperTheme::get($chart->getTheme());
    if ($published) {
        $scripts = array_merge($base_js, array('/lib/vis/' . $the_vis['id'] . '-' . $the_vis['version'] . '.min.js', '/lib/theme/' . $the_theme['id'] . '-' . $the_theme['version'] . '.min.js'));
        $styles = array($chart->getID() . '.min.css');
        $the_vis['__static_path'] = '';
        $the_theme['__static_path'] = '';
    } else {
        $scripts = array_unique(array_merge($base_js, array('/static/js/datawrapper' . ($debug ? '' : '.min') . '.js'), array_reverse($theme_js), array_reverse($vis_js), $vis_libs));
    }
    $cfg = $GLOBALS['dw_config'];
    $published_urls = DatawrapperHooks::execute(DatawrapperHooks::GET_PUBLISHED_URL, $chart);
    if (empty($published_urls)) {
        $chart_url = 'http://' . $cfg['chart_domain'] . '/' . $chart->getID() . '/';
    } else {
        $chart_url = $published_urls[0];
        // ignore urls except from the first one
    }
    $page = array('chartData' => $chart->loadData(), 'chart' => $chart, 'chartLocale' => str_replace('_', '-', $locale), 'lang' => strtolower(substr($locale, 0, 2)), 'metricPrefix' => get_metric_prefix($locale), 'theme' => $the_theme, 'l10n__domain' => $the_theme['__static_path'], 'visualization' => $the_vis, 'stylesheets' => $styles, 'scripts' => $scripts, 'themeJS' => array_reverse($theme_js), 'visJS' => array_merge(array_reverse($vis_js), $vis_libs), 'origin' => !empty($_SERVER['HTTP_REFERER']) ? $_SERVER['HTTP_REFERER'] : '', 'DW_DOMAIN' => 'http://' . $cfg['domain'] . '/', 'DW_CHART_DATA' => 'http://' . $cfg['domain'] . '/chart/' . $chart->getID() . '/data', 'ASSET_PATH' => $published ? '' : $the_theme['__static_path'], 'trackingCode' => !empty($analyticsMod) ? $analyticsMod->getTrackingCode($chart) : '', 'chartUrl' => $chart_url, 'embedCode' => '<iframe src="' . $chart_url . '" frameborder="0" allowtransparency="true" allowfullscreen webkitallowfullscreen mozallowfullscreen oallowfullscreen msallowfullscreen width="' . $chart->getMetadata('publish.embed-width') . '" height="' . $chart->getMetadata('publish.embed-height') . '"></iframe>', 'chartUrlFs' => strpos($chart_url, '.html') > 0 ? str_replace('index.html', 'fs.html', $chart_url) : $chart_url . '?fs=1');
    return $page;
}
Example #20
0
<?php

/*
 * PUBLISH STEP - shows progress of publishing action and thumbnail generation
 */
$app->get('/chart/:id/publish', function ($id) use($app) {
    disable_cache($app);
    check_chart_writable($id, function ($user, $chart) use($app) {
        $cfg = $GLOBALS['dw_config'];
        $chartActions = DatawrapperHooks::execute(DatawrapperHooks::GET_CHART_ACTIONS, $chart);
        // add duplicate action
        $chartActions[] = array('id' => 'duplicate', 'icon' => 'code-fork', 'title' => __('Duplicate this chart'), 'order' => 500);
        // sort actions
        usort($chartActions, function ($a, $b) {
            return (isset($a['order']) ? $a['order'] : 999) - (isset($b['order']) ? $b['order'] : 999);
        });
        $chartW = $chart->getMetadata('publish.embed-width');
        $chartH = $chart->getMetadata('publish.embed-height');
        if (substr($chartW, -1) != '%') {
            $chartW .= 'px';
        }
        if (substr($chartH, -1) != '%') {
            $chartH .= 'px';
        }
        $page = array('title' => $chart->getID() . ' :: ' . __('Publish'), 'chartData' => $chart->loadData(), 'chart' => $chart, 'visualizations' => DatawrapperVisualization::all(), 'vis' => DatawrapperVisualization::get($chart->getType()), 'chartUrl' => $chart->getPublicUrl(), 'chartUrlLocal' => '/chart/' . $chart->getID() . '/preview', 'embedWidth' => $chartW, 'embedHeight' => $chartH, 'themes' => DatawrapperTheme::all(), 'exportStaticImage' => !empty($cfg['phantomjs']), 'chartActions' => $chartActions, 'estExportTime' => ceil(JobQuery::create()->estimatedTime('export') / 60));
        add_header_vars($page, 'chart', 'chart-editor/publish.css');
        add_editor_nav($page, 4);
        $app->render('chart/publish.twig', $page);
    });
});
Example #21
0
    $user->setActivateToken(hash_hmac('sha256', $data->email . '/' . time(), DW_TOKEN_SALT));
    $user->save();
    $result = $user->toArray();
    // send an email
    $name = $data->email;
    $domain = $GLOBALS['dw_config']['domain'];
    if ($invitation) {
        $invitationLink = 'http://' . $domain . '/account/invite/' . $user->getActivateToken();
        $from = $GLOBALS['dw_config']['email']['invite'];
        include ROOT_PATH . 'lib/templates/invitation-email.php';
        DatawrapperHooks::execute(DatawrapperHooks::SEND_EMAIL, $data->email, sprintf(__('You have been invited to %s'), $domain), $invitation_mail, 'From: ' . $from);
    } else {
        $activationLink = 'http://' . $domain . '/account/activate/' . $user->getActivateToken();
        $from = $GLOBALS['dw_config']['email']['activate'];
        include ROOT_PATH . 'lib/templates/activation-email.php';
        DatawrapperHooks::execute(DatawrapperHooks::SEND_EMAIL, $data->email, __('Datawrapper Email Activation'), $activation_mail, 'From: ' . $from);
        // we don't need to annoy the user with a login form now,
        // so just log in..
        DatawrapperSession::login($user);
    }
    ok($result);
});
/*
 * update user profile
 * @needs admin or existing user
 */
$app->put('/users/:id', function ($user_id) use($app) {
    $payload = json_decode($app->request()->getBody());
    $curUser = DatawrapperSession::getUser();
    if ($curUser->isLoggedIn()) {
        if ($user_id == 'current' || $curUser->getId() === $user_id) {
Example #22
0
    if_chart_is_writable($chart_id, function ($user, $chart) use($app) {
        echo _getPublishStatus($chart);
    });
});
/*
 * stores client-side generated chart thumbnail
 */
$app->put('/charts/:id/thumbnail/:thumb', function ($chart_id, $thumb) use($app) {
    disable_cache($app);
    if_chart_is_writable($chart_id, function ($user, $chart) use($app, $thumb) {
        try {
            $imgurl = $app->request()->getBody();
            $imgdata = base64_decode(substr($imgurl, strpos($imgurl, ",") + 1));
            $static_path = get_static_path($chart);
            file_put_contents($static_path . "/" . $thumb . '.png', $imgdata);
            DatawrapperHooks::execute(DatawrapperHooks::PUBLISH_FILES, array(array($static_path . "/" . $thumb . '.png', $chart->getID() . '/' . $thumb . '.png', 'image/png')));
            ok();
        } catch (Exception $e) {
            error('io-error', $e->getMessage());
        }
    });
});
/*
 * stores static snapshot of a chart (data, configuration, etc) as JSON
 * to /test/test-charts. This aims to simplify the generation of test
 * cases using the Datawrapper editor. Only for debugging.
 */
$app->post('/charts/:id/store_snapshot', function ($chart_id) use($app) {
    if (!empty($GLOBALS['dw_config']['debug_export_test_cases'])) {
        if_chart_exists($chart_id, function ($chart) use($app) {
            $json = $chart->serialize();
Example #23
0
function publish_push_to_cdn($cdn_files, $chart)
{
    DatawrapperHooks::execute(DatawrapperHooks::PUBLISH_FILES, $cdn_files);
}
Example #24
0
 * expects payload { "email": "*****@*****.**" }
 */
$app->post('/account/resend-invitation', function () use($app) {
    $payload = json_decode($app->request()->getBody());
    $user = UserQuery::create()->findOneByEmail($payload->email);
    $token = $user->getActivateToken();
    if (!empty($user)) {
        if (empty($token)) {
            return error("token-invalid", __("This activation token is invalid. Your email address is probably already activated."));
        }
        // variables for `templates/invitation-email.php`
        $domain = $GLOBALS['dw_config']['domain'];
        $protocol = get_current_protocol();
        $invitationLink = $protocol . '://' . $domain . '/account/invite/' . $token;
        $name = $user->getEmail();
        DatawrapperHooks::execute(DatawrapperHooks::SEND_INVITE_EMAIL_TO_NEW_USER, $user->getEmail(), $user->guessName(), $invitationLink);
        ok(__('You should soon receive an email with further instructions.'));
    } else {
        error('login-email-unknown', __('The email is not registered yet.'));
    }
});
/*
 * endpoint for validating an invitation. The user sends his new password
 */
$app->post('/account/invitation/:token', function ($token) use($app) {
    $data = json_decode($app->request()->getBody());
    if (!empty($token)) {
        $users = UserQuery::create()->filterByActivateToken($token)->find();
        if (count($users) != 1) {
            error("token-invalid", __("This activation token is invalid. Your email address is probably already activated."));
        } elseif (empty($data->pwd1)) {
Example #25
0
        if ($plugin) {
            switch ($action) {
                case 'enable':
                    $plugin->setEnabled(true);
                    break;
                case 'disable':
                    $plugin->setEnabled(false);
                    break;
                case 'publish':
                    $plugin->setIsPrivate(false);
                    break;
                case 'unpublish':
                    $plugin->setIsPrivate(true);
                    break;
            }
            $plugin->save();
            ok();
        } else {
            error('plugin-not-found', 'No plugin found with that ID');
        }
    });
})->conditions(array('action' => '(enable|disable|publish|unpublish)'));
$pluginApiHooks = DatawrapperHooks::execute(DatawrapperHooks::PROVIDE_API);
if (!empty($pluginApiHooks)) {
    foreach ($pluginApiHooks as $hook) {
        if (!isset($hook['method'])) {
            $hook['method'] = 'GET';
        }
        $app->map('/plugin/' . $hook['url'], $hook['action'])->via($hook['method']);
    }
}
Example #26
0
    fclose($h);
}
// init l10n
$locale = str_replace('-', '_', DatawrapperSession::getLanguage());
$domain = 'messages';
putenv('LANGUAGE=' . $locale);
setlocale(LC_ALL, $locale);
setlocale(LC_TIME, $locale . '.utf8');
$__l10n = new Datawrapper_L10N();
$__l10n->loadMessages($locale);
parse_config();
if (!defined('NO_SLIM')) {
    // Initialize Slim app..
    if (ROOT_PATH == '../') {
        // ..either with TwigView for Datawrapper UI,...
        TwigView::$twigDirectory = ROOT_PATH . 'vendor/Twig';
        $app = new Slim(array('view' => new TwigView(), 'templates.path' => '../templates', 'session.handler' => null));
    } else {
        // ..or with JSONView for API.
        $app = new Slim(array('view' => 'JSONView'));
    }
}
if (isset($dw_config['memcache'])) {
    $memcfg = $dw_config['memcache'];
    $memcache = new Memcache();
    $memcache->connect($memcfg['host'], $memcfg['port']) or die("Could not connect");
}
DatawrapperPluginManager::load();
// notify the core that all plugins are loaded
DatawrapperHooks::execute(DatawrapperHooks::ALL_PLUGINS_LOADED);
Example #27
0
function get_theme_js($theme, $themeJS)
{
    $all = '';
    $org = DatawrapperSession::getUser()->getCurrentOrganization();
    if (!empty($org)) {
        $org = '/' . $org->getID();
    } else {
        $org = '';
    }
    $keys = DatawrapperHooks::execute(DatawrapperHooks::GET_PUBLISH_STORAGE_KEY);
    if (is_array($keys)) {
        $org .= '/' . join($keys, '/');
    }
    foreach ($themeJS as $js) {
        if (substr($js, 0, 7) != "http://" && substr($js, 0, 8) != "https://" && substr($js, 0, 2) != '//') {
            $all .= "\n\n\n" . file_get_contents(ROOT_PATH . 'www' . $js);
        }
    }
    $all = jsminify($all);
    $theme_js_md5 = md5($all . $org);
    $theme_path = 'theme/' . $theme['id'] . '-' . $theme_js_md5 . '.min.js';
    return array($theme_path, $all);
}
Example #28
0
<?php

require_once ROOT_PATH . 'controller/account/activate.php';
require_once ROOT_PATH . 'controller/account/set-password.php';
require_once ROOT_PATH . 'controller/account/reset-password.php';
require_once ROOT_PATH . 'controller/account/profile.php';
require_once ROOT_PATH . 'controller/account/delete.php';
require_once ROOT_PATH . 'controller/account/password.php';
require_once ROOT_PATH . 'controller/account/mycharts.php';
call_user_func(function () {
    global $app;
    $user = DatawrapperSession::getUser();
    $pages = DatawrapperHooks::execute(DatawrapperHooks::GET_ACCOUNT_PAGES, $user);
    foreach ($pages as $page) {
        if (!isset($page['order'])) {
            $page['order'] = 999;
        }
    }
    usort($pages, function ($a, $b) {
        return $a['order'] - $b['order'];
    });
    $app->get('/account/?', function () use($app, $pages) {
        $app->redirect('/account/' . $pages[0]['url'] . '/');
    });
    // redirect to settings
    $app->get('/settings/?', function () use($app) {
        $app->redirect('/account');
    });
    $user = DatawrapperSession::getUser();
    foreach ($pages as $page) {
        $context = array('title' => $page['title'], 'gravatar' => md5(strtolower(trim($user->getEmail()))), 'pages' => $pages, 'active' => $page['url'], 'user' => $user);
Example #29
0
function update($pattern)
{
    _apply($pattern, function ($id) {
        $plugin = new Plugin();
        $plugin->setId($id);
        $repo = $plugin->getRepository();
        if ($repo) {
            if ($repo['type'] == 'git') {
                if (file_exists($plugin->getPath() . '.git/config')) {
                    $ret = array();
                    exec('cd ' . $plugin->getPath() . '; git pull origin master 2>&1', $ret, $err);
                    if ($ret[count($ret) - 1] == 'Already up-to-date.') {
                        print "Plugin {$id} is up-to-date.\n";
                    } else {
                        DatawrapperHooks::execute(DatawrapperHooks::PLUGIN_UPDATED, $id);
                        print "Updated plugin {$id}.\n";
                        install($id);
                    }
                } else {
                    print "Skipping {$id}: Not a valid Git repository.\n";
                }
            } else {
                print "Skipping {$id}: Unhandled repository type " . $repo['type'] . ".\n";
            }
        } else {
            if (file_exists($plugin->getPath() . '.git/config')) {
                print "Skipping {$id}: No repository information found in package.json.\n";
            }
        }
    });
}
Example #30
0
<?php

/*
 * Generic hook script
 */
define('ROOT_PATH', dirname(dirname(__FILE__)) . '/');
define('NO_SLIM', 1);
define('NO_SESSION', 1);
require_once ROOT_PATH . 'lib/bootstrap.php';
date_default_timezone_set('Europe/Berlin');
$hook = $argv[1];
if (!empty($hook)) {
    DatawrapperHooks::execute($argv[1], isset($argv[2]) ? $argv[2] : null);
}