diff --git a/db/patches/V1_6_62_03__multi_accounts.sql b/db/patches/V1_6_62_03__multi_accounts.sql new file mode 100644 index 000000000..2bbd25a1b --- /dev/null +++ b/db/patches/V1_6_62_03__multi_accounts.sql @@ -0,0 +1,14 @@ +-- Rename `account.account_id` to `account.login_id` +ALTER TABLE account CHANGE `account_id` `login_id` smallint(6) unsigned NOT NULL AUTO_INCREMENT; + +-- Add `account_link_login` table +CREATE TABLE account_link_login ( + `account_id` smallint(6) unsigned NOT NULL AUTO_INCREMENT, + `login_id` smallint(6) unsigned NOT NULL, + PRIMARY KEY (`account_id`) +) ENGINE=MyISAM AUTO_INCREMENT=1; + +-- Fill in `account_link_login` from the rows of `account`, +-- setting account_id = login_id. +INSERT INTO account_link_login (account_id, login_id) +SELECT login_id, login_id as account_id FROM account; diff --git a/engine/Default/game_play.php b/engine/Default/game_play.php index 9fdeee033..3b3dd2088 100644 --- a/engine/Default/game_play.php +++ b/engine/Default/game_play.php @@ -8,9 +8,41 @@ $template->assign('Message',$var['msg']); } +// *************************************** +// ** Accounts +// *************************************** + +if (isset($var['switch_account_id'])) { + // Override default account (and do sanity checks) + $account = $account->getLinkedAccount($var['switch_account_id']); + SmrSession::updateAccount($account->getAccountID()); +} + +// Get linked accounts (order the current account first, for simplicity) +$linkedAccounts = $account->getLinkedAccountList(); +if (key($linkedAccounts) != $account->getAccountID()) { + $linkedAccounts = array_reverse($linkedAccounts); +} +$template->assign('AccountLabels', array_values($linkedAccounts)); + +if (count($linkedAccounts) == SmrAccount::MAX_LINKED_ACCOUNTS) { + end($linkedAccounts); + $otherAccountID = key($linkedAccounts); + $switchContainer = create_container('skeleton.php', 'game_play.php'); + $switchContainer['switch_account_id'] = $otherAccountID; +} else { + $switchContainer = create_container('skeleton.php', 'switch_account_create.php'); +} +$template->assign('SwitchAccountHREF', SmrSession::getNewHREF($switchContainer)); + + $template->assign('UserRankingLink',SmrSession::getNewHREF(create_container('skeleton.php', 'rankings_view.php'))); $template->assign('UserRankName',$account->getRankName()); +// *************************************** +// ** Play Game +// *************************************** + $games = array(); $games['Play'] = array(); $game_id_list = array(); diff --git a/engine/Default/switch_account_create.php b/engine/Default/switch_account_create.php new file mode 100644 index 000000000..e9425a5f4 --- /dev/null +++ b/engine/Default/switch_account_create.php @@ -0,0 +1,9 @@ +assign('PageTopic', 'Create Multi Account'); + +$container = create_container('switch_account_create_processing.php'); +$container['action'] = 'Create'; +$template->assign('CreateHREF', SmrSession::getNewHREF($container)); +$container['action'] = 'Link'; +$template->assign('LinkHREF', SmrSession::getNewHREF($container)); diff --git a/engine/Default/switch_account_create_processing.php b/engine/Default/switch_account_create_processing.php new file mode 100644 index 000000000..e48a96797 --- /dev/null +++ b/engine/Default/switch_account_create_processing.php @@ -0,0 +1,41 @@ +getLinkedAccountList()) >= SmrAccount::MAX_LINKED_ACCOUNTS) { + create_error('Cannot create another linked account!'); +} + +if ($var['action'] == 'Create') { + // Create a new multi account + $db->query('INSERT INTO account_link_login (login_id) VALUES ('.$account->getLoginID().')'); + $newAccountID = $db->getInsertID(); + + $container = create_container('skeleton.php', 'game_play.php'); + $container['switch_account_id'] = $newAccountID; + +} elseif ($var['action'] == 'Link') { + $login = $_REQUEST['multi_account_login']; + $password = $_REQUEST['multi_account_password']; + + // Link an existing multi account + $db->query('SELECT login_id FROM account ' . + 'WHERE login = '.$db->escapeString($login).' AND ' . + 'password = '.$db->escapeString(md5($password)).' LIMIT 1'); + if (!$db->nextRecord()) { + create_error('Could not find a matching account. If you believe this is an error, please contact an admin.'); + } + $multiLoginID = $db->getInt('login_id'); + + // Sanity check: multi ID > current ID + if ($multiLoginID <= $account->getLoginID()) { + create_error('Multi account must be newer than main account!'); + } + + // update the account_link_login to reflect the new login association + // For existing accounts login_id == account_id + $db->query('UPDATE account_link_login SET login_id='.$db->escapeNumber($account->getLoginID()).' WHERE account_id='.$db->escapeNumber($multiLoginID)); + + // delete the old login + $db->query('DELETE FROM account WHERE login_id='.$db->escapeNumber($multiLoginID)); + + +} diff --git a/htdocs/login_create.php b/htdocs/login_create.php index ba7fe6669..ce82050bc 100755 --- a/htdocs/login_create.php +++ b/htdocs/login_create.php @@ -31,7 +31,6 @@

