aboutsummaryrefslogtreecommitdiffstats
path: root/Zotlabs/Module
diff options
context:
space:
mode:
Diffstat (limited to 'Zotlabs/Module')
-rw-r--r--Zotlabs/Module/Admin.php9
-rw-r--r--Zotlabs/Module/Admin/Accounts.php127
-rw-r--r--Zotlabs/Module/Admin/Site.php391
-rw-r--r--Zotlabs/Module/Invite.php599
-rw-r--r--Zotlabs/Module/Regate.php347
-rw-r--r--Zotlabs/Module/Register.php498
-rw-r--r--Zotlabs/Module/Settings/Account.php34
7 files changed, 1732 insertions, 273 deletions
diff --git a/Zotlabs/Module/Admin.php b/Zotlabs/Module/Admin.php
index 88b84b9d2..44c10b339 100644
--- a/Zotlabs/Module/Admin.php
+++ b/Zotlabs/Module/Admin.php
@@ -101,11 +101,14 @@ class Admin extends \Zotlabs\Web\Controller {
// pending registrations
- $pdg = q("SELECT account.*, register.hash from account left join register on account_id = register.uid where (account_flags & %d ) > 0 ",
- intval(ACCOUNT_PENDING)
+ // $pdg = q("SELECT account.*, register.reg_hash from account left join register on account_id = register.reg_uid // where (account_flags & %d ) > 0 ",
+ // intval(ACCOUNT_PENDING)
+ // );
+ $pdg = q("SELECT COUNT(*) AS pdg FROM register WHERE reg_vital = 1 AND reg_expires > '%s' ",
+ dbesc(date('Y-m-d H:i:s'))
);
- $pending = (($pdg) ? count($pdg) : 0);
+ $pending = ($pdg ? $pdg[0]['pdg'] : 0);
// available channels, primary and clones
$channels = array();
diff --git a/Zotlabs/Module/Admin/Accounts.php b/Zotlabs/Module/Admin/Accounts.php
index 0c7e089be..74e562a9c 100644
--- a/Zotlabs/Module/Admin/Accounts.php
+++ b/Zotlabs/Module/Admin/Accounts.php
@@ -15,6 +15,9 @@ class Accounts {
*
*/
+ const MYP = 'ZAR'; // ZAR2x
+ const VERSION = '2.0.0';
+
function post() {
$pending = ( x($_POST, 'pending') ? $_POST['pending'] : array() );
@@ -23,6 +26,68 @@ class Accounts {
check_form_security_token_redirectOnErr('/admin/accounts', 'admin_accounts');
+ $isajax = is_ajax();
+ $rc = 0;
+
+ If (!is_site_admin()) {
+ if ($isajax) {
+ killme();
+ exit;
+ }
+ goaway(z_root() . '/');
+ }
+
+ if ($isajax) {
+ //$debug = print_r($_SESSION[self::MYP],true);
+ $zarop = (x($_POST['zardo']) && preg_match('/^[ad]{1,1}$/', $_POST['zardo']) )
+ ? $_POST['zardo'] : '';
+ // zarat arrives with leading underscore _n
+ $zarat = (x($_POST['zarat']) && preg_match('/^_{1,1}[0-9]{1,6}$/', $_POST['zarat']) )
+ ? substr($_POST['zarat'],1) : '';
+ $zarse = (x($_POST['zarse']) && preg_match('/^[0-9a-f]{8,8}$/', $_POST['zarse']) )
+ ? hex2bin($_POST['zarse']) : '';
+
+ if ($zarop && $zarat >= 0 && $zarse && $zarse == $_SESSION[self::MYP]['h'][$zarat]) {
+
+ //
+ if ($zarop == 'd') {
+ $rd = q("UPDATE register SET reg_vital = 0 WHERE reg_id = %d AND SUBSTR(reg_hash,1,4) = '%s' ",
+ intval($_SESSION[self::MYP]['i'][$zarat]),
+ dbesc($_SESSION[self::MYP]['h'][$zarat])
+ );
+ $rc = '× ' . count($rd);
+ }
+ elseif ($zarop == 'a') {
+ // approval, REGISTER_DENIED by user 0x0040, REGISTER_AGREED by user 0x0020 @Regate
+ $rd = q("UPDATE register SET reg_flags = (reg_flags & ~ 16), "
+ . " reg_vital = (CASE (reg_flags & ~ 48) WHEN 0 THEN 0 ELSE 1 END) "
+ . " WHERE reg_vital = 1 AND reg_id = %d AND SUBSTR(reg_hash,1,4) = '%s' ",
+ intval($_SESSION[self::MYP]['i'][$zarat]),
+ dbesc($_SESSION[self::MYP]['h'][$zarat])
+ );
+ $rc = 0;
+ $rs = q("SELECT * from register WHERE reg_id = %d ",
+ intval($_SESSION[self::MYP]['i'][$zarat])
+ );
+ if ($rs && ($rs[0]['reg_flags'] & ~ 48) == 0) {
+
+ // create account
+ $rc='ok'.$rs[0]['reg_id'];
+ $ac = create_account_from_register($rs[0]);
+ if ( $ac['success'] ) $rc .= '✔';
+
+ } else {
+ $rc='oh×';
+ }
+ }
+
+ //
+ echo json_encode(array('re' => $zarop, 'at' => '_' . $zarat, 'rc' => $rc));
+ }
+ killme();
+ exit;
+ }
+
// change to switch structure?
// account block/unblock button was submitted
if (x($_POST, 'page_accounts_block')) {
@@ -82,6 +147,8 @@ class Accounts {
}
check_form_security_token_redirectOnErr('/admin/accounts', 'admin_accounts', 't');
+
+ $debug = '';
switch (argv(2)){
case 'delete':
@@ -112,9 +179,44 @@ class Accounts {
}
/* get pending */
- $pending = q("SELECT account.*, register.hash from account left join register on account_id = register.uid where (account_flags & %d )>0 ",
+ // [hilmar ->
+ /*
+ $pending = q("SELECT account.*, reg_hash FROM account LEFT JOIN register ON account_id = reg_uid WHERE reg_vital = 1 AND (account_flags & %d) > 0",
+ intval(ACCOUNT_PENDING)
+ );
+ */
+ $tao = 'tao.zar.zarax = ' . "'" . '<img src="' . z_root() . '/images/zapax16.gif">' . "';\n";
+
+ $pending = q("SELECT @i:=@i+1 AS reg_n, @i MOD 2 AS reg_z, "
+ ." reg_did2, reg_created, reg_startup, reg_expires, reg_email, reg_atip, reg_hash, reg_id, "
+ ." CASE (reg_flags & %d) WHEN 0 THEN '✔ verified' WHEN 1 THEN '× not yet' END AS reg_vfd "
+ ." FROM register, (SELECT @i:=0) AS i "
+ ." WHERE reg_vital = 1 AND (reg_flags & %d) > 0 ",
+ intval(ACCOUNT_UNVERIFIED),
intval(ACCOUNT_PENDING)
);
+
+ unset($_SESSION[self::MYP]);
+ if ($pending) {
+ // collect and group all ip
+ $atips = q("SELECT reg_atip AS atip, COUNT(reg_atip) AS atips FROM register "
+ ." WHERE reg_vital = 1 GROUP BY reg_atip ");
+ $atips ? $atipn = array_column($atips, 'atips', 'atip') : $atipn = array('' => 0);
+
+ $tao .= 'tao.zar.zarar = {';
+ foreach ($pending as $n => $v) {
+ if (array_key_exists($v['reg_atip'], $atipn)) {
+
+ $pending[$n]['reg_atip'] = $v['reg_atip'] . ' ◄' . $atipn[ $v['reg_atip'] ] . '×';
+ }
+ // better secure
+ $tao .= $n . ": '" . substr(bin2hex($v['reg_hash']),0,8) . "',";
+ $_SESSION[self::MYP]['h'][] = substr($v['reg_hash'],0,4);
+ $_SESSION[self::MYP]['i'][] = $v['reg_id'];
+ }
+ $tao = rtrim($tao,',') . '};' . "\n";
+ }
+ // <- hilmar]
/* get accounts */
@@ -143,7 +245,7 @@ class Accounts {
intval(\App::$pager['itemspage']),
intval(\App::$pager['start'])
);
-
+
// function _setup_users($e){
// $accounts = Array(
// t('Normal Account'),
@@ -163,12 +265,16 @@ class Accounts {
$t = get_markup_template('admin_accounts.tpl');
$o = replace_macros($t, array(
// strings //
+ '$debug' => $debug,
'$title' => t('Administration'),
'$page' => t('Accounts'),
'$submit' => t('Submit'),
'$select_all' => t('select all'),
+ '$sel_tall' => t('SelectToggle'),
+ '$sel_deny' => t('× DenySelected'),
+ '$sel_aprv' => t('✔ ApproveSelected'),
'$h_pending' => t('Registrations waiting for confirm'),
- '$th_pending' => array( t('Request date'), t('Email') ),
+ '$th_pending' => array( t('Request date'), t('Startup,Expires'), 'dId2', t('specified,atip') ),
'$no_pending' => t('No registrations.'),
'$approve' => t('Approve'),
'$deny' => t('Deny'),
@@ -187,21 +293,22 @@ class Accounts {
[ t('Expires'), 'account_expires' ],
[ t('Service Class'), 'account_service_class'] ),
- '$confirm_delete_multi' => t('Selected accounts will be deleted!\n\nEverything these accounts had posted on this site will be permanently deleted!\n\nAre you sure?'),
- '$confirm_delete' => t('The account {0} will be deleted!\n\nEverything this account has posted on this site will be permanently deleted!\n\nAre you sure?'),
+ '$confirm_delete_multi' => p2j(t('Selected accounts will be deleted!\n\nEverything these accounts had posted on this site will be permanently deleted!\n\nAre you sure?')),
+ '$confirm_delete' => p2j(t('The account {0} will be deleted!\n\nEverything this account has posted on this site will be permanently deleted!\n\nAre you sure?')),
'$form_security_token' => get_form_security_token("admin_accounts"),
// values //
- '$baseurl' => z_root(),
-
- '$pending' => $pending,
- '$users' => $users,
+ '$now' => date('Y-m-d H:i:s'),
+ '$baseurl' => z_root(),
+ '$tao' => $tao,
+ '$pending' => $pending,
+ '$users' => $users,
));
$o .= paginate($a);
return $o;
}
-
}
+
diff --git a/Zotlabs/Module/Admin/Site.php b/Zotlabs/Module/Admin/Site.php
index 011bf3ce4..cb919746b 100644
--- a/Zotlabs/Module/Admin/Site.php
+++ b/Zotlabs/Module/Admin/Site.php
@@ -10,9 +10,19 @@ class Site {
*
*/
function post(){
+ // [hilmar->
+ $this->isajax = is_ajax();
+ $this->eol = $this->isajax ? "\n" : EOL;
+ // ]
if (!x($_POST, 'page_site')) {
- return;
+ // [
+ if (!$this->isajax)
+ // ]
+ return;
}
+ // [
+ $this->msgbg = '';
+ // <-hilmar]
check_form_security_token_redirectOnErr('/admin/site', 'admin_site');
@@ -24,14 +34,16 @@ class Site {
$siteinfo = ((x($_POST,'siteinfo')) ? trim($_POST['siteinfo']) : '');
$language = ((x($_POST,'language')) ? notags(trim($_POST['language'])) : '');
$theme = ((x($_POST,'theme')) ? notags(trim($_POST['theme'])) : '');
-// $theme_mobile = ((x($_POST,'theme_mobile')) ? notags(trim($_POST['theme_mobile'])) : '');
-// $site_channel = ((x($_POST,'site_channel')) ? notags(trim($_POST['site_channel'])) : '');
+ // $theme_mobile = ((x($_POST,'theme_mobile')) ? notags(trim($_POST['theme_mobile'])) : '');
+ // $site_channel = ((x($_POST,'site_channel')) ? notags(trim($_POST['site_channel'])) : '');
$maximagesize = ((x($_POST,'maximagesize')) ? intval(trim($_POST['maximagesize'])) : 0);
$register_policy = ((x($_POST,'register_policy')) ? intval(trim($_POST['register_policy'])) : 0);
$minimum_age = ((x($_POST,'minimum_age')) ? intval(trim($_POST['minimum_age'])) : 13);
$access_policy = ((x($_POST,'access_policy')) ? intval(trim($_POST['access_policy'])) : 0);
+ $reg_autochannel = ((x($_POST,'auto_channel_create')) ? True : False);
$invite_only = ((x($_POST,'invite_only')) ? True : False);
+ $invite_also = ((x($_POST,'invite_also')) ? True : False);
$abandon_days = ((x($_POST,'abandon_days')) ? intval(trim($_POST['abandon_days'])) : 0);
$register_text = ((x($_POST,'register_text')) ? notags(trim($_POST['register_text'])) : '');
@@ -75,6 +87,16 @@ class Site {
$maxloadavg = ((x($_POST,'maxloadavg')) ? intval(trim($_POST['maxloadavg'])) : 50);
$feed_contacts = ((x($_POST,'feed_contacts')) ? intval($_POST['feed_contacts']) : 0);
$verify_email = ((x($_POST,'verify_email')) ? 1 : 0);
+ $register_perday = ((x($_POST,'register_perday')) ? intval(trim($_POST['register_perday'])) : 50);
+ $register_sameip = ((x($_POST,'register_sameip')) ? intval(trim($_POST['register_sameip'])) : 3);
+
+ $regdelayn = ((x($_POST,'zardelayn')) ? intval(trim($_POST['zardelayn'])) : 0);
+ $regdelayu = ((x($_POST,'zardelay')) ? notags(trim($_POST['zardelay'])) : '');
+ $reg_delay = (preg_match('/^[a-z]{1,1}$/', $regdelayu) ? $regdelayn . $regdelayu : '');
+ $regexpiren = ((x($_POST,'zarexpiren')) ? intval(trim($_POST['zarexpiren'])) : 0);
+ $regexpireu = ((x($_POST,'zarexpire')) ? notags(trim($_POST['zarexpire'])) : '');
+ $reg_expire = (preg_match('/^[a-z]{1,1}$/', $regexpireu) ? $regexpiren . $regexpireu : '');
+
$imagick_path = ((x($_POST,'imagick_path')) ? trim($_POST['imagick_path']) : '');
$force_queue = ((intval($_POST['force_queue']) > 0) ? intval($_POST['force_queue']) : 3000);
$pub_incl = escape_tags(trim($_POST['pub_incl']));
@@ -82,6 +104,35 @@ class Site {
$permissions_role = escape_tags(trim($_POST['permissions_role']));
+ // [hilmar->
+ $this->register_duty = ((x($_POST,'register_duty')) ? notags(trim($_POST['register_duty'])) : '');
+ if (! preg_match('/^[0-9 .,:\-]{0,191}$/', $this->register_duty)) {
+ $this->msgbg .= 'ZAR0131E,' . t('Invalid input') . $this->eol;
+ $this->error++;
+ } else {
+
+ $this->duty();
+
+ if ($this->isajax) {
+ echo json_encode(array('msgbg' => $this->msgbg, 'me' => 'zar'));
+ // that mission is complete
+ killme();
+ exit;
+
+ } else {
+
+ //logger( print_r( $this->msgbg, true) );
+ //logger( print_r( $this->joo, true) );
+ if ($this->error === 0) {
+ set_config('system', 'register_duty', $this->register_duty);
+ set_config('system', 'register_duty_jso', $this->joo);
+ } else {
+ notice('ZAR0130E,'.t('Errors') . ': ' . $this->error) . EOL . $this->msgfg;
+ }
+ }
+ }
+ // <-hilmar]
+
set_config('system', 'feed_contacts', $feed_contacts);
set_config('system', 'delivery_interval', $delivery_interval);
set_config('system', 'delivery_batch_count', $delivery_batch_count);
@@ -96,6 +147,10 @@ class Site {
set_config('system', 'login_on_homepage', $login_on_homepage);
set_config('system', 'enable_context_help', $enable_context_help);
set_config('system', 'verify_email', $verify_email);
+ set_config('system', 'max_daily_registrations', $register_perday);
+ set_config('system', 'register_sameip', $register_sameip);
+ set_config('system', 'register_delay', $reg_delay);
+ set_config('system', 'register_expire', $reg_expire);
set_config('system', 'default_expire_days', $default_expire_days);
set_config('system', 'active_expire_days', $active_expire_days);
set_config('system', 'reply_address', $reply_address);
@@ -126,17 +181,19 @@ class Site {
set_config('system','siteinfo',$siteinfo);
set_config('system', 'language', $language);
set_config('system', 'theme', $theme);
-// if ( $theme_mobile === '---' ) {
-// del_config('system', 'mobile_theme');
-// } else {
-// set_config('system', 'mobile_theme', $theme_mobile);
-// }
- // set_config('system','site_channel', $site_channel);
+ // if ( $theme_mobile === '---' ) {
+ // del_config('system', 'mobile_theme');
+ // } else {
+ // set_config('system', 'mobile_theme', $theme_mobile);
+ // }
+ // set_config('system','site_channel', $site_channel);
set_config('system','maximagesize', $maximagesize);
set_config('system','register_policy', $register_policy);
set_config('system','minimum_age', $minimum_age);
+ set_config('system','auto_channel_create', $reg_autochannel);
set_config('system','invitation_only', $invite_only);
+ set_config('system','invitation_also', $invite_also);
set_config('system','access_policy', $access_policy);
set_config('system','account_abandon_days', $abandon_days);
set_config('system','register_text', $register_text);
@@ -260,6 +317,9 @@ class Site {
REGISTER_APPROVE => t("Yes - with approval"),
REGISTER_OPEN => t("Yes")
);
+ $this->register_duty ? get_config('system', 'register_duty') : '';
+ $register_perday = get_config('system','max_daily_registrations');
+ $register_perday ? '' : $register_perday = 50;
/* Acess policy */
$access_choices = Array(
@@ -286,9 +346,66 @@ class Site {
$homelogin = get_config('system','login_on_homepage');
$enable_context_help = get_config('system','enable_context_help');
+ // for reuse reg_delay and reg_expire
+ $reg_rabots = array(
+ 'i' => t('Minute(s)'),
+ 'h' => t('Hour(s)') ,
+ 'd' => t('Day(s)') ,
+ 'w' => t('Week(s)') ,
+ 'm' => t('Month(s)') ,
+ 'y' => t('Year(s)')
+ );
+ $regdelay = get_config('system','register_delay');
+ if ($regdelay)
+ list($regdelay_n, $regdelay_u) = array(substr($regdelay,0,-1),substr($regdelay,-1));
+ $reg_delay = replace_macros(get_markup_template('field_duration.qmc.tpl'),
+ array(
+ 'label' => t('Account registration delay'),
+ 'qmc' => 'zar',
+ 'qmcid' => 'ZAR0860C',
+ 'help' => t('How long a registration request has to wait before validation can perform.'
+ . ' No delay if zero or no value.'),
+ 'field' => array(
+ 'name' => 'delay',
+ 'title' => t('duration up from now'),
+ 'value' => ($regdelay_n ? $regdelay_n : 90),
+ 'min' => '0',
+ 'max' => '99',
+ 'size' => '2',
+ 'default' => ($regdelay_u ? $regdelay_u : 'i')
+ ),
+ 'rabot' => $reg_rabots
+ )
+ );
+ $regexpire = get_config('system','register_expire');
+ if ($regexpire)
+ list($regexpire_n, $regexpire_u) = array(substr($regexpire,0,-1),substr($regexpire,-1));
+ $reg_expire = replace_macros(get_markup_template('field_duration.qmc.tpl'),
+ array(
+ 'label' => t('Account registration expiration'),
+ 'qmc' => 'zar',
+ 'qmcid' => 'ZAR0862C',
+ 'help' => t('How long a registration to confirm remains valid.'
+ . ' Not expire if zero or no value.'),
+ 'field' => array(
+ 'name' => 'expire',
+ 'title' => t('duration up from now'),
+ 'value' => ($regexpire_n ? $regexpire_n : 2),
+ 'min' => '0',
+ 'max' => '99',
+ 'size' => '2',
+ 'default' => ($regexpire_u ? $regexpire_u : 'i')
+ ),
+ 'rabot' => $reg_rabots
+ )
+ );
+
+ $tao = '';
$t = get_markup_template("admin_site.tpl");
return replace_macros($t, array(
'$title' => t('Administration'),
+ // interfacing js vars
+ '$tao' => $tao,
'$page' => t('Site'),
'$submit' => t('Submit'),
'$registration' => t('Registration'),
@@ -305,21 +422,88 @@ class Site {
'$siteinfo' => array('siteinfo', t('Site Information'), get_config('system','siteinfo'), t("Publicly visible description of this site. Displayed on siteinfo page. BBCode can be used here")),
'$language' => array('language', t("System language"), get_config('system','language'), "", $lang_choices),
'$theme' => array('theme', t("System theme"), get_config('system','theme'), t("Default system theme - may be over-ridden by user profiles - <a href='#' id='cnftheme'>change theme settings</a>"), $theme_choices),
-// '$theme_mobile' => array('theme_mobile', t("Mobile system theme"), get_config('system','mobile_theme'), t("Theme for mobile devices"), $theme_choices_mobile),
-// '$site_channel' => array('site_channel', t("Channel to use for this website's static pages"), get_config('system','site_channel'), t("Site Channel")),
+ // '$theme_mobile' => array('theme_mobile', t("Mobile system theme"), get_config('system','mobile_theme'), t("Theme for mobile devices"), $theme_choices_mobile),
+ // '$site_channel' => array('site_channel', t("Channel to use for this website's static pages"), get_config('system','site_channel'), t("Site Channel")),
'$feed_contacts' => array('feed_contacts', t('Allow Feeds as Connections'),get_config('system','feed_contacts'),t('(Heavy system resource usage)')),
'$maximagesize' => array('maximagesize', t("Maximum image size"), intval(get_config('system','maximagesize')), t("Maximum size in bytes of uploaded images. Default is 0, which means no limits.")),
- '$register_policy' => array('register_policy', t("Does this site allow new member registration?"), get_config('system','register_policy'), "", $register_choices),
- '$invite_only' => array('invite_only', t("Invitation only"), get_config('system','invitation_only'), t("Only allow new member registrations with an invitation code. Above register policy must be set to Yes.")),
'$minimum_age' => array('minimum_age', t("Minimum age"), (x(get_config('system','minimum_age'))?get_config('system','minimum_age'):13), t("Minimum age (in years) for who may register on this site.")),
'$access_policy' => array('access_policy', t("Which best describes the types of account offered by this hub?"), get_config('system','access_policy'), t("This is displayed on the public server site list."), $access_choices),
- '$register_text' => array('register_text', t("Register text"), htmlspecialchars(get_config('system','register_text'), ENT_QUOTES, 'UTF-8'), t("Will be displayed prominently on the registration page.")),
+
+ // Register
+ // [hilmar->
+ '$register_text' => array('register_text',
+ t("Register text"),
+ htmlspecialchars(get_config('system','register_text'), ENT_QUOTES, 'UTF-8'),
+ t("Will be displayed prominently on the registration page.") . ' '
+ . t('If you operate with register duties (see ZAR0830C), best practise is to tell cleartext about here'),
+ 'ZAR0810C'),
+ '$register_policy' => array('register_policy',
+ t("Does this site allow new member registration?"),
+ get_config('system','register_policy'),
+ "",
+ $register_choices,
+ 'ZAR0820C'),
+ '$register_duty' => array('register_duty',
+ t('Registration office on duty'),
+ $this->register_duty = get_config('system', 'register_duty'),
+ t('The weekdays and hours the register office is open for registrations') . '. '
+ . t('Split weekdays and hours per `:`') . '. '
+ . t('Separate weekday(s):hour(s) pairs with blank(s)') . '. '
+ . t('Several values or ranges are to split by comma') . '. '
+ . t('From-To ranges are joined with `-`') . '. '
+ . t('ie') . ' `1-5:0900-1200,1300-1700 6:900-1230` ' . t('or') .' `1-2,4-5:800-1800` '
+ . ' <a id="zar083a" href="javascript:;">' . t('Parse and test your input') . '</a>'. EOL
+ . t('If left empty, defaults to 24h closed everyday the week.') . ' '
+ . t('To keep open 24h everyday the week, short is `-:-`.') . ' '
+ . t('Note, ranges are specified as open-close pairs and in case of')
+ . ' 0900-1200 '
+ . t('results to: opens 9h and closes 12h. If meant open 9h to 12h exactly, say `0900-1201`'),
+ 'ZAR0830C'),
+ '$register_perday' => array('register_perday',
+ t('Account registrations max per day'),
+ (x(get_config('system', 'max_daily_registrations')))
+ ? get_config('system', 'max_daily_registrations') : 50,
+ t('How many registration requests the site accepts during one day. Unlimited if zero or no value. Default 50'),
+ 'ZAR0840C'),
+ '$register_sameip' => array('register_sameip',
+ t('Account registrations from same ip'),
+ (x(get_config('system', 'register_sameip')))
+ ? get_config('system', 'register_sameip') : 3,
+ t('How many pending registration requests the site accepts from a same ip address.'),
+ 'ZAR0850C'),
+ '$reg_delay'=>$reg_delay,
+ '$reg_expire'=>$reg_expire,
+ '$reg_autochannel' => array('auto_channel_create',
+ t("Auto channel create"),
+ get_config('system','auto_channel_create'),
+ t("Auto create a channel when register a new account. When On, the register form will show additional fields for the channel-name and the nickname."),
+ "", "", 'ZAR0870C'),
+ '$invite_only' => array('invite_only',
+ t("Invitation only"),
+ get_config('system','invitation_only'),
+ t("Only allow new member registrations with an invitation code. Above register policy must be set to Yes."),
+ "", "", 'ZAR0880C'),
+ '$invite_also' => array('invite_also',
+ t("Invitation also"),
+ get_config('system','invitation_also'),
+ t("Also allow new member registrations with an invitation code. Above register policy must be set to Yes."),
+ "", "", 'ZAR0881C'),
+ '$verify_email' => array('verify_email',
+ t("Verify Email Addresses"),
+ get_config('system','verify_email'),
+ t("Check to verify email addresses used in account registration (recommended)."),
+ "", "", 'ZAR0890C'),
+ '$abandon_days' => array('abandon_days',
+ t('Accounts abandoned after x days'),
+ get_config('system','account_abandon_days'),
+ t('Will not waste system resources polling external sites for abandonded accounts. Enter 0 for no time limit.'),
+ 'appears not to be implemented (2010.01)'),
+ // <-hilmar]
+
'$role' => $role,
'$frontpage' => array('frontpage', t("Site homepage to show visitors (default: login box)"), get_config('system','frontpage'), t("example: 'pubstream' to show public stream, 'page/sys/home' to show a system webpage called 'home' or 'include:home.html' to include a file.")),
'$mirror_frontpage' => array('mirror_frontpage', t("Preserve site homepage URL"), get_config('system','mirror_frontpage'), t('Present the site homepage in a frame at the original location instead of redirecting')),
- '$abandon_days' => array('abandon_days', t('Accounts abandoned after x days'), get_config('system','account_abandon_days'), t('Will not waste system resources polling external sites for abandonded accounts. Enter 0 for no time limit.')),
'$allowed_sites' => array('allowed_sites', t("Allowed friend domains"), get_config('system','allowed_sites'), t("Comma separated list of domains which are allowed to establish friendships with this site. Wildcards are accepted. Empty to allow any domains")),
- '$verify_email' => array('verify_email', t("Verify Email Addresses"), get_config('system','verify_email'), t("Check to verify email addresses used in account registration (recommended).")),
'$force_publish' => array('publish_all', t("Force publish"), get_config('system','publish_all'), t("Check to force all profiles on this site to be listed in the site directory.")),
'$disable_discover_tab' => array('disable_discover_tab', t('Import Public Streams'), $discover_tab, t('Import and allow access to public content pulled from other sites. Warning: this content is unmoderated.')),
'$site_firehose' => array('site_firehose', t('Site only Public Streams'), get_config('system','site_firehose'), t('Allow access to public content originating only from this site if Imported Public Streams are disabled.')),
@@ -361,4 +545,179 @@ class Site {
));
}
+ /**
+ * @brief Admin page site common post submit and ajax interaction
+ * @author hilmar runge
+ * @since 2020-02-04
+ * Configure register office duty weekdays and hours
+ * Syntax: weekdays:hours [weekdays:hours]
+ * [.d[,d-d.]]]:hhmm-hhmm[,hhmm-hhmm...]
+ * ranges are between blanks, days are 1-7, where 1 = Monday
+ * hours are [h]hmm 3-4digit 24 clock values
+ * ie 0900-1200,1300-1800 for hours
+ * ie 1-2,4,5 for weekdays
+ * ie 1-2:900-1800 monday and tuesday open from 9 to 18h
+ *
+ * @var $register_duty is the input field from the admin -> site page
+ * @return the results are in the class vars $error, $msgbg and $jsoo
+ * $jsoo is
+ */
+
+ // 3-4 digit 24h clock regex
+ const regxTime34 = '/^(?:2[0-3]|[01][0-9]|[0-9])[0-5][0-9]$/';
+ var $wdconst = array('','mo','tu','we','th','fr','sa','so');
+
+ // in
+ var $register_duty;
+ // intermediate
+ var $isajax;
+ // return
+ var $jsoo;
+ var $msgbg;
+ var $error = 0;
+ var $msgfg = '';
+
+ private function duty() {
+
+ $aro=array_fill(1, 7, 0);
+
+ if ($this->isajax) {
+ $op = (preg_match('/[a-z]{2,4}/', $_REQUEST['zarop'])) ? $_REQUEST['zarop'] : '';
+ if ($op == 'zar083') {
+ $this->msgbg = 'ZAR0130I Testmode:' . $this->eol . $this->msgbg;
+ } else {
+ killme();
+ exit;
+ }
+ }
+
+ if (! $this->register_duty)
+ $this->register_duty = '1-7';
+ $ranges = preg_split('/\s+/', $this->register_duty);
+ $this->msgbg .= '..ranges: ' . print_r(count($ranges),true) . $this->eol;
+
+ foreach ($ranges as $rn => $range) {
+ list($ws,$hs,) = explode(':', $range);
+
+ $ws ? $arw = explode( ',', $ws) : $arw=array();
+ $this->msgbg .= ($rn+1).'.weekday ranges: ' . count($arw) . $this->eol;
+ // $this->msgbg .= print_r($arw,true);
+ $hs ? $arh = explode( ',', $hs) : $arh=array();
+ $this->msgbg .= ($rn+1).'.hour ranges: ' . count($arh) . $this->eol;
+
+ $this->msgbg .= ($rn+1).'.wdays: ' . ( $ws ? print_r($ws,true) : 'none') . ' : '
+ . ' hours: ' . print_r($hs,true) . $this->eol;
+
+ // several hs may belog to one wd
+ // aro[0] is tmp store
+ foreach ($arh as $hs) {
+ list($ho,$hc,) = explode( '-', $hs );
+
+ // no value forces open very early, and be sure having valid hhmm values
+ !$ho ? $ho = "0000" : '';
+ !$hc ? $hc = "0000" : ''; // pseudo
+ if (preg_match(self::regxTime34, $ho)
+ && preg_match(self::regxTime34, $hc)) {
+
+ // fix pseudo, allow no reverse range
+ $hc == "0000" || $ho > $hc ? $hc = "2400" : '';
+
+ $aro[0][$ho] = 0;
+ $aro[0][$hc] = 1;
+
+ $this->msgbg .= ($ho ? ' .open:' . $ho : '') . ($hc ? ' close:' . $hc : '') .$this->eol;
+ } else {
+ $this->msgbg .= ' .' . t('Invalid 24h time value (hhmm/hmm)') . $this->eol;
+ $this->msgfg .= ' .ZAR0132E,' . t('Invalid 24h time value (hhmm/hmm)') . $this->eol;
+ $this->error++;
+ }
+ }
+
+ // the weekday(s) values or ranges
+ foreach ($arw as $ds) {
+ $wd=explode('-', $ds);
+ array_key_exists("1", $wd) && $wd[1]=="" ? $wd[1] = "7" : ''; // a case 3-
+ array_key_exists("1", $wd) && $wd[0]=="" ? $wd[0] = "1" : ''; // a case -3
+ !array_key_exists("1", $wd) ? $wd[1] = $wd[0] : ''; // a case 3
+ if ($wd[0] > $wd[1]) continue; // reverse order will be ignored // a case 5-3
+ if (preg_match('/^[1-7]{1}$/', $wd[0])) {
+ if (preg_match('/^[1-7]{1}$/', $wd[1])) {
+ // $this->msgbg .= print_r($wd,true);
+ for ($i=$wd[0]; $i<=$wd[1]; $i++) {
+ // take the tmp store for the selected day(s)
+ $aro[$i]=$aro[0];
+ }
+ }
+ }
+ }
+ //$this->msgbg .= 'aro0: ' . print_r($aro,true) . $this->eol; // 4devels
+ // clear the tmp store
+ $aro[0]=array();
+ }
+ // discart the tmp store
+ unset($aro[0]);
+ // not configured days close at the beginning 0000h
+ for ($i=1;$i<=7;$i++) { is_array($aro[$i]) ? '' : $aro[$i] = array("0000" => 1); }
+ // $this->msgbg .= 'aro: ' . print_r($aro,true) . $this->eol; // 4devels
+
+ if ($this->isajax) {
+ // tell what we have
+ // $this->msgbg .= 'aro0: ' . print_r($aro,true) . $this->eol; // 4devels
+ $this->msgbg .= 'Duty time table:' . $this->eol;
+ foreach ($aro as $dow => $hrs) {
+ $this->msgbg .= ' ' . $this->wdconst[$dow] . ' ';
+ // $this->msgbg .= '**' . print_r($hrs,true);
+ foreach ($hrs as $h => $o) {
+ $this->msgbg .= ((!$o) ? $h . ':open' : $h . ':close') . ', ';
+ }
+ $this->msgbg = rtrim($this->msgbg, ', ') . $this->eol;
+ }
+
+ $this->msgbg .= 'Generating 6 random times to check duty hours: ' . $this->eol;
+ // we only need some random dates from anyway in past or future
+ // because only the weekday and the clock is to test
+ for ($i=0; $i<6; $i++) {
+ $adow = rand(1, 7); // 1 to 7 (days)
+ $cdow = $this->wdconst[$adow];
+ // below is the essential algo to verify a date (of format Hi) meets an open or closed condition
+ $t = date('Hi', ( rand(time(), 60*60*24+time()) ) );
+ $how='closed';
+ foreach ($aro[$adow] as $o => $v) {
+ // $this->msgbg .= 'debug: ' . $o . ' gt ' . $t . ' / ' . $v . $this->eol; // 4devels
+ if ($o > $t) {
+ $how = ($v ? 'open' : 'closed');
+ break;
+ }
+ }
+ // now we know
+ $this->msgbg .= ' ' . $cdow . '.' . $t . '=' . $how . ', ';
+ }
+ $this->msgbg = rtrim($this->msgbg, ', ') . $this->eol;
+ }
+
+ /*
+ //$jov1 = array( 'view1' => $aro, 'view2' => '');
+ $jov2=array();
+ foreach ($aro as $d => $ts) {
+ foreach ($ts as $t => $ft) {
+ $jov2['view2'][$ft][] = $d.$t;
+ //$ft=="1" && $t=="0000" ? $jov2['view2']["0"][] = $d."2400" : '';
+ }
+ }
+ $this->msgbg .= print_r($jov2, true) . $this->eol; // 4devels
+ */
+
+ $this->joo = json_encode($aro);
+ // $this->msgbg .= $this->joo . $this->eol; // 4devels
+ // $this->msgbg .= print_r($aro, true) . $this->eol; // 4devels
+ $okko = (json_decode($this->joo, true) ? true : false);
+ if (!$okko) {
+ $this->msgbg .= 'ZAR0139D,json 4 duty KO crash' . $this->eol;
+ $this->msgfg .= 'ZAR0139D,json 4 duty KO crash' . $this->eol;
+ $this->error++;
+ }
+ return ;
+ }
+
+
}
diff --git a/Zotlabs/Module/Invite.php b/Zotlabs/Module/Invite.php
index 6359da54c..24792c8c1 100644
--- a/Zotlabs/Module/Invite.php
+++ b/Zotlabs/Module/Invite.php
@@ -6,7 +6,7 @@ use Zotlabs\Lib\Apps;
use Zotlabs\Web\Controller;
/**
- * module: invite.php
+ * module: invitexv2.php
*
* send email invitations to join social network
*
@@ -15,91 +15,291 @@ use Zotlabs\Web\Controller;
class Invite extends Controller {
+ /**
+ * While coding this, I want to introduce a system of qualified messages and notifications.
+ * Each message consists of a 3 letter prefix, a 4 digit number and a one letter suffix (PREnnnnS).
+ * The spirit about is not from me, but many decades used by IBM inc. in devel with best success.
+ *
+ * The system prefix, used uppercase as system message id, lowercase as css and js prefix (classes, ids etc).
+ * Usually not used as self::MYP, but placed in the code dominant enough for easy to find.
+ *
+ * Concrete here:
+ * The prefix indicates Z for the Zlabs(core), A for Account stuff, I for Invite.
+ * The numbers scope will be 00xx within/for templates, 01xx for get, 02xx for post functions.
+ * Message qualification ends with a uppercase suffix, where
+ * I=Info(only),
+ * W=Warning(more then info and less then error),
+ * E=Error,
+ * F=Fatal(for unexpected errors).
+ * Btw, in case of using fail2ban, a scan of messages going to log is very much more with ease,
+ * esspecially in multi language driven systems where messages vary.
+ *
+ * @author Hilmar Runge
+ * @version 2.0.0
+ * @since 2020-01-20
+ *
+ */
+
+ const MYP = 'ZAI';
+ const VERSION = '2.0.0';
+
function post() {
+
+ // zai02
- if(! local_channel()) {
- notice( t('Permission denied.') . EOL);
+ if (! local_channel()) {
+ notice( 'ZAI0201E,' .t('Permission denied.') . EOL);
return;
}
- if(! Apps::system_app_installed(local_channel(), 'Invite')) {
+ if (! Apps::system_app_installed(local_channel(), 'Invite')) {
+ notice( 'ZAI0202E,' . t('Invite App') . ' (' . t('Not Installed') . ')' . EOL);
return;
}
check_form_security_token_redirectOnErr('/', 'send_invite');
-
- $max_invites = intval(get_config('system','max_invites'));
- if(! $max_invites)
- $max_invites = 50;
-
- $current_invites = intval(get_pconfig(local_channel(),'system','sent_invites'));
- if($current_invites > $max_invites) {
- notice( t('Total invitation limit exceeded.') . EOL);
+
+ $ok = $ko = 0;
+ $feedbk = '';
+ $isajax = is_ajax();
+ $eol = $isajax ? "\n" : EOL;
+ $policy = intval(get_config('system','register_policy'));
+ if ($policy == REGISTER_CLOSED) {
+ notice( 'ZAI0212E,' . t('Register is closed') . ')' . EOL);
return;
- };
-
-
- $recips = ((x($_POST,'recipients')) ? explode("\n",$_POST['recipients']) : array());
- $message = ((x($_POST,'message')) ? notags(trim($_POST['message'])) : '');
-
- $total = 0;
-
- if(get_config('system','invitation_only')) {
- $invonly = true;
- $x = get_pconfig(local_channel(),'system','invites_remaining');
- if((! $x) && (! is_site_admin()))
- return;
}
+ if ($policy == REGISTER_OPEN)
+ $flags = 0;
+ elseif ($policy == REGISTER_APPROVE)
+ $flags = ACCOUNT_PENDING;
+ $flags = ($flags | intval(get_config('system','verify_email')));
+
+ // how many max recipients in one mail submit
+ $maxto = get_config('system','invitation_max_recipients', 'na');
+ If (is_site_admin()) {
+ // set, if admin is operator, default to 12
+ if ($maxto === 'na') set_config('system','invitation_max_recipients', 12);
+ }
+ $maxto = ($maxto === 'na') ? 12 : $maxto;
- foreach($recips as $recip) {
-
- $recip = trim($recip);
- if(! $recip)
- continue;
-
- if(! validate_email($recip)) {
- notice( sprintf( t('%s : Not a valid email address.'), $recip) . EOL);
- continue;
+ // language code current for the invitation
+ $lcc = x($_POST['zailcc']) && preg_match('/[a-z\-]{2,5}/', $_POST['zailcc'])
+ ? $_POST['zailcc']
+ : '';
+
+ // expiration duration amount quantity, in case of doubts defaults 2
+ $durn = x($_POST['zaiexpiren']) && preg_match('/[0-9]{1,2}/', $_POST['zaiexpiren'])
+ ? trim(intval($_POST['zaiexpiren']))
+ : '2';
+ !$durn ? $durn = 2 : '';
+
+ // expiration duration unit 1st letter (day, weeks, months, years), defaults days
+ $durq = x($_POST['zaiexpire']) && preg_match('/[ihd]{1,1}/', $_POST['zaiexpire'])
+ ? $_POST['zaiexpire']
+ : 'd';
+
+ $dur = self::calcdue($durn.$durq);
+ $due = t('Note, the invitation code is valid up to') . ' ' . $dur['due'];
+
+ if ($isajax) {
+ $feedbk .= 'ZAI0207I ' . $due . $eol;
+ }
+
+ // take the received email addresses and discart duplicates
+ $recips = array_filter( array_unique( preg_replace('/^\s*$/', '',
+ ((x($_POST,'zaito')) ? explode( "\n",$_POST['zaito']) : array() ) )));
+
+ $havto = count($recips);
+
+ if ( $havto > $maxto) {
+ $feedbk .= 'ZAI0210E ' . sprintf( t('Too many recipients for one invitation (max %d)'), $maxto) . $eol;
+ $ko++;
+
+ } elseif ( $havto == 0 ) {
+ $feedbk .= 'ZAI0211E ' . t('No recipients for this invitation') . $eol;
+ $ko++;
+
+ } else {
+
+ // each email address
+ foreach($recips as $n => $recip) {
+
+ // if empty ignore
+ $recip = $recips[$n] = trim($recip);
+ if(! $recip) continue;
+
+ // see if we have an email address who@domain.tld
+ if (!preg_match('/^.{2,64}\@[a-z0-9.-]{4,32}\.[a-z]{2,12}$/', $recip)) {
+ $feedbk .= 'ZAI0203E ' . ($n+1) . ': ' . sprintf( t('(%s) : Not a valid email address'), $recip) . $eol;
+ $ko++;
+ continue;
+ }
+ if(! validate_email($recip)) {
+ $feedbk .= 'ZAI0204E ' . ($n+1) . ': ' . sprintf( t('(%s) : Not a real email address'), $recip) . $eol;
+ $ko++;
+ continue;
+ }
+
+ // do we accept the email (not black listed)
+ if(! allowed_email($recip)) {
+ $feedbk .= 'ZAI0205E ' . ($n+1) . ': ' . sprintf( t('(%s) : Not allowed email address'), $recip) . $eol;
+ $ko++;
+ continue;
+ }
+
+ // is the email address just in use for account or registered before
+ $r = q("SELECT account_email AS em FROM account WHERE account_email = '%s'"
+ . " UNION "
+ ."SELECT reg_email AS em FROM register WHERE reg_vital = 1 AND reg_email = '%s' LIMIT 1;",
+ dbesc($recip),
+ dbesc($recip)
+ );
+ if($r && $r[0]['em'] == $recip) {
+ $feedbk .= 'ZAI0206E ' . ($n+1) . ': ' . sprintf( t('(%s) : email address already in use'), $recip) . $eol;
+ $ko++;
+ continue;
+ }
+
+ if ($isajax) {
+ // seems we have an email address acceptable
+ $feedbk .= 'ZAI0209I ' . ($n+1) . ': ' . sprintf( t('(%s) : Accepted email address'), $recip) . $eol;
+ }
}
+ }
+
+ if ($isajax) {
+ // we are not silent on the ajax road
+ echo json_encode(array('feedbk' => $feedbk, 'due' => $due));
+
+ // that mission is complete
+ killme();
+ exit;
+ }
+
+ // Total ?todo notice( t('Invitation limit exceeded. Please contact your site administrator.') . EOL);
+
+ // any errors up to now in fg?
+
+
+ // down from here, only on the main road (no more ajax)
+
+ // tell if sth is to tell
+ $feedbk ? notice($feedbk) . $eol : '';
+
+ if ($ko > 0) return;
+
+ // the personal mailtext
+ $mailtext = ((x($_POST,'zaitxt')) ? notags(trim($_POST['zaitxt'])) : '');
+
+ // to log in db
+ $reonar = json_decode( ((x($_POST,'zaireon')) ? notags(trim($_POST['zaireon'])) : ''), TRUE, 8) ;
+
+ // me, the invitor
+ $account = App::get_account();
+ $reonar['from'] = $account['account_email'];
+ $reonar['date'] = datetime_convert();
+ $reonar['fromip'] = $_SERVER['REMOTE_ADDR'];
+
+ // who is the invitor on
+ $inby = local_channel();
+
+ $ok = $ko = 0;
+
+ // send the mail(s)
+ foreach($recips as $n => $recip) {
- else
- $nmessage = $message;
-
- $account = App::get_account();
+ $reonar['due'] = $due;
+ $reonar['to'] = $recip;
+ $reonar['txtpersonal'] = $mailtext;
- $res = z_mail(
+ // generate an invide code to store and pm
+ $invite_code = autoname(8) . rand(1000,9999);
+
+ // again the final localized templates $reonar['subject'] $reonar['lang'] $reonar['tpl']
+
+ // save current operators lc and take the desired to mail
+ push_lang($reonar['lang']);
+ // resolve
+ $tx = replace_macros(get_intltext_template('invite.'.$reonar['tpl'].'.tpl'),
+ array(
+ '$projectname' => t('$Projectname'),
+ '$invite_code' => $invite_code,
+ '$invite_where' => z_root() . '/register',
+ '$invite_whereami' => str_replace('@', '@+', $reonar['whereami']),
+ '$invite_whoami' => z_root() . '/channel/' . $reonar['whoami'],
+ '$invite_anywhere' => z_root() . '/pubsites'
+ )
+ );
+ // restore lc to operator
+ pop_lang();
+
+ $reonar['txttemplate'] = $tx;
+
+ // pm
+ $zem = z_mail(
[
'toEmail' => $recip,
'fromName' => ' ',
- 'fromEmail' => $account['account_email'],
- 'messageSubject' => t('Please join us on $Projectname'),
- 'textVersion' => $nmessage,
+ 'fromEmail' => $reonar['from'],
+ 'messageSubject' => $reonar['subject'],
+ 'textVersion' => ($mailtext ? $mailtext . "\n\n" : '') . $tx . "\n" . $due,
]
);
- if($res) {
- $total ++;
- $current_invites ++;
- set_pconfig(local_channel(),'system','sent_invites',$current_invites);
- if($current_invites > $max_invites) {
- notice( t('Invitation limit exceeded. Please contact your site administrator.') . EOL);
- return;
- }
- }
- else {
- notice( sprintf( t('%s : Message delivery failed.'), $recip) . EOL);
+ if(!$zem) {
+
+ $ko++;
+ $msg = 'ZAI0208E,' . sprintf( t('%s : Message delivery failed.'), $recip);
+
+ } else {
+
+ $ok++;
+ $msg = 'ZAI0208I ' . sprintf( t('To %s : Message delivery success.'), $recip);
+
+ // if verify_email is the rule, email becomes a dId2 - NO
+ // $did2 = ($flags & ACCOUNT_UNVERIFIED) == ACCOUNT_UNVERIFIED ? $recip : '';
+
+ // always enforce verify email with invitations, thus email becomes a dId2
+ $did2 = $recip;
+ $flags |= ACCOUNT_UNVERIFIED;
+
+ // defaults vital, reg_pass
+ $r = q("INSERT INTO register ("
+ . "reg_flags,reg_didx,reg_did2,reg_hash,reg_created,reg_startup,reg_expires,reg_email,reg_byc,reg_uid,reg_atip,reg_lang,reg_stuff)"
+ . " VALUES ( %d, 'i', '%s', '%s', '%s', '%s', '%s', '%s', %d, %d, '%s', '%s', '%s') ",
+ intval($flags),
+ dbesc($did2),
+ dbesc($invite_code),
+ dbesc(datetime_convert()),
+ dbesc(datetime_convert()),
+ dbesc($dur['due']),
+ dbesc($recip),
+ intval($inby),
+ intval($account['account_id']),
+ dbesc($reonar['fromip']),
+ dbesc($reonar['lang']),
+ dbesc(json_encode( array('reon' => $reonar) ))
+ );
}
-
+ $msg .= ' (a' . $account['account_id'] . ', c' . $inby . ', from:' . $reonar['from'] . ')';
+ zar_log( $msg);
}
- notice( sprintf( tt("%d message sent.", "%d messages sent.", $total) , $total) . EOL);
+
+ $ok + $ko > 0
+ ? notice( 'ZAI0212I ' . sprintf( t('%1$d mail(s) sent, %2$d mail error(s)'), $ok, $ko) . EOL)
+ : '';
+ //logger( print_r( $reonar, true) );
+
return;
}
function get() {
+
+ // zai1
if(! local_channel()) {
- notice( t('Permission denied.') . EOL);
+ notice( 'ZAI0101E,' . t('Permission denied.') . EOL);
return;
}
@@ -107,68 +307,263 @@ class Invite extends Controller {
//Do not display any associated widgets at this point
App::$pdl = '';
- $o = '<b>' . t('Invite App') . ' (' . t('Not Installed') . '):</b><br>';
- $o .= t('Send email invitations to join this network');
+ $o = 'ZAI0102E,' . t('Invite App') . ' (' . t('Not Installed') . ')' . EOL;
+ return $o;
+ }
+
+ if (! (get_config('system','invitation_also') || get_config('system','invitation_only')) ) {
+ $o = 'ZAI0103E,' . t('Invites not proposed by configuration') . '. ';
+ $o .= t('Contact the site admin');
return $o;
}
+ // invitation_by_user may still not configured, the default 'na' will tell this
+ // if configured, 0 disables invitations by users, other numbers are how many invites a user may propagate
+ $invuser = get_config('system','invitation_by_user', 'na');
+
+ // if the mortal user drives the invitation
+ If (! is_site_admin()) {
+
+ // when not configured, 4 is the default
+ $invuser = ($invuser === 'na') ? 4 : $invuser;
+
+ // a config value 0 disables invitation by users
+ if (!$invuser) {
+ $o = 'ZAI0104E, ' . t('Invites by users not enabled') . '. ';
+ return $o;
+ }
+
+ if ($ihave >= $invuser) {
+ notice( 'ZAI0105W,' . t('You have no more invitations available') . EOL);
+ return '';
+ }
+
+ } else {
+ // general deity admin invite limit infinite (theoretical)
+ if ($invuser === 'na') set_config('system','invitation_by_user', 4);
+ // for display only
+ $invuser = '∞';
+ }
+
+ // xchan record of the page observer
+ // while quoting matters the user, the sending is associated with a channel (of the user)
+ // also the admin may and should decide, which channel will told to the public
+ $ob = App::get_observer();
+ if(! $ob)
+ return 'ZAI0109F,' . t('Not on xchan') . EOL;
+ $whereami = $ob['xchan_addr'];
+ $channel = App::get_channel();
+ $whoami = $channel['channel_address'];
+
+ // to pass also to post()
+ $tao = 'tao.zai.whereami = ' . "'" . $whereami . "';\n"
+ . 'tao.zai.whoami = ' . "'" . $whoami . "';\n";
+
+ // expirations, duration interval
+ $dur = self::calcdue();
+ $tao .= 'tao.zai.expire = { durn: ' . $dur['durn']
+ . ', durq: ' . "'" . $dur['durq'] . "'"
+ . ', due: ' . "'" . $dur['due'] . "' };\n";
+
+ // to easy redisplay the empty form
nav_set_selected('Invite');
+ // inform about the count of invitations we have at all
+ $r = q("SELECT count(reg_id) as ct FROM register WHERE reg_vital = 1"); // where not admin TODO
+ $wehave = ($r ? $r[0]['ct'] : 0);
+
+ // invites max for all users except admins
+ $invmaxau = intval(get_config('system','invitations_max_users'));
+ if(! $invmaxau) {
+ $invmaxau = 50;
+ if (is_site_admin()) {
+ set_config('system','invitations_max_users',intval($invmaxau));
+ }
+ }
+
+ if ($wehave > $invmaxau) {
+ if (! is_site_admin()) {
+ $feedbk .= 'ZAI0200E,' . t('All users invitation limit exceeded.') . $eol;
+ }
+ }
+
+ // let see how many invites currently used by the user
+ $r = q("SELECT count(reg_id) AS n FROM register WHERE reg_vital = 1 AND reg_byc = %d",
+ intval(local_channel()));
+ $ihave = $r ? $r[0]['n'] : 0;
+
$tpl = get_markup_template('invite.tpl');
- $invonly = false;
+
+ $inv_rabots = array(
+ 'i' => t('Minute(s)'),
+ 'h' => t('Hour(s)') ,
+ 'd' => t('Day(s)')
+ );
+ $inv_expire = replace_macros(get_markup_template('field_duration.qmc.tpl'),
+ array(
+ 'label' => t('Invitation expires after'),
+ 'qmc' => 'zai',
+ 'qmcid' => 'ZAI0014I',
+ 'field' => array(
+ 'name' => 'expire',
+ 'title' => t('duration up from now'),
+ 'value' => ($invexpire_n ? $invexpire_n : 2),
+ 'min' => '1',
+ 'max' => '99',
+ 'size' => '2',
+ 'default' => ($invexpire_u ? $invexpire_u : 'd')
+ ),
+ 'rabot' => $inv_rabots
+ )
+ );
+
+ // let generate an invite code that here and never will be applied (only to fill displayed template)
+ // real invite codes become generated for each recipient when we store the new invitation(s)
+ // $invite_code = substr(str_shuffle('abcdefghijklmnopqrstuvwxyz'), 0, 8) . rand(1000,9999);
+ // let take one descriptive for template (as said is never used)
+ $invite_code = 'INVITATE2020';
- if(get_config('system','invitation_only')) {
- $invonly = true;
- $x = get_pconfig(local_channel(),'system','invites_remaining');
- if((! $x) && (! is_site_admin())) {
- notice( t('You have no more invitations available') . EOL);
- return '';
+ // what languages we use now
+ $lccmy = ((isset(App::$config['system']['language'])) ? App::$config['system']['language'] : 'en');
+ // and all the localized templates belonging to invite
+ $tpls = glob('view/*/invite.*.tpl');
+
+ $tpla=$tplx=$tplxs=array();
+ foreach ($tpls as $tpli) {
+ list( $nop, $l, $t ) = explode( '/', $tpli);
+ if ( preg_match('/\.subject/', $t) =='1' ) {
+ // indicate a subject tpl exists
+ $t=str_replace(array('invite.', '.subject', '.tpl'), '', $t);
+ $tplxs[$l][$t]=true;
+ continue;
}
+ // collect unique template names cross all languages and
+ // tpla[language][]=template those available in each language
+ $tplx[] = $tpla[$l][] = str_replace( array('invite.', '.tpl'), '', $t);
}
-
- if($invonly && ($x || is_site_admin())) {
- $invite_code = autoname(8) . rand(1000,9999);
- $nmessage = str_replace('$invite_code',$invite_code,$message);
-
- $r = q("INSERT INTO register (hash,created,uid,password,lang) VALUES ('%s', '%s',0,'','') ",
- dbesc($invite_code),
- dbesc(datetime_convert())
+ asort( $langs = array_keys($tpla) );
+ asort( $tplx = array_unique($tplx) );
+
+ // prepare current language and the default standard template (causual) for js
+ // With and in js, I use a var 'tao' as a shortcut for top array object
+ // and also qualify the object with the prefix zai = tao.zai as my var used outsite functions
+ // can be unique within the overall included spaghette whirls
+ // one can say Im too lazy to write prototypes and just I can agree.
+ // tao simply applies the fact of using the same var as object and/or array in ja.
+ $tao.='tao.zai.lccmy = ' . "'" . $lccmy . "';\n" . 'tao.zai.itpl = ' . "'" . 'casual' . "';\n";
+
+ $lcclane=$tx=$tplin='';
+ //$lccsym='<span class="fa zai_fa zai_lccsym"></span>'; // alt 
+ $tplsym='<span class="fa zai_fa"></span>';
+
+ // I will uncomment for js console debug
+ // $tao.='tao.zai.debug = ' . "'" . json_encode($tplxs) . "';\n";
+
+ // running thru the localized templates (subjects and textmsgs) and bring them to tao
+ // lcc LanguageCountryCode,
+ // lcc2 is a 2 character and lcc5 a 5 character LanguageCountryCode
+ foreach($tpla as $l => $tn) {
+
+ // restyle lc to iso getttext format to avoid errors in js, hilite the current
+ $lcc = str_replace('-', '_', $l);
+ $hi = ($l == $lccmy) ? ' zai_hi' : '';
+ $lcc2 = strlen($l) == 2 ? ' zai_lcc2' : '';
+ $lcc5 = strlen($l) == 5 ? ' zai_lcc5' : '';
+ $lccg = ' zai_lccg' . substr( $l, 0, 2 );
+ $lcclane
+ .= '<span class="fa zai_fa zai_lccsym' . $lcc2 . $lcc5 . $lccg . '"></span>'
+ . '<a href="javascript:;" class="zai_lcc' . $lcc2 . $lcc5 . $lccg . $hi . '">' . $lcc . '</a>';
+ // textmsg
+ $tao .= 'tao.zai.t.' . $lcc . ' = {};' . "\n";
+ // subject
+ $tao .= 'tao.zai.s.' . $lcc . ' = {};' . "\n";
+
+ // resolve localized templates and take intented lc for
+ foreach($tn as $t1) {
+
+ // save current lc and take the desired
+ push_lang($l);
+
+ // resolve
+ $tx = replace_macros(get_intltext_template('invite.'.$t1.'.tpl'),
+ array(
+ '$projectname' => t('$Projectname'),
+ '$invite_code' => $invite_code,
+ '$invite_where' => z_root() . '/register',
+ '$invite_whereami' => $whereami,
+ '$invite_whoami' => z_root() . '/channel/' . $whoami,
+ '$invite_anywhere' => z_root() . '/pubsites'
+ )
);
-
- if(! is_site_admin()) {
- $x --;
- if($x >= 0)
- set_pconfig(local_channel(),'system','invites_remaining',$x);
- else
- return;
- }
+
+ // a default subject if no associated exists
+ $ts=t('Invitation');
+ if ( $tplxs[$l][$t1] )
+ $ts = replace_macros(get_intltext_template('invite.'.$t1.'.subject.tpl'),
+ array(
+ '$projectname' => t('$Projectname'),
+ '$invite_loc' => get_config('system','sitename')
+ )
+ );
+
+ // restore lc to current foreground
+ pop_lang();
+
+ // bring to tao as js like it
+ $tao .= 'tao.zai.t.' . $lcc . '.' . $t1 . " = '" . rawurlencode($tx) . "';\n";
+ $tao .= 'tao.zai.s.' . $lcc . '.' . $t1 . " = '" . rawurlencode($ts) . "';\n";
}
-
- $ob = App::get_observer();
- if(! $ob)
- return $o;
-
- $channel = App::get_channel();
-
+ }
+
+ // hilite the current defauls just from the beginning
+ foreach ($tplx as $t1) {
+ $hi = ($t1 == 'casual') ? ' zai_hi' : '';
+ $tplin .= $tplsym.'<a href="javascript:;" id="zai-' . $t1
+ . '" class="invites'.$hi.'">' . $t1 . '</a>';
+ }
+
+ // fill the form for foreground
$o = replace_macros($tpl, array(
'$form_security_token' => get_form_security_token("send_invite"),
+ '$zai' => strtolower(self::MYP),
+ '$tao' => $tao,
'$invite' => t('Send invitations'),
- '$addr_text' => t('Enter email addresses, one per line:'),
- '$msg_text' => t('Your message:'),
- '$default_message' => t('Please join my community on $Projectname.') . "\r\n" . "\r\n"
- . $linktxt
- . (($invonly) ? "\r\n" . "\r\n" . t('You will need to supply this invitation code:') . " " . $invite_code . "\r\n" . "\r\n" : '')
- . t('1. Register at any $Projectname location (they are all inter-connected)')
- . "\r\n" . "\r\n" . z_root() . '/register'
- . "\r\n" . "\r\n" . t('2. Enter my $Projectname network address into the site searchbar.')
- . "\r\n" . "\r\n" . $ob['xchan_addr'] . ' (' . t('or visit') . " " . z_root() . '/channel/' . $channel['channel_address'] . ')'
- . "\r\n" . "\r\n"
- . t('3. Click [Connect]')
- . "\r\n" . "\r\n" ,
+ '$ihave' => 'ZAI0106I, ' . t('Invitations I am using') . ': ' . $ihave . ' / ' . $invuser,
+ '$wehave' => 'ZAI0107I, ' . t('Invitations we are using') . ': ' . $wehave . ' / ' . $invmaxau,
+ '$n10' => 'ZAI0010I', '$m10' => t('§ Note, the email(s) sent will be recorded in the system logs'),
+ '$n11' => 'ZAI0011I', '$m11' => t('Enter email addresses, one per line:'),
+ '$n12' => 'ZAI0012I', '$m12' => t('Your message:'),
+ '$n13' => 'ZAI0013I', '$m13' => t('Invite template'),
+ '$inv_expire' => $inv_expire,
+ '$subject_label' => t('Subject:'),
+ '$subject' => t('Invitation'),
+ '$lcclane' => $lcclane,
+ '$tplin' => $tplin,
+ '$standard_message' => '',
+ '$personal_message' => '',
+ '$personal_pointer' => t('Here you may enter personal notes to the recipient(s)'),
+ '$due' => t('Note, the invitation code is valid up to') . ' ' . $dur['due'],
'$submit' => t('Submit')
));
-
+
return $o;
}
-
+
+ function calcdue($duri=false) {
+ // expirations, duration interval
+ if ($duri===false)
+ $duri = get_config('system','register_expire', '2d');
+ if ( preg_match( '/^[0-9]{1,2}[ihdwmy]{1}$/', $duri ) ) {
+ $durq = substr($duri, -1);
+ $durn = substr($duri, 0, -1);
+ $due = date('Y-m-d H:i:s', strtotime('+' . $durn . ' '
+ . str_replace( array(':i',':h',':d',':w',':m',':y'),
+ array('minutes', 'hours', 'days', 'weeks', 'months', 'years'),
+ (':'.$durq))
+ ));
+ return array( 'durn' => $durn, 'durq' => $durq, 'due' => $due);
+ }
+ return false;
+ }
}
+
diff --git a/Zotlabs/Module/Regate.php b/Zotlabs/Module/Regate.php
new file mode 100644
index 000000000..8ec559332
--- /dev/null
+++ b/Zotlabs/Module/Regate.php
@@ -0,0 +1,347 @@
+<?php
+
+namespace Zotlabs\Module;
+
+require_once('include/security.php');
+
+/**
+ *
+ * @version 2.0.0
+ * @author hilmar runge
+ * @since 2020-03-03
+ * Check verification pin
+ * input field email address
+ * input field pin (told during register)
+ * check duty
+ * check startup and expire
+ * compare email address
+ * check pin
+ * limited tries to enter the correct pin/pass 2 handle via f2b
+ * on success create account and update register
+ *
+ */
+
+ define ( 'REGISTER_AGREED', 0x0020 );
+ define ( 'REGISTER_DENIED', 0x0040 );
+
+class Regate extends \Zotlabs\Web\Controller {
+
+ const MYP = 'ZAR'; //ZAR1x
+ const VERSION = '2.0.0';
+
+
+ function post() {
+
+ check_form_security_token_redirectOnErr('/', 'regate');
+
+ if ( argc() > 1 ) {
+ $did2 = hex2bin( substr( argv(1), 0, -1) );
+ $didx = substr( argv(1), -1 );
+ }
+
+ $msg = '';
+ $nextpage = '';
+
+ if ($did2) {
+
+ $nowhhmm = date('Hi');
+ $day = date('N');
+ $now = date('Y-m-d H:i:s');
+ $ip = $_SERVER['REMOTE_ADDR'];
+
+ $isduty = zar_register_dutystate();
+ if ($isduty['isduty'] !== false && $isduty['isduty'] != 1) {
+ // normally, that should never happen here
+ // log suitable for fail2ban also
+ $logmsg = 'ZAR1230S Unexpected registration verification request for '
+ . get_config('system','sitename') . ' arrived from § ' . $ip . ' §';
+ zar_log($logmsg);
+ goaway(z_root() . '/');
+ }
+
+ // do we have a valid dId2 ?
+ if ( ($didx == 'a' && substr( $did2 , -2) == substr( base_convert( md5( substr( $did2, 1, -2) ),16 ,10), -2))
+ || ($didx == 'e') ) {
+ // check startup and expiration via [=[register
+ $r = q("SELECT * FROM register WHERE reg_vital = 1 AND reg_did2 = '%s' ", dbesc($did2) );
+ if ( $r && count($r) == 1 ) {
+ $r = $r[0];
+ // check timeframe
+ if ( $r['reg_startup'] <= $now && $r['reg_expires'] >= $now ) {
+
+ if ( isset($_POST['resend']) && $didx == 'e' ) {
+ $re = q("SELECT * FROM register WHERE reg_vital = 1 AND reg_didx = 'e' AND reg_did2 = '%s' ", dbesc($r['reg_did2']) );
+ if ( $re && count($re) == 1 ) {
+ $re = $re[0];
+ $reonar = json_decode($re['reg_stuff'],true);
+ $reonar['subject'] = 'Re,Fwd,' . $reonar['subject'];
+ if ($reonar) {
+ $zm = zar_reg_mail($reonar);
+ $msg = ($zm) ? 'ZAR1238I ' . t('Email resent')
+ : 'ZAR1238E ' . t('Resent failed');
+ zar_log($msg . ' ' . $r['reg_did2']);
+ info($msg);
+ goaway(z_root() . '/' . $nextpage);
+ }
+ }
+ }
+
+ // check hash
+ if ( $didx == 'a' )
+ $acpin = (preg_match('/^[0-9]{6,6}$/', $_POST['acpin']) ? $_POST['acpin'] : false);
+ elseif ( $didx == 'e' )
+ $acpin = (preg_match('/^[0-9a-f]{24,24}$/', $_POST['acpin']) ? $_POST['acpin'] : false);
+ else $acpin = false;
+
+ if ( $acpin && ($r['reg_hash'] == $acpin )) {
+
+ $flags = $r['reg_flags'];
+ if ( ($flags & ACCOUNT_UNVERIFIED ) == ACCOUNT_UNVERIFIED) {
+
+ // verification success
+ $msg = 'ZAR1237I' . ' ' . t('Verify successfull');
+ $reonar = json_decode( $r['reg_stuff'], true);
+ $reonar['valid'] = $now . ',' . $ip . ' ' . $did2 . ' ' . $msg;
+ // clear flag
+ $flags &= $flags ^ ACCOUNT_UNVERIFIED;
+ // sth todo?
+ $vital = $flags == 0 ? 0 : 1;
+ // set flag
+ $flags |= REGISTER_AGREED;
+ zar_log($msg . ' ' . $did2 . ':flags' . $flags . ',rid' . $r['reg_id']);
+
+ q("START TRANSACTION");
+
+ $qu = q("UPDATE register SET reg_stuff = '%s', reg_vital = %d, reg_flags = %d "
+ ." WHERE reg_id = %d ",
+ dbesc(json_encode($reonar)),
+ intval($vital),
+ intval($flags),
+ intval($r['reg_id'])
+ );
+
+ if ( ($flags & ACCOUNT_PENDING ) == ACCOUNT_PENDING ) {
+ $msg .= "\n".t('Last step will be by an instance admin to agree your account request');
+ q("COMMIT");
+ }
+ elseif ( ($flags ^ REGISTER_AGREED) == 0) {
+
+ $cra = create_account_from_register([ 'reg_id' => $r['reg_id'] ]);
+
+ if ($cra['success']) {
+
+ q("COMMIT");
+ $msg = 'ZAR1238I' . t('Account successfull created');
+ zar_log($msg . ':' . print_r($cra, true));
+ $nextpage = '~';
+ $auto_create = (get_config('system','auto_channel_create') ? true : false);
+
+ if($auto_create) {
+ if($reonar['chan.name'])
+ set_aconfig($cra['account']['account_id'],
+ 'register','channel_name',$reonar['chan.name']);
+ if($reonar['chan.did1'])
+ set_aconfig($cra['account']['account_id'],
+ 'register','channel_address',$reonar['chan.did1']);
+ }
+
+ authenticate_success($cra['account'],null,true,false,true);
+
+ if($auto_create) {
+ $new_channel = auto_channel_create($cra['account']['account_id']);
+ if($new_channel['success']) {
+ $channel_id = $new_channel['channel']['channel_id'];
+ change_channel($channel_id);
+ $nextpage = 'profiles/' . $channel_id;
+ }
+ else {
+ zar_log($new_channel['message']
+ . ', ' . $reonar['chan.did1']
+ . ', ' . $reonar['chan.name']
+ );
+ }
+ }
+ unset($_SESSION['login_return_url']);
+ }
+ else {
+ q("ROLLBACK");
+ $msg = 'ZAR1239E ' . t('Account creation error');
+ zar_log($msg . ':' . print_r($cra, true));
+ }
+ }
+ else {
+ // new flags implemented and not recognized or sth like
+ zar_log('ZAR1237D unexpected,' . $flags);
+ }
+ }
+ else {
+ // nothing to confirm
+ $msg = 'ZAR1236E' . ' ' . t('Verify failed');
+ }
+ }
+ else {
+ $msg = 'ZAR1235E' . ' ' . t('Token verification failed');
+ }
+ }
+ else {
+ $msg = 'ZAR1234W' . ' ' . t('Request not inside time frame');
+ //info($r[0]['reg_startup'] . EOL . $r[0]['reg_expire'] );
+ }
+ }
+ else {
+ $msg = 'ZAR1232E' . ' ' . t('Identity unknown');
+ zar_log($msg . ':' . $did2 . $didx);
+ }
+ }
+ else {
+ $msg = 'ZAR1231E' . t('dId2 mistaken');
+ }
+
+ }
+
+ if ($msg > '') info($msg);
+ goaway( z_root() . '/' . $nextpage );
+ }
+
+
+ function get() {
+
+ if ( argc() > 1 ) {
+ $did2 = hex2bin( substr( argv(1), 0, -1) );
+ $didx = substr( argv(1), -1 );
+ $deny = argc() > 2 ? argv(2) : '';
+ $deny = preg_match('/^[0-9a-f]{8,8}$/', $deny) ? hex2bin($deny) : false;
+ }
+
+ if ($_SESSION['zar']['msg']) {
+ $o = replace_macros(get_markup_template('plain.tpl'), [
+ '$title' => t('Your Registration'),
+ '$now' => '',
+ '$infos' => $_SESSION['zar']['msg'] . EOL,
+ ]);
+ unset($_SESSION['zar']['msg']);
+ return $o;
+ }
+
+ $now = date('Y-m-d H:i:s');
+ $ip = $_SERVER['REMOTE_ADDR'];
+
+ $isduty = zar_register_dutystate();
+ $nowfmt = $isduty['nowfmt'];
+ $atform = $isduty['atform'];
+
+ $title = t('Register Verification');
+
+ // do we have a valid dId2 ?
+ if ( ($didx == 'a' && substr( $did2 , -2) == substr( base_convert( md5( substr( $did2, 1, -2) ),16 ,10), -2))
+ || ($didx == 'e') ) {
+
+ $r = q("SELECT * FROM register WHERE reg_vital = 1 AND reg_didx = '%s' AND reg_did2 = '%s'",
+ dbesc($didx),
+ dbesc($did2)
+ );
+
+ if ( $r && count($r) == 1 && $r[0]['reg_flags'] &= (ACCOUNT_UNVERIFIED | ACCOUNT_PENDING)) {
+ $r = $r[0];
+
+ // provide a button in case
+ $resend = ($r['reg_didx'] == 'e') ? t('Resend') : false;
+
+ // is still only instance admins intervention required?
+ if ( $r['reg_flags'] == ACCOUNT_PENDING ) {
+ $o = replace_macros(get_markup_template('plain.tpl'), [
+ '$title' => t('Register Verification Status'),
+ '$now' => $nowfmt,
+ '$infos' => t('Soon all is well.') . EOL
+ . t('Only one instance admin has still to agree your account request.') . EOL
+ . t('Please be patient') . EOL . EOL . 'ZAR1138I',
+ ]);
+ }
+ else {
+
+ if ($deny) {
+
+ if (substr($r['reg_hash'],0,4) == $deny) {
+
+ zar_log('ZAR1134S email verfication denied ' . $did2);
+
+ $msg = 'ZAR1133A' . ' ' . t('Sorry for any inconvience. Thank you for your response.');
+ $o = replace_macros(get_markup_template('plain.tpl'), [
+ '$title' => t('Registration request denied'),
+ '$now' => $nowf,
+ '$infos' => $msg . EOL,
+ ]);
+
+ $reonar = json_decode( $r['reg_stuff'], true);
+ $reonar['deny'] = $now . ',' . $ip . ' ' . $did2 . ' ' . $msg;
+ $flags = ( $r['reg_flags'] &= ( $r['reg_flags'] ^ ACCOUNT_UNVERIFIED) )
+ | ( $r['reg_flags'] |= REGISTER_DENIED);
+ $rd = q("UPDATE register SET reg_stuff='%s', reg_vital=0, reg_flags=%d WHERE reg_id = %d ",
+ dbesc(json_encode($reonar)),
+ intval($flags),
+ intval($r['reg_id'])
+ );
+ }
+ else {
+ zar_log('ZAR1135E not awaited url parameter received');
+ goaway(z_root);
+ }
+ }
+ else {
+
+ if ( $r['reg_startup'] <= $now && $r['reg_expires'] >= $now) {
+ $o = replace_macros(get_markup_template('regate.tpl'), [
+ '$form_security_token' => get_form_security_token("regate"),
+ '$title' => $title,
+ '$desc' => t('You were given a validation token. Please enter that token here to continue the register verification step and allow some delay for proccessing.'),
+ '$did2' => bin2hex($did2) . $didx,
+ '$now' => $nowfmt,
+ '$atform' => $atform,
+ '$resend' => $resend,
+ '$submit' => t('Submit'),
+ '$acpin' => [ 'acpin', t('Validation token'),'','' ],
+ ]);
+ }
+ else {
+ // expired ?
+ if ( $now > $r['reg_expires'] ) {
+ $rd = q("UPDATE register SET reg_vital = 0 WHERE reg_id = %d ",
+ intval($r['reg_id'])
+ );
+ }
+
+ $o = replace_macros(get_markup_template('plain.tpl'), [
+ '$title' => $title,
+ '$now' => $nowf,
+ '$infos' => 'ZAR1132W' . ' ' . t('Request not inside time frame') . EOL,
+ ]);
+ }
+ }
+ }
+ }
+ else {
+ $msg = 'ZAR1132E' . ' ' . t('Identity unknown');
+ zar_log($msg . ':' . $did2 . ',' . $didx);
+ $o = replace_macros(get_markup_template('plain.tpl'), [
+ '$title' => $title,
+ '$now' => $nowf,
+ '$infos' => $msg . EOL,
+ ]);
+ }
+
+ }
+ else {
+ $msg = 'ZAR1131E ' . t('dId2 mistaken');
+ // $log = ' from § ' . $ip . ' §' . ' (' . dbesc($did2) . ')';
+ zar_log($msg);
+ $o = replace_macros(get_markup_template('plain.tpl'), [
+ '$title' => $title,
+ '$now' => $nowf,
+ '$infos' => ($msg) . EOL,
+ ]);
+ }
+
+ return $o;
+ }
+}
+
diff --git a/Zotlabs/Module/Register.php b/Zotlabs/Module/Register.php
index 278cf15ca..d0a41b3c2 100644
--- a/Zotlabs/Module/Register.php
+++ b/Zotlabs/Module/Register.php
@@ -1,4 +1,5 @@
<?php
+
namespace Zotlabs\Module;
use Zotlabs\Web\Controller;
@@ -7,7 +8,12 @@ require_once('include/security.php');
class Register extends Controller {
+ const MYP = 'ZAR'; // ZAR0x
+ const VERSION = '2.0.0';
+
function init() {
+
+ // ZAR0
$result = null;
$cmd = ((argc() > 1) ? argv(1) : '');
@@ -43,25 +49,98 @@ class Register extends Controller {
check_form_security_token_redirectOnErr('/register', 'register');
- $max_dailies = intval(get_config('system','max_daily_registrations'));
- if($max_dailies) {
- $r = q("select count(account_id) as total from account where account_created > %s - INTERVAL %s",
- db_utcnow(), db_quoteinterval('1 day')
+ /**
+ * [hilmar:]
+ * It may happen, the posted form arrives in a strange fashion. With the control of the duty hours
+ * for registration, the input form was disabled at html. While receiving posted data, checks are
+ * required if all is on the right road (no posts accepted during off duty).
+ *
+ */
+
+ $act = q("SELECT COUNT(*) AS act FROM account")[0]['act'];
+ $duty = zar_register_dutystate();
+ $ip = $_SERVER['REMOTE_ADDR'];
+ $sameip = intval(get_config('system','register_sameip'));
+
+ $arr = $_POST;
+ $invite_code = ( (x($arr,'invite_code')) ? notags(trim($arr['invite_code'])) : '');
+ $email = ( (x($arr,'email')) ? notags(punify(trim($arr['email']))) : '');
+ $password = ( (x($arr,'password')) ? trim($arr['password']) : '');
+ $reonar = array();
+
+ // assume someone tries to validate (dId2 C/D/E), because only field email entered
+ if ( $email && ( ! $invite_code ) && ( ! $password ) && ( ! $_POST['password2'] ) ) {
+
+ // dId2 logic
+
+ if ( preg_match('/^\@{1,1}.{2,64}\@[a-z0-9.-]{4,32}\.[a-z]{2,12}$/', $email ) ) {
+ // dId2 C channel - ffu
+ }
+
+ if ( preg_match('/^.{2,64}\@[a-z0-9.-]{4,32}\.[a-z]{2,12}$/', $email ) ) {
+ // dId2 E email
+ goaway(z_root() . '/regate/' . bin2hex($email) . 'e' );
+ }
+
+ if ( preg_match('/^d{1,1}[0-9]{1,10}$/', $email ) ) {
+ // dId2 A artifical & anonymous
+ goaway(z_root() . '/regate/' . bin2hex($email) . 'a' );
+ }
+
+ }
+
+ if ($act > 0 && !$duty['isduty']) {
+ // normally, that should never arrive here (ie js hack or sth like)
+ // log suitable for f2b also
+ $logmsg = 'ZAR0230S Unexpected registration request';
+ zar_log($logmsg);
+ goaway(z_root() . '/');
+ }
+
+ if ($sameip) {
+ $f = q("SELECT COUNT(reg_atip) AS atip FROM register WHERE reg_vital = 1 AND reg_atip = '%s' ",
+ dbesc($ip)
);
- if($r && $r[0]['total'] >= $max_dailies) {
- notice( t('Maximum daily site registrations exceeded. Please try again tomorrow.') . EOL);
- return;
+ if ($f && $f[0]['atip'] > $sameip) {
+ $logmsg = 'ZAR0239S Exceeding same ip register request of ' . $sameip;
+ zar_log($logmsg);
+ goaway(z_root() . '/');
}
}
-
+
+ // s2 max daily
+ if ( self::check_max_daily_exceeded() ) return;
+
+ // accept tos
if(! x($_POST,'tos')) {
- notice( t('Please indicate acceptance of the Terms of Service. Registration failed.') . EOL);
+ notice( 'ZAR0230E '
+ . t('Please indicate acceptance of the Terms of Service. Registration failed.') . EOL);
return;
}
- $policy = get_config('system','register_policy');
+ // pw1 == pw2
+ if((! $_POST['password']) || ($_POST['password'] !== $_POST['password2'])) {
+ notice( 'ZAR0230E '
+ . t('Passwords do not match.') . EOL);
+ return;
+ }
+
+
+ $email_verify = intval(get_config('system','verify_email'));
+
+ if ($email) {
+ if ( ! preg_match('/^.{2,64}\@[a-z0-9.-]{4,32}\.[a-z]{2,12}$/', $_POST['email'] ) ) {
+ notice('ZAR0239E '
+ . t('Email address mistake') . EOL);
+ return;
+ }
+ }
- $email_verify = get_config('system','verify_email');
+ $policy = intval(get_config('system','register_policy'));
+ $invonly = intval(get_config('system','invitation_only'));
+ $invalso = intval(get_config('system','invitation_also'));
+ $auto_create = (get_config('system','auto_channel_create') ? true : false);
+ $auto_create = true;
switch($policy) {
@@ -71,7 +150,7 @@ class Register extends Controller {
break;
case REGISTER_APPROVE:
- $flags = ACCOUNT_BLOCKED | ACCOUNT_PENDING;
+ $flags = ACCOUNT_PENDING;
break;
default:
@@ -84,103 +163,224 @@ class Register extends Controller {
break;
}
- if($email_verify && $policy == REGISTER_OPEN)
- $flags = $flags | ACCOUNT_UNVERIFIED;
+ if($email_verify && ($policy == REGISTER_OPEN || $policy == REGISTER_APPROVE) )
+ $flags = ($flags | ACCOUNT_UNVERIFIED);
-
- if((! $_POST['password']) || ($_POST['password'] !== $_POST['password2'])) {
- notice( t('Passwords do not match.') . EOL);
- return;
- }
-
- $arr = $_POST;
+ // $arr has $_POST;
$arr['account_flags'] = $flags;
-
- $result = create_account($arr);
-
- if(! $result['success']) {
- notice($result['message']);
- return;
- }
- require_once('include/security.php');
-
-
- if($_REQUEST['name'])
- set_aconfig($result['account']['account_id'],'register','channel_name',$_REQUEST['name']);
- if($_REQUEST['nickname'])
- set_aconfig($result['account']['account_id'],'register','channel_address',$_REQUEST['nickname']);
- if($_REQUEST['permissions_role'])
- set_aconfig($result['account']['account_id'],'register','permissions_role',$_REQUEST['permissions_role']);
-
-
- $using_invites = intval(get_config('system','invitation_only'));
- $num_invites = intval(get_config('system','number_invites'));
- $invite_code = ((x($_POST,'invite_code')) ? notags(trim($_POST['invite_code'])) : '');
-
- if($using_invites && $invite_code) {
- q("delete from register where hash = '%s'", dbesc($invite_code));
- // @FIXME - this also needs to be considered when using 'invites_remaining' in mod/invite.php
- set_aconfig($result['account']['account_id'],'system','invites_remaining',$num_invites);
- }
-
- if($policy == REGISTER_OPEN ) {
- if($email_verify) {
- $res = verify_email_address($result);
- }
- else {
- $res = send_register_success_email($result['email'],$result['password']);
- }
- if($res) {
- if($invite_code) {
- info( t('Registration successful. Continue to create your first channel...') . EOL ) ;
- }
- else {
- info( t('Registration successful. Please check your email for validation instructions.') . EOL ) ;
+ $now = datetime_convert();
+ $well = false;
+
+ // s3
+ if ($invite_code) {
+
+ if ($invonly || $invalso) {
+
+ $reg = q("SELECT * from register WHERE reg_vital = 1 AND reg_didx = 'i' AND reg_hash = '%s'",
+ dbesc($invite_code));
+
+ if ( $reg && count($reg) == 1 ) {
+ $reg = $reg[0];
+ if ($reg['reg_email'] == ($email)) {
+
+ if ($reg['reg_startup'] <= $now && $reg['reg_expires'] >= $now) {
+
+ // is invitor admin
+ $isa = get_account_by_id($reg['reg_uid']);
+ $isa = ( $isa && ($isa['account_roles'] && ACCOUNT_ROLE_ADMIN) );
+
+ // approve contra invite by admin
+ if ($isa && $policy == REGISTER_APPROVE)
+ $flags &= $flags ^ ACCOUNT_PENDING;
+
+ // if $flags == 0 ??
+
+ // trans ?
+
+ // update reg vital 0 off
+ $icdone = q("UPDATE register SET reg_vital = 0 WHERE reg_id = %d ",
+ intval($reg['reg_id'])
+ );
+
+ info('ZAR0237I ' . t('Invitation code succesfully applied') . EOL);
+
+ $well = true;
+
+
+ } else {
+ notice('ZAR0236E ' . t('Invitation not in time or too late') . EOL);
+ goaway(z_root());
+ }
+
+ } else {
+ // no match email adr
+ $msg = 'ZAR0235S ' . t('Invitation email failed');
+ zar_log($msg);
+ notice($msg . EOL);
+ goaway(z_root());
+ }
+
+ } else {
+ // no match invitecode
+ $msg = 'ZAR0234S ' . t('Invitation code failed') ;
+ zar_log($msg);
+ notice( $msg . EOL);
+ goaway(z_root());
}
+
+ } else {
+ notice('ZAR0232E ' . t('Invitations are not available') . EOL);
+ goaway(z_root());
}
- }
- elseif($policy == REGISTER_APPROVE) {
- $res = send_reg_approval_email($result);
- if($res) {
- info( t('Your registration is pending approval by the site owner.') . EOL ) ;
- }
- else {
- notice( t('Your registration can not be processed.') . EOL);
+
+
+ } else {
+
+ $icdone = false;
+ // no ivc entered
+ if ( ! $invonly) {
+ // possibly the email is just in use ?
+ $reg = q("SELECT * from register WHERE reg_vital = 1 AND reg_email = '%s'",
+ dbesc('e' . $email));
+
+ if ( ! $reg)
+ $act = q("SELECT * from account WHERE account_email = '%s'", dbesc($email));
+
+ // in case an invitation was made but the invitecode was not entered, better ignore.
+ // goaway(z_root() . '/regate/' . bin2hex($reg['email']));
+
+ if ( ! $reg && ! $act) {
+ // email useable
+
+ $well = true;
+
+
+ } else {
+ $msg = 'ZAR0237E ' . t('Email address already in use') . EOL;
+ notice($msg);
+ // problem, the msg tells to anonymous about existant email addrs
+ // use another msg instead ? TODO ?
+ // on the other hand can play the fail2ban game
+ zar_log($msg . ' (' . $email . ')');
+ goaway(z_root());
+ }
+
+ } else {
+ $msg = 'ZAR0233E ' . t('Registration on this hub is by invitation only') . EOL;
+ notice($msg);
+ zar_log($msg);
+ goaway(z_root());
}
- goaway(z_root());
- }
-
- if($email_verify) {
- goaway(z_root() . '/email_validation/' . bin2hex($result['email']));
+
}
- // fall through and authenticate if no approvals or verifications were required.
+ if ($well) {
- authenticate_success($result['account'],null,true,false,true);
-
- $new_channel = false;
- $next_page = 'new_channel';
-
- if(get_config('system','auto_channel_create')) {
- $new_channel = auto_channel_create($result['account']['account_id']);
- if($new_channel['success']) {
- $channel_id = $new_channel['channel']['channel_id'];
- change_channel($channel_id);
- $next_page = '~';
+ if($policy == REGISTER_OPEN || $policy == REGISTER_APPROVE ) {
+
+ $cfgdelay = get_config( 'system', 'register_delay' );
+ $regdelay = calculate_adue( $cfgdelay );
+ $regdelay = $regdelay ? $regdelay['due'] : $now;
+
+ $cfgexpire = get_config('system','register_expire' );
+ $regexpire = calculate_adue( $cfgexpire );
+ $regexpire = $regexpire ? $regexpire['due'] : '2099-12-31 23:59:59';
+
+ // handle an email request that will be verified or an ivitation associated with an email address
+ if ( $email > '' && ($email_verify || $icdone) ) {
+ // enforce in case of icdone
+ $flags |= ACCOUNT_UNVERIFIED;
+ $empin = $pass2 = random_string(24);
+ $did2 = $email;
+ $didx = 'e';
+
+ push_lang(($reg['lang']) ? $reg['lang'] : 'en');
+ $reonar['from'] = get_config('system', 'from_email');
+ $reonar['to'] = $email;
+ $reonar['subject'] = sprintf( t('Registration confirmation for %s'), get_config('system','sitename'));
+ $reonar['txtpersonal']= t('Valid from') . ' ' . $regdelay . ' ' . t('and expire') . ' ' . $regexpire;
+ $reonar['txttemplate']= replace_macros(get_intltext_template('register_verify_member.tpl'),
+ [
+ '$sitename' => get_config('system','sitename'),
+ '$siteurl' => z_root(),
+ '$email' => $email,
+ '$due' => $reonar['txtpersonal'],
+ '$mail' => bin2hex($email) . 'e',
+ '$ko' => bin2hex(substr($empin,0,4)),
+ '$hash' => $empin
+ ]
+ );
+ pop_lang();
+ zar_reg_mail($reonar);
+
+ } else {
+ // that is an anonymous request without email or with email not to verify
+ $acpin = $pass2 = rand(100000,999999);
+ $did2 = rand(10,99);
+ $didx = 'a';
+ // enforce delayed verify
+ $flags = ($flags | ACCOUNT_UNVERIFIED);
+ if ($email) {
+ $reonar['email.untrust'] = $email;
+ $reonar['email.comment'] = 'received, but no need for';
+ }
+ }
+
+ if ( $auto_create ) {
+ $reonar['chan.name'] = notags(trim($arr['name']));
+ $reonar['chan.did1'] = notags(trim($arr['nickname']));
+ }
+
+ $reg = q("INSERT INTO register ("
+ . "reg_flags,reg_didx,reg_did2,reg_hash,reg_created,reg_startup,reg_expires,"
+ . "reg_email,reg_pass,reg_lang,reg_atip,reg_stuff)"
+ . " VALUES (%d, '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s') ",
+ intval($flags),
+ dbesc($didx),
+ dbesc($did2),
+ dbesc($pass2),
+ dbesc(datetime_convert('','',$now)),
+ dbesc(datetime_convert('','',$regdelay)),
+ dbesc(datetime_convert('','',$regexpire)),
+ dbesc($email),
+ dbesc(bin2hex($password)),
+ dbesc(substr(get_best_language(),0,2)),
+ dbesc($ip),
+ dbesc(json_encode( $reonar ))
+ );
+
+ if ($didx == 'a') {
+
+ $lid = q("SELECT reg_id FROM register WHERE reg_vital = 1 AND reg_did2 = '%s' AND reg_pass = '%s' ",
+ dbesc($did2), dbesc(bin2hex($password)) );
+
+ if ($lid && count($lid) == 1 ) {
+
+ $didnew = ( $lid[0]['reg_id'] . $did2 )
+ . ( substr( base_convert( md5( $lid[0]['reg_id'] . $did2 ), 16, 10 ),-2 ) );
+
+ $reg = q("UPDATE register SET reg_did2 = CONCAT('d','%s') WHERE reg_id = %d ",
+ dbesc($didnew), intval($lid[0]['reg_id'])
+ );
+
+ // notice( 'ZAR0239I,' . t( 'Your didital id is' ) . EOL . 'd' . $didnew . EOL
+ $_SESSION['zar']['msg'] = ( 'ZAR0239I,' . t( 'Your didital id is' ) . EOL . 'd' . $didnew . EOL
+ . t('and your pin for is') . ' ' . $pass2 . EOL
+ . t('Keep these infos and your entered password safe') . EOL
+ . t('Valid from') . ' ' . $regdelay . ' ' . t('and expire') . ' ' . $regexpire . EOL );
+
+ // acpin verify
+ // goaway(z_root() . '/regate/' . bin2hex('d' . $didnew) . 'a' );
+ goaway(z_root() . '/regate');
+ }
+ else {
+ $msg = 'ZAR0239D,' . t('Error creating dId A');
+ notice( $msg );
+ zar_log( $msg . ' ' . $did2);
+ }
+ }
}
- else
- $new_channel = false;
- }
-
- $x = get_config('system','workflow_register_next');
- if($x) {
- $next_page = $x;
- $_SESSION['workflow'] = true;
}
-
- unset($_SESSION['login_return_url']);
- goaway(z_root() . '/' . $next_page);
-
}
@@ -192,7 +392,7 @@ class Register extends Controller {
if(intval(get_config('system','register_policy')) === REGISTER_CLOSED) {
if(intval(get_config('system','directory_mode')) === DIRECTORY_MODE_STANDALONE) {
- notice( t('Registration on this hub is disabled.') . EOL);
+ notice( 'ZAR0130E ' . t('Registration on this hub is disabled.') . EOL);
return;
}
@@ -201,37 +401,34 @@ class Register extends Controller {
}
if(intval(get_config('system','register_policy')) == REGISTER_APPROVE) {
- $registration_is = t('Registration on this hub is by approval only.');
- $other_sites = t('<a href="pubsites">Register at another affiliated hub.</a>');
+ $registration_is = t('Registration on this hub is by approval only.') . '<sup>ZAR0131I</sup>';
+ $other_sites = '<a href="pubsites">' . t('Register at another affiliated hub in case when prefered') . '</a>';
}
+ if ( !get_config('system', 'register_duty_jso') ) {
+ // duty yet not configured
+ $duty = array( 'isduty' => false, 'atfrm' => '', 'nowfmt' => '');
+ } else {
+ $duty = zar_register_dutystate();
+ }
$invitations = false;
-
if(intval(get_config('system','invitation_only'))) {
$invitations = true;
- $registration_is = t('Registration on this hub is by invitation only.');
- $other_sites = t('<a href="pubsites">Register at another affiliated hub.</a>');
- }
-
- $max_dailies = intval(get_config('system','max_daily_registrations'));
- if($max_dailies) {
- $r = q("select count(account_id) as total from account where account_created > %s - INTERVAL %s",
- db_utcnow(), db_quoteinterval('1 day')
- );
- if($r && $r[0]['total'] >= $max_dailies) {
- logger('max daily registrations exceeded.');
- notice( t('This site has exceeded the number of allowed daily account registrations. Please try again tomorrow.') . EOL);
- return;
- }
+ $registration_is = t('Registration on this hub is by invitation only.') . '<sup>ZAR0132I</sup>';
+ $other_sites = '<a href="pubsites">' . t('Register at another affiliated hub') . '</a>';
+ } elseif (intval(get_config('system','invitation_also'))) {
+ $invitations = true;
}
+ if ( self::check_max_daily_exceeded() )
+ $duty['atform'] = 'disabled';
+
$privacy_role = ((x($_REQUEST,'permissions_role')) ? $_REQUEST['permissions_role'] : "");
$perm_roles = \Zotlabs\Access\PermissionRoles::roles();
// Configurable terms of service link
-
$tosurl = get_config('system','tos_url');
if(! $tosurl)
$tosurl = z_root() . '/help/TermsOfService';
@@ -254,16 +451,35 @@ class Register extends Controller {
$enable_tos = 1 - intval(get_config('system','no_termsofservice'));
- $email = array('email', t('Your email address'), ((x($_REQUEST,'email')) ? strip_tags(trim($_REQUEST['email'])) : ""));
+ $emailval = ((x($_REQUEST,'email')) ? strip_tags(trim($_REQUEST['email'])) : "");
+ $email = array('email',
+ t('Your email address (or leave blank to register without email)') . ' <sup>ZAR0136I</sup>',
+ $emailval,
+ t('If the registation was already submitted with your data once ago, enter your identity (like email) here and submit') . '<sup>ZAR0133I</sup>'
+ );
+
$password = array('password', t('Choose a password'), '');
$password2 = array('password2', t('Please re-enter your password'), '');
+
$invite_code = array('invite_code', t('Please enter your invitation code'), ((x($_REQUEST,'invite_code')) ? strip_tags(trim($_REQUEST['invite_code'])) : ""));
- $name = array('name', t('Your Name'), ((x($_REQUEST,'name')) ? $_REQUEST['name'] : ''), t('Real names are preferred.'));
+
+ //
+ $name = array('name', t('Your Name'),
+ ((x($_REQUEST,'name')) ? $_REQUEST['name'] : ''), t('Real names are preferred.'));
$nickhub = '@' . str_replace(array('http://','https://','/'), '', get_config('system','baseurl'));
- $nickname = array('nickname', t('Choose a short nickname'), ((x($_REQUEST,'nickname')) ? $_REQUEST['nickname'] : ''), sprintf( t('Your nickname will be used to create an easy to remember channel address e.g. nickname%s'), $nickhub));
- $role = array('permissions_role' , t('Channel role and privacy'), ($privacy_role) ? $privacy_role : 'social', t('Select a channel permission role for your usage needs and privacy requirements.') . ' <a href="help/member/member_guide#Channel_Permission_Roles" target="_blank">' . t('Read more about channel permission roles') . '</a>',$perm_roles);
- $tos = array('tos', $label_tos, '', '', array(t('no'),t('yes')));
+ $nickname = array('nickname', t('Choose a short nickname'),
+ ((x($_REQUEST,'nickname')) ? $_REQUEST['nickname'] : ''),
+ sprintf( t('Your nickname will be used to create an easy to remember channel address e.g. nickname%s'),
+ $nickhub));
+ $role = array('permissions_role' , t('Channel role and privacy'),
+ ($privacy_role) ? $privacy_role : 'social',
+ t('Select a channel permission role for your usage needs and privacy requirements.')
+ . ' <a href="help/member/member_guide#Channel_Permission_Roles" target="_blank">'
+ . t('Read more about channel permission roles')
+ . '</a>',$perm_roles);
+ //
+ $tos = array('tos', $label_tos, '', '', array(t('no'),t('yes')));
$auto_create = (get_config('system','auto_channel_create') ? true : false);
$default_role = get_config('system','default_permissions_role');
@@ -280,6 +496,9 @@ class Register extends Controller {
'$other_sites' => $other_sites,
'$invitations' => $invitations,
'$invite_code' => $invite_code,
+ '$haveivc' => t('I have an invite code') . '.<sup>ZAR0134I</sup>',
+ '$now' => $duty['nowfmt'],
+ '$atform' => $duty['atform'],
'$auto_create' => $auto_create,
'$name' => $name,
'$role' => $role,
@@ -288,15 +507,40 @@ class Register extends Controller {
'$enable_tos' => $enable_tos,
'$tos' => $tos,
'$email' => $email,
+ '$validate' => $validate,
+ '$validate_link'=> $validate_link,
+ '$validate_here'=> $validate_here,
'$pass1' => $password,
'$pass2' => $password2,
'$submit' => t('Register'),
- '$verify_note' => (($email_verify) ? t('This site requires email verification. After completing this form, please check your email for further instructions.') : ''),
+ '$verify_note' => (($email_verify) ? t('This site requires verification. After completing this form, please check the notice or your email for further instructions.') . '<sup>ZAR0135I</sup>' : ''),
));
return $o;
-
}
-
-
+
+ function check_max_daily_exceeded() {
+ // check against register, account
+ $max_dailies = intval(get_config('system','max_daily_registrations'));
+ if ( $max_dailies ) {
+ $r = q("SELECT COUNT(reg_id) AS nr FROM register WHERE reg_vital = 1 AND reg_created > %s - INTERVAL %s",
+ db_utcnow(), db_quoteinterval('1 day')
+ );
+ $re = ( $r && $r[0]['nr'] >= $max_dailies ) ? true : false;
+ if ( !$re ) {
+ $r = q("SELECT COUNT(account_id) AS nr FROM account WHERE account_created > %s - INTERVAL %s",
+ db_utcnow(), db_quoteinterval('1 day')
+ );
+ $re = ( $r && $r[0]['nr'] >= $max_dailies ) ? true : false;
+ }
+ if ( $re ) {
+ zar_log('ZAR0333W max daily registrations exceeded.');
+ notice( 'ZAR0333W '
+ . t('This site has exceeded the number of allowed daily account registrations. Please try again tomorrow.')
+ . EOL);
+ return true;
+ }
+ }
+ return false;
+ }
}
diff --git a/Zotlabs/Module/Settings/Account.php b/Zotlabs/Module/Settings/Account.php
index b40f516ca..97cc9389a 100644
--- a/Zotlabs/Module/Settings/Account.php
+++ b/Zotlabs/Module/Settings/Account.php
@@ -15,20 +15,23 @@ class Account {
$account = \App::get_account();
if($email != $account['account_email']) {
- if(! validate_email($email))
- $errs[] = t('Not valid email.');
- $adm = trim(get_config('system','admin_email'));
- if(($adm) && (strcasecmp($email,$adm) == 0)) {
- $errs[] = t('Protected email address. Cannot change to that email.');
- $email = \App::$account['account_email'];
- }
- if(! $errs) {
- $r = q("update account set account_email = '%s' where account_id = %d",
- dbesc($email),
- intval($account['account_id'])
- );
- if(! $r)
- $errs[] = t('System failure storing new email. Please try again.');
+ // a DId2 not an email addr does not allow to change to email addr
+ if (strpos($email, '@') > 0) {
+ if(! validate_email($email))
+ $errs[] = t('Not valid email.');
+ $adm = trim(get_config('system','admin_email'));
+ if(($adm) && (strcasecmp($email,$adm) == 0)) {
+ $errs[] = t('Protected email address. Cannot change to that email.');
+ $email = \App::$account['account_email'];
+ }
+ if(! $errs) {
+ $r = q("update account set account_email = '%s' where account_id = %d",
+ dbesc($email),
+ intval($account['account_id'])
+ );
+ if(! $r)
+ $errs[] = t('System failure storing new email. Please try again.');
+ }
}
}
@@ -92,6 +95,7 @@ class Account {
call_hooks('account_settings', $account_settings);
$email = \App::$account['account_email'];
+ $attremail = (!strpos($email, '@')) ? 'disabled="disabled"' : '';
$tpl = get_markup_template("settings_account.tpl");
$o .= replace_macros($tpl, array(
@@ -101,7 +105,7 @@ class Account {
'$password1'=> array('npassword', t('Enter New Password'), '', ''),
'$password2'=> array('confirm', t('Confirm New Password'), '', t('Leave password fields blank unless changing')),
'$submit' => t('Submit'),
- '$email' => array('email', t('Email Address:'), $email, ''),
+ '$email' => array('email', t('DId2 or Email Address:'), $email, '', '', $attremail),
'$removeme' => t('Remove Account'),
'$removeaccount' => t('Remove this account including all its channels'),
'$account_settings' => $account_settings