瀏覽代碼

*** empty log message ***

Pascal Peridont 19 年之前
父節點
當前提交
eff705e7e7
共有 2 個文件被更改,包括 321 次插入0 次删除
  1. 240 0
      std/mtwin/web/Handler.hx
  2. 81 0
      std/mtwin/web/Request.hx

+ 240 - 0
std/mtwin/web/Handler.hx

@@ -0,0 +1,240 @@
+package mtwin.web;
+
+import mtwin.web.Request;
+import Reflect.Class;
+
+enum ActionError {
+	UnknownAction(name:String);
+	ObjectNotFound(id:Int);
+	ActionReservedToLoggedUsers;
+	ActionReservedToObjectOwner;
+	ActionReservedToAdministrators;
+	ActionReservedToModerators;
+	CallingObjectMethodWithoutId;
+}
+
+/**
+	Generic class to handle web actions.
+
+	Add to your .htaccess :
+
+	<FilesMatch "^(actionName|actionName|...)$">
+	RewriteEngine On
+	RewriteRule (.*) /index.n
+	</FilesMatch>
+**/
+class Handler<T> {
+
+	public static var STATIC_DEFAULT = "default";
+	public static var OBJECT_DEFAULT = "objectDefault";
+
+	var ReadWrite : Bool;
+	var ReadOnly : Bool;
+
+	var actions : Hash<Void->Void>;
+	var id : Int;
+	var level : Int;
+	var request : mtwin.web.Request;
+
+	public function new(){
+		actions = new Hash();
+		ReadWrite = true;
+		ReadOnly = false;
+	}
+
+	public function execute( request:Request, ?pathLevel:Int ){
+		if (pathLevel == null)
+			pathLevel = 0;
+
+		var part = request.getPathInfoPart(pathLevel);
+		if (~/^[0-9]+$/.match(part)){
+			id = Std.parseInt(part);
+			part = request.getPathInfoPart(++pathLevel);
+			if (part == "")
+				part = OBJECT_DEFAULT;
+		}
+
+		this.request = request;
+		this.level = pathLevel;
+
+		if (part == "")
+			part = STATIC_DEFAULT;
+		if (actions.exists(part)){
+			actions.get(part)();
+			return;
+		}
+		throw UnknownAction(part);
+	}
+
+	// Methods to override when needed
+
+	function prepareTemplate( t:String ) : Void {
+		throw "not implemented";
+	}
+
+	function isLogged() : Bool {
+		throw "not implemented";
+		return false;
+	}
+	
+	function isAdmin() : Bool {
+		throw "not implemented";
+		return false;
+	}
+	
+	function isModerator() : Bool {
+		throw "not implemented";
+		return false;
+	}
+
+	function isOwner( o:T ) : Bool {
+		throw "not implemented";
+		return false;
+	}
+
+	function findObject( id : Int, lock:Bool ) : T {
+		throw "findObject(Int) not implemented";
+		return null;
+	}
+
+	// callback wrappers
+	
+	function object( cb:T->Void, ?lock:Bool ) : Void->Void {
+		if (lock == null) lock = ReadWrite;
+		var me = this;
+		return function(){
+			if (me.id == null)
+				throw CallingObjectMethodWithoutId;
+			var obj = me.findObject(me.id, lock);
+			if (obj == null)
+				throw ObjectNotFound(me.id);
+			cb(obj);
+		}
+	}
+
+	function owner( cb:T->Void ) : T->Void {
+		var me = this;
+		return function(u:T){
+			if (!me.isOwner(u))
+				throw ActionReservedToObjectOwner;
+			cb(u);
+		}
+	}
+
+	function handler( h:Handler<Dynamic> ) : Void->Void {
+		var me = this;
+		return function(){
+			h.execute(me.request, me.level+1);
+		}
+	}
+
+	// action declarators
+
+	function free( n:String, ?t:String, ?cb:Void->Void ){
+		var me = this;
+		actions.set(n, function(){
+			me.run(t,cb);
+		});
+	}
+
+	function logged( n:String, ?t:String, ?cb:Void->Void ){
+		var me = this;
+		actions.set(n, function(){
+			if (!me.isLogged())
+				throw ActionReservedToLoggedUsers;
+			me.run(t,cb);
+		});
+	}
+
+	function admin( n:String, ?t:String, ?cb:Void->Void ){
+		var me = this;
+		actions.set(n, function(){
+			if (!me.isAdmin())
+				throw ActionReservedToAdministrators;
+			me.run(t,cb);
+		});
+	}
+
+	function moderator( n:String, ?t:String, ?cb:Void->Void ){
+		var me = this;
+		actions.set(n, function(){
+			if (!me.isModerator())
+				throw ActionReservedToModerators;
+			me.run(t,cb);
+		});
+	}
+
+	function run( ?t:String, ?cb:Void->Void ){
+		if (t != null) prepareTemplate(t);
+		if (cb != null) cb();
+	}
+}
+
+
+/**
+
+
+// if your application is going to contain many handlers, you may whish to extends the Handler once to
+// override prepareTemplate(), isLogged(), isAdmin(), ....
+//
+class Handler<T> extends mtwin.web.Handler<T> {
+
+	override function prepareTemplate( t:String ){
+		//App.template = new mtwin.Templo(t);
+	}
+
+	override function isLogged(){
+		//return App.user != null;
+		return true;
+	}
+}
+
+// handler example
+//
+class UserHandler extends Handler<User> {
+
+	public function new(){
+		super();
+		free("preview", "preview.mtt", doPreview);
+		free("view", "userView.mtt", object(doUserView));
+		logged("view", "userView.mtt", object(owner(doUserView)));
+	}
+
+	override function isOwner( u:User ) {
+		// return App.user.id == u.id;
+		return true;
+	}
+
+	override function findObject( id:Int ) : User {
+		return User.get(id);
+	}
+
+	function doLogin(){
+		// ...
+	}
+	
+	function doView( u:User ){
+		// ...
+	}
+}
+
+// our main application handler which will dispatch requests
+// to sub handlers (or main functions)
+class MainHandler extends Handler<Void> {
+	public function new(){
+		super();
+		// /preview action
+		free("preview", "preview.mtt", doPreview);
+		// /user/* action are delayed to the UserHandler
+		handler("user", new UserHandler());
+	}
+}
+
+class App {
+	function main(){
+		var h = new MainHandler();
+		h.execute(new Request());
+	}
+}
+
+**/

