<?php if (!defined('PmWiki')) exit();

/*	=== UserAdmin-Profiles ===
 *	Copyright 2010 Eemeli Aro <eemeli@gmail.com>
 *
 *	AuthUser account self-registration and management using profile pages
 *
 *	For more information, please see the online documentation at
 *		http://www.pmwiki.org/wiki/Cookbook/UserAdmin
 *
 *
 *  This script is free software: you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation, either version 3 of the License, or
 *  (at your option) any later version.
 *
 *  This script is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

$RecipeInfo['UserAdmin-Profiles']['Version'] = '2010-06-14';


if (!IsEnabled($EnableAuthorTracking,1)) Abort('$EnableAuthorTracking required for UserAdmin-Profiles');


SDV($AuthUserFunctions['userprofilegroup'], 'AuthUserProfiles');
function AuthUserProfiles($pagename, $id, $pw, $pwlist/*, &$authlist*/) {
	foreach ((array)$pwlist as $pgroup) {
		$pn = MakePageName($pagename, "$pgroup.$id");
		$page = ReadPage($pn, READPAGE_CURRENT);
		if ($page
			&& !empty($page['username'])
			&& ($id == $page['username'])
			&& !empty($page['userpwhash'])
			&& (_crypt($pw, $page['userpwhash']) == $page['userpwhash'])
		) {
			//if (!empty($page['usergroups']) && preg_match_all('/@[^,\s]+/', $page['usergroups'], $m))
			//	foreach ($m[0] as $g) $authlist[$g] = 1;
			return true;
		}
	}
	return false;
}


if (strncmp($action, 'user', 4)) return;


require_once('useradmin-core.php');


class UserAdminProfiles extends UserAdmin {
	var $pgroup = 'Profiles';
	var $username_chars = '[:alnum:]';
	var $username_denied = 'HomePage|SideBar|(Group(Print)?(Attributes|Header|Footer))';


	####################################################################################################################
	##                                                                                           implementation-specific

	function ProfilePageName($username) {
		return MakePageName("{$this->pgroup}.{$this->pgroup}", "{$this->pgroup}.$username");
	}

	## array of pages with user data; also PCaches all user pages
	function UserPages() {
		static $ls = array();
		if (!$ls) foreach(ListPages("/^{$this->pgroup}./") as $pn) {
			$page = RetrieveAuthPage($pn, 'read', FALSE, READPAGE_CURRENT);
			if (!$page || empty($page['username'])) continue;
			PCache($pn, $page);
			$ls[] = $pn;
		}
		return $ls;
	}


	####################################################################################################################
	##                                                                                                read & write users

	function ReadUser($username) {
		global $PCache;
		if (!$username) return array();
		$pn = $this->ProfilePageName($username);
		if (empty($PCache[$pn])) {
			$page = ReadPage($pn, READPAGE_CURRENT);
			PCache($pn, $page);
		} else $page = &$PCache[$pn];
		$data = preg_grep_keys('/^user(?!groups)/', $page);
		return $data;
		//$uap_data = parent::ReadUser($username);
		//if (isset($data['usergroups']) && !empty($uap_data['usergroups'])) $data['usergroups'] .= " {$uap_data['usergroups']}";
		//return $data + parent::ReadUser($username);
	}

	function WriteUser($username, $data, $csum='', $auth='read') {
		global $Now, $EditFunctions, $IsPagePosted;
		$pn = $this->ProfilePageName($username);
		$data = preg_grep_keys('/^user/', $data);
		Lock(2);
			$page = RetrieveAuthPage($pn, $auth, TRUE);
			if (!$page) Abort("?cannot write to $pn"); 
			$new = $page;
			foreach((array)$data as $k => $v) {
				if ($v) $new[$k] = $v;
				else unset($new[$k]);
			}
			$new['csum'] = $csum;
			if ($csum) $new["csum:$Now"] = $csum;
			PCache($pn, $new);
			$k = array_search('SaveAttributes', $EditFunctions);
			if ($k !== FALSE) unset($EditFunctions[$k]);
			UpdatePage($pn, $page, $new);
		Lock(0);
		return $IsPagePosted;
	}


	####################################################################################################################
	##                                                                                                overloaded methods

	function UserName($pagename, $opt) {
		$n = parent::UserName($pagename, $opt);
		if ($n) return $n;
		if (!empty($opt['username'])) return FALSE;
		$page = ReadPage($pagename, READPAGE_CURRENT);
		PCache($pagename, $page);
		return empty($page['username']) ? FALSE : $page['username'];
	}

	function Superuser($pagename, $prompt=FALSE) {
		if (!empty($this->input['username'])) $pagename = $this->ProfilePageName($this->input['username']);
		return (boolean)RetrieveAuthPage($pagename, 'attr', $prompt, READPAGE_CURRENT);
	}

	function ListUsers($pat=NULL, $inc_uap=FALSE) {
		global $PCache;
		$ls = array();
		foreach($this->UserPages() as $pn) $ls[] = $PCache[$pn]['username'];
		$ls = MatchPageNames($ls, $pat);
		if ($inc_uap) $ls = array_unique(array_merge($ls, parent::ListUsers($pat)));
		return $ls;
	}

	function ValidName(&$username) {
		$username = preg_replace("/[^{$this->username_chars}]+/", '', $username);
		if (!$username) return FALSE;

		return !preg_match("/\.({$this->username_denied}|{$this->pgroup})$/", $this->ProfilePageName($username));
	}

	function MakeUserLink($username, $useraction = '', $opt = array()) {
		$pn = $this->ProfilePageName($username);
		$action = $useraction ? 'user/'.urlencode($useraction) : 'user';
		$url = FmtPageName("\$PageUrl?action=$action", $pn);
		foreach ($opt as $k => $v) $url .= '&'.urlencode($k).'='.urlencode($v);
		return $url;
	}
}

SDV($UserAdmin, new UserAdminProfiles());