From f159862bbdf00263d94a56304a8d9c67409a254f Mon Sep 17 00:00:00 2001 From: Hisham Ismail Date: Sat, 7 Nov 2015 02:27:09 +0800 Subject: [PATCH] Created new script, and app to jumpstart the development --- README.md | 375 ++++-------------- example/foo/.gitignore | 10 + example/foo/Makefile | 1 + example/foo/include/foo.hrl | 9 + example/foo/run.sh | 3 + example/foo/src/auth_controller.erl | 70 ++++ example/foo/src/foo.app.src | 23 +- example/foo/src/foo_app.erl | 12 +- example/foo/src/home_controller.erl | 20 +- example/foo/src/secret_controller.erl | 21 + example/foo/templates/error.dtl | 12 +- example/foo/templates/home.dtl | 16 +- .../foo/templates/jumbotron-narrow/index.html | 85 ---- .../jumbotron-narrow/jumbotron-narrow.css | 79 ---- example/foo/templates/login.dtl | 44 ++ example/foo/templates/public.dtl | 11 + example/foo/templates/register.dtl | 54 +++ new_app.sh | 37 ++ 18 files changed, 393 insertions(+), 489 deletions(-) create mode 100644 example/foo/.gitignore create mode 100644 example/foo/include/foo.hrl create mode 100755 example/foo/run.sh create mode 100644 example/foo/src/auth_controller.erl create mode 100644 example/foo/src/secret_controller.erl delete mode 100755 example/foo/templates/jumbotron-narrow/index.html delete mode 100755 example/foo/templates/jumbotron-narrow/jumbotron-narrow.css create mode 100644 example/foo/templates/login.dtl create mode 100644 example/foo/templates/public.dtl create mode 100644 example/foo/templates/register.dtl create mode 100755 new_app.sh diff --git a/README.md b/README.md index 9e2691c..ec2b6bf 100644 --- a/README.md +++ b/README.md @@ -1,312 +1,109 @@ -Tuah -==== +> Tuah +> ==== +> Tuah is a simple, HTTP framework, inspired by BeepBeep with Cowboy as the underlying mechanism. +> +> Easy to extend, comes with session management and continous code compilations make it a very productive framework to begin with. +> +> Built on the strength of Cowboy and MongoDB, development time is greatly reduced. -Tuah is a simple, HTTP framework, inspired by BeepBeep with Cowboy as the underlying mechanism. - -Usage ------ +Quick Start +----------- 1. Create A New Project - Create a new project using rebar template - - ```` bash - $ mkdir ~/Projects/Erlang/foo - $ cd ~/Projects/Erlang/foo - $ wget https://raw.githubusercontent.com/ninenines/erlang.mk/master/erlang.mk - ```` - - Create a skeleton for the OTP project - ```` bash - $ make bootstrap bootstrap-rel - ```` - - Edit the generated Makefile, and add the content as per below - ```` bash - $ cat Makefile - PROJECT = foo - DEPS = tuah sync eunit_formatters - - dep_tuah = git https://github.com/mhishami/tuah.git master - - include erlang.mk - ```` - - -2. Add The Codes - - The content might be similar to these: - - ````erlang - %% file: foo.app.src - application, foo, [ - {description, ""}, - {vsn, "0.1"}, - {modules, []}, - {registered, [fishbid_sup]}, - {applications, [kernel,stdlib,tuah,sync,eunit_formatters]}, - {mod, {foo_app, []}}, - {env, [ - {http, [{port, 8080}]}, - {pools, [ - {foo, [ - {size, 10}, - {max_overflow, 30} - ], [ - {database, <<"foo">>}, - {w_mode, safe} - ]} - ]} - ]} - - ]}. - ```` - - ```` erlang - - -module(foo_app). - -behaviour(application). - - -export([start/2]). - -export([stop/1]). - - start(_Type, _Args) -> - application:start(sync), - application:ensure_all_started(lager), - application:ensure_all_started(mongodb), - application:ensure_all_started(cowboy), - application:start(erlydtl), - - %% set debug for console logs - lager:set_loglevel(lager_console_backend, debug), - - foo_sup:start_link(). - - stop(_State) -> - ok. - - ```` + Create a new project is made simple via the addition of `new_app.sh` script -3. Implement Your Controller - - ```` bash - $ touch src/home_controller_.erl - ```` - - ```` erlang - -module (home_controller). - -export ([handle_request/5]). - % -export ([before_filter/1]). - - % before_filter(SessionId) -> - % %% do some checking - % Sid = session_worker:get_cookies(SessionId), - % case Sid of - % {error, undefined} -> - % {redirect, <<"/auth/login">>}; - % _ -> - % {ok, proceed} - % end. - - handle_request(<<"GET">>, <<"/">>, _Args, _Params, _Req) -> - %% Action / will render home.dtl - {render, []}; - - handle_request(_, _, _, _, _) -> - {error, <<"Opps, Forbidden">>}. - - ```` - - ```` bash - $ touch src/auth_controller_.erl - ```` - - ```` erlang - -module (auth_controller). - -export ([handle_request/5]). - - handle_request(<<"GET">>, <<"login">> = Action, _Args, _Params, _Req) -> - %% Action login will render login.dtl - {render, Action, []}; - - handle_request(<<"POST">>, <<"login">>, _, Params, _) -> - {ok, PostVals} = maps:find(<<"qs_body">>, Params), - Email = proplists:get_value(<<"email">>, PostVals), - Password = proplists:get_value(<<"password">>, PostVals), - - %% authenticate the user - case authenticate(Email, Password) of - {ok, proceed} -> - %% set the session id, and user email - Sid = web_util:hash_password(word_util:gen_pnr()), - session_worker:set_cookies(Sid, Email), - - %% redirect, assuming "main" is defined. - {redirect, <<"/main">>}; - _ -> - {redirect, <<"/">>} - end; - - handle_request(_, _, _, _, _) -> - {error, <<"Opps, Forbidden">>}. - - %% private function - authenticate(_Email, _Password) -> - {ok, proceed}. - - - ```` - -4. Do The Templates - - ```` bash - $ mkdir templates - $ cd templates - $ touch home.dtl - ```` + ``` shell + hisham@skrall:tuah$ ./new_app.sh foo + Creating new app: foo + Creating directory... + Creating template files... + Creating bootstrap files... + Finishing up... + Done. Your app is created in ../foo. + +----------------------+ + | Happy coding! | + +----------------------+ + hisham@skrall:tuah$ - We will be using a bootstrap sample page for this example. - ```` bash - $ cd ~/Projects/Web - $ git clone https://github.com/twitter/bootstrap.git - ```` + ``` - Put all the static files in the `priv` directory, and prepend it with `static` name, i.e. - ```` bash - $ cd ~/Projects/Erlang/foo - $ mkdir -p priv/static/css - $ cp -r ~/Projects/Web/bootstrap/dist priv/static/. - $ cp -r ~/Projects/Web/bootstrap/assets priv/static/. - $ cp ~/Projects/Web/bootstrap/docs/examples/jumbotron-narrow/index.html templates/base.dtl - $ cp ~/Projects/Web/bootstrap/docs/examples/jumbotron-narrow/jumbotron-narrow.css priv/static/css/style.css - ```` +2. The project structure looks like - Replace all references to css and js files - Edit `base.dtl` header file to be: - - ``` html + ``` shell + foo + ├── Makefile + ├── erlang.mk + ├── include + │   └── bb.hrl + ├── priv + │   └── static + │   ├── assets/ + │   ├── css/ + │   └── dist/ + ├── rel + │   ├── sys.config + │   └── vm.args + ├── relx.config + ├── run.sh + ├── src + │   ├── foo.app.src + │   ├── foo_app.erl + │   ├── foo_sup.erl + │   └── home_controller.erl + └── templates + ├── error.dtl + ├── home.dtl + ├── login.dtl + ├── public.dtl + └── register.dtl - - - + ``` +3. Start the mongodb server, as the sample application does live registration and all. +4. Run The App +> The App +> ==== +> +> This simple app does user registration, login and logout. +> Extend this further to your likings. - - + ``` shell + $ make + $ ./run.sh console ``` - Edit the `base.dtl` file to include the `content` block to be: - - ``` html - - {% block content %} -
-