+ 81 - 0
std/mtwin/web/Request.hx

@@ -0,0 +1,81 @@
+package mtwin.web;
+import neko.Web;
+
+class Request {
+
+	var pathInfoParts  : Array<String>;
+	var params         : Hash<String>;
+
+	public function new() {
+		pathInfoParts = Web.getURI().split( "/" );
+		pathInfoParts.shift();
+		setParams( Web.getParams() );
+	}
+
+	public function getPathInfoPart ( level ) : String {
+		if( pathInfoParts.length > level )
+			return pathInfoParts[ level ];
+		return "";
+	}
+
+	public function setParams( list : Hash<String> ) {
+		params = new Hash();
+		for( k in list.keys() ){
+			params.set( k, list.get(k) );
+		}
+	}
+
+	public function getParamsObject( ?keys : List<String> ) : Dynamic<String> {
+		var ret = cast Reflect.empty();
+		if( keys == null ){
+			for( k in params.keys() ){
+				Reflect.setField( ret, k, params.get(k) );
+			}
+		}else{
+			for( k in keys ){
+				Reflect.setField( ret, k, params.get(k) );
+			}
+		}		
+		return ret;
+	}
+
+	public function get( key : String , ?or : String ) : String {
+		if( params.exists( key ) ) return params.get( key );
+		return or;
+	}
+
+	public function getInt( key : String, ?or : Int ) : Int {
+		if( params.exists(key) ){
+			var v = params.get(key);
+			if( v == "NULL" )
+				return null;
+			return Std.parseInt(v);
+		}
+		return or;
+	}
+
+	public function getBool( key:String ) : Bool {
+		var val = params.get(key);
+		return (val != null) && (val == "1" || val == "true");
+	}
+
+	public function getURI() : String {
+		return Web.getURI();
+	}
+
+	public function getReferer() : String {
+		return Web.getClientHeader("Referer");
+	}
+
+	public function exists( key ) {
+		return params.exists( key );
+	}
+
+	public function toString() : String {
+		var lst = new List();
+		for (i in params.keys()){
+			lst.add("['"+i+"'] => '"+params.get(i)+"'");
+		}
+		return lst.join(",\n");
+	}
+}