aboutsummaryrefslogtreecommitdiffstats
path: root/Zotlabs/Module/Invite.php
diff options
context:
space:
mode:
Diffstat (limited to 'Zotlabs/Module/Invite.php')
-rw-r--r--Zotlabs/Module/Invite.php599
1 files changed, 497 insertions, 102 deletions
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;
+ }
}
+