Create Login

Creating multiple logins is not allowed. - Click HERE for more information.

diff --git a/htdocs/login_processing.php b/htdocs/login_processing.php index c2d5ef65b..550a87d05 100644 --- a/htdocs/login_processing.php +++ b/htdocs/login_processing.php @@ -75,6 +75,7 @@ } $db->query('SELECT account_id,old_account_id FROM account ' . + 'JOIN account_link_login USING (login_id) ' . 'WHERE login = '.$db->escapeString($login).' AND ' . 'password = '.$db->escapeString(md5($password)).' LIMIT 1'); if ($db->nextRecord()) { diff --git a/lib/Default/AbstractSmrAccount.class.inc b/lib/Default/AbstractSmrAccount.class.inc index e354e4aa1..d21b66bb9 100644 --- a/lib/Default/AbstractSmrAccount.class.inc +++ b/lib/Default/AbstractSmrAccount.class.inc @@ -3,6 +3,8 @@ abstract class AbstractSmrAccount { const USER_RANKINGS_EACH_STAT_POW = .9; const USER_RANKINGS_TOTAL_SCORE_POW = .3; const USER_RANKINGS_RANK_BOUNDARY = 5.2; + const MAX_LINKED_ACCOUNTS = 2; + protected static $USER_RANKINGS_SCORE = array( // [Stat, a, b] // Used as: pow(Stat * a, USER_RANKINGS_EACH_STAT_POW) * b @@ -35,6 +37,7 @@ abstract class AbstractSmrAccount { protected $db; protected $account_id; + protected $login_id; protected $login; protected $password; protected $email; @@ -91,7 +94,7 @@ abstract class AbstractSmrAccount { public static function &getAccountByName($login,$forceUpdate = false) { $db = new SmrMySqlDatabase(); - $db->query('SELECT account_id FROM account WHERE login = '.$db->escapeString($login).' LIMIT 1'); + $db->query('SELECT account_id FROM account JOIN account_link_login USING (login_id) WHERE login = '.$db->escapeString($login).' LIMIT 1'); if($db->nextRecord()) return self::getAccount($db->getField('account_id'),$forceUpdate); $return = null; @@ -110,7 +113,7 @@ abstract class AbstractSmrAccount { public static function &getAccountByHofName($hofName,$forceUpdate = false) { $db = new SmrMySqlDatabase(); - $db->query('SELECT account_id FROM account WHERE hof_name = '.$db->escapeString($hofName).' LIMIT 1'); + $db->query('SELECT account_id FROM account JOIN account_link_login USING (login_id) WHERE hof_name = '.$db->escapeString($hofName).' LIMIT 1'); if($db->nextRecord()) return self::getAccount($db->getField('account_id'),$forceUpdate); $return = null; @@ -119,7 +122,7 @@ abstract class AbstractSmrAccount { public static function getAccountByDiscordId($id, $forceUpdate=false) { $db = new SmrMySqlDatabase(); - $db->query('SELECT account_id FROM account where discord_id = '.$db->escapeString($id).' LIMIT 1'); + $db->query('SELECT account_id FROM account JOIN account_link_login USING (login_id) where discord_id = '.$db->escapeString($id).' LIMIT 1'); if ($db->nextRecord()) { return self::getAccount($db->getField('account_id'), $forceUpdate); } else { @@ -129,7 +132,7 @@ abstract class AbstractSmrAccount { public static function &getAccountByIrcNick($nick, $forceUpdate = false) { $db = new SmrMySqlDatabase(); - $db->query('SELECT account_id FROM account WHERE irc_nick = '.$db->escapeString($nick).' LIMIT 1'); + $db->query('SELECT account_id FROM account JOIN account_link_login USING (login_id) WHERE irc_nick = '.$db->escapeString($nick).' LIMIT 1'); if($db->nextRecord()) return self::getAccount($db->getField('account_id'), $forceUpdate); $return = null; @@ -138,7 +141,7 @@ abstract class AbstractSmrAccount { public static function &findAccountByIrcNick($nick, $forceUpdate = false) { $db = new SmrMySqlDatabase(); - $db->query('SELECT account_id FROM account WHERE irc_nick LIKE '.$db->escapeString($nick).' LIMIT 2'); + $db->query('SELECT account_id FROM account JOIN account_link_login USING (login_id) WHERE irc_nick LIKE '.$db->escapeString($nick).' LIMIT 2'); if($db->getNumRows() > 1) { $return = true; return $return; @@ -181,12 +184,13 @@ abstract class AbstractSmrAccount { function __construct($accountID) { $this->db = new SmrMySqlDatabase(); - $this->db->query('SELECT * FROM account WHERE account_id = '.$this->db->escapeNumber($accountID).' LIMIT 1'); + $this->db->query('SELECT * FROM account JOIN account_link_login USING (login_id) WHERE account_id = '.$this->db->escapeNumber($accountID).' LIMIT 1'); if ($this->db->nextRecord()) { $row = $this->db->getRow(); $this->account_id = $row['account_id']; + $this->login_id = $row['login_id']; $this->login = $row['login']; $this->password = $row['password']; $this->email = $row['email']; @@ -308,7 +312,7 @@ abstract class AbstractSmrAccount { ', friendly_colour = ' . $this->db->escapeString($this->friendlyColour, true, true). ', neutral_colour = ' . $this->db->escapeString($this->neutralColour, true, true). ', enemy_colour = ' . $this->db->escapeString($this->enemyColour, true, true). - ' WHERE account_id = '.$this->db->escapeNumber($this->account_id).' LIMIT 1'); + ' WHERE login_id = '.$this->db->escapeNumber($this->login_id).' LIMIT 1'); $this->hasChanged = false; } @@ -751,6 +755,10 @@ abstract class AbstractSmrAccount { return false; } + public function getLoginID() { + return $this->login_id; + } + public function getLogin() { return $this->login; } @@ -1301,6 +1309,36 @@ abstract class AbstractSmrAccount { public function getPersonalHofHREF() { return SmrSession::getNewHREF(create_container('skeleton.php','hall_of_fame_player_detail.php',array('account_id' => $this->getAccountID()))); } -} + /** + * Return an array of account_ids associated with this login. + * We assume that each login has only MAX_LINKED_ACCOUNTS accounts and + * that the smallest ID (created first) is the primary account_id. + */ + public function getLinkedAccountList() { + $this->db->query('SELECT account_id FROM account_link_login WHERE login_id='.$this->db->escapeNumber($this->getLoginID()).' ORDER BY account_id ASC LIMIT '.$this->db->escapeNumber(self::MAX_LINKED_ACCOUNTS)); + $result = array(); + while ($this->db->nextRecord()) { + $name = count($result) == 0 ? 'Main' : 'Multi'; + $result[$this->db->getInt('account_id')] = $name; + } + return $result; + } + + /** + * Returns another account that is linked to this login. + */ + public function getLinkedAccount($accountID) { + if ($accountID == $this->getAccountID()) { + return $this; + } + $linkedAccounts = $this->getLinkedAccountList(); + if (isset($linkedAccounts[$accountID])) { + return $this::getAccount($accountID); + } else { + throw new Exception('No linked account with ID: ' . $accountID); + } + } + +} ?> diff --git a/lib/Default/SmrSession.class.inc b/lib/Default/SmrSession.class.inc index 89d5cc417..e472305ae 100644 --- a/lib/Default/SmrSession.class.inc +++ b/lib/Default/SmrSession.class.inc @@ -266,6 +266,17 @@ class SmrSession { self::$db->query('UPDATE active_session SET game_id=' . self::$db->escapeNumber(self::$game_id) . ' WHERE session_id=' . self::$db->escapeString(self::$session_id)); } + /** + * Updates the `account_id` attribute of the session. + */ + public static function updateAccount($accountID) { + if (self::$account_id == $accountID) { + return; + } + self::$account_id = $accountID; + self::$db->query('UPDATE active_session SET account_id=' . self::$db->escapeNumber(self::$account_id) . ' WHERE session_id=' . self::$db->escapeString(self::$session_id)); + } + public static function updateSN() { self::$db = new SmrSessionMySqlDatabase(); if(!USING_AJAX) diff --git a/templates/Default/engine/Default/game_play.php b/templates/Default/engine/Default/game_play.php index cb656d5dc..f6513227b 100644 --- a/templates/Default/engine/Default/game_play.php +++ b/templates/Default/engine/Default/game_play.php @@ -6,6 +6,12 @@ echo $Message; ?>

+ +Accounts
+You are on your account. +[Switch to ] +

+ Rankings
You are ranked as doAn($ThisAccount->getRankName()); ?> player.

@@ -133,4 +139,4 @@ else { ?>

There are no previous games.

- \ No newline at end of file + diff --git a/templates/Default/engine/Default/switch_account_create.php b/templates/Default/engine/Default/switch_account_create.php new file mode 100644 index 000000000..01529226a --- /dev/null +++ b/templates/Default/engine/Default/switch_account_create.php @@ -0,0 +1,49 @@ +

Create New Multi Account

+

All players are allowed a second ("multi") account in addition to their +primary ("main") account. It is created only through this interface, so +DO NOT create a second login!

+ +

There are very specific rules about how you can use you multi account. +Click HERE for more information.

+ +

If you have an existing multi account, please link it below instead of +creating a new one.

+ +
+ Create Multi +
+


+ +

Link Existing Multi Account

+ +

If you are logged in on an existing multi account, DO NOT CONTINUE. +Instead, please log into your main account and link your multi account from +there.

+ +

WARNING: When you do this, your multi login +will be deleted. This action cannot be undone! However, your multi account +data will then be associated as the multi of the account you are currently +logged in as.

+ +

If you are at all unsure how to procede, please contact an admin for +assistance.

+ + + + + + + + + + + + + + + + + + +
Enter Existing Account Credentials
Login:
Password:
+