Advertisement:

Navigation

Readme

This MOD adds an invite system to SMF. Users get invite credits which they can use to invite people to the forum, and showing who invited whom. The forum can also be set to only accept registrations through invitations, meaning that you need to be invited to join.

Admin options are in "Features and Options" -> "Invite", and "Manage Permissions".

As always, I'm open to feedback and improvement ideas.


Changelog:

1.14 (May 15, 2007)
- Fixed incompatibility with older MySQL version in db.php.
- Improved compatibility with other mods that also change the permissions.

1.13 (Mar 21, 2007)
- Added "Invited By" edit box on the Account Related Settings, so the admin can easily set the inviter of a member.
- Fixed unlimited credits permission being available as a guest permission.

1.12 (Mar 13, 2007)
- Changed how the mod works when "invitation only" isn't set; instead of invite keys, an inviter can use the same link several times.
- Added permission to grant membergroups unlimited credits.
- Fixed the top_inviter() function for block code so it sorts the inviters properly.

1.11 (Mar 10, 2007)
- Fixed uninitialised array from 1.10.

1.10 (Mar 10, 2007)
- Added Stats.
- Added option to disable mailing feature.
- Increased compatibility with other mods that also add a new menu button.

1.09 (Mar 08, 2007)
- Moved the invitees list to the member list page instead, so it looks the same as the regular member list.
- In the profile summary, added "Members Invited" count and removed the old link at the bottom.

1.08 (Mar 06, 2007)
- [Invite.php] Fixed two undefined globals, caused when I moved stuff around for 1.06.
- [Invite.php] Fixed a bug that incorrectly calculated the credits based on the admin's registration date instead of the user's.

1.07 (Mar 06, 2007)
- [Invite.php] Fixed undefined variable notice.

1.06 (Mar 05, 2007)
- Moved it from the profile to it's own page with it's own menu link.
- Added mailing feature.
- Further reduced the number of changes made to the SMF code.
- Other minor stuff I don't remember.

1.05 (Mar 05, 2007)
- Removed text that said the forum only accepted invitations through invitation even when that wasn't true.
- Increased compatibility with other mods that also change the profile summary page's "Additional Information" area (notably "Show Topics").
- Reduced the number of changes made to the SMF code.

1.04 (Mar 04, 2007)
- Fixed bug that didn't set the inviter and caused a undefined variable notice (caused by renaming a variable and good ol' copy+paste).

1.03 (Mar 01, 2007)
- Added input field on the registration "invitation only" page so the invite key can be entered manually.
- Fixed undefined index notice in Register.php when invite_key is not set.
- Fixed bug that displayed deleted members in the invitees list.

1.02 (Feb 20, 2007)
- Security improvement.
- Minor SMF-conformity fixes.

1.01 (Feb 02, 2007)
- Fixed bug that didn't send the invite key properly to the registration template.
- Fixed bug that still displayed used keys in the invite screen if keys were set to not expire.

1.00 (Jan 30, 2007)
- Initial release.

File Edits

./index.php

Find: [Select]

'jsoption' => array('Themes.php', 'SetJavaScript'),
Add Before: [Select]

'invite' => array('Invite.php', 'InviteMain'),

./Sources/ModSettings.php

Find: [Select]

$context['sub_template'] = 'show_settings';

