added bulk content imporer

This commit is contained in:
Rodolfo Berrios 2020-08-25 20:24:23 -04:00
parent 892dc79d4a
commit 178173f9ae
33 changed files with 2503 additions and 352 deletions

View file

@ -0,0 +1,11 @@
<FilesMatch "\.(txt)$">
# Apache 2.2
<IfModule !mod_authz_core.c>
Order Allow,Deny
Deny from all
</IfModule>
# Apache 2.4
<IfModule mod_authz_core.c>
Require all denied
</IfModule>
</FilesMatch>

View file

@ -117,22 +117,17 @@ try {
case 'extract':
$zip_file = $update_temp_dir . $_REQUEST['file'];
if (false === preg_match('/^Chevereto-Chevereto-Free-([\d.]+)-\d+-g(.*)_.*$/i', $_REQUEST['file'], $matches)) {
if (false === preg_match('/^(chevereto-chevereto-free)-([\d.]+)-\d+-g(.*)_.*$/i', $_REQUEST['file'], $matches)) {
throw new Exception("Can't detect target zip file version");
}
$version = $matches[1];
$etag_short = $matches[2];
// Test .zip
$version = $matches[2];
$etag_short = $matches[3];
if (!is_readable($zip_file)) {
throw new Exception('Missing '.$zip_file.' file', 400);
}
// Unzip .zip
$zip = new \ZipArchive;
if ($zip->open($zip_file) === true) {
// At this point we will enter the website in maintenance mode (if needed)
try {
$toggle_maintenance = !getSetting('maintenance');
if ($toggle_maintenance) {
@ -147,14 +142,12 @@ try {
} else {
throw new Exception(_s("Can't extract %s", G\absolute_to_relative($zip_file)), 401);
}
// Recursive copy UPDATE -> CURRENT
$source = $update_temp_dir . G_APP_GITHUB_OWNER . '-' . G_APP_GITHUB_REPO . '-' . $etag_short . '/';
$source = $update_temp_dir . $matches[1] . '-' . $etag_short . '/';
$dest = G_ROOT_PATH;
foreach ($iterator = new \RecursiveIteratorIterator(new \RecursiveDirectoryIterator($source, \RecursiveDirectoryIterator::SKIP_DOTS), \RecursiveIteratorIterator::SELF_FIRST) as $item) {
$target = $dest . $iterator->getSubPathName();
$target_visible = G\absolute_to_relative($target);
if ($item->isDir()) {
if (!file_exists($target) and !@mkdir($target)) {
$error = error_get_last();
@ -164,7 +157,6 @@ try {
]), 402);
}
} else {
// Touch anything but .htaccess files
if (!preg_match('/\.htaccess$/', $item)) {
if (!@copy($item, $target)) {
$error = error_get_last();
@ -174,7 +166,7 @@ try {
]), 403);
}
}
unlink($item); // Save some valuable seconds...
unlink($item);
}
}
@ -184,8 +176,6 @@ try {
$todo = ($fileinfo->isDir() ? 'rmdir' : 'unlink');
$todo($fileinfo->getRealPath());
}
// Turn off maintenance mode (if needed)
try {
if ($toggle_maintenance) {
DB::update('settings', ['value' => 0], ['name' => 'maintenance']);
@ -203,7 +193,7 @@ try {
$json_array['request'] = $_REQUEST;
G\Render\json_output($json_array);
}
die(); // Terminate any remaining execution (if any)
die();
} catch (Exception $e) {
if (!isset($_REQUEST['action'])) {
Render\chevereto_die($e->getMessage(), "This installation can't use the automatic update functionality because this server is missing some crucial elements to allow Chevereto to perform the automatic update:", "Can't perform automatic update");

View file

@ -2919,7 +2919,7 @@ CHV.fn.system = {
checkUpdates: function (callback) {
$.ajax({
url: CHEVERETO.api.get.info + "/",
data: null,
data: { id: CHEVERETO.id },
cache: false,
}).always(function (data, status, XHR) {
if (typeof callback == "function") {
@ -5865,3 +5865,248 @@ CHV.fn.queuePixel = function () {
'" width="1" height="1" alt="" style="display: none;">';
$("body").append(img);
};
CHV.fn.import = {
errorHandler: function (response) {
PF.fn.growl.call(response.error.message);
},
reset: function (id) {
var id = parseInt(id);
CHV.obj.import.working[id].stats = $.ajax({
type: "POST",
data: {
action: "importReset",
id: id,
},
});
CHV.obj.import.working[id].stats.complete(function (XHR) {
var response = XHR.responseJSON;
if (response) {
var $html = CHV.fn.import.parseTemplate(response.import);
$(
"[data-id=" + response.import.id + "]",
CHV.obj.import.sel.root
).replaceWith($html);
if (response.import.status != "working") {
clearInterval(CHV.obj.import.working[id].interval);
}
}
});
},
updateStats: function (id) {
var id = parseInt(id);
if (
"readyState" in CHV.obj.import.working[id].stats &&
CHV.obj.import.working[id].stats.readyState != 4
) {
console.log(
"Aborting stats timeout call (previous call is still not ready)"
);
return;
}
CHV.obj.import.working[id].stats = $.ajax({
type: "POST",
data: {
action: "importStats",
id: id,
},
});
CHV.obj.import.working[id].stats.complete(function (XHR) {
var response = XHR.responseJSON;
if (response) {
var $html = CHV.fn.import.parseTemplate(response.import);
$(
"[data-id=" + response.import.id + "]",
CHV.obj.import.sel.root
).replaceWith($html);
if (response.import.status != "working") {
clearInterval(CHV.obj.import.working[id].interval);
}
}
});
},
add: {
submit: function () {
var modal = PF.obj.modal.selectors.root;
PF.obj.modal.form_data = {
action: "importAdd",
path: $("[name=form-path]", modal).val(),
options: {
root: $("[name=form-structure]", PF.obj.modal.selectors.root).val(),
},
};
return true;
},
deferred: {
success: function (XHR) {
var response = XHR.responseJSON;
PF.fn.growl.expirable(
PF.fn._s(
"Import job ID %s added successfully, you can process the import now",
response.import.id
)
);
var $html = CHV.fn.import.parseTemplate(response.import);
$html.insertAfter(CHV.obj.import.sel.header, CHV.obj.import.sel.root);
$(CHV.obj.import.sel.root).removeClass("hidden");
},
error: function (XHR) {
CHV.fn.import.errorHandler(XHR.responseJSON);
},
},
},
process: {
abortAll: function (id) {
var id = parseInt(id);
if (id in CHV.obj.import.working) {
CHV.obj.import.aborted.push(id);
for (var key in CHV.obj.import.working[id].threads) {
CHV.obj.import.working[id].threads[key].abort();
}
PF.fn.growl.expirable(
"Aborted all threads for import job ID " +
id +
", changing status now"
);
if ("interval" in CHV.obj.import.working[id]) {
clearInterval(CHV.obj.import.working[id].interval);
if ("abort" in CHV.obj.import.working[id].stats) {
CHV.obj.import.working[id].stats.abort();
}
}
}
},
xhr: function (id, thread) {
var id = parseInt(id);
console.log("New XHR for thread #" + thread + " for import job ID");
if (id in CHV.obj.import.working == false) {
CHV.obj.import.working[id] = {
threads: {},
interval: {},
stats: {},
};
}
CHV.obj.import.working[id].threads[thread] = $.ajax({
type: "POST",
data: {
action: "importProcess",
id: id,
thread: thread,
},
});
CHV.obj.import.working[id].threads[thread].complete(function (XHR) {
if (XHR.status == 400) {
CHV.fn.import.errorHandler(XHR.responseJSON);
return;
}
var status = $("[data-id=" + id + "]", CHV.obj.import.sel.root).data(
"status"
);
if ($.inArray(id, CHV.obj.import.aborted) == -1) {
CHV.fn.import.process.xhr(id, thread);
}
});
},
load: function () {
$("html").data("modal-form-values", "");
return true;
},
submit: function (id) {
var modal = PF.obj.modal.selectors.root;
var threads = $("[name=form-threads]", modal).val();
if (threads == 0) {
PF.fn.growl.expirable(PF.fn._s("Select number of threads"));
return false;
}
PF.obj.modal.form_data = {
action: "importEdit",
id: id,
threads: threads,
values: {
status: "working",
},
};
return true;
},
deferred: {
success: function (XHR) {
var response = XHR.responseJSON;
PF.fn.growl.expirable(
PF.fn._s(
"Import job ID %s is being processed now",
response.import.id
)
);
var $html = CHV.fn.import.parseTemplate(response.import);
$(
"[data-id=" + response.import.id + "]",
CHV.obj.import.sel.root
).replaceWith($html);
// Once the row has been edited, start the actual jobs
var threads = parseInt(response.request.threads);
for (var i = 1; i <= threads; i++) {
CHV.fn.import.process.xhr(response.import.id, i);
}
CHV.obj.import.working[response.import.id].interval = setInterval(
function () {
CHV.fn.import.updateStats(response.import.id);
},
5000
);
},
error: function (XHR) {
var response = XHR.responseJSON;
if (response.error.code == 900) {
console.log("Aborting current working process (status changed)");
CHV.fn.import.process.abortAll(response.id);
} else {
CHV.fn.import.errorHandler();
}
},
},
},
delete: {
submit: function (id) {
PF.obj.modal.form_data = {
action: "importDelete",
id: id,
};
return true;
},
deferred: {
success: function (XHR) {
var response = XHR.responseJSON;
PF.fn.growl.call(PF.fn._s("Import ID %s removed", response.import.id));
$(
"[data-id=" + response.import.id + "]",
CHV.obj.import.sel.root
).remove();
if ($("li", CHV.obj.import.sel.root).size() == 1) {
$(CHV.obj.import.sel.root).addClass("hidden");
}
},
error: function (XHR) {
CHV.fn.import.errorHandler(XHR.responseJSON);
},
},
},
parseTemplate: function (dataset, $el) {
var tpl = CHV.obj.import.rowTpl;
for (var key in CHV.obj.import.importTr) {
if (typeof dataset[key] != typeof undefined) {
tpl = tpl.replaceAll("%" + key + "%", dataset[key]);
}
}
tpl = tpl.replaceAll("%parse%", dataset.options.root);
tpl = tpl.replaceAll("%shortParse%", dataset.options.root.charAt(0));
tpl = tpl.replaceAll(
"%displayStatus%",
CHV.obj.import.statusesDisplay[dataset.status]
);
var $html = $($.parseHTML(tpl)).attr(
"data-object",
JSON.stringify(dataset)
);
return $html;
},
};

File diff suppressed because one or more lines are too long

File diff suppressed because it is too large Load diff

View file

@ -129,7 +129,7 @@ function check_system_integrity()
}
} else { // Can write?
if (!is_writable($v)) {
$install_errors[] = 'No write permission in <code>'.G\absolute_to_relative($v).'</code> directory. Chevereto needs to be able to write in this directory.';
$install_errors[] = 'No write permission for user '.get_current_user().' in <code>'.G\absolute_to_relative($v).'</code> directory. Chevereto needs to be able to write in this directory.';
}
}
}
@ -178,6 +178,10 @@ function check_system_integrity()
}
if (is_array($install_errors) && count($install_errors) > 0) {
if (access === 'cli') {
G\debug($install_errors);
die(255);
}
Render\chevereto_die($install_errors);
}
}

View file

@ -23,8 +23,6 @@ namespace CHV;
use G;
use Exception;
error_reporting(E_ALL);
if (!defined('access') or !access) {
die('This file cannot be directly accessed.');
}

View file

@ -44,11 +44,12 @@ $route = function ($handler) {
$route_prefix = 'dashboard';
$sub_routes = [
'stats' => _s('Stats'),
'images' => _s('Images'),
'albums' => _s('Albums'),
'users' => _s('Users'),
'settings' => _s('Settings')
'stats' => _s('Stats'),
'images' => _s('Images'),
'albums' => _s('Albums'),
'users' => _s('Users'),
'settings' => _s('Settings'),
'bulk' => _s('Bulk importer'),
];
$default_route = 'stats';
@ -75,7 +76,7 @@ $route = function ($handler) {
);
}
$route_menu['upgrade'] = [
'label' => '💎 Upgrade to premium',
'label' => '⭐ Upgrade',
'id' => 'upgrade'
];
@ -188,6 +189,7 @@ $route = function ($handler) {
$chevereto_urls = [
'Chevereto' => 'https://chevereto.com',
_s('Community') => 'https://chevereto.com/community/',
_s('Collaboration') => 'https://chevereto.com/community/collaboration/',
_s('Support') => 'https://chevereto.com/support',
_s('Documentation') => 'https://v3-docs.chevereto.com/',
_s('Changelog') => 'https://chevereto.com/changelog',

View file

@ -0,0 +1,43 @@
<?php
/* --------------------------------------------------------------------
Chevereto
http://chevereto.com/
@author Rodolfo Berrios A. <http://rodolfoberrios.com/>
<inbox@rodolfoberrios.com>
Copyright (C) Rodolfo Berrios A. All rights reserved.
BY USING THIS SOFTWARE YOU DECLARE TO ACCEPT THE CHEVERETO EULA
http://chevereto.com/license
--------------------------------------------------------------------- */
$route = function ($handler) {
try {
if (!CHV\Login::isAdmin()) {
$this->template = 'request-denied';
return;
}
// Allow 3 levels only -> /importer-jobs/X/process
if ($handler->isRequestLevel(4)) {
return $handler->issue404();
}
if (is_null($handler->request[0]) || is_null($handler->request[1])) {
return $handler->issue404();
}
$filepath = G_ROOT_PATH . sprintf('app/importer/jobs/%1$s/%2$s.txt', $handler->request[0], $handler->request[1]);
if (!file_exists($filepath)) {
return $handler->issue404();
}
if (!headers_sent()) {
header('Content-Type: text/plain');
}
readfile($filepath);
exit;
} catch (Exception $e) {
G\exception_to_error($e);
}
};

View file

@ -34,6 +34,12 @@ $route = function ($handler) {
$doing = 'deny';
}
if (in_array($doing, ['importAdd', 'importStats', 'importProcess', 'importEdit', 'importDelete']) && $logged_user['is_admin'] == false) {
throw new Exception(_s('Request denied'), 400);
} else {
$import = new CHV\Import();
}
switch ($doing) {
case 'deny':
throw new Exception(_s('Request denied'), 403);
@ -1314,11 +1320,91 @@ $route = function ($handler) {
} catch (Exception $e) {
throw new Exception('Error: ' . $e->getMessage());
}
break;
break;
// Adds the importer job (path+options)
case 'importAdd':
if ($_REQUEST['path'] == false) {
throw new Exception('Missing path parameter', 100);
}
$import->path = $_REQUEST['path'];
if ($_REQUEST['options'] != false) {
$import->options = $_REQUEST['options'];
}
$import->add();
$import->get();
$json_array['status_code'] = 200;
$json_array['import'] = $import->parsedImport;
break;
// Common operations
case 'importStats':
case 'importProcess':
case 'importEdit':
case 'importDelete':
case 'importReset':
case 'importResume':
if ($_REQUEST['id'] == false) {
throw new Exception('Missing id parameter', 100);
}
$import->id = (int) $_REQUEST['id'];
$import->get();
break;
case 'toggleTone':
if (!$logged_user) {
throw new Exception('Invalid request', 403);
}
CHV\User::update($logged_user['id'], ['is_dark_mode' => $logged_user['is_dark_mode'] ? 0 : 1]);
$json_array['status_code'] = 200;
$logged_user = CHV\User::getSingle($logged_user['id']);
$json_array['is_dark_mode'] = (bool) $logged_user['is_dark_mode'];
break;
default: // EX X
throw new Exception(!G\check_value($_REQUEST['action']) ? 'empty action' : 'invalid action', !G\check_value($_REQUEST['action']) ? 0 : 1);
break;
throw new Exception(!G\check_value($doing) ? 'empty action' : 'invalid action', !G\check_value($doing) ? 0 : 1);
break;
}
if (isset($import->id)) {
switch ($doing) {
// Check the importer stats (id)
case 'importStats':
$json_array['status_code'] = 200;
$json_array['import'] = $import->parsedImport;
break;
// Issue/Resume import operation (id+thread)
case 'importProcess':
session_write_close();
$import->thread = (int) $_REQUEST['thread'] ?: 1;
$import->process();
$json_array['status_code'] = 200;
break;
// Edit import job (id,values)
case 'importEdit':
if ($_REQUEST['values'] == false) {
throw new Exception('Missing values parameter', 101);
}
if (is_array($_REQUEST['values']) == false) {
throw new Exception('Expecting array values', 102);
}
$import->edit($_REQUEST['values']);
$import->get();
$json_array['import'] = $import->parsedImport;
$json_array['status_code'] = 200;
break;
case 'importReset':
$import->reset();
$json_array['import'] = $import->parsedImport;
$json_array['status_code'] = 200;
break;
case 'importResume':
$import->resume();
$json_array['import'] = $import->parsedImport;
$json_array['status_code'] = 200;
break;
case 'importDelete':
$import->delete();
$json_array['status_code'] = 200;
$json_array['import'] = $import->parsedImport;
break;
}
}
// Inject any missing status_code
if (isset($json_array['success']) and !isset($json_array['status_code'])) {

View file

@ -52,11 +52,11 @@ if (CHV\Login::isAdmin()) {
</script>
<div data-modal="form-upgrade" class="hidden" data-is-xhr data-submit-fn="CHV.fn.submit_upgradeToPaid" data-ajax-deferred="CHV.fn.complete_upgradeToPaid">
<span class="modal-box-title">Upgrade to premium</span>
<div class="text-align-center margin-top-30 margin-bottom-30" style="font-size: 90px;">💎👏💖</div>
<p>Upgrading to paid Chevereto allows you to enjoy more <a href="https://chevereto.com/features" target="_blank">features</a> like multiple external storage servers, bulk content importer, manage banners, content likes, user followers, social login signup and more. It also comes with support in case you need help.</p>
<p>👍🏾 Keep in mind that <b>Chevereto is made by a single developer</b>. Your purchase helps to sustain ongoing development of this software.</p>
<p>You can upgrade now by pasting your <a href="https://chevereto.com/panel/license" target="_blank">license key</a>. If you don't have one you can <a href="https://chevereto.com/pricing" target="_blank">buy it now</a> with PayPal, AliPay, UnionPay and cryptocurrency.</p>
<span class="modal-box-title">Upgrade Chevereto</span>
<div class="text-align-center margin-top-30 margin-bottom-30" style="font-size: 90px;">⭐⭐⭐</div>
<p>Upgrading to paid Chevereto allows you to get more <a href="https://chevereto.com/features" target="_blank">features</a> like multiple external storage servers, manage banners, content likes, user followers, social login signup, etc. Support included.</p>
<p>Keep in mind that Chevereto is made <b>by a single developer</b>, your purchase helps to sustain ongoing development of this software.</p>
<p>You can upgrade now by pasting your <a href="https://chevereto.com/panel/license" target="_blank">license key</a>. If you don't have one you can <a href="https://chevereto.com/pricing" target="_blank">buy it now</a> with PayPal, AliPay, UnionPay and crypto.</p>
<div class="btn-container text-align-center"><button class="btn btn-input green" data-action="submit" type="submit">Upgrade now</button> <span class="btn-alt"><?php _se('or'); ?><a class="cancel" data-action="cancel">maybe later</a></span></div>
</div>
<?php

View file

@ -280,7 +280,7 @@ if (is_maintenance() || is_show_consent_screen() || in_array($templateUsed, ['re
<li><a href="<?php echo G\get_base_url(sprintf('logout/?auth_token=%s', get_auth_token())); ?>"><?php _se('Sign out'); ?></a></li>
<?php if (is_admin()) { ?>
<div class="or-separator margin-0" style="height: 1px;"></div>
<li><a data-action="upgrade">💎 Upgrade</a></li>
<li><a data-action="upgrade"> Upgrade</a></li>
<?php } ?>
</ul>
</div>

View file

@ -34,7 +34,7 @@ foreach ($tabs as $tab) {
parse_str($QS, $current_page_qs);
unset($current_page_qs['lang']); // Get rid of any ?lang=
$current_url = $currentUrlPath . '?' . http_build_query($current_page_qs);
$page = intval($_GET['page'] ? $_GET['page'] : $current_page_qs['page'] ?: 1);
$page = intval(($_GET['page'] ? $_GET['page'] : $current_page_qs['page']) ?: 1);
$pages = [];
foreach (['prev', 'next'] as $v) {
$params = $current_page_qs;

View file

@ -1,54 +0,0 @@
<?php if (!defined('access') or !access) {
die('This file cannot be directly accessed.');
} ?>
<div data-modal="login" class="hidden">
<span class="modal-box-title"><?php _se('Login needed'); ?></span>
<p><?php _se("To use all the features of this site you must be logged in."); ?><?php
if (CHV\getSetting('enable_signups')) {
echo ' ' . _s("If you don't have an account you can <a href=\"%s\">sign up</a> right now.", G\get_base_url("signup"));
}
?></p>
<div class="position-relative overflow-auto margin-top-20">
<?php
if (CHV\getSetting('social_signin')) {
?>
<div class="text-align-center hidden phone-show phablet-show">
<span><?php _se('Sign in with another account'); ?></span>
<ul class="sign-services margin-top-10"><?php G\Render\include_theme_file('snippets/sign_services_buttons'); ?></ul>
<div class="or-separator margin-top-30"><span class="separator"><?php _se('or'); ?></span></div>
</div>
<?php
}
?>
<div class="c6 phone-c1 phablet-c1 grid-columns">
<form method="post" action="<?php echo G\get_base_url("login"); ?>" data-beforeunload="continue">
<div class="input"><input type="text" class="text-input" name="login-subject" placeholder="<?php _se('Username or Email address'); ?>" autocomplete="off" required></div>
<div class="input"><input type="password" class="text-input" name="password" placeholder="<?php _se('Password'); ?>" autocomplete="off" required><button type="submit" class="icon-input-submit"></button></div>
<div class="input">
<div class="checkbox-label margin-0 display-inline-block"><label for="keep-login-modal"><input type="checkbox" name="keep-login-modal" id="keep-login-modal"><?php _se('Keep me logged in'); ?></label></div>
<div class="float-right"><a href="<?php echo G\get_base_url("account/password-forgot"); ?>"><?php _se('Forgot password?'); ?></a></div>
</div>
<?php if (is_captcha_needed()) { ?>
<div class="input-label">
<label for="recaptcha_response_field">reCAPTCHA</label>
<?php echo CHV\Render\get_recaptcha_html('g-recaptcha-modal'); ?>
</div>
<?php } ?>
</form>
</div>
<?php
if (CHV\getSetting('social_signin')) {
?>
<div class="c9 phone-hide phablet-hide grid-columns float-right">
<div class="or-separator c2 float-left margin-left-10 margin-right-10"><span class="separator"><?php _se('or'); ?></span></div>
<div class="c6 float-left margin-left-10">
<span class="h2-title"><?php _se('Sign in with another account'); ?></span>
<ul class="sign-services sign-services-compact margin-top-10"><?php G\Render\include_theme_file('snippets/sign_services_buttons'); ?></ul>
</div>
</div>
<?php
}
?>
</div>
</div>

View file

@ -2331,6 +2331,7 @@ body.full--wh {
[data-content="dashboard-imports"] [data-status="paused"] [data-action="pause"],
[data-content="dashboard-imports"] [data-status="canceled"] [data-action="pause"],
[data-content="dashboard-imports"] [data-status="completed"] [data-action="pause"],
[data-content="dashboard-imports"] [data-status="queued"] [data-action="pause"],
[data-content="dashboard-imports"] [data-status="canceled"] [data-action="cancel"],
[data-content="dashboard-imports"] [data-status="canceled"] [data-target="modal-process-import"],

File diff suppressed because one or more lines are too long

View file

@ -108,7 +108,359 @@ function free_version_waring($wrap=true)
</ul>
<script async defer src="https://buttons.github.io/buttons.js"></script>
</div>
</div>
<?php
break;
case 'bulk':
?>
<div class="header header--centering default-margin-bottom">
<h1><?php _se('Bulk importer'); ?></h1>
<div class="header-content-right phone-float-none">
<div class="list-selection header--centering">
<a class="header-link" href="https://goo.gl/q5poeY" target="_blank"><?php _se('documentation'); ?></a>
</div>
</div>
</div>
<div class="text-content">
<p><?php _se('This tool allows to mass add content to your website by pointing a system path with the content you want to import. It supports the addition of users, albums, and images using a folder based structure.'); ?></p>
</div>
<div class ="text-content margin-bottom-20">
<h3>🤖 <?php _se('Automatic importing'); ?></h3>
<p><?php _se('The system automatically parses any content by a continuous observation of the %path% path.', ['%path%' => '<b>' . G_ROOT_PATH . 'importing</b>']); ?> <?php _se('Completed jobs will be automatically re-started after %n %m.', [
'%n' => '1',
'%m' => _n('minute', 'minutes', '1')
]); ?> <?php _se('Reset to clear stats and logs.'); ?></p>
</div>
<div data-content="dashboard-imports" class="margin-top-0 margin-bottom-20">
<?php
$statusesDisplay = [
'queued' => _s('Queued'),
'working' => _s('Working'),
'paused' => _s('Paused'),
'canceled' => _s('Canceled'),
'completed' => _s('Completed'),
];
if ($continuous = CHV\Import::getContinuous()) {
foreach ($continuous as $v) {
$boxTpl = '<div class="importing phone-c1 phablet-c1 c8 fluid-column display-inline-block" data-status="%status%" data-id="%id%" data-object="%object%" data-errors="%errors%" data-started="%started%">
<h3 class="margin-bottom-5">Path <b title="%path%">%pathRelative%</b></h3>
<span data-content="log-errors" class="icon icon-warning color-red position-absolute top-10 right-10"></span>
<div data-content="pop-selection" class="pop-btn">
<span class="pop-btn-text">' . _s('Actions') . '<span class="arrow-down"></span></span>
<div class="pop-box arrow-box arrow-box-top anchor-left">
<div class="pop-box-inner pop-box-menu">
<ul>
<li data-action="reset"><a>' . _s('Reset') . '</a></li>
<li data-action="pause"><a>' . _s('Pause') . '</a></li>
<li data-action="resume"><a>' . _s('Resume') . '</a></li>
<li data-content="log-process"><a href="' . G\get_base_url('importer-jobs/%id%/process') . '" target="_blank">' . _s('Process log') . '</a></li>
<li data-content="log-errors"><a href="' . G\get_base_url('importer-jobs/%id%/errors') . '" target="_blank"><span class="icon icon-warning color-red"></span> ' . _s('Errors') . '</a></li>
</ul>
</div>
</div>
</div>
<div class="importing-stats">
<span class="figure"><span data-content="images">%images%</span> images</span>
<span class="figure"><span data-content="albums">%albums%</span> albums</span>
<span class="figure"><span data-content="users">%users%</span> users</span>
</div>
<div class="importing-status">' . _s('Status') . ': <span data-content="status">%displayStatus%</span></div>
<div class="importing-status">@<span data-content="dateTime">%dateTime%</span> UTC</div>
<div class="loading-container position-absolute right-10 bottom-10"><div class="loading"></div></div>
</div>';
echo strtr($boxTpl, [
'%id%' => $v['id'],
'%dateTime%' => $v['time_updated'],
'%object%' => htmlspecialchars(json_encode($v), ENT_QUOTES, 'UTF-8'),
'%status%' => $v['status'],
'%parse%' => $v['options']['root'],
'%shortParse%' => $v['options']['root'][0],
'%displayStatus%' => $statusesDisplay[$v['status']],
'%path%' => $v['path'],
'%pathRelative%' => '.' . G\absolute_to_relative($v['path']),
'%users%' => $v['users'] ?: 0,
'%images%' => $v['images'] ?: 0,
'%albums%' => $v['albums'] ?: 0,
'%errors%' => $v['errors'] ?: 0,
'%started%' => $v['started'] ?: 0,
]);
}
} ?>
</div>
<div class="margin-bottom-40">
<div class="margin-bottom-10"><?php _se('The system works with a scheduled command to continuously process the importing. It requires a crontab entry.'); ?></div>
<div class="margin-bottom-10">
<code class="code">* * * * * IS_CRON=1 THREAD_ID=1 /usr/bin/php <?php echo G_ROOT_PATH . 'importing.php'; ?> >/dev/null 2>&1</code>
</div>
<div class="margin-bottom-10"><?php _se('You can run the command in parallel by changing the integer value of %s%.', ['%s%' => '<code>THREAD_ID</code>']); ?></div>
<div class="margin-bottom-10">
<span class="highlight padding-5 display-inline-block"> <?php _se('All file-system permissions must be granted for the crontab user at %path%', ['%path%' => G_ROOT_PATH . 'importing']); ?></span>
</div>
</div>
</div>
<div data-modal="modal-add-import" class="hidden" data-submit-fn="CHV.fn.import.add.submit" data-ajax-deferred="CHV.fn.import.add.deferred">
<span class="modal-box-title"><?php _se('Add import job'); ?></span>
<div class="modal-form">
<?php G\Render\include_theme_file('snippets/form_import_add'); ?>
</div>
</div>
<div data-modal="modal-process-import" data-prompt="skip" class="hidden" data-load-fn="CHV.fn.import.process.load" data-submit-fn="CHV.fn.import.process.submit" data-ajax-deferred="CHV.fn.import.process.deferred">
<span class="modal-box-title"><?php _se('Process import'); ?></span>
<div class="modal-form">
<?php G\Render\include_theme_file('snippets/form_import_process'); ?>
</div>
</div>
<?php
if ($imports = CHV\Import::getOneTime()) {
foreach ($imports as $k => &$v) {
if ($v['status'] != 'working') {
continue;
}
$then = strtotime($v['time_updated']);
$now = strtotime(G\datetimegmt());
if ($now > ($then + 300)) { // 5 min
$v['status'] = 'paused';
CHV\DB::update('imports', ['status' => 'paused'], ['id' => $v['id']]);
}
}
$imports = array_reverse($imports);
}
$rowTpl = '<li data-status="%status%" data-id="%id%" data-object="%object%" data-errors="%errors%" data-started="%started%">
<span class="fluid-column c2 col-2-max display-table-cell padding-right-10">%id%</span>
<span class="fluid-column c2 col-2-max display-table-cell padding-right-10 text-transform-uppercase" title="' . _s('Top level folders as %s', '%parse%') . '">%shortParse%</span>
<span class="fluid-column c3 col-3-max display-table-cell padding-right-10">
<span class="icon icon-warning2 color-red" data-result="error"></span>
<span class="icon icon-checkmark-circle color-green" data-result="success"></span>
<span class="status-text">%displayStatus%</span>
</span>
<span class="fluid-column c7 col-7-max col-7-min display-table-cell padding-right-10 text-overflow-ellipsis phone-display-block" title="%path%">%path%</span>
<span class="fluid-column c2 display-table-cell padding-right-10"><span>%users%</span><span class="table-li--mobile-display"> ' . _s('Users') . '</span></span>
<span class="fluid-column c2 display-table-cell padding-right-10"><span>%albums%</span><span class="table-li--mobile-display"> ' . _s('Albums') . '</span></span>
<span class="fluid-column c3 display-table-cell padding-right-10"><span>%images%</span><span class="table-li--mobile-display"> ' . _s('Images') . '</span></span>
<div class="fluid-column c3 display-table-cell margin-bottom-0 phone-display-block">
<div class="loading"></div>
<div data-content="pop-selection" class="pop-btn">
<span class="pop-btn-text">' . _s('Actions') . '<span class="arrow-down"></span></span>
<div class="pop-box arrow-box arrow-box-top anchor-left">
<div class="pop-box-inner pop-box-menu">
<ul>
<li data-args="%id%" data-modal="form" data-target="modal-process-import"><a>' . _s('Process') . '</a></li>
<li data-action="pause"><a>' . _s('Pause') . '</a></li>
<li data-action="cancel"><a>' . _s('Cancel') . '</a></li>
<li data-content="log-process"><a href="' . G\get_base_url('importer-jobs/%id%/process') . '" target="_blank">' . _s('Process log') . '</a></li>
<li data-content="log-errors"><a href="' . G\get_base_url('importer-jobs/%id%/errors') . '" target="_blank">' . _s('Errors') . '</a></li>
<li data-args="%id%" data-confirm="' . _s('Do you really want to remove the import ID %s?', '%id%') . '" data-submit-fn="CHV.fn.import.delete.submit" data-ajax-deferred="CHV.fn.import.delete.deferred"><a>' . _s('Delete') . '</a></li>
</ul>
</div>
</div>
</div>
</div>
</li>';
$manualImportingClass = is_array($imports) == false ? ' hidden' : '';
?>
<div class="text-content">
<h3> <?php _se('Manual importing'); ?></h3>
<p><?php _se('The system will parse the contents of any available filesystem path.'); ?> <?php _se('These processes must be manually created and handled with the web browser tab open.'); ?> <a data-modal="form" data-target="modal-add-import"><?php _se('Add import job'); ?></a></p>
</div>
<ul data-content="dashboard-imports" class="tabbed-content-list table-li-hover table-li margin-top-20 margin-bottom-20<?php echo $manualImportingClass; ?>">
<li class="table-li-header phone-hide">
<span class="fluid-column c2 display-table-cell">ID</span>
<span class="fluid-column c2 display-table-cell"><?php _se('Parser'); ?></span>
<span class="fluid-column c3 display-table-cell"><?php _se('Status'); ?></span>
<span class="fluid-column c7 col-7-max col-7-min display-table-cell"><?php _se('Path'); ?></span>
<span class="fluid-column c2 display-table-cell"><?php _se('Users'); ?></span>
<span class="fluid-column c2 display-table-cell"><?php _se('Albums'); ?></span>
<span class="fluid-column c3 display-table-cell"><?php _se('Images'); ?></span>
<span class="fluid-column c3 display-table-cell">&nbsp;</span>
</li>
<?php
if (is_array($imports)) {
foreach ($imports as $k => $v) {
echo strtr($rowTpl, [
'%id%' => $v['id'],
'%object%' => htmlspecialchars(json_encode($v), ENT_QUOTES, 'UTF-8'),
'%status%' => $v['status'],
'%parse%' => $v['options']['root'],
'%shortParse%' => $v['options']['root'][0],
'%displayStatus%' => $statusesDisplay[$v['status']],
'%path%' => $v['path'],
'%users%' => $v['users'] ?: 0,
'%images%' => $v['images'] ?: 0,
'%albums%' => $v['albums'] ?: 0,
'%errors%' => $v['errors'] ?: 0,
'%started%' => $v['started'] ?: 0,
]);
}
}
?>
</ul>
<script>
$(document).ready(function() {
CHV.obj.import = {
working: {
// importId: {
// threads: {threadId: xhr},
// interval: interval,
// stats: xhr
// }
},
aborted: [],
boxTpl: <?php echo json_encode($boxTpl); ?>,
rowTpl: <?php echo json_encode($rowTpl); ?>,
importTr: {
'id': null,
// 'object' : null,
'status': null,
'parse': null,
'shortParse': null,
'displayStatus': null,
'path': null,
'users': null,
'images': null,
'albums': null,
'errors': null,
'started': null,
},
sel: {
root: "[data-content=dashboard-imports]",
header: ".table-li-header"
},
statusesDisplay: <?php echo json_encode($statusesDisplay); ?>
};
var updateContinuous = function( object) {
var $sel = $("[data-id=" + object.id + "]", CHV.obj.import.sel.root);
$sel.attr({
"data-status": object.status,
"data-object": JSON.stringify(object),
"data-errors": object.errors,
"data-started": object.started,
});
$("[data-content=images]", $sel).text(object.images);
$("[data-content=dateTime]", $sel).text(object.time_updated);
$("[data-content=users]", $sel).text(object.users);
$("[data-content=albums]", $sel).text(object.albums);
$("[data-content=status]", $sel).text(CHV.obj.import.statusesDisplay[object.status]);
};
$('.importing', '[data-content=dashboard-imports]').each(function(i, v) {
var id = $(this).data("id");
var $this = $(this);
CHV.obj.import.working[id] = {
threads: {},
interval: setInterval(function() {
var $loading = $this.find(".loading");
if($loading.html() !== "") {
$loading.removeClass("hidden");
} else {
PF.fn.loading.inline($loading, {
size: "small"
});
}
CHV.obj.import.working[id].stats = $.ajax({
type: "POST",
data: {
action: "importStats",
id: id
}
});
CHV.obj.import.working[id].stats.complete(function (XHR) {
var response = XHR.responseJSON;
if (response) {
updateContinuous(response.import);
}
$loading.addClass("hidden");
});
}, 10000),
stats: {}
};
});
$(document).on("click", CHV.obj.import.sel.root + " [data-action]", function() {
var $el = $(this).closest("[data-object]");
var $loading = $el.find(".loading");
var $actions = $el.find("[data-content=pop-selection]");
var localData = $el.data("object");
var backupData = $.extend({}, localData);
var action = $(this).data("action");
var data = {};
if (localData.id) {
data.id = localData.id;
}
if($el.is("li")) {
CHV.fn.import.process.abortAll(data.id);
}
switch (action) {
case "resume":
data.action = "importResume";
localData.status = "working";
break;
case "reset":
data.action = "importReset";
localData.status = "working";
break;
case "pause":
data.action = "importEdit";
localData.status = "paused";
data.values = {
status: localData.status
};
break;
case "cancel":
localData.status = "canceled";
data.action = "importEdit";
data.values = {
status: localData.status
};
break;
case "process":
localData.status = "working";
data.action = "importEdit";
data.values = {
status: localData.status
};
break;
default:
alert('null');
return;
break;
}
if($loading.html() !== "") {
$loading.removeClass("hidden");
} else {
PF.fn.loading.inline($loading, {
size: "small"
});
}
$actions.addClass("pointer-events-none");
$.ajax({
type: "POST",
data: data
}).complete(function(XHR) {
var response = XHR.responseJSON;
if (XHR.status == 200) {
var dataset = response.import;
if($el.is("li")) {
var $html = CHV.fn.import.parseTemplate(dataset);
$el.replaceWith($html);
if (action == "process") {
CHV.fn.import.process.deferred.success(XHR);
}
} else {
updateContinuous(response.import);
}
} else {
PF.fn.growl.call(response.error.message);
}
$loading.addClass("hidden");
$actions.removeClass("pointer-events-none");
});
});
});
</script>
<?php
break;

View file

@ -37,8 +37,8 @@ namespace Composer\Autoload;
*
* @author Fabien Potencier <fabien@symfony.com>
* @author Jordi Boggiano <j.boggiano@seld.be>
* @see http://www.php-fig.org/psr/psr-0/
* @see http://www.php-fig.org/psr/psr-4/
* @see https://www.php-fig.org/psr/psr-0/
* @see https://www.php-fig.org/psr/psr-4/
*/
class ClassLoader
{

View file

@ -0,0 +1,245 @@
<?php
namespace Composer;
use Composer\Semver\VersionParser;
class InstalledVersions
{
private static $installed = array (
'root' =>
array (
'pretty_version' => 'dev-master',
'version' => 'dev-master',
'aliases' =>
array (
),
'reference' => '892dc79d4abe4d0139868de4b440739906564564',
'name' => 'chevereto/chevereto-free',
),
'versions' =>
array (
'chevereto/chevereto-free' =>
array (
'pretty_version' => 'dev-master',
'version' => 'dev-master',
'aliases' =>
array (
),
'reference' => '892dc79d4abe4d0139868de4b440739906564564',
),
'jbroadway/urlify' =>
array (
'pretty_version' => '1.1.3-stable',
'version' => '1.1.3.0',
'aliases' =>
array (
),
'reference' => '37fe4e7680a1c8cd68ac43a27dac7ef4be476300',
),
'mobiledetect/mobiledetectlib' =>
array (
'pretty_version' => '2.8.34',
'version' => '2.8.34.0',
'aliases' =>
array (
),
'reference' => '6f8113f57a508494ca36acbcfa2dc2d923c7ed5b',
),
'phpmailer/phpmailer' =>
array (
'pretty_version' => 'v6.1.7',
'version' => '6.1.7.0',
'aliases' =>
array (
),
'reference' => '2c2370ba3df7034f9eb7b8f387c97b52b2ba5ad0',
),
'tijsverkoyen/akismet' =>
array (
'pretty_version' => '1.1.1',
'version' => '1.1.1.0',
'aliases' =>
array (
),
'reference' => '6f7987fe181fd0fddbc9832f2ddeaf088425c83f',
),
),
);
public static function getInstalledPackages()
{
return array_keys(self::$installed['versions']);
}
public static function isInstalled($packageName)
{
return isset(self::$installed['versions'][$packageName]);
}
public static function satisfies(VersionParser $parser, $packageName, $constraint)
{
$constraint = $parser->parseConstraints($constraint);
$provided = $parser->parseConstraints(self::getVersionRanges($packageName));
return $provided->matches($constraint);
}
public static function getVersionRanges($packageName)
{
if (!isset(self::$installed['versions'][$packageName])) {
throw new \OutOfBoundsException('Package "' . $packageName . '" is not installed');
}
$ranges = array();
if (isset(self::$installed['versions'][$packageName]['pretty_version'])) {
$ranges[] = self::$installed['versions'][$packageName]['pretty_version'];
}
if (array_key_exists('aliases', self::$installed['versions'][$packageName])) {
$ranges = array_merge($ranges, self::$installed['versions'][$packageName]['aliases']);
}
if (array_key_exists('replaced', self::$installed['versions'][$packageName])) {
$ranges = array_merge($ranges, self::$installed['versions'][$packageName]['replaced']);
}
if (array_key_exists('provided', self::$installed['versions'][$packageName])) {
$ranges = array_merge($ranges, self::$installed['versions'][$packageName]['provided']);
}
return implode(' || ', $ranges);
}
public static function getVersion($packageName)
{
if (!isset(self::$installed['versions'][$packageName])) {
throw new \OutOfBoundsException('Package "' . $packageName . '" is not installed');
}
if (!isset(self::$installed['versions'][$packageName]['version'])) {
return null;
}
return self::$installed['versions'][$packageName]['version'];
}
public static function getPrettyVersion($packageName)
{
if (!isset(self::$installed['versions'][$packageName])) {
throw new \OutOfBoundsException('Package "' . $packageName . '" is not installed');
}
if (!isset(self::$installed['versions'][$packageName]['pretty_version'])) {
return null;
}
return self::$installed['versions'][$packageName]['pretty_version'];
}
public static function getReference($packageName)
{
if (!isset(self::$installed['versions'][$packageName])) {
throw new \OutOfBoundsException('Package "' . $packageName . '" is not installed');
}
if (!isset(self::$installed['versions'][$packageName]['reference'])) {
return null;
}
return self::$installed['versions'][$packageName]['reference'];
}
public static function getRootPackage()
{
return self::$installed['root'];
}
public static function getRawData()
{
return self::$installed;
}
public static function reload($data)
{
self::$installed = $data;
}
}

View file

@ -6,6 +6,7 @@ $vendorDir = dirname(dirname(__FILE__));
$baseDir = dirname(dirname($vendorDir));
return array(
'Composer\\InstalledVersions' => $vendorDir . '/composer/InstalledVersions.php',
'Detection\\MobileDetect' => $vendorDir . '/mobiledetect/mobiledetectlib/namespaced/Detection/MobileDetect.php',
'Mobile_Detect' => $vendorDir . '/mobiledetect/mobiledetectlib/Mobile_Detect.php',
'PHPMailer\\PHPMailer\\Exception' => $vendorDir . '/phpmailer/phpmailer/src/Exception.php',
@ -16,5 +17,4 @@ return array(
'TijsVerkoyen\\Akismet\\Akismet' => $vendorDir . '/tijsverkoyen/akismet/Akismet.php',
'TijsVerkoyen\\Akismet\\Exception' => $vendorDir . '/tijsverkoyen/akismet/Exception.php',
'URLify' => $vendorDir . '/jbroadway/urlify/URLify.php',
'URLifyTest' => $vendorDir . '/jbroadway/urlify/tests/URLifyTest.php',
);

View file

@ -22,13 +22,15 @@ class ComposerAutoloaderInit5ebab6dc32ca006b1a67a63e20c04846
return self::$loader;
}
require __DIR__ . '/platform_check.php';
spl_autoload_register(array('ComposerAutoloaderInit5ebab6dc32ca006b1a67a63e20c04846', 'loadClassLoader'), true, true);
self::$loader = $loader = new \Composer\Autoload\ClassLoader();
spl_autoload_unregister(array('ComposerAutoloaderInit5ebab6dc32ca006b1a67a63e20c04846', 'loadClassLoader'));
$useStaticLoader = PHP_VERSION_ID >= 50600 && !defined('HHVM_VERSION') && (!function_exists('zend_loader_file_encoded') || !zend_loader_file_encoded());
if ($useStaticLoader) {
require_once __DIR__ . '/autoload_static.php';
require __DIR__ . '/autoload_static.php';
call_user_func(\Composer\Autoload\ComposerStaticInit5ebab6dc32ca006b1a67a63e20c04846::getInitializer($loader));
} else {

View file

@ -38,6 +38,7 @@ class ComposerStaticInit5ebab6dc32ca006b1a67a63e20c04846
);
public static $classMap = array (
'Composer\\InstalledVersions' => __DIR__ . '/..' . '/composer/InstalledVersions.php',
'Detection\\MobileDetect' => __DIR__ . '/..' . '/mobiledetect/mobiledetectlib/namespaced/Detection/MobileDetect.php',
'Mobile_Detect' => __DIR__ . '/..' . '/mobiledetect/mobiledetectlib/Mobile_Detect.php',
'PHPMailer\\PHPMailer\\Exception' => __DIR__ . '/..' . '/phpmailer/phpmailer/src/Exception.php',
@ -48,7 +49,6 @@ class ComposerStaticInit5ebab6dc32ca006b1a67a63e20c04846
'TijsVerkoyen\\Akismet\\Akismet' => __DIR__ . '/..' . '/tijsverkoyen/akismet/Akismet.php',
'TijsVerkoyen\\Akismet\\Exception' => __DIR__ . '/..' . '/tijsverkoyen/akismet/Exception.php',
'URLify' => __DIR__ . '/..' . '/jbroadway/urlify/URLify.php',
'URLifyTest' => __DIR__ . '/..' . '/jbroadway/urlify/tests/URLifyTest.php',
);
public static function getInitializer(ClassLoader $loader)

View file

@ -1,226 +1,237 @@
[
{
"name": "jbroadway/urlify",
"version": "1.1.3-stable",
"version_normalized": "1.1.3.0",
"source": {
"type": "git",
"url": "https://github.com/jbroadway/urlify.git",
"reference": "37fe4e7680a1c8cd68ac43a27dac7ef4be476300"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/jbroadway/urlify/zipball/37fe4e7680a1c8cd68ac43a27dac7ef4be476300",
"reference": "37fe4e7680a1c8cd68ac43a27dac7ef4be476300",
"shasum": ""
},
"require": {
"php": ">=5.3.0"
},
"require-dev": {
"phpunit/phpunit": "^4.8.36 || ^5.7 || ^6.5"
},
"time": "2019-06-13T18:30:56+00:00",
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "1.0-dev"
}
},
"installation-source": "dist",
"autoload": {
"psr-0": {
"URLify": ""
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"BSD-3-Clause-Clear"
],
"authors": [
{
"name": "Johnny Broadway",
"email": "johnny@johnnybroadway.com",
"homepage": "http://www.johnnybroadway.com/"
}
],
"description": "PHP port of URLify.js from the Django project. Transliterates non-ascii characters for use in URLs.",
"homepage": "https://github.com/jbroadway/urlify",
"keywords": [
"encode",
"iconv",
"link",
"slug",
"translit",
"transliterate",
"transliteration",
"url",
"urlify"
]
},
{
"name": "mobiledetect/mobiledetectlib",
"version": "2.8.34",
"version_normalized": "2.8.34.0",
"source": {
"type": "git",
"url": "https://github.com/serbanghita/Mobile-Detect.git",
"reference": "6f8113f57a508494ca36acbcfa2dc2d923c7ed5b"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/serbanghita/Mobile-Detect/zipball/6f8113f57a508494ca36acbcfa2dc2d923c7ed5b",
"reference": "6f8113f57a508494ca36acbcfa2dc2d923c7ed5b",
"shasum": ""
},
"require": {
"php": ">=5.0.0"
},
"require-dev": {
"phpunit/phpunit": "~4.8.35||~5.7"
},
"time": "2019-09-18T18:44:20+00:00",
"type": "library",
"installation-source": "dist",
"autoload": {
"classmap": [
"Mobile_Detect.php"
{
"packages": [
{
"name": "jbroadway/urlify",
"version": "1.1.3-stable",
"version_normalized": "1.1.3.0",
"source": {
"type": "git",
"url": "https://github.com/jbroadway/urlify.git",
"reference": "37fe4e7680a1c8cd68ac43a27dac7ef4be476300"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/jbroadway/urlify/zipball/37fe4e7680a1c8cd68ac43a27dac7ef4be476300",
"reference": "37fe4e7680a1c8cd68ac43a27dac7ef4be476300",
"shasum": ""
},
"require": {
"php": ">=5.3.0"
},
"require-dev": {
"phpunit/phpunit": "^4.8.36 || ^5.7 || ^6.5"
},
"time": "2019-06-13T18:30:56+00:00",
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "1.0-dev"
}
},
"installation-source": "dist",
"autoload": {
"psr-0": {
"URLify": ""
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"BSD-3-Clause-Clear"
],
"psr-0": {
"Detection": "namespaced/"
}
"authors": [
{
"name": "Johnny Broadway",
"email": "johnny@johnnybroadway.com",
"homepage": "http://www.johnnybroadway.com/"
}
],
"description": "PHP port of URLify.js from the Django project. Transliterates non-ascii characters for use in URLs.",
"homepage": "https://github.com/jbroadway/urlify",
"keywords": [
"encode",
"iconv",
"link",
"slug",
"translit",
"transliterate",
"transliteration",
"url",
"urlify"
],
"install-path": "../jbroadway/urlify"
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Serban Ghita",
"email": "serbanghita@gmail.com",
"homepage": "http://mobiledetect.net",
"role": "Developer"
}
],
"description": "Mobile_Detect is a lightweight PHP class for detecting mobile devices. It uses the User-Agent string combined with specific HTTP headers to detect the mobile environment.",
"homepage": "https://github.com/serbanghita/Mobile-Detect",
"keywords": [
"detect mobile devices",
"mobile",
"mobile detect",
"mobile detector",
"php mobile detect"
]
},
{
"name": "phpmailer/phpmailer",
"version": "v6.1.6",
"version_normalized": "6.1.6.0",
"source": {
"type": "git",
"url": "https://github.com/PHPMailer/PHPMailer.git",
"reference": "c2796cb1cb99d7717290b48c4e6f32cb6c60b7b3"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/PHPMailer/PHPMailer/zipball/c2796cb1cb99d7717290b48c4e6f32cb6c60b7b3",
"reference": "c2796cb1cb99d7717290b48c4e6f32cb6c60b7b3",
"shasum": ""
},
"require": {
"ext-ctype": "*",
"ext-filter": "*",
"php": ">=5.5.0"
},
"require-dev": {
"doctrine/annotations": "^1.2",
"friendsofphp/php-cs-fixer": "^2.2",
"phpunit/phpunit": "^4.8 || ^5.7"
},
"suggest": {
"ext-mbstring": "Needed to send email in multibyte encoding charset",
"hayageek/oauth2-yahoo": "Needed for Yahoo XOAUTH2 authentication",
"league/oauth2-google": "Needed for Google XOAUTH2 authentication",
"psr/log": "For optional PSR-3 debug logging",
"stevenmaguire/oauth2-microsoft": "Needed for Microsoft XOAUTH2 authentication",
"symfony/polyfill-mbstring": "To support UTF-8 if the Mbstring PHP extension is not enabled (^1.2)"
},
"time": "2020-05-27T12:24:03+00:00",
"type": "library",
"installation-source": "dist",
"autoload": {
"psr-4": {
"PHPMailer\\PHPMailer\\": "src/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"LGPL-2.1-only"
],
"authors": [
{
"name": "Marcus Bointon",
"email": "phpmailer@synchromedia.co.uk"
{
"name": "mobiledetect/mobiledetectlib",
"version": "2.8.34",
"version_normalized": "2.8.34.0",
"source": {
"type": "git",
"url": "https://github.com/serbanghita/Mobile-Detect.git",
"reference": "6f8113f57a508494ca36acbcfa2dc2d923c7ed5b"
},
{
"name": "Jim Jagielski",
"email": "jimjag@gmail.com"
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/serbanghita/Mobile-Detect/zipball/6f8113f57a508494ca36acbcfa2dc2d923c7ed5b",
"reference": "6f8113f57a508494ca36acbcfa2dc2d923c7ed5b",
"shasum": ""
},
{
"name": "Andy Prevost",
"email": "codeworxtech@users.sourceforge.net"
"require": {
"php": ">=5.0.0"
},
{
"name": "Brent R. Matzelle"
}
],
"description": "PHPMailer is a full-featured email creation and transfer class for PHP",
"funding": [
{
"url": "https://github.com/synchro",
"type": "github"
}
]
},
{
"name": "tijsverkoyen/akismet",
"version": "1.1.1",
"version_normalized": "1.1.1.0",
"source": {
"type": "git",
"url": "https://github.com/tijsverkoyen/Akismet.git",
"reference": "6f7987fe181fd0fddbc9832f2ddeaf088425c83f"
"require-dev": {
"phpunit/phpunit": "~4.8.35||~5.7"
},
"time": "2019-09-18T18:44:20+00:00",
"type": "library",
"installation-source": "dist",
"autoload": {
"classmap": [
"Mobile_Detect.php"
],
"psr-0": {
"Detection": "namespaced/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Serban Ghita",
"email": "serbanghita@gmail.com",
"homepage": "http://mobiledetect.net",
"role": "Developer"
}
],
"description": "Mobile_Detect is a lightweight PHP class for detecting mobile devices. It uses the User-Agent string combined with specific HTTP headers to detect the mobile environment.",
"homepage": "https://github.com/serbanghita/Mobile-Detect",
"keywords": [
"detect mobile devices",
"mobile",
"mobile detect",
"mobile detector",
"php mobile detect"
],
"install-path": "../mobiledetect/mobiledetectlib"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/tijsverkoyen/Akismet/zipball/6f7987fe181fd0fddbc9832f2ddeaf088425c83f",
"reference": "6f7987fe181fd0fddbc9832f2ddeaf088425c83f",
"shasum": ""
{
"name": "phpmailer/phpmailer",
"version": "v6.1.7",
"version_normalized": "6.1.7.0",
"source": {
"type": "git",
"url": "https://github.com/PHPMailer/PHPMailer.git",
"reference": "2c2370ba3df7034f9eb7b8f387c97b52b2ba5ad0"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/PHPMailer/PHPMailer/zipball/2c2370ba3df7034f9eb7b8f387c97b52b2ba5ad0",
"reference": "2c2370ba3df7034f9eb7b8f387c97b52b2ba5ad0",
"shasum": ""
},
"require": {
"ext-ctype": "*",
"ext-filter": "*",
"php": ">=5.5.0"
},
"require-dev": {
"doctrine/annotations": "^1.2",
"friendsofphp/php-cs-fixer": "^2.2",
"phpunit/phpunit": "^4.8 || ^5.7"
},
"suggest": {
"ext-mbstring": "Needed to send email in multibyte encoding charset",
"hayageek/oauth2-yahoo": "Needed for Yahoo XOAUTH2 authentication",
"league/oauth2-google": "Needed for Google XOAUTH2 authentication",
"psr/log": "For optional PSR-3 debug logging",
"stevenmaguire/oauth2-microsoft": "Needed for Microsoft XOAUTH2 authentication",
"symfony/polyfill-mbstring": "To support UTF-8 if the Mbstring PHP extension is not enabled (^1.2)"
},
"time": "2020-07-14T18:50:27+00:00",
"type": "library",
"installation-source": "dist",
"autoload": {
"psr-4": {
"PHPMailer\\PHPMailer\\": "src/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"LGPL-2.1-only"
],
"authors": [
{
"name": "Marcus Bointon",
"email": "phpmailer@synchromedia.co.uk"
},
{
"name": "Jim Jagielski",
"email": "jimjag@gmail.com"
},
{
"name": "Andy Prevost",
"email": "codeworxtech@users.sourceforge.net"
},
{
"name": "Brent R. Matzelle"
}
],
"description": "PHPMailer is a full-featured email creation and transfer class for PHP",
"support": {
"issues": "https://github.com/PHPMailer/PHPMailer/issues",
"source": "https://github.com/PHPMailer/PHPMailer/tree/v6.1.7"
},
"funding": [
{
"url": "https://github.com/synchro",
"type": "github"
}
],
"install-path": "../phpmailer/phpmailer"
},
"require": {
"ext-curl": "*",
"php": ">=5.2.0"
},
"time": "2016-07-19T13:50:18+00:00",
"type": "library",
"installation-source": "dist",
"autoload": {
"classmap": [
""
]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"BSD"
],
"authors": [
{
"name": "Tijs Verkoyen",
"email": "akismet@verkoyen.eu",
"role": "Developer"
}
],
"description": "Akismet is a wrapper-class to communicate with the Akismet API.",
"homepage": "https://github.com/tijsverkoyen/Akismet"
}
]
{
"name": "tijsverkoyen/akismet",
"version": "1.1.1",
"version_normalized": "1.1.1.0",
"source": {
"type": "git",
"url": "https://github.com/tijsverkoyen/Akismet.git",
"reference": "6f7987fe181fd0fddbc9832f2ddeaf088425c83f"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/tijsverkoyen/Akismet/zipball/6f7987fe181fd0fddbc9832f2ddeaf088425c83f",
"reference": "6f7987fe181fd0fddbc9832f2ddeaf088425c83f",
"shasum": ""
},
"require": {
"ext-curl": "*",
"php": ">=5.2.0"
},
"time": "2016-07-19T13:50:18+00:00",
"type": "library",
"installation-source": "dist",
"autoload": {
"classmap": [
""
]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"BSD"
],
"authors": [
{
"name": "Tijs Verkoyen",
"email": "akismet@verkoyen.eu",
"role": "Developer"
}
],
"description": "Akismet is a wrapper-class to communicate with the Akismet API.",
"homepage": "https://github.com/tijsverkoyen/Akismet",
"install-path": "../tijsverkoyen/akismet"
}
],
"dev": true
}

60
app/vendor/composer/installed.php vendored Normal file
View file

@ -0,0 +1,60 @@
<?php return array (
'root' =>
array (
'pretty_version' => 'dev-master',
'version' => 'dev-master',
'aliases' =>
array (
),
'reference' => '892dc79d4abe4d0139868de4b440739906564564',
'name' => 'chevereto/chevereto-free',
),
'versions' =>
array (
'chevereto/chevereto-free' =>
array (
'pretty_version' => 'dev-master',
'version' => 'dev-master',
'aliases' =>
array (
),
'reference' => '892dc79d4abe4d0139868de4b440739906564564',
),
'jbroadway/urlify' =>
array (
'pretty_version' => '1.1.3-stable',
'version' => '1.1.3.0',
'aliases' =>
array (
),
'reference' => '37fe4e7680a1c8cd68ac43a27dac7ef4be476300',
),
'mobiledetect/mobiledetectlib' =>
array (
'pretty_version' => '2.8.34',
'version' => '2.8.34.0',
'aliases' =>
array (
),
'reference' => '6f8113f57a508494ca36acbcfa2dc2d923c7ed5b',
),
'phpmailer/phpmailer' =>
array (
'pretty_version' => 'v6.1.7',
'version' => '6.1.7.0',
'aliases' =>
array (
),
'reference' => '2c2370ba3df7034f9eb7b8f387c97b52b2ba5ad0',
),
'tijsverkoyen/akismet' =>
array (
'pretty_version' => '1.1.1',
'version' => '1.1.1.0',
'aliases' =>
array (
),
'reference' => '6f7987fe181fd0fddbc9832f2ddeaf088425c83f',
),
),
);

23
app/vendor/composer/platform_check.php vendored Normal file
View file

@ -0,0 +1,23 @@
<?php
// platform_check.php @generated by Composer
$issues = array();
if (!(PHP_VERSION_ID >= 50500)) {
$issues[] = 'Your Composer dependencies require a PHP version ">= 5.5.0". You are running ' . PHP_VERSION . '.';
}
$missingExtensions = array();
extension_loaded('ctype') || $missingExtensions[] = 'ctype';
extension_loaded('curl') || $missingExtensions[] = 'curl';
extension_loaded('filter') || $missingExtensions[] = 'filter';
if ($missingExtensions) {
$issues[] = 'Your Composer dependencies require the following PHP extensions to be installed: ' . implode(', ', $missingExtensions);
}
if ($issues) {
echo 'Composer detected issues in your platform:' . "\n\n" . implode("\n", $issues);
exit(104);
}

View file

@ -1 +1 @@
6.1.6
6.1.7

View file

@ -19,8 +19,8 @@ $PHPMAILER_LANG['invalid_address'] = 'Felaktig adress: ';
$PHPMAILER_LANG['provide_address'] = 'Du måste ange minst en mottagares e-postadress.';
$PHPMAILER_LANG['mailer_not_supported'] = ' mailer stöds inte.';
$PHPMAILER_LANG['recipients_failed'] = 'SMTP fel: Följande mottagare är felaktig: ';
$PHPMAILER_LANG['signing'] = 'Signerings fel: ';
$PHPMAILER_LANG['signing'] = 'Signeringsfel: ';
$PHPMAILER_LANG['smtp_connect_failed'] = 'SMTP Connect() misslyckades.';
$PHPMAILER_LANG['smtp_error'] = 'SMTP server fel: ';
$PHPMAILER_LANG['smtp_error'] = 'SMTP serverfel: ';
$PHPMAILER_LANG['variable_set'] = 'Kunde inte definiera eller återställa variabel: ';
$PHPMAILER_LANG['extension_missing'] = 'Tillägg ej tillgängligt: ';

View file

@ -441,6 +441,8 @@ class PHPMailer
* Only supported in `mail` and `sendmail` transports, not in SMTP.
*
* @var bool
*
* @deprecated 6.0.0 PHPMailer isn't a mailing list manager!
*/
public $SingleTo = false;
@ -745,7 +747,7 @@ class PHPMailer
*
* @var string
*/
const VERSION = '6.1.6';
const VERSION = '6.1.7';
/**
* Error severity: message only, continue processing.
@ -1307,7 +1309,7 @@ class PHPMailer
$patternselect = static::$validator;
}
if (is_callable($patternselect)) {
return $patternselect($address);
return call_user_func($patternselect, $address);
}
//Reject line breaks in addresses; it's valid RFC5322, but not RFC5321
if (strpos($address, "\n") !== false || strpos($address, "\r") !== false) {
@ -2975,7 +2977,6 @@ class PHPMailer
if ('' === $name) {
$name = $filename;
}
if (!$this->validateEncoding($encoding)) {
throw new Exception($this->lang('encoding') . $encoding);
}
@ -3990,7 +3991,8 @@ class PHPMailer
* @param string $message HTML message string
* @param string $basedir Absolute path to a base directory to prepend to relative paths to images
* @param bool|callable $advanced Whether to use the internal HTML to text converter
* or your own custom converter @return string $message The transformed message Body
* or your own custom converter
* @return string The transformed message body
*
* @throws Exception
*
@ -4114,7 +4116,7 @@ class PHPMailer
public function html2text($html, $advanced = false)
{
if (is_callable($advanced)) {
return $advanced($html);
return call_user_func($advanced, $html);
}
return html_entity_decode(

View file

@ -45,7 +45,7 @@ class POP3
*
* @var string
*/
const VERSION = '6.1.6';
const VERSION = '6.1.7';
/**
* Default POP3 port number.

View file

@ -34,7 +34,7 @@ class SMTP
*
* @var string
*/
const VERSION = '6.1.6';
const VERSION = '6.1.7';
/**
* SMTP line break constant.
@ -311,12 +311,6 @@ class SMTP
*/
public function connect($host, $port = null, $timeout = 30, $options = [])
{
static $streamok;
//This is enabled by default since 5.0.0 but some providers disable it
//Check this once and cache the result
if (null === $streamok) {
$streamok = function_exists('stream_socket_client');
}
// Clear errors to avoid confusion
$this->setError('');
// Make sure we are __not__ connected
@ -335,12 +329,48 @@ class SMTP
(count($options) > 0 ? var_export($options, true) : 'array()'),
self::DEBUG_CONNECTION
);
$this->smtp_conn = $this->getSMTPConnection($host, $port, $timeout, $options);
if ($this->smtp_conn === false) {
//Error info already set inside `getSMTPConnection()`
return false;
}
$this->edebug('Connection: opened', self::DEBUG_CONNECTION);
// Get any announcement
$this->last_reply = $this->get_lines();
$this->edebug('SERVER -> CLIENT: ' . $this->last_reply, self::DEBUG_SERVER);
return true;
}
/**
* Create connection to the SMTP server.
*
* @param string $host SMTP server IP or host name
* @param int $port The port number to connect to
* @param int $timeout How long to wait for the connection to open
* @param array $options An array of options for stream_context_create()
*
* @return false|resource
*/
protected function getSMTPConnection($host, $port = null, $timeout = 30, $options = [])
{
static $streamok;
//This is enabled by default since 5.0.0 but some providers disable it
//Check this once and cache the result
if (null === $streamok) {
$streamok = function_exists('stream_socket_client');
}
$errno = 0;
$errstr = '';
if ($streamok) {
$socket_context = stream_context_create($options);
set_error_handler([$this, 'errorHandler']);
$this->smtp_conn = stream_socket_client(
$connection = stream_socket_client(
$host . ':' . $port,
$errno,
$errstr,
@ -356,7 +386,7 @@ class SMTP
self::DEBUG_CONNECTION
);
set_error_handler([$this, 'errorHandler']);
$this->smtp_conn = fsockopen(
$connection = fsockopen(
$host,
$port,
$errno,
@ -365,8 +395,9 @@ class SMTP
);
restore_error_handler();
}
// Verify we connected properly
if (!is_resource($this->smtp_conn)) {
if (!is_resource($connection)) {
$this->setError(
'Failed to connect to server',
'',
@ -381,22 +412,19 @@ class SMTP
return false;
}
$this->edebug('Connection: opened', self::DEBUG_CONNECTION);
// SMTP server can take longer to respond, give longer timeout for first read
// Windows does not have support for this timeout function
if (strpos(PHP_OS, 'WIN') !== 0) {
$max = (int) ini_get('max_execution_time');
$max = (int)ini_get('max_execution_time');
// Don't bother if unlimited
if (0 !== $max && $timeout > $max) {
@set_time_limit($timeout);
}
stream_set_timeout($this->smtp_conn, $timeout, 0);
stream_set_timeout($connection, $timeout, 0);
}
// Get any announcement
$announce = $this->get_lines();
$this->edebug('SERVER -> CLIENT: ' . $announce, self::DEBUG_SERVER);
return true;
return $connection;
}
/**
@ -1166,13 +1194,40 @@ class SMTP
$selW = null;
while (is_resource($this->smtp_conn) && !feof($this->smtp_conn)) {
//Must pass vars in here as params are by reference
if (!stream_select($selR, $selW, $selW, $this->Timelimit)) {
//solution for signals inspired by https://github.com/symfony/symfony/pull/6540
set_error_handler([$this, 'errorHandler']);
$n = stream_select($selR, $selW, $selW, $this->Timelimit);
restore_error_handler();
if ($n === false) {
$message = $this->getError()['detail'];
$this->edebug(
'SMTP -> get_lines(): select failed (' . $message . ')',
self::DEBUG_LOWLEVEL
);
//stream_select returns false when the `select` system call is interrupted by an incoming signal, try the select again
if (stripos($message, 'interrupted system call') !== false) {
$this->edebug(
'SMTP -> get_lines(): retrying stream_select',
self::DEBUG_LOWLEVEL
);
$this->setError('');
continue;
}
break;
}
if (!$n) {
$this->edebug(
'SMTP -> get_lines(): select timed-out in (' . $this->Timelimit . ' sec)',
self::DEBUG_LOWLEVEL
);
break;
}
//Deliberate noise suppression - errors are handled afterwards
$str = @fgets($this->smtp_conn, self::MAX_REPLY_LENGTH);
$this->edebug('SMTP INBOUND: "' . trim($str) . '"', self::DEBUG_LOWLEVEL);

28
composer.lock generated
View file

@ -61,6 +61,10 @@
"url",
"urlify"
],
"support": {
"issues": "https://github.com/jbroadway/urlify/issues",
"source": "https://github.com/jbroadway/urlify/tree/1.1.3-stable"
},
"time": "2019-06-13T18:30:56+00:00"
},
{
@ -113,20 +117,24 @@
"mobile detector",
"php mobile detect"
],
"support": {
"issues": "https://github.com/serbanghita/Mobile-Detect/issues",
"source": "https://github.com/serbanghita/Mobile-Detect/tree/2.8.34"
},
"time": "2019-09-18T18:44:20+00:00"
},
{
"name": "phpmailer/phpmailer",
"version": "v6.1.6",
"version": "v6.1.7",
"source": {
"type": "git",
"url": "https://github.com/PHPMailer/PHPMailer.git",
"reference": "c2796cb1cb99d7717290b48c4e6f32cb6c60b7b3"
"reference": "2c2370ba3df7034f9eb7b8f387c97b52b2ba5ad0"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/PHPMailer/PHPMailer/zipball/c2796cb1cb99d7717290b48c4e6f32cb6c60b7b3",
"reference": "c2796cb1cb99d7717290b48c4e6f32cb6c60b7b3",
"url": "https://api.github.com/repos/PHPMailer/PHPMailer/zipball/2c2370ba3df7034f9eb7b8f387c97b52b2ba5ad0",
"reference": "2c2370ba3df7034f9eb7b8f387c97b52b2ba5ad0",
"shasum": ""
},
"require": {
@ -175,13 +183,17 @@
}
],
"description": "PHPMailer is a full-featured email creation and transfer class for PHP",
"support": {
"issues": "https://github.com/PHPMailer/PHPMailer/issues",
"source": "https://github.com/PHPMailer/PHPMailer/tree/v6.1.7"
},
"funding": [
{
"url": "https://github.com/synchro",
"type": "github"
}
],
"time": "2020-05-27T12:24:03+00:00"
"time": "2020-07-14T18:50:27+00:00"
},
{
"name": "tijsverkoyen/akismet",
@ -220,6 +232,10 @@
],
"description": "Akismet is a wrapper-class to communicate with the Akismet API.",
"homepage": "https://github.com/tijsverkoyen/Akismet",
"support": {
"issues": "https://github.com/tijsverkoyen/Akismet/issues",
"source": "https://github.com/tijsverkoyen/Akismet/tree/master"
},
"time": "2016-07-19T13:50:18+00:00"
}
],
@ -231,5 +247,5 @@
"prefer-lowest": false,
"platform": [],
"platform-dev": [],
"plugin-api-version": "1.1.0"
"plugin-api-version": "2.0.0"
}

52
importing.php Normal file
View file

@ -0,0 +1,52 @@
<?php
/* --------------------------------------------------------------------
Chevereto
http://chevereto.com/
@author Rodolfo Berrios A. <http://rodolfoberrios.com/>
<inbox@rodolfoberrios.com>
Copyright (C) Rodolfo Berrios A. All rights reserved.
BY USING THIS SOFTWARE YOU DECLARE TO ACCEPT THE CHEVERETO EULA
http://chevereto.com/license
--------------------------------------------------------------------- */
define('access', 'cli');
$isCron = getenv('IS_CRON');
if (!$isCron) {
header('HTTP/1.0 403 Forbidden');
die("403 Forbidden\n");
}
$threadID = getenv('THREAD_ID');
if (!$threadID) {
die("Missing thread id (int)\n");
}
if (!include_once('app/loader.php')) {
die("Can't find app/loader.php\n");
}
do {
try {
CHV\Import::refresh();
$jobs = CHV\Import::autoJobs();
if (!$jobs) {
echo "No jobs left.\n";
die(0);
}
$id = $jobs[0]['import_id'];
$import = new CHV\Import();
$import->id = $id;
$import->thread = (int) $threadID;
$import->process();
echo "Processed job id #$id\n";
$loop++;
} catch (Exception $e) {
echo $e->getMessage() . "\n";
die(255);
}
} while (CHV\isSafeToExecute());
echo "--\nLooped $loop times ~ /dashboard/bulk for stats \n";
die(0);

1
importing/.htaccess Normal file
View file

@ -0,0 +1 @@
SetHandler default-handler