Jelajahi Sumber

Registration/activation

Nathaniel van Diepen 9 tahun lalu
induk
melakukan
b2377967ae

+ 2 - 0
config.php

@@ -5,4 +5,6 @@
 	define('DB_PASS','bugs');
 	define('DB','bugs');
 	define('URL_BASE','/bugs/');
+	define('URL_HOST','localhost');
+	define('ADMIN_EMAIL','bugs@localhost');
 ?>

+ 4 - 1
index.php

@@ -16,7 +16,10 @@
 		require_once($filename);
 	}
 	Router::base(URL_BASE);
-	Router::handle(rtrim($_SERVER['REDIRECT_URL'],'/'),null,function($res,$url){
+	if(empty($_SERVER['REDIRECT_URL'])){
+		$_SERVER['REDIRECT_URL'] = 'http://'.URL_HOST.URL_BASE;
+	}
+	Router::handle($_SERVER['REDIRECT_URL'],null,function($res,$url){
 		trigger_error("Not implemented");
 	});
 ?>

+ 45 - 10
lib/bugs.class.php

@@ -30,23 +30,34 @@
 			static::$sql = new SQL($server,$user,$pass,$db);
 		}
 		static function user($id){
-			if(is_string($id)){
-				$user = static::$sql->query("
-					SELECT id
-					FROM users
-					WHERE name = ?;
-				",'s',$id)->assoc_result;
-				if(is_null($user)){
-					trigger_error("User {$id} does not exist");
-				}else{
-					$id = $user['id'];
+			if(func_num_args()==1){
+				if(is_string($id)){
+					$id = Bugs::user_id($id);
+					if(!$id){
+						trigger_error("User {$id} does not exist");
+					}
 				}
+			}else{
+				$id = new User(func_get_arg(0),func_get_arg(1),func_get_arg(2));
+				$id = $id->id;
 			}
 			if(!isset(static::$cache['users'][$id])){
 				static::$cache['users'][$id] = new User($id);
 			}
 			return static::$cache['users'][$id];
 		}
+		static function user_id($name){
+			$user = static::$sql->query("
+				SELECT id
+				FROM users
+				WHERE name = ?;
+			",'s',$name)->assoc_result;
+			if(is_null($user)){
+				return false;
+			}else{
+				return $user['id'];
+			}
+		}
 		static function issue($id){
 			if(!isset(static::$cache['issues'][$id])){
 				static::$cache['issues'][$id] = new Issue($id);
@@ -99,4 +110,28 @@
 			",'is',static::action($action),$description)->execute();
 		}
 	}
+	register_shutdown_function(function(){
+		$emails = Bugs::$sql->query("
+			SELECT	u.email,
+					u_id,
+					e.subject,
+					e.body,
+					e.date_created
+			FROM emails e
+			JOIN users u
+				ON u.id = e.u_id
+			ORDER by e.date_created ASC
+		")->assoc_results;
+		foreach($emails as $email){
+			$status = @mail($email['email'],$email['subject'],$email['body'],"From: ".ADMIN_EMAIL."\r\nMIME-Version: 1.0\r\nContent-type: text/html; charset=iso-8859-1\r\n");
+			if($status){
+				Bugs::$sql->query("
+					DELETE FROM emails
+					WHERE subject = ?
+					AND body = ?
+					AND u_id = ?
+				",'ssi',$email['subject'],$email['body'],$email['u_id'])->execute();
+			}
+		}
+	});
 ?>

+ 1 - 1
lib/errorhandler.php

@@ -1,6 +1,6 @@
 <?php
 	error_reporting(E_ALL);
-	ini_set('display_errors', 'Off');
+	//ini_set('display_errors', 'Off');
 	set_error_handler(function($errno, $errstr, $errfile, $errline){
 		Router::write(
 			Bugs::template('error')

+ 3 - 3
lib/router.class.php

@@ -47,8 +47,8 @@
 		}
 		public static function handle($url,$res = null,$fn = null){
 			if(strpos($url,static::$base) !== false){
-				$url = substr($url,strpos($url,static::$base)+strlen(static::$base));
-				if($url[0] != '/'){
+				$url = rtrim(substr($url,strpos($url,static::$base)+strlen(static::$base)),'/');
+				if(empty($url) || $url[0] != '/'){
 					$url = '/'.$url;
 				}
 				if(is_null($res)){
@@ -82,7 +82,7 @@
 		}
 		public static function write($chunk){
 			if(!isset(static::$responses[0])){
-				array_push($responses,new Response($_SERVER['REQUEST_URI']));
+				array_push(static::$responses,new Response($_SERVER['REQUEST_URI']));
 			}
 			static::$responses[0]->write($chunk);
 		}

+ 5 - 4
lib/sql.class.php

@@ -16,6 +16,7 @@
 		* @required
 		*/
 		private $sql;
+		public $insert_id;
 		public function __construct($server,$user,$pass,$db){
 			$this->sql = new mysqli($server,$user,$pass,$db) or die('Unable to connect to mysql');
 		}
@@ -27,9 +28,6 @@
 				case 'error':
 					return $this->sql->error;
 				break;
-				case 'insert_id':
-					return $this->sql->insert_id;
-				break;
 			}
 		}
 		/**
@@ -62,9 +60,11 @@
 	class Query {
 		private $query;
 		private $sql;
+		private $parent;
 		public function __construct($sql,$source,$types=null){
 			$args = func_get_args();
 			$args = array_splice($args,2);
+			$this->parent = $sql;
 			$this->sql = $sql();
 			$this->query = $sql()->prepare($source);
 			if(!is_null($types)){
@@ -77,6 +77,7 @@
 		public function execute(){
 			if($this->query){
 				$r = $this->query->execute();
+				$this->parent->insert_id = $this->sql->insert_id;
 				$this->sql->commit();
 				return $r;
 			}else{
@@ -172,7 +173,7 @@
 					}
 				break;
 				case 'insert_id':
-					return $this->sql->insert_id;
+					return $this->parent->insert_id;
 				break;
 			}
 		}

+ 56 - 16
lib/user.class.php

@@ -5,24 +5,44 @@
 			'name'=>null,
 			'email'=>null,
 			'date_registered'=>null,
-			'date_modified'=>null
+			'date_modified'=>null,
+			'active'=>null
 		);
 		public function __construct($id){
-			$this->id = intval($id);
-			$cache = Bugs::$sql->query("
-				SELECT	name,
-						email,
-						date_registered,
-						date_modified
-				FROM users
-				WHERE id = ?;
-			",'i',$this->id)->assoc_result;
-			if($cache){
-				foreach($cache as $key => $value){
-					$this->cache[$key] = $value;
-				}
-			}else{
-				trigger_error("User with id {$id} does not exist");
+			switch(func_num_args()){
+				// name, email, password
+				case 3:
+					$name = func_get_arg(0);
+					$email= func_get_arg(1);
+					$salt = md5($name.$email);
+					$pass = hash_hmac('sha512',func_get_arg(2),$salt);
+					Bugs::$sql->query("
+						INSERT INTO users (name,email,password,salt)
+						VALUES (?,?,?,?)
+					",'ssss',$name,$email,$pass,$salt)->execute();
+					$id = Bugs::$sql->insert_id;
+				// id
+				case 1:
+					$this->id = intval($id);
+					$cache = Bugs::$sql->query("
+						SELECT	name,
+								email,
+								date_registered,
+								date_modified,
+								active
+						FROM users
+						WHERE id = ?;
+					",'i',$this->id)->assoc_result;
+					if($cache){
+						foreach($cache as $key => $value){
+							$this->cache[$key] = $value;
+						}
+					}else{
+						trigger_error("User with id {$id} does not exist");
+					}
+				break;
+				default:
+					trigger_error("Invalid Arguments");
 			}
 		}
 		public function jsonSerialize(){
@@ -46,6 +66,14 @@
 						WHERE id = ?
 					",'si',$value,$this->id)->execute();
 				break;
+				case 'active':
+					$value = $value?1:0;
+					Bugs::$sql->query("
+						UPDATE users
+						SET active = ?
+						WHERE id = ?
+					",'is',$value,$this->id)->execute();
+				break;
 				default:
 					if(isset($this->cache[$name])){
 						$this->cache[$name] = $value;
@@ -54,14 +82,26 @@
 		}
 		public function __get($name){
 			switch($name){
+				case 'active':
+					return $this->cache['active']==1;
+				break;
 				case 'date_registered':case 'date_modified':
 					return strtotime($this->cache[$name]);
 				break;
+				case 'activation_code':
+					return hash_hmac('sha512',$this->name.$this->email.$this->date_registered,md5($this->name.$this->email));
+				break;
 				default:
 					if(isset($this->cache)){
 						return $this->cache[$name];
 					}
 			}
 		}
+		public function email($subject,$body){
+			Bugs::$sql->query("
+				INSERT INTO emails (u_id,subject,body)
+				VALUES(?,?,?)
+			",'iss',$this->id,$subject,$body)->execute();
+		}
 	}
 ?>

+ 7 - 0
paths/index.php

@@ -0,0 +1,7 @@
+<?php
+	Router::paths(array(
+		'/'=>function($res,$args){
+			$res->write('Hello World');
+		}
+	));
+?>

+ 69 - 0
paths/register.php

@@ -0,0 +1,69 @@
+<?php
+	Bugs::actions(
+		'register'
+	);
+	Router::paths(array(
+		'/register'=>function($res,$args){
+			$res->write(
+				Bugs::template('register')
+			);
+		},
+		'/register/error'=>function($res,$args){
+			$res->write(
+				Bugs::template('register')
+					->run(array(
+						'error'=>'Invalid input'
+					))
+			);
+		},
+		'/register/error/{error}'=>function($res,$args){
+			$res->write(
+				Bugs::template('register')
+					->run(array(
+						'error'=>$args->error
+					))
+			);
+		},
+		'/register/complete'=>function($res,$args){
+			if(empty($_POST['name']) || empty($_POST['email']) || empty($_POST['password'])){
+				$res->header(
+					'Location',
+					Router::url(Router::$base.'/register/error')
+				);
+			}else{
+				if(!Bugs::user_id($_POST['name'])){
+					$user = Bugs::user($_POST['name'],$_POST['email'],$_POST['password']);
+					$res->write(
+						Bugs::template('registered')
+							->run($user)
+					);
+					$user->email('Registered',"
+						<a href=\"http://".URL_HOST.URL_BASE."/register/activate/{$user->name}/{$user->activation_code}\">Activate Account</a>
+					");
+					Bugs::activity('register',$_POST['name'].' has registered.');
+				}else{
+					$res->header(
+						'Location',
+						Router::url(Router::$base."/register/error/User {$_POST['name']} already exists")
+					);
+				}
+			}
+		},
+		'/register/activate/{user}/{code}'=>function($res,$args){
+			$user = Bugs::user($args->user);
+			if($args->code == $user->activation_code){
+				if(!$user->active){
+					$user->active = true;
+					$res->write(
+						Bugs::template('activated')
+							->run($user)
+					);
+				}else{
+					trigger_error("User is already active");
+				}
+			}else{
+				trigger_error("Invalid activation code for user {$args->user}");
+			}
+		}
+	));
+?>

+ 9 - 5
paths/user.php

@@ -4,11 +4,15 @@
 	);
 	Router::paths(array(
 		'/~{user}'=>function($res,$args){
-			$res->write(
-				Bugs::template('user')
-					->run(Bugs::user($args->user))
-			);
-			Bugs::activity('view_profile',$args->user);
+			$user = Bugs::user($args->user);
+			if($user->active){
+				$res->write(
+					Bugs::template('user')
+						->run($user)
+				);
+			}else{
+				trigger_error("User {$args->user} is inactive");
+			}
 		},
 		'/user/{user}'=>function($res,$args){
 			$res->header(

+ 19 - 0
templates/activated.php

@@ -0,0 +1,19 @@
+<?php
+	// Expecting the context to be a user
+	global $context;
+?>
+<!doctype html>
+	<head>
+		<meta charset="utf8"/>
+		<title>Register</title>
+		<script src="js/juju/core.js"></script>
+		<script src="js/juju/page.js"></script>
+		<script src="js/juju/dom.js"></script>
+		<script src="js/juju/keyboard.js"></script>
+		<script src="js/juju/mouse.js"></script>
+		<link rel="stylesheet" href="css/main.css"></link>
+	</head>
+	<body>
+		<?=$context->name?> has been activated.
+	</body>
+</html>

+ 25 - 23
templates/error.php

@@ -1,36 +1,38 @@
 <?php
 	global $context;
-	function get_class_name($obj){
-		$name = get_class($obj);
-		if(!$name){
-			if(is_string($obj)){
-				$name = 'String';
-			}elseif(is_numeric($obj)){
-				$name = 'Number';
-			}elseif(is_array($obj)){
-				$name = 'Array';
-			}elseif(is_null($obj)){
-				$name = 'Null';
-			}else{
-				$name = 'Object';
-			}
+	if(!function_exists('get_class_name')){
+		function get_class_name($obj){
+			$name = @get_class($obj);
+			if(!$name){
+				if(is_string($obj)){
+					$name = 'String';
+				}elseif(is_numeric($obj)){
+					$name = 'Number';
+				}elseif(is_array($obj)){
+					$name = 'Array';
+				}elseif(is_null($obj)){
+					$name = 'Null';
+				}else{
+					$name = 'Object';
+				}
 
+			}
+			return $name;
 		}
-		return $name;
 	}
 ?>
 <!doctype html>
 	<head>
 		<meta charset="utf8"/>
 		<title>Error</title>
-		<script src="js/juju/core.js"></script>
-		<script src="js/juju/page.js"></script>
-		<script src="js/juju/dom.js"></script>
-		<script src="js/juju/keyboard.js"></script>
-		<script src="js/juju/mouse.js"></script>
-		<script src="js/error.js"></script>
-		<link rel="stylesheet" href="css/main.css"></link>
-		<link rel="stylesheet" href="css/error.css"></link>
+		<script src="<?=Router::$base?>/js/juju/core.js"></script>
+		<script src="<?=Router::$base?>/js/juju/page.js"></script>
+		<script src="<?=Router::$base?>/js/juju/dom.js"></script>
+		<script src="<?=Router::$base?>/js/juju/keyboard.js"></script>
+		<script src="<?=Router::$base?>/js/juju/mouse.js"></script>
+		<script src="<?=Router::$base?>/js/error.js"></script>
+		<link rel="stylesheet" href="<?=Router::$base?>/css/main.css"></link>
+		<link rel="stylesheet" href="<?=Router::$base?>/css/error.css"></link>
 	</head>
 	<body>
 		<h2>

+ 51 - 0
templates/register.php

@@ -0,0 +1,51 @@
+<?php
+	// Expecting the context to be a user
+	global $context;
+?>
+<!doctype html>
+	<head>
+		<meta charset="utf8"/>
+		<title>Register</title>
+		<script src="js/juju/core.js"></script>
+		<script src="js/juju/page.js"></script>
+		<script src="js/juju/dom.js"></script>
+		<script src="js/juju/keyboard.js"></script>
+		<script src="js/juju/mouse.js"></script>
+		<script src="js/register.js"></script>
+		<link rel="stylesheet" href="css/main.css"></link>
+	</head>
+	<body>
+		<?php
+			if(!empty($context['error'])){
+		?>
+			<div class="error">
+				<?=$context['error']?>
+			</div>
+		<?php
+			}
+		?>
+		<form action="<?=Router::url(Router::$base.'/register/complete')?>" method="POST">
+			<div>
+				<label for="name">
+					Name:
+				</label>
+				<input name="name"/>
+			</div>
+			<div>
+				<label for="email">
+					Email:
+				</label>
+				<input name="email" type="email"/>
+			</div>
+			<div>
+				<label for="password">
+					Password:
+				</label>
+				<input name="password" type="password"/>
+			</div>
+			<div>
+				<input type="submit" value="Register"/>
+			</div>
+		</form>
+	</body>
+</html>

+ 19 - 0
templates/registered.php

@@ -0,0 +1,19 @@
+<?php
+	// Expecting the context to be a user
+	global $context;
+?>
+<!doctype html>
+	<head>
+		<meta charset="utf8"/>
+		<title>Register</title>
+		<script src="js/juju/core.js"></script>
+		<script src="js/juju/page.js"></script>
+		<script src="js/juju/dom.js"></script>
+		<script src="js/juju/keyboard.js"></script>
+		<script src="js/juju/mouse.js"></script>
+		<link rel="stylesheet" href="css/main.css"></link>
+	</head>
+	<body>
+		<?=$context->name?> has been registered. An email has been sent to your email address with a link to activate your account.
+	</body>
+</html>