$subActions = array(
Add After: [Select]
'invite' => 'ModifyInviteSettings',

Find: [Select]

require_once($sourcedir . '/ManageServer.php');

$subActions = array(
Add After: [Select]
'invite' => 'ModifyInviteSettings',

Find: [Select]

'layout' => array(
'title' => $txt['mods_cat_layout'],
'href' => $scripturl . '?action=featuresettings;sa=layout;sesc=' . $context['session_id'],
),
Add After: [Select]

'invite' => array(
'title' => $txt['invite_title'],
'href' => $scripturl . '?action=featuresettings;sa=invite;sesc=' . $context['session_id'],
),

Find: [Select]

function ModifyKarmaSettings()
Add Before: [Select]

// Invite MOD
function ModifyInviteSettings()
{
global $sourcedir;
require_once($sourcedir . '/Invite.php');
InviteSettings();
}


./Sources/ManagePermissions.php

Find: [Select]

$groupLevels['global']['restrict'] = array(
Add After: [Select]
'invitees_any',

Find: [Select]

$groupLevels['global']['standard'] = array_merge($groupLevels['global']['restrict'], array(
Add After: [Select]
'invite',
'invite_unlimited',
'invitees_own',

Find: [Select]

$context['permissions'] = array();
Add Before: [Select]
// Invite MOD.
$permissionList['membergroup']['invite'] = array(
'invite' => false,
'invite_unlimited' => false,
'invitees' => true,
);

$non_guest_permissions[] = 'invite';
$non_guest_permissions[] = 'invite_unlimited';
// End Invite MOD.


./Sources/Register.php

Find: [Select]

// Check if the administrator has it disabled.
if (!empty($modSettings['registration_method']) && $modSettings['registration_method'] == 3)
fatal_lang_error('registration_disabled', false);

Add After: [Select]

// Invite MOD; check if we're only accepting invites, and if so check for a valid invite key.
global $sourcedir;
require_once($sourcedir . '/Invite.php');
$context['invite_key'] = validateInviteKey(empty($_REQUEST['invite_key']) ? '' : $_REQUEST['invite_key'], !empty($modSettings['invite_only']));


Find: [Select]

// You can't register if it's disabled.
if (!empty($modSettings['registration_method']) && $modSettings['registration_method'] == 3)
fatal_lang_error('registration_disabled', false);

Add After: [Select]

// Invite MOD; check if we're only accepting invites, and if so check for a valid invite key.
global $sourcedir;
require_once($sourcedir . '/Invite.php');
$context['invite_key'] = validateInviteKey(empty($_REQUEST['invite_key']) ? '' : $_REQUEST['invite_key'], !empty($modSettings['invite_only']));


Find: [Select]

$memberID = registerMember($regOptions);
Add After: [Select]


// Invite MOD; looks like registration went ok, let's mark the invite key as used and who it was used by.
if ($context['invite_key'] !== false)
{
db_query("
UPDATE {$db_prefix}invites
SET ID_REGISTRATION = '$memberID'
WHERE inviteKey = '{$context['invite_key']}'
LIMIT 1", __FILE__, __LINE__);
}
elseif (!empty($_REQUEST['inviter']) && (int)$_REQUEST['inviter'] !== 0)
{
db_query("
INSERT INTO {$db_prefix}invites (ID_MEMBER, ID_REGISTRATION, inviteTime)
VALUES ('" . (int)$_REQUEST['inviter'] . "', '$memberID', " . time() . ")
", __FILE__, __LINE__);
}

./Sources/Memberlist.php

Find: [Select]

// They're searching..
if (isset($_REQUEST['search']) && isset($_REQUEST['fields']))
Replace With: [Select]

// Invite MOD. Not really a user search, just using the fine table and such that's already here for the invitees list...
if (isset($_REQUEST['inviter']) && loadMemberData(array($_REQUEST['inviter'])))
{
global $user_profile;

if (($_REQUEST['inviter'] == $context['user']['id'] && !allowedTo('invitees_own')) || !allowedTo('invitees_any'))
fatal_lang_error('invitees_any', false);

// Just to let the members know it's not really a search.
$context['page_title'] = $txt['invited_by'] . ' ' . $user_profile[$_REQUEST['inviter']]['realName'];
$context['sort_links'][1]['label'] = $context['page_title'];

// We need this so it thinks it's a regular search and won't be all bitchy about variables...
$context['old_search'] = '';
$context['old_search_value'] = '';

// Find the number of results.
$request = db_query("
SELECT COUNT(*)
FROM {$db_prefix}members AS mem
LEFT JOIN {$db_prefix}invites AS inv ON (inv.ID_REGISTRATION = mem.ID_MEMBER)
WHERE inv.ID_MEMBER = $_REQUEST[inviter]
AND is_activated = 1", __FILE__, __LINE__);
list ($numResults) = mysql_fetch_row($request);
mysql_free_result($request);

$context['page_index'] = constructPageIndex($scripturl . '?action=mlist;sa=search;inviter=' . $_GET['inviter'], $_REQUEST['start'], $numResults, $modSettings['defaultMaxMembers']);

// Find the members from the database.
// !!!SLOW This query is slow.
$request = db_query("
SELECT mem.ID_MEMBER
FROM {$db_prefix}members AS mem
LEFT JOIN {$db_prefix}invites AS inv ON (inv.ID_REGISTRATION = mem.ID_MEMBER)
LEFT JOIN {$db_prefix}log_online AS lo ON (lo.ID_MEMBER = mem.ID_MEMBER)
LEFT JOIN {$db_prefix}membergroups AS mg ON (mg.ID_GROUP = IF(mem.ID_GROUP = 0, mem.ID_POST_GROUP, mem.ID_GROUP))
WHERE inv.ID_MEMBER = $_REQUEST[inviter]
AND is_activated = 1
LIMIT $_REQUEST[start], $modSettings[defaultMaxMembers]", __FILE__, __LINE__);
printMemberListRows($request);
mysql_free_result($request);
} // End Invite MOD.
// They're really doing a search.
elseif (isset($_REQUEST['search']) && isset($_REQUEST['fields']))

./Sources/Stats.php

Find: [Select]

// Activity by month.
Add Before: [Select]

// Invite MOD. Top 10 Inviters.
global $sourcedir;
require_once($sourcedir . '/Invite.php');
InviteStats();
// End Invite MOD.


./Sources/Profile.php

Find: [Select]

// This block is only concerned with email address validation..
Add Before: [Select]

// Invite MOD. Change the number of inviter.
if (!empty($_POST['inviter']) && (int)$_POST['inviter'] != 0 && (int)$_POST['inviter'] != $memID && allowedTo('moderate_forum'))
{
global $sourcedir;
require_once($sourcedir . '/Invite.php');

if (inviter($memID))
db_query("
UPDATE {$db_prefix}invites SET ID_MEMBER = {$_POST['inviter']}
WHERE ID_REGISTRATION = $memID
LIMIT 1", __FILE__, __LINE__);
else
db_query("
INSERT INTO {$db_prefix}invites (ID_MEMBER, ID_REGISTRATION)
VALUES ({$_POST['inviter']}, $memID)", __FILE__, __LINE__);
}
elseif (isset($_POST['inviter']) && empty($_POST['inviter']))
{
db_query("
DELETE FROM {$db_prefix}invites
WHERE ID_REGISTRATION = $memID
LIMIT 1", __FILE__, __LINE__);
}


./Themes/default/index.template.php

Find: [Select]
)))
$current_action = $context['current_action'];
Add Before: [Select]
, 'invite'
Find: [Select]

// If the user is a guest, show [login] button.
Add Before: [Select]

// Invite MOD.
if (allowedTo('invite'))
{
global $modSettings;
echo ($current_action == 'invite' || $context['browser']['is_ie4']) ? '<td class="maintab_active_' . $first . '">&nbsp;</td>' : '' , '
<td valign="top" class="maintab_' , $current_action == 'invite' ? 'active_back' : 'back' , '">
<a href="', $scripturl, '?action=invite">' , (!empty($modSettings['invite_menu_title']) ? $modSettings['invite_menu_title'] : $txt['invite_title']) , '</a>
</td>' , $current_action == 'invite' ? '<td class="maintab_active_' . $last . '">&nbsp;</td>' : '';
}


./Themes/default/Profile.template.php

Find: [Select]

<td>', $context['member']['registered'], '</td>
</tr><tr>
<td><b>', $txt['lastLoggedIn'], ': </b></td>
Replace With: [Select]

<td>', $context['member']['registered'], '</td>
</tr>';

// Invite MOD.
global $sourcedir;
require_once($sourcedir . '/Invite.php');
if (($context['user']['is_owner'] && allowedTo('invitees_own')) || allowedTo('invitees_any'))
{
if (inviter($context['member']['id']))
echo '
<tr>
<td><b>', $txt['invited_by'], ': </b></td>
<td><a href="', $scripturl, '?action=profile;u=', $context['member']['invited_by'], '">', $context['member']['invited_by_name'], '</a></td>
</tr>';

if ($context['member']['invitees_count'] = invitees($context['member']['id']))
echo '
<tr>
<td><b>', $txt['invitees_count'], ': </b></td>
<td><a href="', $scripturl, '?action=mlist;sa=search;inviter=', $context['member']['id'], '">', $context['member']['invitees_count'], '</a></td>
</tr>';
}
// End Invite MOD.

echo '
<tr>
<td><b>', $txt['lastLoggedIn'], ': </b></td>

Find: [Select]

// Only display if admin has enabled "user selectable language".
Add Before: [Select]

// Invite MOD. Allow the administrator to change the inviter.
if ($context['user']['is_admin'])
{
global $sourcedir;
require_once($sourcedir . '/Invite.php');
echo '
<tr>
<td><b>', $txt['invited_by'], ' (ID): </b></td>
<td><input type="text" name="inviter" size="4" value="', inviter($context['member']['id']), '" /></td>
</tr>';
}


./Themes/default/Stats.template.php

Find: [Select]

</tr><tr>
<td class="catbg" colspan="4"><b>', $txt['smf_stats_5'], '</b></td>
Replace With: [Select]

</tr><tr>
<td class="catbg" colspan="2" width="50%"><b>', $txt['top_inviters'], '</b></td>
<td class="catbg" colspan="2" width="50%"><b>', $txt['top_inviters_by_posts'], '</b></td>
</tr><tr>
<td class="windowbg" width="20" valign="middle" align="center"><img src="', $settings['images_url'], '/stats_posters.gif" width="20" height="20" alt="" /></td>
<td class="windowbg2" width="50%" valign="top">
<table border="0" cellpadding="1" cellspacing="0" width="100%">';
foreach ($context['top_inviters'] as $inviter)
echo '
<tr>
<td width="60%" valign="top">', $inviter['link'], '</td>
<td width="20%" align="left" valign="top">', $inviter['num'] > 0 ? '<img src="' . $settings['images_url'] . '/bar.gif" width="' . $inviter['percent'] . '" height="15" alt="" />' : '&nbsp;', '</td>
<td width="20%" align="right" valign="top">', $inviter['num'], '</td>
</tr>';
echo '
</table>
</td>
<td class="windowbg" width="20" valign="middle" align="center" nowrap="nowrap"><img src="', $settings['images_url'], '/stats_posters.gif" width="20" height="20" alt="" /></td>
<td class="windowbg2" width="50%" valign="top">
<table border="0" cellpadding="1" cellspacing="0" width="100%">';
foreach ($context['top_inviters_by_posts'] as $inviter)
echo '
<tr>
<td width="60%" valign="top">', $inviter['link'], '</td>
<td width="20%" align="left" valign="top">', $inviter['num'] > 0 ? '<img src="' . $settings['images_url'] . '/bar.gif" width="' . $inviter['percent'] . '" height="15" alt="" />' : '&nbsp;', '</td>
<td width="20%" align="right" valign="top">', $inviter['num'], '</td>
</tr>';
echo '
</table>
</td>
</tr><tr>
<td class="catbg" colspan="4"><b>', $txt['smf_stats_5'], '</b></td>

./Themes/default/Register.template.php

Find: [Select]

echo '
<br />
<div align="center">
<input type="submit" name="regSubmit" value="', $txt[97], '" />
</div>
Add Before: [Select]

// Invite MOD
if (!empty($context['invite_key']))
echo '
<input type="hidden" name="invite_key" value="', $context['invite_key'], '" />';
elseif (!empty($_REQUEST['inviter']) && (int)$_REQUEST['inviter'] !== 0)
echo '
<input type="hidden" name="inviter" value="', $_REQUEST['inviter'], '" />';


./Themes/default/languages/Modifications.english.php

Find: [Select]

?>
Add Before: [Select]


// Invite MOD.
$txt['invite_title'] = 'Invite';
$txt['invite_only'] = 'Only allow registrations through invitation.';
$txt['invite_menu_title'] = 'Invite menu title.';
$txt['invite_days'] = 'Number of days for members to get a new invite credit.<div class="smalltext">(0 for no limit, admins are exempt)</div>';
$txt['invite_max'] = 'Max number of invite credits.<div class="smalltext">(0 for no limit, admins are exempt)</div>';
$txt['invite_expire'] = 'Number of days for an invite key to be valid.<div class="smalltext">(0 for no limit)</div>';
$txt['invite_group_settings'] = 'Set group permission for sending invites';

$txt['invite_email_disable'] = 'Disable mailing feature.';
$txt['invite_email_subject'] = 'E-mail subject.';
$txt['invite_email_message'] = 'E-mail message.
<div class="smalltext">{invitee} = Recipient\'s name</div>
<div class="smalltext">{inviter} = Inviter\'s memebername</div>
<div class="smalltext">{forum} = Forum name</div>
<div class="smalltext">{link} = Link to registration page (with key)</div>
<div class="smalltext">{message} = Message by inviter</div>';
$txt['invite_default_email_subject'] = '{invitee}, you have received an invitation to {forum} by {inviter}!';
$txt['invite_default_email_message'] = 'Hi {invitee},

You have received an invitation to {forum}, click the following link to register:

{link}

{inviter} also sent this comment to you:

{message}


This message is not spam.';

$txt['invite_someone'] = 'Invite someone';
$txt['invite_info'] = 'You can invite someone new if you have invite credits by making a new key and sending them the link.';
$txt['invite_link'] = 'You can invite someone new by sending them the following link.';
$txt['invitees'] = 'Invitees';
$txt['invitees_info'] = 'The following list which members you have invited.';
$txt['no_invitees'] = 'There are no invitees to display';
$txt['invite_unlimited'] = 'unlimited';
$txt['invite_max_reached'] = 'max reached';
$txt['make_new_invite_key'] = 'Make new invite key';
$txt['invite_credits'] = 'Invite credits';
$txt['next_invite_credit'] = 'Next credit';
$txt['invite_key'] = 'Invite Key';
$txt['invite_email'] = 'Invitation E-mail';
$txt['invite_send_email'] = 'Send invitation e-mail';
$txt['invite_expires'] = 'Expires';
$txt['invited_by'] = 'Invited by';
$txt['invitees_count'] = 'Members invited';
$txt['show_invitees'] = 'Show members invited by this person';


$txt['invite_email_info'] = 'Enter the name and email of the person you wish to invite, and the invite link will be sent to them.';
$txt['invite_recipient_name'] = 'Recipient\'s name';
$txt['invite_recipient_email'] = 'Recipient\'s e-mail';
$txt['invite_message'] = 'Personal message to recipient';
$txt['invite_sent'] = 'The invitation has been sent.';

$txt['invite_no_name'] = 'You did not enter a name.';
$txt['invite_no_email'] = 'You did not enter a valid e-mail address.';
$txt['cannot_send_invite'] = 'Sorry, the invite key could not be sent (already sent maybe?).';

$txt['permissiongroup_invite'] = 'Invite';
$txt['permissionname_invite'] = 'Invite';
$txt['permissionhelp_invite'] = 'When the forum is set to accept registrations by invitation only, this permission will allow a membergroup to invite people to the forum so they can register.';
$txt['permissionname_invite_unlimited'] = 'Unlimted invite credits';
$txt['permissionhelp_invite_unlimited'] = 'When the forum is set to accept registrations by invitation only, this permission will allow a membergroup to have unlimited invite credits.';
$txt['permissionname_invitees'] = 'View invitees';
$txt['permissionhelp_invitees'] = 'This will show a list of members that the user has invited to the forum using the Invite MOD.';
$txt['permissionname_invitees_own'] = 'Own invitees';
$txt['permissionname_invitees_any'] = 'Any invitees';

$txt['cannot_invite'] = 'Sorry, you\'re not allowed to send invitations.';
$txt['cannot_invite_as_other'] = 'Sorry, you can\'t send invitations as someone else.';
$txt['cannot_invitees_any'] = 'Sorry, you\'re not allowed to view this member\'s invitees.';
$txt['registration_invite_only'] = 'Sorry, registration is by invitation only.<br /><br />If you have a valid invite key enter it below:<br /><form method="POST" action="index.php?action=register"><input type="text" name="invite_key" size="40"> <input type="submit" value="Register"></form>';
$txt['registration_invite_expired'] = 'Sorry, the invite key has expired.';

$txt['top_inviters'] = 'Top Inviters (by Invitees)';
$txt['top_inviters_by_posts'] = 'Top Inviters (by Invitees\' Posts)';
// End Invite MOD.


Code

db.php

This file should not be able to execute standalone. You may have to run the following queries manually.

Query: [Select]
CREATE TABLE IF NOT EXISTS {$db_prefix}invites (
ID_INVITE mediumint(8) unsigned NOT NULL auto_increment,
ID_MEMBER mediumint(8) unsigned NOT NULL default '0',
ID_REGISTRATION mediumint(8) unsigned NOT NULL default '0',
inviteTime int(10) unsigned NOT NULL default '0',
inviteKey varchar(64) NOT NULL default '',
PRIMARY KEY (ID_INVITE),
KEY ID_MEMBER (ID_MEMBER),
KEY inviteTime (inviteTime),
KEY inviteKey (inviteKey)
)
Query: [Select]

SHOW COLUMNS
FROM {$db_prefix}invites
Query: [Select]
ALTER TABLE {$db_prefix}invites ADD inviteEmail TINYTEXT NOT NULL

File Operations

Move the included file "Invite.php" to "./Sources".
Move the included file "Invite.template.php" to "./Themes/default".