Jumbotron heading

- ... - - ... -

Subheading

-

Maecenas sed diam eget risus varius blandit sit amet non magna.

-
- - {% endblock %} - - ``` - - Edit `home.dtl` to use the said template - - ```` bash - $ cat home.dtl - - {% extends "base.dtl" %} - - ```` - - ``` bash - +-- Project - +-- deps - +-- ebin - +-- include - +-- priv - +-- assets - +-- css - - bootstrap.css - - ... - +-- js - +-- img - ``` + View the app at http://localhost:8080 + That's it! - -5. Run The App +5. Extend the app the way you like it by adding more templates, controllers to make a full blown app - ``` shell - $ make; make run - ``` - View the app at http://localhost:8080 +6. Feel free to fork this. Cheers! -6. Deploy to Heroku +Mongo Backend +------------- +1. Tuah framework comes with mongo client integration. Almost *all* the APIs are supported. Feel free to browse the source code. - Once everything is fine, we can then deploy it to Heroku +2. Advanced examples such as regex search, complex find and match are supported. Details query and projection operators can be found at [https://docs.mongodb.org/manual/reference/operator/](MongoDB Reference) + +3. Different notations for find (use which you like). I prefer the second as it is easier to read and comprehend. - Add git repo, and remove `ebin/*` from your `.gitignore` dir as heroku will not compile the dtl template we compiled earlier. - - ```` bash - $ git init - ```` - - Edit `.gitignore` - ```` bash - $ cat .gitignore - deps/* - priv/db - log/* - - $ git commit -am 'initial commit' - ```` - - - ``` bash - $ heroku create <> --stack cedar \ - --buildpack https://github.com/archaelus/heroku-buildpack-erlang.git - ``` - - Create a Profile that contains the above running instructions. Ensure all are in one line. - ``` bash - $ cat Procfile - web: erl -sname foo -pa ebin include deps/*/ebin deps/*/include ebin include __ - -boot start_sasl -s reloader -s tuah -s foo -noshell -noinput - ``` - - Specify Erlang version - - ``` bash - $ echo OTP_R15B01 > .preferred_otp_version ``` - - Add all to git, and do - - ``` bash - $ git add . - $ git commit -am 'commit to heroku' - $ git push heroku master - $ heroku ps:scale worker=1 - $ heroku open + mongo_worker:find(<<"posts">>, {}, [{batchsize, 3}, {skip, 1}, + {projector, {<<"created_at">>, 1, <<"grpid">>, 1}}]). + + mongo_worker:find(<<"posts">>, {}, [{batchsize, 3}, {skip, 1}, + {projector, #{<<"created_at">> => 1, <<"grpid">> => 1}}]). ``` - - That's it! +4. Regular expressions are also there. -Notes -===== - -1. Reply can be done in several ways in the controller: - ``` erlang - {redirect, <<"/page">>} %% redirect to page_controller -> page.dtl - {render, Data} %% return the page for the current controller with Data - {render, <<"adm">>, Data} %% render the page adm.dtl in the current controller with data - {json, DataList} %% return json data from erlang list ``` - -2. Customize your error view with custom error.dtl page that takes `{{ error }}` as the message - - + mongo_worker:find(<<"posts">>, {}, [{batchsize, 1}, {skip, 1}]). + mongo_worker:find(<<"posts">>, + {<<"title">>, #{<<"$regex">> => <<"some*">>, + <<"$options">> => <<"i">>}}, + [{projector, #{<<"grpid">> => 1, + <<"title">> => 1, + <<"author.fullname">> => 1}}]). + ``` \ No newline at end of file diff --git a/example/foo/.gitignore b/example/foo/.gitignore new file mode 100644 index 0000000..32959cb --- /dev/null +++ b/example/foo/.gitignore @@ -0,0 +1,10 @@ +ebin/* +deps/* +_rel +rel +relx +relx.config +.erlang.mk/ +foo.d +.foo.plt +logs diff --git a/example/foo/Makefile b/example/foo/Makefile index f7ea54f..40a33db 100644 --- a/example/foo/Makefile +++ b/example/foo/Makefile @@ -3,5 +3,6 @@ DEPS = tuah sync cowboy erlydtl jsx lager cowlib ranch bson pbkdf2 mongodb dep_tuah = git https://github.com/mhishami/tuah.git master dep_mongodb = git https://github.com/comtihon/mongodb-erlang.git master +dep_pbkdf2 = git https://github.com/basho/erlang-pbkdf2.git 2.0.0 include erlang.mk diff --git a/example/foo/include/foo.hrl b/example/foo/include/foo.hrl new file mode 100644 index 0000000..2bced38 --- /dev/null +++ b/example/foo/include/foo.hrl @@ -0,0 +1,9 @@ + + +-define(CHILD(I, Type), {I, {I, start_link, []}, permanent, 5000, Type, [I]}). + +-define(DEBUG(Text, Args), lager:log(debug, ?MODULE, "~p:~p: " ++ Text, [?MODULE, ?LINE | Args])). +-define(INFO(Text, Args), lager:log(info, ?MODULE, "~p:~p: " ++ Text, [?MODULE, ?LINE | Args])). +-define(ERROR(Text, Args), lager:log(error, ?MODULE, "~p:~p: " ++ Text, [?MODULE, ?LINE | Args])). + +-define (DB_USERS, <<"users">>). diff --git a/example/foo/run.sh b/example/foo/run.sh new file mode 100755 index 0000000..5dd5951 --- /dev/null +++ b/example/foo/run.sh @@ -0,0 +1,3 @@ +#!/bin/sh +# +./_rel/foo_release/bin/foo_release $* diff --git a/example/foo/src/auth_controller.erl b/example/foo/src/auth_controller.erl new file mode 100644 index 0000000..bc9df6b --- /dev/null +++ b/example/foo/src/auth_controller.erl @@ -0,0 +1,70 @@ +-module (auth_controller). +-export ([handle_request/5]). +-export ([before_filter/1]). + +-include("foo.hrl"). + +before_filter(_SessionId) -> + {ok, proceed}. + +handle_request(<<"GET">>, <<"logout">>, _Args, Params, _Req) -> + session_worker:del_cookies(maps:get(<<"sid">>, Params)), + {redirect, <<"/">>}; + +handle_request(<<"GET">>, <<"login">>, _Args, _Params, _Req) -> + {render, <<"login">>, []}; + +handle_request(<<"POST">>, <<"login">> = Action, _Args, Params, _Req) -> + PostVals = maps:get(<<"qs_body">>, Params), + Username = proplists:get_value(<<"username">>, PostVals), + Password = proplists:get_value(<<"password">>, PostVals), + + case Username =:= <<>> orelse Password =:= <<>> of + true -> + {render, Action, [{error, <<"All fields are required.">>}]}; + _ -> + case mongo_worker:find(?DB_USERS, #{<<"username">> => Username}) of + {ok, []} -> + {render, Action, [{error, <<"Invalid username, or password">>}]}; + {ok, [User]} -> + ?DEBUG("User= ~p~n", [User]), + HashPass = web_util:hash_password(Password), + Pass = maps:get(<<"password">>, User), + case Pass =/= HashPass of + true -> + {render, Action, [{error, <<"Invalid username, or password">>}]}; + _ -> + Sid = maps:get(<<"sid">>, Params), + session_worker:set_cookies(Sid, Username), + + %% redirect, assuming "main" is defined. + {redirect, <<"/secret">>, {cookie, <<"auth">>, Username}} + end + end + end; + +handle_request(<<"GET">>, <<"register">>, _Args, _Params, _Req) -> + {render, <<"register">>, []}; + +handle_request(<<"POST">>, <<"register">> = Action, _Args, Params, _Req) -> + PostVals = maps:get(<<"qs_body">>, Params), + Username = proplists:get_value(<<"username">>, PostVals), + Pass1 = proplists:get_value(<<"password">>, PostVals), + Pass2 = proplists:get_value(<<"password2">>, PostVals), + + case Username =:= <<>> orelse Pass2 =:= <<>> orelse Pass1 =:= <<>> of + true -> + {render, Action, [{error, <<"All fields are required.">>} | PostVals]}; + _ -> + case Pass1 =/= Pass2 of + true -> + {render, Action, [{error, <<"Passwords are not the same">>} | PostVals]}; + _ -> + %% ok, we can register + User = #{ <<"username">> => Username, + <<"password">> => web_util:hash_password(Pass2), + <<"created_at">> => erlang:timestamp()}, + mongo_worker:save(?DB_USERS, User), + {redirect, <<"/auth/login">>} + end + end. diff --git a/example/foo/src/foo.app.src b/example/foo/src/foo.app.src index 5e13c78..895dd9e 100644 --- a/example/foo/src/foo.app.src +++ b/example/foo/src/foo.app.src @@ -1,25 +1,36 @@ {application, foo, [ {description, ""}, - {vsn, "rolling"}, + {vsn, "0.1.0"}, {modules, []}, {registered, [foo_sup]}, {applications, [ kernel, stdlib, - tuah, + crypto, + mnesia, + tuah, + sync, cowboy, erlydtl, jsx, lager, cowlib, ranch, - mongodb, bson, - mnesia + pbkdf2, + mongodb ]}, {mod, {foo_app, []}}, {env, [ {http, [{port, 8080}]}, - {dirname, foo} + {pools, [ + {foo, [ + {size, 10}, + {max_overflow, 30} + ], [ + {database, <<"foo">>}, + {w_mode, safe} + ]} + ]} ]} -]}. \ No newline at end of file +]}. diff --git a/example/foo/src/foo_app.erl b/example/foo/src/foo_app.erl index a5cb13f..c4d8162 100644 --- a/example/foo/src/foo_app.erl +++ b/example/foo/src/foo_app.erl @@ -2,7 +2,7 @@ -behaviour(application). -export([start/2]). --export([stop/1, res/0]). +-export([stop/1]). start(_Type, _Args) -> application:start(sync), @@ -10,7 +10,6 @@ start(_Type, _Args) -> application:ensure_all_started(mongodb), application:ensure_all_started(cowboy), application:start(erlydtl), - application:start(merl), %% set debug for console logs lager:set_loglevel(lager_console_backend, debug), @@ -19,12 +18,3 @@ start(_Type, _Args) -> stop(_State) -> ok. - -res() -> - C1 = lists:foldl( - fun(C, Acu) -> - {match, [{A, 16}]} = re:run(C, "_controller.beam"), - [string:sub_string(C, 22, A)|Acu] - end, [], filelib:wildcard("lib/*/ebin/*_controller.beam")), - C2 = [ {list_to_binary(W), list_to_atom(W ++ "_controller")} || W <- C1 ], - C2. diff --git a/example/foo/src/home_controller.erl b/example/foo/src/home_controller.erl index 011eb51..3249769 100644 --- a/example/foo/src/home_controller.erl +++ b/example/foo/src/home_controller.erl @@ -1,19 +1,13 @@ -module (home_controller). -export ([handle_request/5]). --export ([before_filter/2]). +-export ([before_filter/1]). -before_filter(SessionId) -> - %% do some checking - Sid = session_worker:get_cookies(SessionId), - case Sid of - {error, undefined} -> - {redirect, <<"/auth/login">>}; - _ -> - {ok, proceed} - end. +-include ("foo.hrl"). -handle_request(<<"GET">>, _Action, _Args, _Params, _Req) -> - %% / will render home.dtl - {ok, []}. +before_filter(_SessionId) -> + {ok, proceed}. + +handle_request(<<"GET">>, _Action, _Args, _Params, _Req) -> + {render, <<"public">>, []}. diff --git a/example/foo/src/secret_controller.erl b/example/foo/src/secret_controller.erl new file mode 100644 index 0000000..c886b95 --- /dev/null +++ b/example/foo/src/secret_controller.erl @@ -0,0 +1,21 @@ +-module (secret_controller). +-export ([handle_request/5]). +-export ([before_filter/1]). + +-include ("foo.hrl"). + +before_filter(SessionId) -> + %% do some checking + Sid = session_worker:get_cookies(SessionId), + case Sid of + {error, undefined} -> + {redirect, <<"/auth/login">>}; + _ -> + {ok, proceed} + end. + +handle_request(<<"GET">>, _Action, _Args, Params, _Req) -> + Username = maps:get(<<"auth">>, Params), + {render, <<"home">>, [{user, Username}]}. + + diff --git a/example/foo/templates/error.dtl b/example/foo/templates/error.dtl index fa2d1ad..2182ef6 100644 --- a/example/foo/templates/error.dtl +++ b/example/foo/templates/error.dtl @@ -1 +1,11 @@ -{% extends "base.dtl" %} +{% extends "home.dtl" %} + +{% block content %} + +
+

Oppss!

+

Something went wrong!

+

Sign up today

+
+ +{% endblock %} \ No newline at end of file diff --git a/example/foo/templates/home.dtl b/example/foo/templates/home.dtl index ab5000b..23db193 100644 --- a/example/foo/templates/home.dtl +++ b/example/foo/templates/home.dtl @@ -15,6 +15,7 @@ + @@ -34,21 +35,26 @@

Project name

+ {% block content %}

Jumbotron heading

Cras justo odio, dapibus ac facilisis in, egestas eget quam. Fusce dapibus, tellus ac cursus commodo, tortor mauris condimentum nibh, ut fermentum massa justo sit amet risus.

Sign up today

- {% block content %}

Subheading

@@ -75,7 +81,7 @@ {% endblock %}
-

© Company 2014

+

© Company 2015

diff --git a/example/foo/templates/jumbotron-narrow/index.html b/example/foo/templates/jumbotron-narrow/index.html deleted file mode 100755 index 78e9e2c..0000000 --- a/example/foo/templates/jumbotron-narrow/index.html +++ /dev/null @@ -1,85 +0,0 @@ - - - - - - - - - - - - Narrow Jumbotron Template for Bootstrap - - - - - - - - - - - - - - - - - -
-
- -

Project name

-
- -
-

Jumbotron heading

-

Cras justo odio, dapibus ac facilisis in, egestas eget quam. Fusce dapibus, tellus ac cursus commodo, tortor mauris condimentum nibh, ut fermentum massa justo sit amet risus.

-

Sign up today

-
- -
-
-

Subheading

-

Donec id elit non mi porta gravida at eget metus. Maecenas faucibus mollis interdum.

- -

Subheading

-

Morbi leo risus, porta ac consectetur ac, vestibulum at eros. Cras mattis consectetur purus sit amet fermentum.

- -

Subheading

-

Maecenas sed diam eget risus varius blandit sit amet non magna.

-
- -
-

Subheading

-

Donec id elit non mi porta gravida at eget metus. Maecenas faucibus mollis interdum.

- -

Subheading

-

Morbi leo risus, porta ac consectetur ac, vestibulum at eros. Cras mattis consectetur purus sit amet fermentum.

- -

Subheading

-

Maecenas sed diam eget risus varius blandit sit amet non magna.

-
-
- -
-

© Company 2014

-
- -
- - - - - - diff --git a/example/foo/templates/jumbotron-narrow/jumbotron-narrow.css b/example/foo/templates/jumbotron-narrow/jumbotron-narrow.css deleted file mode 100755 index 952adc5..0000000 --- a/example/foo/templates/jumbotron-narrow/jumbotron-narrow.css +++ /dev/null @@ -1,79 +0,0 @@ -/* Space out content a bit */ -body { - padding-top: 20px; - padding-bottom: 20px; -} - -/* Everything but the jumbotron gets side spacing for mobile first views */ -.header, -.marketing, -.footer { - padding-right: 15px; - padding-left: 15px; -} - -/* Custom page header */ -.header { - padding-bottom: 20px; - border-bottom: 1px solid #e5e5e5; -} -/* Make the masthead heading the same height as the navigation */ -.header h3 { - margin-top: 0; - margin-bottom: 0; - line-height: 40px; -} - -/* Custom page footer */ -.footer { - padding-top: 19px; - color: #777; - border-top: 1px solid #e5e5e5; -} - -/* Customize container */ -@media (min-width: 768px) { - .container { - max-width: 730px; - } -} -.container-narrow > hr { - margin: 30px 0; -} - -/* Main marketing message and sign up button */ -.jumbotron { - text-align: center; - border-bottom: 1px solid #e5e5e5; -} -.jumbotron .btn { - padding: 14px 24px; - font-size: 21px; -} - -/* Supporting marketing content */ -.marketing { - margin: 40px 0; -} -.marketing p + h4 { - margin-top: 28px; -} - -/* Responsive: Portrait tablets and up */ -@media screen and (min-width: 768px) { - /* Remove the padding we set earlier */ - .header, - .marketing, - .footer { - padding-right: 0; - padding-left: 0; - } - /* Space out the masthead */ - .header { - margin-bottom: 30px; - } - /* Remove the bottom border on the jumbotron for visual effect */ - .jumbotron { - border-bottom: 0; - } -} diff --git a/example/foo/templates/login.dtl b/example/foo/templates/login.dtl new file mode 100644 index 0000000..9b722a8 --- /dev/null +++ b/example/foo/templates/login.dtl @@ -0,0 +1,44 @@ +{% extends "home.dtl" %} + +{% block content %} +
+
+ + Login + + {% if error %} + + {% endif %} + + +
+ +
+ + Your username please +
+
+ + +
+ +
+ + Your password please +
+
+ + +
+ +
+ + Register? +
+
+
+
+{% endblock %} diff --git a/example/foo/templates/public.dtl b/example/foo/templates/public.dtl new file mode 100644 index 0000000..0004db7 --- /dev/null +++ b/example/foo/templates/public.dtl @@ -0,0 +1,11 @@ +{% extends "home.dtl" %} + +{% block content %} + +
+

Hello!

+

This is a general page. Login to see the secret!

+

Sign In

+
+ +{% endblock %} \ No newline at end of file diff --git a/example/foo/templates/register.dtl b/example/foo/templates/register.dtl new file mode 100644 index 0000000..430fd69 --- /dev/null +++ b/example/foo/templates/register.dtl @@ -0,0 +1,54 @@ +{% extends "home.dtl" %} + +{% block content %} +
+
+ + Register + + {% if error %} + + {% endif %} + + +
+ +
+ + Your username please +
+
+ + +
+ +
+ + Your password please +
+
+ + +
+ +
+ + Your password (again) please +
+
+ + +
+ +
+ + Login? +
+
+
+
+ +{% endblock %} diff --git a/new_app.sh b/new_app.sh new file mode 100755 index 0000000..9418750 --- /dev/null +++ b/new_app.sh @@ -0,0 +1,37 @@ +#!/bin/bash +# +function new_app { + echo "Creating new app: $1" + CURR=$(pwd) + ROOT="../$1" + SKEL="example/foo" + echo "Creating directory..." + $(mkdir -p $ROOT/include) + echo "Creating template files..." + $(cp -r $SKEL/erlang.mk $SKEL/priv $SKEL/templates $ROOT/.) + echo "Creating bootstrap files..." + $(cd $ROOT; make -f erlang.mk bootstrap bootstrap-rel) + echo "Finishing up..." + $(sed s/foo/$1/g $SKEL/Makefile > $ROOT/Makefile) + $(sed s/tuah/$1/g .gitignore > $ROOT/.gitignore) + $(sed s/foo/$1/g $SKEL/src/foo.app.src > $ROOT/src/${1}.app.src) + $(sed s/foo/$1/g $SKEL/src/foo_app.erl > $ROOT/src/${1}_app.erl) + $(sed s/foo/$1/g $SKEL/src/home_controller.erl > $ROOT/src/home_controller.erl) + $(sed s/foo/$1/g $SKEL/src/auth_controller.erl > $ROOT/src/auth_controller.erl) + $(sed s/foo/$1/g $SKEL/src/secret_controller.erl > $ROOT/src/secret_controller.erl) + $(sed s/foo/$1/g $SKEL/include/foo.hrl > $ROOT/include/${1}.hrl) + $(sed s/foo/$1/g $SKEL/run.sh > $ROOT/run.sh; chmod +x $ROOT/run.sh) + echo "Done. Your app is created in $ROOT." + echo "+----------------------+" + echo "| Happy coding! |" + echo "+----------------------+" +} + +if [ "$1" = "" ]; then + echo "USAGE: $0 appname" + exit 1 +else + new_app $1 +fi + +