12 | Note: If you see a 'pub.lua.mymodule' not found error message you need to configure the LuaMapHandler directive - this is explained here.
--------------------------------------------------------------------------------
/test/dev-app/models/category.lua:
--------------------------------------------------------------------------------
1 | -- Uncomment this to use validation rules
2 | -- local val = require "valua"
3 | local M = {}
4 |
5 | -- Attributes and their validation rules
6 | M.attributes = {
7 | -- { = }
8 | -- Ex. {id = val:new().integer()}
9 | { id = "safe" },
10 | { name = "safe" },
11 | }
12 |
13 | M.db = {
14 | key = 'id',
15 | table = 'category'
16 | }
17 |
18 | M.relations = {
19 | posts = {relation = "MANY_MANY", model = "post", table = "post_category", attributes = {"category_id","post_id"}}
20 | }
21 |
22 | return M
23 |
--------------------------------------------------------------------------------
/test/dev-app/views/test/runat_client.lp:
--------------------------------------------------------------------------------
1 | ')
4 | js.document:write('Your User-Agent is: '..js.navigator.userAgent..' ')
5 | if js.navigator.cookieEnabled == true then
6 | js.document:write('Cookie support is enabled. ')
7 | else
8 | js.document:write('Cookie support is disabled. ')
9 | end
10 |
11 | function say_bye()
12 | js.document:write('Bye! :)')
13 | end
14 |
15 | ?>
16 |
17 |
20 |
21 |
22 | The text above was generated using client-side Lua.
--------------------------------------------------------------------------------
/test/dev-app/views/main/index.lp:
--------------------------------------------------------------------------------
1 |
2 |
Welcome to your first Sailor application
3 |
4 |
This is the default view file, you will find it under /views/main/index.lp.
5 | It is rendered by a controller, you will find it under /controllers/main.lua. This layout is provided by Twitter Bootstrap, an open source front-end framework. You can use this layout as is, modify it, or get new layouts and place them under /layouts/. Further documentation of Sailor MVC can be found here.
This is the default view file, you will find it under /views/main/index.lp.
5 | It is rendered by a controller, you will find it under /controllers/main.lua. This layout is provided by Twitter Bootstrap, an open source front-end framework. You can use this layout as is, modify it, or get new layouts and place them under /layouts/. Further documentation of Sailor MVC can be found here.
3 |
4 | There was an error while saving.
5 |
6 |
17 |
18 | <- Back to View All
19 |
--------------------------------------------------------------------------------
/test/dev-app/views/error/inspect.lp:
--------------------------------------------------------------------------------
1 |
20 |
21 |
3 |
4 | There was an error while saving.
5 |
6 |
19 |
20 | <- Back to View All
21 |
--------------------------------------------------------------------------------
/docs/manual_sailor_functions.md:
--------------------------------------------------------------------------------
1 | ###Reference Manual
2 |
3 | ###Sailor built-in functions
4 | Can be used anywhere in a Sailor web application.
5 |
6 | ####sailor.make_url( route [*, params*] )
7 | Creates a url for an internal app route depending on friendly url configuration.
8 |
9 | * route: string, controller/action or controller.
10 |
11 | * params: [optional] table, vars and values to be sent via GET.
12 |
13 | Example 1: `sailor.make_url( 'post/view', {id = 5, title = 'Manual'} )`
14 |
15 | ####sailor.model( model_name )
16 | Creates a sailor model that can be instantiated in objects with :new().
17 |
18 | * model_name: string, model's name. There must be a .lua file with the model's name under /model.
19 |
20 | Example 1:
21 |
22 | -- In this case there must be a file inside /model called user.lua
23 | local User = sailor.model( 'user' )
24 | local u = User:new( )
--------------------------------------------------------------------------------
/src/sailor/db.lua:
--------------------------------------------------------------------------------
1 | --------------------------------------------------------------------------------
2 | -- db.lua, v0.3.2: DB module for connecting and querying through different DB modules
3 | -- This file is a part of Sailor project
4 | -- Copyright (c) 2014 Etiene Dalcol
5 | -- License: MIT
6 | -- http://sailorproject.org
7 | --------------------------------------------------------------------------------
8 |
9 | local main_conf = require "conf.conf"
10 | local conf = main_conf.db[main_conf.sailor.environment]
11 | local remy = require "remy"
12 |
13 | local function detect()
14 | if conf == nil then error("DB environment not found.") return end
15 | local m
16 | if remy.detect() == remy.MODE_NGINX and conf.driver == "mysql" then
17 | m = require "sailor.db.resty_mysql"
18 | else
19 | m = require "sailor.db.luasql_common"
20 | end
21 | m.detect = detect
22 | return m
23 | end
24 |
25 | return detect()
26 |
--------------------------------------------------------------------------------
/test/dev-app/index-magnet.lua:
--------------------------------------------------------------------------------
1 | -- Alternative index and launcher for LightTPD's mod_magnet
2 | if lighty ~= nil then
3 | -- Note: package.loaded.lighty ~= nil will not work because lighty is a
4 | -- local variable and not a package
5 | local docroot = lighty.env['physical.doc-root']
6 | package.path = package.path..";"..docroot.."/../lib/lua/?.lua"
7 | package.cpath = package.cpath..";"..docroot.."/../lib/clibs/?.dll"
8 | package.path = package.path..";"..docroot.."/sailor/?.lua"
9 |
10 | -- FIXME: os.tmpname(), used by web_utils\utils.lua not
11 | -- working in LightTPD (affects Windows build only?)
12 | -- This breaks every script using "session"
13 | function os.tmpname()
14 | return 'tmp'
15 | end
16 |
17 | -- Makes lighty global so it can be accessed by Remy or controllers
18 | _G["lighty"] = lighty
19 | local sailor = require "sailor"
20 | sailor.launch()
21 | return sailor.r.status
22 | end
23 |
24 |
--------------------------------------------------------------------------------
/src/sailor/blank-app/index-magnet.lua:
--------------------------------------------------------------------------------
1 | -- Alternative index and launcher for LightTPD's mod_magnet
2 | if lighty ~= nil then
3 | -- Note: package.loaded.lighty ~= nil will not work because lighty is a
4 | -- local variable and not a package
5 | local docroot = lighty.env['physical.doc-root']
6 | package.path = package.path..";"..docroot.."/../lib/lua/?.lua"
7 | package.cpath = package.cpath..";"..docroot.."/../lib/clibs/?.dll"
8 | package.path = package.path..";"..docroot.."/sailor/?.lua"
9 |
10 | -- FIXME: os.tmpname(), used by web_utils\utils.lua not
11 | -- working in LightTPD (affects Windows build only?)
12 | -- This breaks every script using "session"
13 | function os.tmpname()
14 | return 'tmp'
15 | end
16 |
17 | -- Makes lighty global so it can be accessed by Remy or controllers
18 | _G["lighty"] = lighty
19 | local sailor = require "sailor"
20 | sailor.launch()
21 | return sailor.r.status
22 | end
23 |
24 |
--------------------------------------------------------------------------------
/test/dev-app/sql/sqlite3.sql:
--------------------------------------------------------------------------------
1 | -- SQLite3
2 | drop table if exists users;
3 | create table users(
4 | 'id' integer primary key autoincrement,
5 | 'username' varchar(20),
6 | 'password' varchar(64)
7 | );
8 |
9 | drop table if exists post;
10 | create table post(
11 | `id` INTEGER PRIMARY KEY AUTOINCREMENT,
12 | `body` TEXT,
13 | `author_id` INTEGER REFERENCES users (id)
14 | );
15 |
16 | drop table if exists comment;
17 | create table comment(
18 | id integer primary key autoincrement,
19 | body text,
20 | author_id integer references users (id),
21 | post_id integer references post (id)
22 | );
23 |
24 | drop table if exists category;
25 | create table category(
26 | id integer primary key autoincrement,
27 | name text
28 | );
29 |
30 | drop table if exists post_category;
31 | create table post_category(
32 | post_id integer references post (id),
33 | category_id integer references category(id),
34 | primary key(post_id,category_id)
35 | );
36 |
--------------------------------------------------------------------------------
/test/dev-app/themes/default/config.json:
--------------------------------------------------------------------------------
1 | {
2 | "vars": {},
3 | "css": [
4 | "print.less",
5 | "type.less",
6 | "code.less",
7 | "grid.less",
8 | "tables.less",
9 | "forms.less",
10 | "buttons.less",
11 | "glyphicons.less",
12 | "button-groups.less",
13 | "input-groups.less",
14 | "navs.less",
15 | "navbar.less",
16 | "breadcrumbs.less",
17 | "pagination.less",
18 | "pager.less",
19 | "labels.less",
20 | "badges.less",
21 | "jumbotron.less",
22 | "thumbnails.less",
23 | "alerts.less",
24 | "progress-bars.less",
25 | "media.less",
26 | "list-group.less",
27 | "panels.less",
28 | "wells.less",
29 | "close.less",
30 | "dropdowns.less",
31 | "tooltip.less",
32 | "popovers.less",
33 | "modals.less",
34 | "carousel.less",
35 | "utilities.less",
36 | "responsive-utilities.less",
37 | "component-animations.less"
38 | ],
39 | "js": []
40 | }
--------------------------------------------------------------------------------
/src/sailor/blank-app/themes/default/config.json:
--------------------------------------------------------------------------------
1 | {
2 | "vars": {},
3 | "css": [
4 | "print.less",
5 | "type.less",
6 | "code.less",
7 | "grid.less",
8 | "tables.less",
9 | "forms.less",
10 | "buttons.less",
11 | "glyphicons.less",
12 | "button-groups.less",
13 | "input-groups.less",
14 | "navs.less",
15 | "navbar.less",
16 | "breadcrumbs.less",
17 | "pagination.less",
18 | "pager.less",
19 | "labels.less",
20 | "badges.less",
21 | "jumbotron.less",
22 | "thumbnails.less",
23 | "alerts.less",
24 | "progress-bars.less",
25 | "media.less",
26 | "list-group.less",
27 | "panels.less",
28 | "wells.less",
29 | "close.less",
30 | "dropdowns.less",
31 | "tooltip.less",
32 | "popovers.less",
33 | "modals.less",
34 | "carousel.less",
35 | "utilities.less",
36 | "responsive-utilities.less",
37 | "component-animations.less"
38 | ],
39 | "js": []
40 | }
--------------------------------------------------------------------------------
/test/dev-app/models/user.lua:
--------------------------------------------------------------------------------
1 | local user = {}
2 | local val = require "valua"
3 | local access = require "sailor.access"
4 | -- Attributes and their validation rules
5 | user.attributes = {
6 | --{ = < "safe" or validation function, requires valua >}
7 | {id = "safe"},
8 | {username = val:new().not_empty() },
9 | {password = val:new().not_empty().len(6,10) }
10 | }
11 |
12 | user.db = {
13 | key = 'id',
14 | table = 'users'
15 | }
16 |
17 | user.relations = {
18 | posts = {relation = "HAS_MANY", model = "post", attribute = "author_id"},
19 | comments = {relation = "HAS_MANY", model = "comment", attribute = "author_id"}
20 | }
21 |
22 | -- Public Methods
23 | function user.test() return "test" end
24 |
25 | function user.authenticate(login,password,use_hashing)
26 | if use_hashing == nil then use_hashing = true end
27 | access.settings({model = 'user', hashing = use_hashing})
28 | return access.login(login,password)
29 | end
30 |
31 | function user.logout()
32 | return access.logout()
33 | end
34 |
35 | return user
36 |
--------------------------------------------------------------------------------
/test/dev-app/views/test/index.lp:
--------------------------------------------------------------------------------
1 |
2 |
3 | SAILOR!
4 |
5 |
6 |
7 | This comes from a .lp file. "LP" stands for Lua Page.
8 |
9 | You can use lua scripts here inside tags, everything else looks like regular HTML.
10 |
11 | More info about it here.
12 |
13 |
14 |
23 |
24 |
25 |
26 |
27 | if test==true then ?>
28 | =var?>
29 | else ?>
30 | it will never print this
31 | end ?>
32 |
33 | for i = 0, 10, 1 do ?>
34 | this is in a loop = i ?>
35 |
36 | end ?>
37 | = stringVariable ?>
38 | = anotherVar ?>
39 |
40 |
41 |
42 |
--------------------------------------------------------------------------------
/test/dev-app/themes/default/css/sticky-footer-navbar.css:
--------------------------------------------------------------------------------
1 | /* Sticky footer styles
2 | -------------------------------------------------- */
3 |
4 | html,
5 | body {
6 | height: 100%;
7 | /* The html and body elements cannot have any padding or margin. */
8 | }
9 |
10 | /* Wrapper for page content to push down footer */
11 | #wrap {
12 | min-height: 100%;
13 | height: auto;
14 | /* Negative indent footer by its height */
15 | margin: 0 auto -60px;
16 | /* Pad bottom by footer height */
17 | padding: 0 0 60px;
18 | }
19 |
20 | /* Set the fixed height of the footer here */
21 | #footer {
22 | height: 60px;
23 | background-color: #f5f5f5;
24 | }
25 |
26 |
27 | /* Custom page CSS
28 | -------------------------------------------------- */
29 | /* Not required for template or sticky footer method. */
30 |
31 | #wrap > .container {
32 | padding: 60px 15px 0;
33 | }
34 | .container .text-muted {
35 | margin: 20px 0;
36 | }
37 |
38 | #footer > .container {
39 | padding-left: 15px;
40 | padding-right: 15px;
41 | }
42 |
43 | code {
44 | font-size: 80%;
45 | }
46 |
--------------------------------------------------------------------------------
/src/sailor/blank-app/themes/default/css/sticky-footer-navbar.css:
--------------------------------------------------------------------------------
1 | /* Sticky footer styles
2 | -------------------------------------------------- */
3 |
4 | html,
5 | body {
6 | height: 100%;
7 | /* The html and body elements cannot have any padding or margin. */
8 | }
9 |
10 | /* Wrapper for page content to push down footer */
11 | #wrap {
12 | min-height: 100%;
13 | height: auto;
14 | /* Negative indent footer by its height */
15 | margin: 0 auto -60px;
16 | /* Pad bottom by footer height */
17 | padding: 0 0 60px;
18 | }
19 |
20 | /* Set the fixed height of the footer here */
21 | #footer {
22 | height: 60px;
23 | background-color: #f5f5f5;
24 | }
25 |
26 |
27 | /* Custom page CSS
28 | -------------------------------------------------- */
29 | /* Not required for template or sticky footer method. */
30 |
31 | #wrap > .container {
32 | padding: 60px 15px 0;
33 | }
34 | .container .text-muted {
35 | margin: 20px 0;
36 | }
37 |
38 | #footer > .container {
39 | padding-left: 15px;
40 | padding-right: 15px;
41 | }
42 |
43 | code {
44 | font-size: 80%;
45 | }
46 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | Copyright 2013-2014 Etiene Dalcol
2 |
3 | Permission is hereby granted, free of charge, to any person obtaining a copy
4 | of this software and associated documentation files (the "Software"), to deal
5 | in the Software without restriction, including without limitation the rights
6 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7 | copies of the Software, and to permit persons to whom the Software is
8 | furnished to do so, subject to the following conditions:
9 |
10 | The above copyright notice and this permission notice shall be included in all
11 | copies or substantial portions of the Software.
12 |
13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
19 | SOFTWARE.
--------------------------------------------------------------------------------
/src/sailor/cookie.lua:
--------------------------------------------------------------------------------
1 | --------------------------------------------------------------------------------
2 | -- cookie.lua, v1.1: lib for cookies
3 | -- This file is a part of Sailor project
4 | -- Copyright (c) 2014 Etiene Dalcol
5 | -- License: MIT
6 | -- http://sailorproject.org
7 | --------------------------------------------------------------------------------
8 |
9 | local cookie = {}
10 | local remy = require "remy"
11 |
12 | function cookie.set(r, key, value, path)
13 | path = path or "/"
14 | if remy.detect(r) == remy.MODE_CGILUA then
15 | local ck = require "cgilua.cookies"
16 | return ck.set(key,value,{path=path})
17 | end
18 | r.headers_out['Set-Cookie'] = ("%s=%s;Path=%s;"):format(key, value, path)
19 | end
20 |
21 | function cookie.get(r, key)
22 | local remy_mode = remy.detect(r)
23 | if remy_mode == remy.MODE_CGILUA then
24 | local ck = require "cgilua.cookies"
25 | return ck.get(key)
26 | elseif remy_mode == remy.MODE_LWAN then
27 | return r.native_request:cookie(key)
28 | end
29 | return (r.headers_in['Cookie'] or ""):match(key .. "=([^;]+)") or ""
30 | end
31 |
32 | return cookie
33 |
--------------------------------------------------------------------------------
/test/dev-app/sql/pgsql.sql:
--------------------------------------------------------------------------------
1 | -- PostgreSQL
2 | drop table if exists users cascade;
3 | drop table if exists post cascade;
4 | drop table if exists comment cascade;
5 | drop table if exists post_category cascade;
6 |
7 | drop table if exists users cascade;
8 | create table users(
9 | id serial primary key,
10 | username varchar(20),
11 | password varchar(64)
12 | );
13 |
14 | drop table if exists post cascade;
15 | create table post(
16 | id serial primary key,
17 | body text,
18 | author_id int references users ON DELETE set null
19 | );
20 |
21 | drop table if exists comment cascade;
22 | create table comment(
23 | id serial primary key,
24 | body text,
25 | author_id int references users ON DELETE set null,
26 | post_id int references post ON DELETE CASCADE
27 | );
28 |
29 | drop table if exists category cascade;
30 | create table category(
31 | id serial primary key,
32 | name text
33 | );
34 |
35 | drop table if exists post_category cascade;
36 | create table post_category(
37 | post_id int references post ON DELETE CASCADE,
38 | category_id int references category ON DELETE CASCADE,
39 | primary key(post_id,category_id)
40 | );
--------------------------------------------------------------------------------
/src/web_utils/utils.lua:
--------------------------------------------------------------------------------
1 | local os_tmpname, gsub = os.tmpname, string.gsub
2 |
3 | local M = {
4 | }
5 |
6 | -- Default function for temporary names
7 | -- @returns a temporay name using os.tmpname
8 | function M.tmpname ()
9 | local tempname = os_tmpname()
10 | -- Lua os.tmpname returns a full path in Unix, but not in Windows
11 | -- so we strip the eventual prefix
12 | tempname = gsub(tempname, "(/tmp/)", "")
13 | return tempname
14 | end
15 |
16 | -- deep copies a table
17 | function M.deepcopy(orig)
18 | local orig_type = type(orig)
19 | local copy
20 | if orig_type == 'table' then
21 | copy = {}
22 | for orig_key, orig_value in next, orig, nil do
23 | copy[M.deepcopy(orig_key)] = M.deepcopy(orig_value)
24 | end
25 | setmetatable(copy, M.deepcopy(getmetatable(orig)))
26 | else -- number, string, boolean, etc
27 | copy = orig
28 | end
29 | return copy
30 | end
31 |
32 | -- performs string split
33 | function M.split(str,sep)
34 | sep = sep or ":"
35 | local fields = {}
36 | local pattern = string.format("([^%s]+)", sep)
37 | str:gsub(pattern, function(c) fields[#fields+1] = c end)
38 | return fields
39 | end
40 |
41 | return M
42 |
--------------------------------------------------------------------------------
/test/dev-app/views/test/starlight.lp:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
hey
5 |
6 |
7 |
8 |
20 |
21 |
43 |
44 |
45 |
51 |
--------------------------------------------------------------------------------
/test/dev-app/tests/unit/openresty.lua:
--------------------------------------------------------------------------------
1 | --[[local remy = require "remy"
2 | --remy.forced_mode = remy.MODE_NGINX
3 | --local mysql = require "resty.mysql"
4 | --local rest =
5 | local helper = require "tests.helper"
6 | --local remy = require 'remy'
7 | fakengx = require 'fake.fakengx'
8 | ngx = fakengx.new()
9 | ngx.config = {}
10 | ngx.config.ngx_lua_version = 10000
11 | local old_tcp = ngx.socket.tcp
12 | ngx.socket.tcp = function()
13 | local sock,err = old_tcp()
14 | sock.getreusedtimes = function()
15 | return 0
16 | end
17 | return sock,err
18 | end
19 |
20 |
21 | local db
22 | describe("Testing #openresty", function()
23 |
24 | setup(function()
25 | remy.force_mode(remy.MODE_NGINX)
26 |
27 | db = require "sailor.db"
28 | db = db.detect()
29 | end)
30 |
31 | it("should do nothing", function()
32 | --print(tstring(remy,0,' ','\n'))
33 | print("mode:",remy.detect())
34 | assert.is_equal(1,1)
35 |
36 | end)
37 |
38 | it("should find 1 result",function()
39 | db.connect()
40 | local res = db.query("select * from post where id = 1")
41 | print(helper.tostring(res))
42 | db.close()
43 | assert.is_equal(1,#res)
44 | end)
45 |
46 | teardown(function()
47 |
48 | end)
49 | --remy.forced_mode = nil
50 | --ngx = nil
51 | end)
52 | ]]
--------------------------------------------------------------------------------
/src/sailor/blank-app/conf/conf.lua:
--------------------------------------------------------------------------------
1 | local conf = {
2 | sailor = {
3 | app_name = 'Sailor! A Lua MVC Framework',
4 | default_static = nil, -- If defined, default page will be a rendered lp as defined.
5 | -- Example: 'maintenance' will render /views/maintenance.lp
6 | default_controller = 'main',
7 | default_action = 'index',
8 | theme = 'default',
9 | layout = 'main',
10 | route_parameter = 'r',
11 | default_error404 = 'error/404',
12 | enable_autogen = false, -- default is false, should be true only in development environment
13 | friendly_urls = false,
14 | max_upload = 1024 * 1024,
15 | environment = "development", -- this will use db configuration named development
16 | hide_stack_trace = false -- false recommended for development, true recommended for production
17 | },
18 |
19 | db = {
20 | development = { -- current environment
21 | driver = 'mysql',
22 | host = '',
23 | user = '',
24 | pass = '',
25 | dbname = ''
26 | }
27 | },
28 |
29 | smtp = {
30 | server = '',
31 | user = '',
32 | pass = '',
33 | from = ''
34 | },
35 |
36 | lua_at_client = {
37 | vm = "starlight", -- starlight is default. Other options are moonshine, lua51js and luavmjs. They need to be downloaded.
38 | },
39 |
40 | debug = {
41 | inspect = false
42 | }
43 | }
44 |
45 | return conf
46 |
--------------------------------------------------------------------------------
/src/sailor/blank-app/tests/bootstrap_resty.lua:
--------------------------------------------------------------------------------
1 | sailor = require "sailor"
2 | local t = require "sailor.test"
3 | local busted = require 'busted.runner'
4 | local lfs = require 'lfs'
5 |
6 | -- load fixtures
7 | -- t.load_fixtures()
8 |
9 | -- prepare busted
10 | busted()
11 |
12 | local busted_lib = {
13 | describe = describe,
14 | it = it,
15 | setup = setup,
16 | assert = assert,
17 | teardown = teardown,
18 | before_each = before_each,
19 | finally = finally,
20 | pending = pending,
21 | spy = spy,
22 | stub = stub,
23 | mock = mock,
24 | }
25 |
26 | local test_dirs = {
27 | "tests/unit",
28 | "tests/functional",
29 | }
30 |
31 | -- Get busted vars to pass them ahead when loading each test file
32 |
33 | local env = {}
34 | for k,v in pairs(_G) do env[k] = v end
35 | for name,f in pairs(busted_lib) do
36 | env[name] = f
37 | end
38 |
39 | -- Looping through test dirs and loading them with environment with busted vars
40 |
41 | for _,dir in pairs(test_dirs) do
42 | dir = sailor.path..'/'..dir
43 | for file in lfs.dir(dir) do
44 | if file ~= '.' and file ~= '..' then
45 | local test
46 | if _VERSION == "Lua 5.1" then
47 | test = assert(loadfile(dir..'/'..file))
48 | setfenv(test,env)
49 | else
50 | test = assert(loadfile(dir..'/'..file, env))
51 | end
52 | test()
53 | end
54 | end
55 | end
56 |
57 |
--------------------------------------------------------------------------------
/test/dev-app/conf/nginx.conf:
--------------------------------------------------------------------------------
1 | worker_processes 1;
2 | error_log stderr notice;
3 |
4 | events {
5 | worker_connections 16384;
6 | }
7 | http {
8 | server {
9 | listen 8080;
10 | include mime.types;
11 | default_type application/octet-stream;
12 | root .;
13 | sendfile on;
14 | access_log off;
15 | location / {
16 | lua_need_request_body on;
17 | lua_code_cache on;
18 | content_by_lua_file index.lua;
19 | index index.lua index.lp;
20 | }
21 |
22 | location ~ ^/[^\.]+$ {
23 | lua_need_request_body on;
24 | lua_code_cache off;
25 | content_by_lua_file index.lua;
26 | index index.lp index.lua;
27 | rewrite_by_lua_block {
28 | local conf = require "conf.conf"
29 | if conf.sailor.friendly_urls then
30 | local args = ngx.req.get_uri_args()
31 | args[conf.sailor.route_parameter] = ngx.var.uri:sub(2)
32 |
33 | ngx.req.set_uri_args(args)
34 | ngx.req.set_uri("/index.lua")
35 | end
36 | }
37 | }
38 |
39 | location ~ \.(css|eot|js|json|gif|jpg|png|svg|ttf|woff|map)$ {
40 | }
41 | }
42 | }
--------------------------------------------------------------------------------
/src/sailor/blank-app/conf/nginx.conf:
--------------------------------------------------------------------------------
1 | worker_processes 1;
2 | error_log stderr notice;
3 |
4 | events {
5 | worker_connections 16384;
6 | }
7 | http {
8 | server {
9 | listen 8080;
10 | include mime.types;
11 | default_type application/octet-stream;
12 | root .;
13 | sendfile on;
14 | access_log off;
15 | location / {
16 | lua_need_request_body on;
17 | lua_code_cache on;
18 | content_by_lua_file index.lua;
19 | index index.lua index.lp;
20 | }
21 |
22 | location ~ ^/[^\.]+$ {
23 | lua_need_request_body on;
24 | lua_code_cache on;
25 | content_by_lua_file index.lua;
26 | index index.lp index.lua;
27 | rewrite_by_lua_block {
28 | local conf = require "conf.conf"
29 | if conf.sailor.friendly_urls then
30 | local args = ngx.req.get_uri_args()
31 | args[conf.sailor.route_parameter] = ngx.var.uri:sub(2)
32 |
33 | ngx.req.set_uri_args(args)
34 | ngx.req.set_uri("/index.lua")
35 | end
36 | }
37 | }
38 |
39 | location ~ \.(css|eot|js|json|gif|jpg|png|svg|ttf|woff|map)$ {
40 | }
41 | }
42 | }
--------------------------------------------------------------------------------
/test/dev-app/tests/bootstrap_resty.lua:
--------------------------------------------------------------------------------
1 | sailor = require "sailor"
2 | local t = require "sailor.test"
3 | local busted = require 'busted.runner'
4 | local lfs = require 'lfs'
5 |
6 | -- load fixtures
7 |
8 | t.load_fixtures('user')
9 | t.load_fixtures('post')
10 | t.load_fixtures('category')
11 |
12 | -- prepare busted
13 | busted()
14 |
15 | local busted_lib = {
16 | describe = describe,
17 | it = it,
18 | setup = setup,
19 | assert = assert,
20 | teardown = teardown,
21 | before_each = before_each,
22 | finally = finally,
23 | pending = pending,
24 | spy = spy,
25 | stub = stub,
26 | mock = mock,
27 | }
28 |
29 | local test_dirs = {
30 | "tests/unit",
31 | "tests/functional",
32 | }
33 |
34 | -- Get busted vars to pass them ahead when loading each test file
35 |
36 | local env = {}
37 | for k,v in pairs(_G) do env[k] = v end
38 | for name,f in pairs(busted_lib) do
39 | env[name] = f
40 | end
41 |
42 | -- Looping through test dirs and loading them with environment with busted vars
43 |
44 | for _,dir in pairs(test_dirs) do
45 | dir = sailor.path..'/'..dir
46 | for file in lfs.dir(dir) do
47 | if file ~= '.' and file ~= '..' then
48 | local test
49 | if _VERSION == "Lua 5.1" then
50 | test = assert(loadfile(dir..'/'..file))
51 | setfenv(test,env)
52 | else
53 | test = assert(loadfile(dir..'/'..file, env))
54 | end
55 | test()
56 | end
57 | end
58 | end
59 |
60 |
--------------------------------------------------------------------------------
/.luacheckrc:
--------------------------------------------------------------------------------
1 |
2 | codes = true
3 |
4 | std = 'max'
5 | files['src/sailor/blank-app/tests'].std = 'max+busted'
6 | files['test/dev-app/tests'].std = 'max+busted'
7 |
8 | ignore = { '11./sailor', -- global variable
9 | '113/lighty', -- global variable
10 | '211', -- unused variable
11 | '6..' } -- formatting
12 |
13 | files['src/sailor.lua'].ignore = { '111/handle', -- setting non-standard global variable handle
14 | '113/apr_table', -- accessing undefined variable apr_table
15 | '113/apache2', -- accessing undefined variable apache2
16 | '231/GETMULTI', -- variable GETMULTI is never accessed
17 | '321/res', -- accessing uninitialized variable res
18 | '431/autogen' } -- shadowing upvalue autogen
19 | files['src/sailor/blank-app/index-magnet.lua'].ignore = { '122' } -- setting read-only field tmpname of global os
20 | files['src/sailor/model.lua'].ignore = { '431/model' } -- shadowing upvalue model
21 | files['src/sailor/page.lua'].ignore = { '212/self' } -- unused argument self
22 | files['src/sailor/db/luasql_common.lua'].ignore = { '212/key' } -- unused argument key
23 | files['test/dev-app/index-magnet.lua'].ignore = { '122' } -- setting read-only field tmpname of global os
24 | files['test/dev-app/tests/unit/model.lua'].ignore = { '431/u' } -- shadowing upvalue u
25 |
26 |
--------------------------------------------------------------------------------
/test/dev-app/controllers/category.lua:
--------------------------------------------------------------------------------
1 | local sailor = require "sailor"
2 |
3 | local M = {}
4 |
5 | function M.index(page)
6 | local categorys = sailor.model("category"):find_all()
7 | page:render('index',{categorys = categorys})
8 | end
9 |
10 | function M.create(page)
11 | local category = sailor.model("category"):new()
12 | local saved
13 | if next(page.POST) then
14 | category:get_post(page.POST)
15 | saved = category:save()
16 | if saved then
17 | page:redirect('category/index')
18 | end
19 | end
20 | page:render('create',{category = category, saved = saved})
21 | end
22 |
23 | function M.update(page)
24 | local category = sailor.model("category"):find_by_id(page.GET.id)
25 | if not category then
26 | return 404
27 | end
28 | local saved
29 | if next(page.POST) then
30 | category:get_post(page.POST)
31 | saved = category:update()
32 | if saved then
33 | page:redirect('category/index')
34 | end
35 | end
36 | page:render('update',{category = category, saved = saved})
37 | end
38 |
39 | function M.view(page)
40 | local category = sailor.model("category"):find_by_id(page.GET.id)
41 | if not category then
42 | return 404
43 | end
44 | page:render('view',{category = category})
45 | end
46 |
47 | function M.delete(page)
48 | local category = sailor.model("category"):find_by_id(page.GET.id)
49 | if not category then
50 | return 404
51 | end
52 |
53 | if category:delete() then
54 | page:redirect('category/index')
55 | end
56 | end
57 |
58 | return M
59 |
--------------------------------------------------------------------------------
/test/dev-app/conf/conf.lua:
--------------------------------------------------------------------------------
1 |
2 | local db_driver, db_user, db_pass, db_name
3 |
4 | if os.getenv("TRAVIS") == "true" then
5 | db_driver = assert(os.getenv("DB_DRIVER"))
6 | db_user = assert(os.getenv("DB_USER"))
7 | db_pass = os.getenv("DB_PASS")
8 | db_name = os.getenv("DB_NAME")
9 | end
10 |
11 | local conf = {
12 | sailor = {
13 | app_name = 'Sailor! A Lua MVC Framework',
14 | default_static = nil, -- If defined, default page will be a rendered lp as defined.
15 | -- Example: 'maintenance' will render /views/maintenance.lp
16 | default_controller = 'main',
17 | default_action = 'index',
18 | theme = 'default',
19 | layout = 'main',
20 | route_parameter = 'r',
21 | default_error404 = 'error/404',
22 | enable_autogen = true, -- default is false, should be true only in development environment
23 | friendly_urls = false,
24 | max_upload = 1024 * 1024,
25 | environment = "test", -- this will use db configuration named test
26 | },
27 |
28 | db = {
29 | test = { -- current environment
30 | driver = db_driver or 'mysql',
31 | host = 'localhost',
32 | user = db_user or '',
33 | pass = db_pass or '',
34 | dbname = db_name or ''
35 | }
36 | },
37 |
38 | smtp = {
39 | server = '',
40 | user = '',
41 | pass = '',
42 | from = ''
43 | },
44 |
45 | lua_at_client = {
46 | vm = "starlight", -- starlight is default. Other options are: "lua51js", "luavmjs" and "moonshine"
47 | },
48 |
49 | debug = {
50 | inspect = true
51 | }
52 | }
53 |
54 | return conf
55 |
--------------------------------------------------------------------------------
/test/dev-app/tests/unit/form.lua:
--------------------------------------------------------------------------------
1 | local form = require "sailor.form"
2 | local model = require "sailor.model"
3 | local User = model("user")
4 |
5 | describe("Testing form generator", function()
6 | local u = User:new()
7 |
8 | it("should not create fields that don't exist", function ()
9 | assert.has_error(
10 | function() form.blah(u,'password') end
11 | )
12 | end)
13 |
14 | it("should create a generic field accordingly", function()
15 | local html = form.text(u,'password')
16 | assert.equal('',html)
17 | end)
18 |
19 | it("should create textarea field accordingly", function()
20 | local html = form.textarea(u,'password')
21 | assert.equal(html,'')
22 | end)
23 |
24 | it("should create a dropdown list accordingly", function()
25 | local html = form.dropdown(u,'password',{'a','b'},'Select...')
26 | assert.equal(html,'')
27 | end)
28 |
29 | it("should create a radio list accordingly", function()
30 | local html = form.radio_list(u,'password',{'a','b'},1,'vertical')
31 | assert.equal(html,' a b')
32 | end)
33 |
34 | it("should create a checkbox accordingly", function()
35 | local html = form.checkbox(u,'password',nil, true)
36 | assert.equal(html,' password')
37 | end)
38 |
39 | end)
40 |
--------------------------------------------------------------------------------
/src/sailor/session.lua:
--------------------------------------------------------------------------------
1 | --------------------------------------------------------------------------------
2 | -- session.lua, v0.2.1: cgilua session abstraction
3 | -- This file is a part of Sailor project
4 | -- Copyright (c) 2014 Etiene Dalcol
5 | -- License: MIT
6 | -- http://sailorproject.org
7 | --------------------------------------------------------------------------------
8 |
9 | local sailor = require "sailor"
10 | local utils = require "web_utils.utils"
11 | local session = require "web_utils.session"
12 | local cookie = require "sailor.cookie"
13 |
14 | local ID_NAME = "SAILORSESSID"
15 |
16 | session.id = nil
17 | session.setsessiondir (sailor.path..'/runtime/tmp')
18 |
19 | function session.open (r)
20 | if session.id then
21 | return session.id
22 | end
23 |
24 | local id = cookie.get(r,ID_NAME )
25 | if not id then
26 | session.new(r)
27 | else
28 | session.data = session.load(id)
29 | if session.data then
30 | session.id = id
31 | else
32 | session.new(r)
33 | end
34 | end
35 |
36 | session.cleanup()
37 | return id
38 | end
39 |
40 | function session.destroy (r)
41 | local id = session.id or cookie.get(r,ID_NAME )
42 | if id then
43 | session.data = {}
44 | session.delete (id)
45 | end
46 | session.id = nil
47 | return true
48 | end
49 |
50 | local new = session.new
51 | function session.new(r)
52 | session.id = new()
53 | session.data = {}
54 | cookie.set(r,ID_NAME,session.id)
55 | end
56 |
57 | local save = session.save
58 | function session.save(data)
59 | save(session.id,data)
60 | session.data = data
61 | return true
62 | end
63 |
64 | function session.is_active()
65 | return session.id ~= nil
66 | end
67 |
68 |
69 | return session
70 |
--------------------------------------------------------------------------------
/test/dev-app/views/test/luavmjs.lp:
--------------------------------------------------------------------------------
1 |
2 |
Hello
3 |
Hello
4 |
17 | max then return false,"should have "..min.."-"..max.." characters" end
48 | return true
49 | end
50 | local test = {}
51 | table.insert(test,len)
52 | for i=1,10000 do
53 | for k, v in ipairs(test) do
54 | v('oi',3,5)
55 | end
56 | -- Something is up with ipairs?
57 | end
58 | t()
59 |
60 |
61 | t = timer("Function 8 Insert on table")
62 | test = {}
63 | for i=1,1000 do
64 | test[i] = i
65 | end
66 | t()
67 |
68 | t = timer("Function 9 Read from table using ipairs")
69 | test = {}
70 | for i=1,10000 do
71 | for k, v in ipairs(test) do
72 | test[k] = k + 1
73 | end
74 | end
75 | t()
76 |
77 | t = timer("Function 10 Read from table using pairs")
78 | test = {}
79 | for i=1,10000 do
80 | for k, v in ipairs(test) do
81 | test[k] = k + 1
82 | end
83 | end
84 | t()
85 |
86 | ?>
--------------------------------------------------------------------------------
/test/dev-app/views/test/lua51js.lp:
--------------------------------------------------------------------------------
1 |
2 |
Hello
3 |
Hello
4 |
17 | max then return false,"should have "..min.."-"..max.." characters" end
48 | return true
49 | end
50 | local test = {}
51 | table.insert(test,len)
52 | for i=1,10000 do
53 | for k, v in ipairs(test) do
54 | v('oi',3,5)
55 | end
56 | -- Something is up with ipairs?
57 | end
58 | t()
59 |
60 |
61 | t = timer("Function 8 Insert on table")
62 | test = {}
63 | for i=1,1000 do
64 | test[i] = i
65 | end
66 | t()
67 |
68 | t = timer("Function 9 Read from table using ipairs")
69 | test = {}
70 | for i=1,10000 do
71 | for k, v in ipairs(test) do
72 | test[k] = k + 1
73 | end
74 | end
75 | t()
76 |
77 | t = timer("Function 10 Read from table using pairs")
78 | test = {}
79 | for i=1,10000 do
80 | for k, v in ipairs(test) do
81 | test[k] = k + 1
82 | end
83 | end
84 | t()
85 |
86 | ?>
--------------------------------------------------------------------------------
/test/dev-app/sql/mysql.sql:
--------------------------------------------------------------------------------
1 | -- MySQL
2 | drop table if exists users;
3 | create table users(
4 | id int primary key auto_increment,
5 | username varchar(20),
6 | password varchar(64)
7 | );
8 |
9 | drop table if exists post;
10 | create table post(
11 | id int primary key auto_increment,
12 | body text,
13 | author_id int references users (id)
14 | );
15 |
16 | drop table if exists comment;
17 | create table comment(
18 | id int primary key auto_increment,
19 | body text,
20 | author_id int references users (id),
21 | post_id int references post (id)
22 | );
23 |
24 | drop table if exists category;
25 | create table category(
26 | id int primary key auto_increment,
27 | name text
28 | );
29 |
30 | drop table if exists post_category;
31 | create table post_category(
32 | post_id int references post (id),
33 | category_id int references category(id),
34 | primary key(post_id,category_id)
35 | );
36 |
37 | insert into users values (1,'etiene','geronimo');
38 | insert into users values (2,'pedro','fantastic');
39 |
40 | insert into post values (1,'This is a post',1);
41 | insert into post values (2,'This is another post',2);
42 | insert into post values (3,'This is yet anoter post',1);
43 |
44 | insert into category values (1,'Politics');
45 | insert into category values (2,'Internet');
46 | insert into category values (3,'Programming');
47 | insert into category values (4,'Personal');
48 | insert into category values (5,'Other');
49 |
50 | insert into post_category values (1,1);
51 | insert into post_category values (1,2);
52 | insert into post_category values (1,3);
53 | insert into post_category values (2,5);
54 | insert into post_category values (2,4);
55 | insert into post_category values (3,3);
56 | insert into post_category values (3,4);
57 |
58 | insert into comment values(1,"This is a comment",2,1);
59 | insert into comment values(2,"This is another comment",2,1);
60 | insert into comment values(3,"This is yet another comment",1,2);
61 |
--------------------------------------------------------------------------------
/docs/manual_access_module.md:
--------------------------------------------------------------------------------
1 | ##Reference Manual
2 | ###The access module
3 | The access module is useful if you want to have a login system and pages that are not visible to guests. It needs to be required from either the controller or view: `local access = require "sailor.access"`. If you want to deactive the default login and password, you must setup a model to act as a User model.
4 |
5 | This is the default configuration of the access module
6 |
7 | local settings = {
8 | default_login = 'admin', -- Default login details
9 | default_password = 'demo',
10 | grant_time = 604800, -- 1 week
11 | model = nil, -- Setting this field will deactivate default login details and activate below fields
12 | login_attributes = {'username'},-- Allows multiple options, for example, username or email. The one used in the hash of the password should come first.
13 | password_attribute = 'password',
14 | salt_attribute = 'salt',
15 | hashing = true -- setting to false will deactivate hashing passwords
16 | }
17 |
18 |
19 |
20 | ####access.is_guest()
21 | Verifies if there is session data and returns a boolean.
22 |
23 | Example: ` if access.is_guest( ) return 404 end `
24 |
25 |
26 | ####access.login( username, password )
27 | Tries to login with the given username and password (raw). If using a User model, it will encrypt the given password string before making the comparison. Returns a boolean and an error string.
28 |
29 | * username, string.
30 | * password, string.
31 |
32 | Example 1: `local ok, err = access.login('admin','notdemo') -- false, Invalid username or password.`
33 |
34 | Example 2: `local ok, err = access.login('admin','demo') -- true, nil`
35 |
36 | ####access.logout()
37 | Logs user out and erases session.
38 |
39 | Example: `access.logout()`
40 |
41 | ####access.settings(s)
42 | Changes settings of the access module.
43 |
44 | * s: table with new settings.
45 |
46 | Example: ` access.settings{ default_login = 'IamGod', default_password = 'StairwayToHeaven' } `
47 |
48 |
--------------------------------------------------------------------------------
/test/dev-app/tests/functional/autogen.lua:
--------------------------------------------------------------------------------
1 | local test = require "sailor.test"
2 | local lfs = require "lfs"
3 | local conf = require "conf.conf"
4 | local model = require "sailor.model"
5 |
6 |
7 | local db = require "sailor.db"
8 | local helper = require "tests.helper"
9 |
10 |
11 |
12 | describe("Testing #Autogen", function()
13 |
14 | it("should not open autogen page", function()
15 | conf.sailor.enable_autogen = false
16 | local res = test.request('autogen')
17 | assert.truthy(res.body:match('Error'))
18 | end)
19 |
20 | it("should open autogen page", function()
21 | conf.sailor.enable_autogen = true
22 | local res = test.request('autogen')
23 | assert.same(200,res.status)
24 | assert.truthy(res.body:match('Generate CRUD'))
25 | end)
26 |
27 | it("should not generate model", function()
28 | local res = test.request('autogen',{post={table_name ='asdasd'}})
29 | assert.falsy(res.body:match('Model generated with success'))
30 | end)
31 |
32 | it("should generate model", function()
33 | local path = 'models/category.lua'
34 | os.remove(path)
35 | local res = test.request('autogen',{post={table_name ='category'}})
36 | assert.truthy(res.body:match('Model generated with success'))
37 | assert.truthy(lfs.attributes(path))
38 | end)
39 |
40 | it("should not generate CRUD", function()
41 | local res = test.request('autogen',{post={model_name ='asdasd'}})
42 | assert.falsy(res.body:match('CRUD generated with success'))
43 | end)
44 |
45 | it("should generate CRUD", function()
46 | local paths = {
47 | 'controllers/category.lua',
48 | 'views/category/create.lp',
49 | 'views/category/index.lp',
50 | 'views/category/update.lp',
51 | 'views/category/view.lp'
52 | }
53 | for _,f in ipairs(paths) do
54 | os.remove(f)
55 | end
56 |
57 | local res = test.request('autogen',{post={model_name ='category'}})
58 | assert.truthy(res.body:match('CRUD generated with success'))
59 | for _,f in ipairs(paths) do
60 | assert.truthy(lfs.attributes(f))
61 | end
62 | end)
63 |
64 | end)
--------------------------------------------------------------------------------
/docs/tutorial_controllers.md:
--------------------------------------------------------------------------------
1 | ##Controllers
2 |
3 | When you access a Sailor application, you will be routed to your page depending on the url. If there is nothing to route, sailor will load the default action specified in your conf.lua. Suppose the accessed url is `localhost/your_application/?r=main/index` (no friendly urls) or `localhost/your_application/main/index` (friendly urls activated). That means Sailor will try to find an action named 'index' inside a controller named 'main' on your application and run that function.
4 |
5 | A controller is a .lua file inside `/controllers` on your app's directory tree named after your controller's name. This is the basic structure of our `main.lua`:
6 |
7 | local main = {} --a table
8 |
9 | --Your actions are functions indexed by this table. They receive the 'page' object.
10 | function main.index(page)
11 | --Let's send a message to our view
12 | page:render("index", { msg = "Hello"})
13 | end
14 |
15 | return main --don't forget to return your controller at the end of the file.
16 |
17 |
18 | You can have multiple actions inside your controller, all of them are functions indexed to a table you will return at the end of your controller. The action receives the 'page' object as an argument and this object contains attributes and methods for interacting with your page. The first method we will learn is `page:render()`. For other methods of the page object, please consult the reference manual.
19 |
20 | The render method has two parameters, a string with the view file to be rendered and a table with the vars that are being passed ahead. Sailor will look for your view file inside `/views/controller_name/file_name.lp`. So, a `page:render('index',{msg="Hello"})` executed from the main controller will render `/views/main/index.lp` and from that view you will have access to a variable named 'msg' containing the string 'Hello' (and the page object, which is also passed ahead by default). If you have configured a theme and a layout or are using the default theme and layout, Sailor will first render the layout and then render your view wrapped inside it, otherwise it will render your view directly.
21 |
--------------------------------------------------------------------------------
/test/dev-app/tests/unit/access.lua:
--------------------------------------------------------------------------------
1 | local test = require "sailor.test"
2 | local access = require "sailor.access"
3 | local User = require "sailor.model"('user')
4 | local fixtures = require "tests.fixtures.user" or {}
5 |
6 | describe("Testing #UserController", function()
7 |
8 | it("should know no one has logged in", function()
9 | assert.is_true(access.is_guest())
10 | end)
11 |
12 | it("should not login with wrong pass", function()
13 | assert.is_false(User.authenticate(fixtures[1].username,"dummy",true))
14 | end)
15 |
16 | it("should not login with wrong username", function()
17 | assert.is_false(User.authenticate("meh",fixtures[1].password,false))
18 | end)
19 |
20 | it("should not login with default settings", function()
21 | assert.is_false(access.login('admin','demo'))
22 | end)
23 |
24 | it("should login", function()
25 | assert.is_true(User.authenticate(fixtures[1].username,fixtures[1].password,false))
26 | end)
27 |
28 | it("should know the user is logged in", function()
29 | assert.is_false(access.is_guest())
30 | end)
31 |
32 | it("should logout", function()
33 | assert.is_true(User.logout())
34 | end)
35 |
36 | it("should know the user is logged out", function()
37 | assert.is_true(access.is_guest())
38 | end)
39 |
40 | it("should login with encrypted pass", function()
41 | local u = User:new()
42 | u.username = 'Hermione'
43 | local raw_pass = 'freeelf54'
44 | u.password = access.hash(u.username,raw_pass)
45 | u:save(false)
46 | assert.is_true(User.authenticate(u.username,raw_pass,true))
47 | assert.is_false(access.is_guest())
48 | User.logout()
49 | u:delete()
50 | end)
51 |
52 | it("should with default settings", function()
53 | access.settings({model = false, hashing = false, default_login = 'admin', default_password = 'demo'})
54 | assert.is_true(access.login('admin','demo'))
55 | assert.is_false(access.is_guest())
56 | assert.is_true(User.logout())
57 | assert.is_true(access.is_guest())
58 |
59 | end)
60 |
61 | it("should not login with default settings", function()
62 | assert.is_false(access.login('admin','demon'))
63 | assert.is_true(access.is_guest())
64 | end)
65 |
66 | end)
67 |
--------------------------------------------------------------------------------
/test/dev-app/start-server.lua:
--------------------------------------------------------------------------------
1 | local xavante = require "xavante"
2 | local filehandler = require "xavante.filehandler"
3 | local cgiluahandler = require "xavante.cgiluahandler"
4 | local redirect = require "xavante.redirecthandler"
5 | local conf = (require "conf.conf").sailor
6 |
7 | -- Define here where Xavante HTTP documents scripts are located
8 | local webDir = "."
9 |
10 | local uri_map
11 |
12 | if conf.friendly_urls then
13 | uri_map = { -- URI remapping
14 | match = "^[^%./]*/?([^%.]*)$",
15 | with = redirect,
16 | params = {
17 | "/",
18 | function(req,_,cap)
19 | local vars = {}
20 |
21 | for var in string.gmatch(cap[1], '([^/]+)') do
22 | table.insert(vars,var)
23 | end
24 |
25 | if #vars > 0 then
26 | local mod = (#vars % 2) - 1
27 | local get = ""
28 |
29 | if #vars > 1 - mod then
30 | for i = 2 - mod, #vars, 2 do
31 | get = get.."&"..vars[i].."="..vars[i+1]
32 | end
33 | end
34 |
35 | if mod == -1 then
36 | get = vars[2]..get
37 | end
38 |
39 | req.cmd_url = "/index.lua?"..conf.route_parameter.."="..vars[1].."/"..get
40 | else
41 | req.cmd_url = "/index.lua"
42 | end
43 |
44 | return "reparse"
45 | end
46 | }
47 | }
48 | else
49 | uri_map = {
50 | match = "^[^%./]*/$",
51 | with = redirect,
52 | params = {"index.lua"}
53 | }
54 | end
55 |
56 | local simplerules = {
57 |
58 | uri_map,
59 |
60 | { -- cgiluahandler example
61 | match = {"%.lp$", "%.lp/.*$", "%.lua$", "%.lua/.*$" },
62 | with = cgiluahandler.makeHandler (webDir,{ reload = true })
63 | },
64 |
65 | { -- filehandler example
66 | match = ".",
67 | with = filehandler,
68 | params = {baseDir = webDir}
69 | },
70 | }
71 |
72 | xavante.HTTP{
73 | server = {host = "*", port = 8080},
74 |
75 | defaultHost = {
76 | rules = simplerules
77 | }
78 | }
79 | xavante.start()
80 |
--------------------------------------------------------------------------------
/src/sailor/blank-app/start-server.lua:
--------------------------------------------------------------------------------
1 | local xavante = require "xavante"
2 | local filehandler = require "xavante.filehandler"
3 | local cgiluahandler = require "xavante.cgiluahandler"
4 | local redirect = require "xavante.redirecthandler"
5 | local conf = (require "conf.conf").sailor
6 |
7 | -- Define here where Xavante HTTP documents scripts are located
8 | local webDir = "."
9 |
10 | local uri_map
11 |
12 | if conf.friendly_urls then
13 | uri_map = { -- URI remapping
14 | match = "^[^%./]*/?([^%.]*)$",
15 | with = redirect,
16 | params = {
17 | "/",
18 | function(req,_,cap)
19 | local vars = {}
20 |
21 | for var in string.gmatch(cap[1], '([^/]+)') do
22 | table.insert(vars,var)
23 | end
24 |
25 | if #vars > 0 then
26 | local mod = (#vars % 2) - 1
27 | local get = ""
28 |
29 | if #vars > 1 - mod then
30 | for i = 2 - mod, #vars, 2 do
31 | get = get.."&"..vars[i].."="..vars[i+1]
32 | end
33 | end
34 |
35 | if mod == -1 then
36 | get = vars[2]..get
37 | end
38 |
39 | req.cmd_url = "/index.lua?"..conf.route_parameter.."="..vars[1].."/"..get
40 | else
41 | req.cmd_url = "/index.lua"
42 | end
43 |
44 | return "reparse"
45 | end
46 | }
47 | }
48 | else
49 | uri_map = {
50 | match = "^[^%./]*/$",
51 | with = redirect,
52 | params = {"index.lua"}
53 | }
54 | end
55 |
56 | local simplerules = {
57 |
58 | uri_map,
59 |
60 | { -- cgiluahandler example
61 | match = {"%.lp$", "%.lp/.*$", "%.lua$", "%.lua/.*$" },
62 | with = cgiluahandler.makeHandler (webDir, { reload = true })
63 | },
64 |
65 | { -- filehandler example
66 | match = ".",
67 | with = filehandler,
68 | params = {baseDir = webDir}
69 | },
70 | }
71 |
72 | xavante.HTTP{
73 | server = {host = "*", port = 8080},
74 |
75 | defaultHost = {
76 | rules = simplerules
77 | }
78 | }
79 | xavante.start()
80 |
--------------------------------------------------------------------------------
/docs/manual_validation_module.md:
--------------------------------------------------------------------------------
1 | ##Reference Manual
2 | ###Valua: the validation module
3 | This is a module external to Sailor that is useful for setting validation rules to model attributes but it can also be used elsewhere. It needs to be required: `local valua = require "valua"`. It works in chains. First you need to create your validation object then you chain the validation functions you wish in the order you wish. If a test fails, it will break the chain. More info: Valua - validation for Lua
4 | ####Examples
5 | Example 1 - Just create, chain and use:
6 |
7 | valua:new().type("string").len(3,5)("test string!")
8 | -- false, "should have 3-5 characters"`
9 |
10 | Example 2 - Create, chain and later use it multiple times:
11 |
12 | local reusable_validation = valua:new().type("string").len(3,5)
13 | reusable_validation("test string!") -- false, "should have 3-5 characters"
14 | reusable_validation("test!") -- true`
15 |
16 | Example 3 - On a model:
17 |
18 | local user.attributes = {
19 | { username = valua:new().not_empty().len(6,20) }
20 | }
21 |
22 |
23 | ####Validation functions
24 |
25 | `alnum()` - Checks if string is alphanumeric.
26 |
27 | `boolean()` - Checks if value is a boolean.
28 |
29 | `compare(another_value)` - Checks if value is equal to another value.
30 |
31 | `contains(substr)` - Checks if a string contains a substring.
32 |
33 | `date()` or `date(format)` - Checks if a string is a valid date. Default format is UK (dd/mm/yyyy). Also checks for US and ISO formats.
34 |
35 | `email()` - Checks if a string is a valid email address.
36 |
37 | `empty()` - Checks if a value is empty.
38 |
39 | `integer()` - Checks if a number is an integer.
40 |
41 | `in_list(list)` - Checks if a value is inside an array.
42 |
43 | `len(min,max)` - Checks if a string's length is between min and max.
44 |
45 | `match(pattern)` - Checks if a string matches a given pattern.
46 |
47 | `max(n)` - Checks if a number is equal or less than n.
48 |
49 | `min(n)` - Checks if a number is equal or greater than n.
50 |
51 | `not_empty()` - Checks if a value is not empty.
52 |
53 | `no_white()` - Checks if a string contains no white spaces.
54 |
55 | `number()` - Checks if a value is a number.
56 |
57 | `string()` - Checks if a value is a string.
58 |
59 | `type(t)` - Checks if a value is of type t.
60 |
--------------------------------------------------------------------------------
/CODE_OF_CONDUCT.md:
--------------------------------------------------------------------------------
1 | # Sailor Contributor Code of Conduct
2 |
3 | As contributors and maintainers of Sailor, and in the interest of
4 | fostering an open and welcoming community, we pledge to respect all people who
5 | contribute through reporting issues, posting feature requests, updating
6 | documentation, submitting pull requests or patches, and other activities.
7 |
8 | We are committed to making participation in this project a harassment-free
9 | experience for everyone, regardless of level of experience, gender, gender
10 | identity and expression, sexual orientation, disability, personal appearance,
11 | body size, race, ethnicity, age, religion, or nationality.
12 |
13 | Examples of unacceptable behavior by participants include:
14 |
15 | * The use of sexualized language or imagery
16 | * Personal attacks
17 | * Trolling or insulting/derogatory comments
18 | * Public or private harassment
19 | * Publishing other's private information, such as physical or electronic
20 | addresses, without explicit permission
21 | * Other unethical or unprofessional conduct
22 |
23 | Project maintainers have the right and responsibility to remove, edit, or
24 | reject comments, commits, code, wiki edits, issues, and other contributions
25 | that are not aligned to this Code of Conduct, or to ban temporarily or
26 | permanently any contributor for other behaviors that they deem inappropriate,
27 | threatening, offensive, or harmful.
28 |
29 | By adopting this Code of Conduct, project maintainers commit themselves to
30 | fairly and consistently applying these principles to every aspect of managing
31 | this project. Project maintainers who do not follow or enforce the Code of
32 | Conduct may be permanently removed from the project team.
33 |
34 | This code of conduct applies both within project spaces and in public spaces
35 | when an individual is representing the project or its community.
36 |
37 | Instances of abusive, harassing, or otherwise unacceptable behavior may be
38 | reported by contacting the project maintainer at dalcol@etiene.net. All
39 | complaints will be reviewed and investigated and will result in a response that
40 | is deemed necessary and appropriate to the circumstances. Maintainers are
41 | obligated to maintain confidentiality with regard to the reporter of an
42 | incident.
43 |
44 |
45 | This Code of Conduct is adapted from the [Contributor Covenant][homepage],
46 | version 1.3.0, available at
47 | [http://contributor-covenant.org/version/1/3/0/][version]
48 |
49 | [homepage]: http://contributor-covenant.org
50 | [version]: http://contributor-covenant.org/version/1/3/0/
51 |
--------------------------------------------------------------------------------
/test/dev-app/tests/unit/db.lua:
--------------------------------------------------------------------------------
1 | local db = require "sailor.db"
2 | local helper = require "tests.helper"
3 |
4 | describe("Testing db module", function()
5 |
6 | local fixtures = require "tests.fixtures.post"
7 | local count = #fixtures
8 |
9 | it("should find 1 result",function()
10 | db.connect()
11 | local res = db.query("select * from post where id = 1")
12 | db.close()
13 | assert.is_equal(1,#res)
14 | end)
15 |
16 | it("should insert and give me the id",function()
17 | db.connect()
18 | local res = db.query_insert("insert into post(author_id,body) values(2,'Hello darkness my old friend')")
19 | db.close()
20 | count = count + 1
21 | -- should be posts already inserted by the fixtures plus this one
22 | assert.is_equal(count,res)
23 | end)
24 |
25 | it("should find multiple results",function()
26 | db.connect()
27 | local res = db.query("select * from post limit 2")
28 | db.close()
29 | assert.is_equal(2,#res)
30 | end)
31 |
32 | it("should begin transaction and commit",function()
33 | db.begin_transaction()
34 | local res = db.query_insert("insert into post(author_id,body) values(2,'Transaction 1')")
35 | db.commit()
36 | count = count + 1
37 | assert.is_equal(count,res)
38 |
39 | db.connect()
40 | local res2 = db.query_one("select count(*) from post")
41 | db.close()
42 |
43 | assert.is_equal(count,tonumber(res2))
44 | end)
45 |
46 | it("should begin transaction and rollback",function()
47 | db.begin_transaction()
48 | local res = db.query_insert("insert into post(author_id,body) values(2,'Transaction 2')")
49 | db.rollback()
50 | count = count + 1
51 | assert.is_equal(count,res)
52 |
53 | db.connect()
54 | local res2 = db.query_one("select count(*) from post")
55 | db.close()
56 | count = count -1
57 | assert.is_equal(count,tonumber(res2))
58 | end)
59 |
60 | it("should see if a table exists",function()
61 | db.connect()
62 | local res = db.table_exists("category")
63 | local res2 = db.table_exists("asdasda")
64 | db.close()
65 | assert.is_true(res)
66 | assert.is_false(res2)
67 | end)
68 |
69 | it("should get columns and key of a table",function()
70 | db.connect()
71 | local columns,key = db.get_columns("category")
72 | db.close()
73 |
74 | local col_id,col_name = false
75 |
76 | for _,v in ipairs(columns) do
77 | if v == 'id' then col_id = true end
78 | if v == 'name' then col_name = true end
79 | end
80 |
81 | assert.same(2,#columns)
82 | assert.is_true(col_id)
83 | assert.is_true(col_name)
84 | assert.same('id',key)
85 | end)
86 |
87 | it("should not get columns ",function()
88 | db.connect()
89 | local columns,key = db.get_columns("asdas")
90 | db.close()
91 | assert.same(0,#columns)
92 | assert.same(nil,key)
93 | end)
94 |
95 | end)
--------------------------------------------------------------------------------
/docs/create_app.md:
--------------------------------------------------------------------------------
1 | ##App Creation
2 | Once Sailor is installed, there are various ways to generate your app.
3 |
4 | ####Sailor with luarocks in Unix system
5 | An installation via luarocks will install a binary called `sailor`. You can use it to generate your apps by typing:
6 |
7 | sailor create []
8 |
9 |
10 | The directory is optional, if not set, it will create your app in the same directory you are. Example:
11 |
12 | sailor create 'Hey arnold' /var/www
13 |
14 |
15 | This will create the directory /var/www/hey_arnold with the base of your app. I'll tell more about this later.
16 |
17 |
18 | ####Sailor by direct download / git clone in Unix system
19 | Sailor comes bundled with a lua file called sailor. To create your app, on terminal, you cd to where Sailor is and execute `sailor create` using the app name and the installation dir as parameters. Example:
20 |
21 |
22 |
23 | ./sailor create 'Hey arnold' /var/www
24 |
25 |
26 | This will create the directory `/var/www/hey_arnold` with the base of your app. I'll tell more about this later.
27 |
28 |
29 | ####Other
30 | Under src/sailor you will find a dir called `blank-app`. You can just copy paste this folder, rename it and use it as a blank base app.
31 |
32 |
33 | ##App structure
34 | Sailor values convention over configuration to make our tasks easier. That's why our base app has a default structure.
35 |
36 |
37 | `/conf` - Contains configuration files, open and edit them to suit your needs.
38 |
39 |
40 | `/controllers` - Contains a default controller and will contain other controllers you will make!
41 |
42 |
43 | `/themes` - Contains themes. Themes are folders that contain regular HTML + CSS + Javascript. Except that pages are named .lp instead of .html and you will place one {{content}} where you want your app views to be rendered.
44 |
45 |
46 | `/models` - Will contain models you will make!
47 |
48 |
49 | `/pub` - Contains public files (js libraries, for example)
50 |
51 |
52 | `/runtime` - Contains temporary files generated by sailor during runtime. You don't need to touch this.
53 |
54 |
55 | `/tests` - Contains unit and functional tests for your app.
56 |
57 |
58 | `/views` - This is where your view, Lua pages in .lp, will go.
59 |
60 |
61 | `index.lua` - This is the file that will run your app. You don't need to touch this either (unless you want to).
62 |
63 | `index-magnet.lua` - This is the file that will run your app in case you are using Lighttpd mod_magnet.
64 |
65 |
66 | `start-server.lua` - This file will be used for those who want to run Sailor using Xavante server. If that's the case you only need to install Xavante using luarocks and execute this file to put your app up.
67 |
68 |
69 | `.htaccess` - This files sets some stuff for those who use Apache2 as a webserver.
70 |
--------------------------------------------------------------------------------
/test/dev-app/views/test/frontend_performance.lp:
--------------------------------------------------------------------------------
1 |
2 |
Hello
3 |
Hello
4 |
17 | max then return false,"should have "..min.."-"..max.." characters" end
84 | return true
85 | end
86 | local test = {}
87 | table.insert(test,len)
88 | for i=1,10000 do
89 | for k, v in ipairs(test) do
90 | v('oi',3,5)
91 | end
92 | -- Something is up with ipairs?
93 | end
94 | t()
95 |
96 |
97 | t = timer("Function 8 Insert on table")
98 | test = {}
99 | for i=1,1000 do
100 | test[i] = i
101 | end
102 | t()
103 |
104 | t = timer("Function 9 Read from table using ipairs")
105 | test = {}
106 | for i=1,10000 do
107 | for k, v in ipairs(test) do
108 | test[k] = k + 1
109 | end
110 | end
111 | t()
112 |
113 | t = timer("Function 10 Read from table using pairs")
114 | test = {}
115 | for i=1,10000 do
116 | for k, v in ipairs(test) do
117 | test[k] = k + 1
118 | end
119 | end
120 | t()
121 | ?>
--------------------------------------------------------------------------------
/src/sailor/access.lua:
--------------------------------------------------------------------------------
1 | --------------------------------------------------------------------------------
2 | -- access.lua, v0.5: controls user login on sailor apps
3 | -- This file is a part of Sailor project
4 | -- Copyright (c) 2014 Etiene Dalcol
5 | -- License: MIT
6 | -- http://sailorproject.org
7 | --------------------------------------------------------------------------------
8 |
9 | local sailor = require "sailor"
10 | local session = require "sailor.session"
11 | local bcrypt = require( "bcrypt" )
12 | local log_rounds = 11
13 |
14 | local access = {}
15 |
16 | session.open(sailor.r)
17 |
18 | local INVALID = "Invalid username or password."
19 |
20 | local function default_settings()
21 | return {
22 | default_login = 'admin', -- Default login details
23 | default_password = 'demo',
24 | grant_time = 604800, -- 1 week
25 | model = nil, -- Setting this field will deactivate default login details and activate below fields
26 | login_attributes = {'username'},-- Allows multiple options, for example, username or email. The one used to hash the
27 | password_attribute = 'password',-- password should come first.
28 | hashing = true
29 | }
30 | end
31 |
32 | local settings = default_settings()
33 |
34 | -- Changes settings
35 | function access.settings(s)
36 | settings = default_settings()
37 | for k, v in pairs(s) do
38 | settings[k] = v
39 | end
40 | end
41 |
42 | -- Simple hashing algorithm for encrypting passworsd
43 | function access.hash(username, password)
44 | return bcrypt.digest( username .. password, log_rounds )
45 | end
46 |
47 | function access.verify_hash(username, password, model_password)
48 | if not settings.hashing then return model_password == password end
49 | return bcrypt.verify( username..password, model_password )
50 | end
51 |
52 |
53 | function access.is_guest()
54 | if not access.data then
55 | access.data = session.data
56 | end
57 | return not access.data.login
58 | end
59 |
60 | function access.grant(data,time)
61 | session.setsessiontimeout (time or 604800) -- 1 week
62 | if not data.login then return false end
63 | access.data = data
64 | return session.save(data)
65 | end
66 |
67 | function access.find_object(login)
68 | local Model = sailor.model(settings.model)
69 | local o
70 | for _, attr in pairs(settings.login_attributes) do
71 | local a = {}
72 | a[attr] = login
73 | o = Model:find_by_attributes(a)
74 | if o ~= nil then return o end
75 | end
76 | return false
77 | end
78 |
79 | function access.login(login,password)
80 | local id
81 | if settings.model then
82 | local model = access.find_object(login)
83 | if not model then
84 | return false, INVALID
85 | end
86 | if not access.verify_hash(model[settings.login_attributes[1]], password, model[settings.password_attribute]) then
87 | return false, INVALID
88 | end
89 |
90 | id = model.id
91 | else
92 | if login ~= settings.default_login or password ~= settings.default_password then
93 | return false, INVALID
94 | end
95 | id = 1
96 | end
97 | return access.grant({login=login,id=id})
98 | end
99 |
100 |
101 | function access.logout()
102 | session.data = {}
103 | access.data = {}
104 | return session.destroy(sailor.r)
105 | end
106 |
107 | return access
108 |
--------------------------------------------------------------------------------
/test/dev-app/pub/moonshine/DOMAPI.moonshine.min.js:
--------------------------------------------------------------------------------
1 | /*
2 | * Moonshine - a Lua virtual machine.
3 | *
4 | * Email: moonshine@gamesys.co.uk
5 | * http://moonshinejs.org
6 | *
7 | * Copyright (c) 2013-2015 Gamesys Limited. All rights reserved.
8 | *
9 | * Permission is hereby granted, free of charge, to any person obtaining
10 | * a copy of this software and associated documentation files (the
11 | * "Software"), to deal in the Software without restriction, including
12 | * without limitation the rights to use, copy, modify, merge, publish,
13 | * distribute, sublicense, and/or sell copies of the Software, and to
14 | * permit persons to whom the Software is furnished to do so, subject to
15 | * the following conditions:
16 | *
17 | * The above copyright notice and this permission notice shall be
18 | * included in all copies or substantial portions of the Software.
19 | *
20 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
21 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
22 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
23 | * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
24 | * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
25 | * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
26 | * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
27 | */
28 |
29 | !function(shine){function jsToLua(obj){var t,mt;return mt=new shine.Table({__index:function(t,key){var property=obj[key],i,children,child;if("function"==typeof property||property&&property.prototype&&"function"==typeof property.prototype.constructor){var f=function(){var e=convertArguments(arguments,luaToJS),t=property.apply(e.shift(),e);return"object"==typeof t?jsToLua(t):[t]};if(Object.getOwnPropertyNames)for(children=Object.getOwnPropertyNames(property),i=0;child=children[i];i++)"caller"!=child&&"callee"!=child&&"arguments"!=child&&(f[child]=property[child]);return f["new"]=function(){var args=convertArguments(arguments,luaToJS),argStr,obj,i,l;for(argStr=(l=args.length)?"args[0]":"",i=1;l>i;i++)argStr+=",args["+i+"]";return obj=eval("new property("+argStr+")"),jsToLua(obj)},f}return"object"==typeof property?jsToLua(property):property},__newindex:function(e,t,r){obj[t]=luaToJS(r)}}),mt.source=obj,t=new shine.Table,shine.gc.incrRef(t),shine.lib.setmetatable(t,mt)}function luaToJS(e){var t;if(e instanceof shine.Function)return function(){return jsToLua(e.apply(void 0,convertArguments(arguments,jsToLua)))};if(e instanceof shine.Table){if((t=shine.lib.getmetatable(e))&&t.source)return t.source;var r,n=shine.lib.table.getn(e)>0,o=shine.gc["create"+(n?"Array":"Object")](),i=e.__shine.numValues,a=i.length;for(r=1;a>r;r++)o[r-1]=(i[r]||shine.EMPTY_OBJ)instanceof shine.Table?luaToJS(i[r]):i[r];for(r in e)!e.hasOwnProperty(r)||r in shine.Table.prototype||"__shine"===r||(o[r]=(e[r]||shine.EMPTY_OBJ)instanceof shine.Table?luaToJS(e[r]):e[r]);return o}return"object"==typeof e?shine.utils.toObject(e):e}function convertArguments(e,t){var r,n,o=[];for(r=0,n=e.length;n>r;r++)o.push(t(e[r]));return o}shine.DOMAPI={window:jsToLua(window)},shine.DOMAPI.window.extract=function(){var e=shine.getCurrentVM(),t=Object.getOwnPropertyNames&&Object.getOwnPropertyNames(window);for(var r in t||window)t&&(r=t[r]),"print"!==r&&"window"!==r&&null!==window[r]&&e.setGlobal(r,shine.DOMAPI.window.getMember(r))}}(shine||{});
30 |
--------------------------------------------------------------------------------
/test/dev-app/tests/functional/category.lua:
--------------------------------------------------------------------------------
1 | --[-[
2 | local model = require "sailor.model"
3 | local form = require "sailor.form"('category')
4 | local test = require "sailor.test"
5 | local helper = require "tests.helper"
6 |
7 | describe("Testing #CategoryController", function()
8 | local Category = model('category')
9 | local fixtures = require "tests.fixtures.category"
10 |
11 | setup(function()
12 | test.load_fixtures('category')
13 | end)
14 |
15 | it("should open index", function()
16 | local res = test.request('category')
17 | assert.same(200,res.status)
18 | assert.truthy(res.body:match('View all'))
19 | end)
20 |
21 | it("should open create page", function()
22 | local res = test.request('category/create')
23 | assert.same(200,res.status)
24 | assert.truthy(res.body:match('Create category'))
25 | end)
26 |
27 | it("should create new category", function()
28 | local count_before = Category:count()
29 | local res = test.request('category/create', {post = form.ify(fixtures[1])})
30 | assert.same(Category:count(), count_before + 1)
31 | assert.is_true(res:redirected('category/index'))
32 | end)
33 |
34 | it("should open update page with a category", function()
35 | local res = test.request('category/update', {get = {id = 1}})
36 | assert.same(200,res.status)
37 | assert.truthy(res.body:match('Update category'))
38 | end)
39 |
40 | it("should not open update page without a category", function()
41 | local res = test.request('category/update')
42 | assert.truthy(res.body:match('Error'))
43 | end)
44 |
45 | it("should update category", function()
46 | local res = test.request('category/update', {get = {id = 1}, post = form.ify(fixtures[2])})
47 | assert.same(fixtures[2].name, Category:find_by_id(1).name)
48 | assert.is_true(res:redirected('category/index'))
49 | end)
50 |
51 | it("should get category", function()
52 | local res = test.request('category/view', {get = {id = 2}})
53 | assert.same(200,res.status)
54 | assert.truthy(res.body:match(fixtures[2].name))
55 | end)
56 |
57 | it("should not get category if id not found", function()
58 | local res = test.request('category/view', {get = {id = 42}})
59 | assert.same(404,res.status)
60 | assert.truthy(res.body:match('Error'))
61 | end)
62 | it("should not get category without id", function()
63 | local res = test.request('category/view')
64 | assert.same(404,res.status)
65 | assert.truthy(res.body:match('Error'))
66 | end)
67 |
68 | it("should delete category", function()
69 | local count_before = Category:count()
70 | local res = test.request('category/delete', {get = {id = 1}})
71 | assert.same(count_before - 1, Category:count())
72 | assert.falsy(Category:find_by_id(1))
73 | assert.is_true(res:redirected('category/index'))
74 | end)
75 |
76 | it("should not delete category without id", function()
77 | local count_before = Category:count()
78 | local res = test.request('category/delete')
79 | assert.same(count_before, Category:count())
80 | assert.truthy(res.body:match('Error'))
81 | end)
82 |
83 | it("should not delete category if id not found", function()
84 | local count_before = Category:count()
85 | local res = test.request('category/delete',{get={id=42}})
86 | assert.same(count_before, Category:count())
87 | assert.truthy(res.body:match('Error'))
88 | end)
89 |
90 | end)
91 | --]]
--------------------------------------------------------------------------------
/test/dev-app/themes/default/main.lp:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 | <%=page.title%>
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
22 |
23 |
24 |
25 |
26 |
27 |
66 |
67 |
75 |
76 |
77 |
79 |
80 |
81 |
82 |
83 |
84 |
--------------------------------------------------------------------------------
/src/web_utils/serialize.lua:
--------------------------------------------------------------------------------
1 | ----------------------------------------------------------------------------
2 | -- Serialize tables.
3 | -- It works only for tables without cycles and without functions or
4 | -- userdata inside it.
5 | -- @release $Id: serialize.lua,v 1.7 2007/04/16 14:01:32 tomas Exp $
6 | ----------------------------------------------------------------------------
7 |
8 | local ipairs, pairs, type = ipairs, pairs, type
9 | local format = string.format
10 | local sort, tinsert = table.sort, table.insert
11 |
12 | --
13 | local value = nil
14 |
15 | ----------------------------------------------------------------------------
16 | -- Serializes a table.
17 | -- @param tab Table representing the session.
18 | -- @param outf Function used to generate the output.
19 | -- @param ind String with indentation pattern (default = "").
20 | -- @param pre String with indentation prefix (default = "").
21 | ----------------------------------------------------------------------------
22 | local function tabledump (tab, outf, ind, pre)
23 | local sep_n, sep, _n = ",\n", ", ", "\n"
24 | if (not ind) or (ind == "") then ind = ""; sep_n = ", "; _n = "" end
25 | if not pre then pre = "" end
26 | outf ("{")
27 | local p = pre..ind
28 | -- prepare list of keys
29 | local keys = { boolean = {}, number = {}, string = {} }
30 | local total = 0
31 | for key in pairs (tab) do
32 | total = total + 1
33 | local t = type(key)
34 | if t == "string" then
35 | tinsert (keys.string, key)
36 | else
37 | keys[t][key] = true
38 | end
39 | end
40 | local many = total > 5
41 | if not many then sep_n = sep; _n = " " end
42 | outf (_n)
43 | -- serialize entries with numeric keys
44 | if many then
45 | local _f,_s,_v = ipairs(tab)
46 | if _f(_s,_v) then outf (p) end
47 | end
48 | local num = keys.number
49 | local ok = false
50 | -- entries with automatic index
51 | for key, val in ipairs (tab) do
52 | value (val, outf, ind, p)
53 | outf (sep)
54 | num[key] = nil
55 | ok = true
56 | end
57 | if ok and many then outf (_n) end
58 | -- entries with explicit index
59 | for key in pairs (num) do
60 | if many then outf (p) end
61 | outf ("[")
62 | outf (key)
63 | outf ("] = ")
64 | value (tab[key], outf, ind, p)
65 | outf (sep_n)
66 | end
67 | -- serialize entries with boolean keys
68 | local tr = keys.boolean[true]
69 | if tr then
70 | outf (format ("%s[true] = ", many and p or ''))
71 | value (tab[true], outf, ind, p)
72 | outf (sep_n)
73 | end
74 | local fa = keys.boolean[false]
75 | if fa then
76 | outf (format ("%s[false] = ", many and p or ''))
77 | value (tab[false], outf, ind, p)
78 | outf (sep_n)
79 | end
80 | -- serialize entries with string keys
81 | sort (keys.string)
82 | for _, key in ipairs (keys.string) do
83 | outf (format ("%s[%q] = ", many and p or '', key))
84 | value (tab[key], outf, ind, p)
85 | outf (sep_n)
86 | end
87 | if many then outf (pre) end
88 | outf ("}")
89 | end
90 |
91 |
92 | --
93 | -- Serializes a value.
94 | --
95 | value = function (v, outf, ind, pre)
96 | local t = type (v)
97 | if t == "string" then
98 | outf (format ("%q", v))
99 | elseif t == "number" then
100 | outf (tostring(v))
101 | elseif t == "boolean" then
102 | outf (tostring(v))
103 | elseif t == "table" then
104 | tabledump (v, outf, ind, pre)
105 | else
106 | outf (format ("%q", tostring(v)))
107 | end
108 | end
109 |
110 | ----------------------------------------------------------------------------
111 | return {
112 | serialize = tabledump,
113 | }
--------------------------------------------------------------------------------
/test/dev-app/tests/unit/page.lua:
--------------------------------------------------------------------------------
1 | local conf = require "conf.conf"
2 | local test = require "sailor.test"
3 | local page = test.page
4 |
5 | describe("Testing Sailor core functions", function()
6 | local base_path
7 | local parms = {id = 5, name = 'a_test'}
8 |
9 | it("should create URLs accordingly without friendly urls", function()
10 | conf.sailor.friendly_urls = false
11 |
12 |
13 | local url = page:make_url('test')
14 | assert.is_equal('?r=test',url)
15 |
16 | url = page:make_url('test/etc')
17 | assert.is_equal('?r=test/etc',url)
18 |
19 | url = page:make_url('test', parms)
20 | local exp = '?r=test'
21 | for k,v in pairs(parms) do exp = exp .. '&' .. k .. '=' .. v end
22 | assert.is_equal(exp,url)
23 |
24 | url = page:make_url('test/etc', parms)
25 | exp = '?r=test/etc'
26 | for k,v in pairs(parms) do exp = exp .. '&' .. k .. '=' .. v end
27 | assert.is_equal(exp,url)
28 |
29 | base_path, page.base_path = page.base_path, '/sailor/test/dev-app'
30 | url = page:make_url('test/etc')
31 | assert.is_equal('/sailor/test/dev-app/?r=test/etc',url)
32 |
33 | url = page:make_url('test', parms)
34 | exp = '/sailor/test/dev-app/?r=test'
35 | for k,v in pairs(parms) do exp = exp .. '&' .. k .. '=' .. v end
36 | assert.is_equal(exp,url)
37 |
38 | url = page:make_url('test/etc')
39 | assert.is_equal('/sailor/test/dev-app/?r=test/etc',url)
40 |
41 | url = page:make_url('test/etc', parms)
42 | exp = '/sailor/test/dev-app/?r=test/etc'
43 | for k,v in pairs(parms) do exp = exp .. '&' .. k .. '=' .. v end
44 | assert.is_equal(exp,url)
45 | base_path, page.base_path = page.base_path, base_path
46 | end)
47 |
48 | it("should create URLs accordingly with friendly urls", function()
49 | conf.sailor.friendly_urls = true
50 | page.base_path = ''
51 | local url = page:make_url('test')
52 | assert.is_equal('/test',url)
53 |
54 | url = page:make_url('test/etc')
55 | assert.is_equal('/test/etc',url)
56 |
57 | url = page:make_url('test',parms)
58 | local exp = '/test'
59 | for k,v in pairs(parms) do exp = exp .. '/' .. k .. '/' .. v end
60 | assert.is_equal(exp,url)
61 |
62 | url = page:make_url('test/etc',parms)
63 | exp = '/test/etc'
64 | for k,v in pairs(parms) do exp = exp .. '/' .. k .. '/' .. v end
65 | assert.is_equal(exp,url)
66 |
67 | base_path, page.base_path = page.base_path, '/sailor/test/dev-app'
68 | url = page:make_url('test/etc')
69 | assert.is_equal('/sailor/test/dev-app/test/etc',url)
70 |
71 | url = page:make_url('test')
72 | assert.is_equal('/sailor/test/dev-app/test',url)
73 |
74 | url = page:make_url('test',parms)
75 | exp = '/sailor/test/dev-app/test'
76 | for k,v in pairs(parms) do exp = exp .. '/' .. k .. '/' .. v end
77 | assert.is_equal(exp,url)
78 |
79 | url = page:make_url('test/etc',parms)
80 | exp = '/sailor/test/dev-app/test/etc'
81 | for k,v in pairs(parms) do exp = exp .. '/' .. k .. '/' .. v end
82 | assert.is_equal(exp,url)
83 | base_path, page.base_path = page.base_path, base_path
84 | end)
85 |
86 | it("can render a table as JSON", function()
87 | assert.has_no.errors(function()
88 | page:json(parms)
89 | end)
90 | end)
91 |
92 | it("can send CORS headers", function()
93 | assert.has_no.errors(function()
94 | page:enable_cors()
95 | end)
96 |
97 | assert.has_no.errors(function()
98 | page:enable_cors({allow_origin = "http://sailorproject.org"})
99 | end)
100 | end)
101 | end)
102 |
--------------------------------------------------------------------------------
/src/sailor/test.lua:
--------------------------------------------------------------------------------
1 | --------------------------------------------------------------------------------
2 | -- test.lua, v0.5: Helper functions for testing functionality
3 | -- This file is a part of Sailor project
4 | -- Copyright (c) 2014-2015 Etiene Dalcol
5 | -- License: MIT
6 | -- http://sailorproject.org
7 | --------------------------------------------------------------------------------
8 |
9 | local sailor = require "sailor"
10 | local lfs = require "lfs"
11 | local db = require "sailor.db"
12 | local main_conf = require "conf.conf"
13 | local db_conf = main_conf.db[main_conf.sailor.environment]
14 |
15 | local M = {req = {}, page = nil}
16 |
17 | local body
18 | local function write(_,data) body = (body or "") .. data end
19 |
20 | -- Prepares for making a request
21 | function M:prepare(headers_in)
22 | headers_in = headers_in or {}
23 | self.req = { uri = '', write = write, puts = write, headers_in = headers_in, headers_out = {} }
24 | self.page = sailor.init(M.req)
25 | return self
26 | end
27 |
28 | -- Loads tests fixtures into the database
29 | -- Warning, this will truncate the table, make sure you have configured a test database
30 | -- Returns table with objects created
31 | local function load_fixtures(model_name)
32 | local Model = sailor.model(model_name)
33 | local fixtures = require("tests.fixtures."..model_name) or {}
34 | local objects = {}
35 | db.connect()
36 | db.truncate(Model.db.table) -- Reseting current state
37 | db.close()
38 |
39 |
40 | for _,v in pairs(fixtures) do -- loading fixtures
41 | local o = Model:new(v)
42 | o:save(false)
43 | table.insert(objects, o)
44 | end
45 | return objects
46 |
47 | end
48 |
49 | function M.load_fixtures(model_name)
50 | -- if model name is specific, load fixtures from a file
51 | if model_name then
52 | return load_fixtures(model_name)
53 | end
54 |
55 | -- if not specified, loads all fixtures in fixtures dir
56 | for filename,_ in lfs.dir(sailor.path..'/tests/fixtures') do
57 | model_name = string.match(filename,'(%w*).lua')
58 | if model_name then
59 | load_fixtures(model_name)
60 | end
61 | end
62 | end
63 |
64 | -- Function that is a part of the request response.
65 | -- Verifies if the request redirected somewhere
66 | -- Requires path: string
67 | -- Returns boolean
68 | local function redirected(response, path)
69 | if response.status ~= 302 then return false end
70 | return (response.headers['Location']):match(path) and true or false
71 | end
72 |
73 | -- Makes a mockup request to an internal sailor path
74 | -- path: string. The path you want to make a request to, such as a controller or controller/action. Example: 'user/view'
75 | -- data: table. A table containing some data you want to send to the request, such as get or post. Example: {get = {id = 1}}
76 | -- additional_headers: A table containing additional headers you may want to send. Example: {ACCEPT = 'application/json'}
77 | -- Returns a table with the following fields:
78 | -- status: number. The status of the response.
79 | -- body: string. The body of the response.
80 | -- headers: table. Any headers out that were set.
81 | -- redirected: function. The above redirect function
82 |
83 |
84 | function M.request(path, data, additional_headers)
85 | local conf = require "conf.conf"
86 | data = data or {}
87 | body = ''
88 | conf.sailor.friendly_urls = false
89 |
90 | M:prepare(additional_headers)
91 | M.page.POST = data.post or {}
92 | M.page.GET = data.get or {}
93 | M.page.GET[conf.sailor.route_parameter] = path
94 | local status = sailor.route(M.page)
95 |
96 | return {status = status, body = body, headers = M.req.headers_out, redirected = redirected}
97 | end
98 |
99 | return M:prepare()
100 |
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | language: python
2 | sudo: false
3 |
4 | addons:
5 | apt:
6 | packages:
7 | - libmysqlclient-dev
8 | - libpq-dev
9 | - libsqlite3-dev
10 |
11 | services:
12 | - mysql
13 | - postgresql
14 |
15 | env:
16 | # Lua 5.1 on different DBs
17 | - LUA="lua 5.1" DB_DRIVER=mysql DB_USER=travis DB_NAME=sailor_test
18 | - LUA="lua 5.1" DB_DRIVER=postgres DB_USER=postgres DB_NAME=sailor_test
19 | - LUA="lua 5.1" DB_DRIVER=sqlite3 DB_USER="" DB_NAME=$TRAVIS_BUILD_DIR/sailor_test
20 | # Lua 5.2 on different DBs
21 | - LUA="lua 5.2" DB_DRIVER=mysql DB_USER=travis DB_NAME=sailor_test
22 | - LUA="lua 5.2" DB_DRIVER=postgres DB_USER=postgres DB_NAME=sailor_test
23 | - LUA="lua 5.2" DB_DRIVER=sqlite3 DB_USER="" DB_NAME=$TRAVIS_BUILD_DIR/sailor_test
24 | # Lua 5.3 on different DBs
25 | - LUA="lua 5.3" DB_DRIVER=mysql DB_USER=travis DB_NAME=sailor_test
26 | - LUA="lua 5.3" DB_DRIVER=postgres DB_USER=postgres DB_NAME=sailor_test
27 | - LUA="lua 5.3" DB_DRIVER=sqlite3 DB_USER="" DB_NAME=$TRAVIS_BUILD_DIR/sailor_test
28 | # LuaJIT 2.0.x on different DBs
29 | - LUA="luajit 2.0" DB_DRIVER=mysql DB_USER=travis DB_NAME=sailor_test
30 | - LUA="luajit 2.0" DB_DRIVER=postgres DB_USER=postgres DB_NAME=sailor_test
31 | - LUA="luajit 2.0" DB_DRIVER=sqlite3 DB_USER="" DB_NAME=$TRAVIS_BUILD_DIR/sailor_test
32 | # Openresty + LuaJIT 2.1.x + mysql
33 | - LUA="luajit 2.1" DB_DRIVER=mysql DB_USER=travis DB_NAME=sailor_test SERVER=openresty
34 |
35 | before_install:
36 | - pip install hererocks
37 | - hererocks HERE --$LUA --no-readline --luarocks latest --verbose
38 | - hererocks HERE --show
39 | - source HERE/bin/activate
40 |
41 | install:
42 | - luarocks install luacheck
43 | - luarocks install luacov
44 | - luarocks install luacov-coveralls
45 | - luarocks make rockspecs/sailor-current-1.rockspec
46 | - if [ "$DB_DRIVER" == "mysql" ]; then luarocks install luasql-mysql MYSQL_INCDIR=/usr/include/mysql; fi
47 | - if [ "$DB_DRIVER" == "postgres" ]; then luarocks install luasql-postgres PGSQL_INCDIR=/usr/include/postgresql; fi
48 | - if [ "$DB_DRIVER" == "sqlite3" ]; then luarocks install luasql-sqlite3; fi
49 | - luarocks list
50 | - |
51 | if [ "$SERVER" == "openresty" ]; then
52 | OPENRESTY_VERSION="1.11.2.5"
53 | wget https://openresty.org/download/openresty-$OPENRESTY_VERSION.tar.gz
54 | tar xzf openresty-$OPENRESTY_VERSION.tar.gz
55 | cd openresty-$OPENRESTY_VERSION/
56 | ln -s $TRAVIS_BUILD_DIR/HERE/include $TRAVIS_BUILD_DIR/HERE/include/luajit-2.1
57 | ./configure --prefix=$TRAVIS_BUILD_DIR/HERE --with-luajit=$TRAVIS_BUILD_DIR/HERE
58 | make
59 | make install
60 | ln -s $TRAVIS_BUILD_DIR/HERE/nginx/sbin/nginx $TRAVIS_BUILD_DIR/HERE/bin/nginx
61 | cd ..
62 | rm -rf openresty-$OPENRESTY_VERSION
63 | nginx -v
64 | resty -V
65 | fi
66 |
67 | before_script:
68 | - mysql -e 'create database sailor_test;'
69 | - mysql sailor_test < test/dev-app/sql/mysql.sql
70 | - psql -c 'create database sailor_test;' -U postgres
71 | - psql sailor_test < test/dev-app/sql/pgsql.sql
72 | - sqlite3 $TRAVIS_BUILD_DIR/sailor_test < test/dev-app/sql/sqlite3.sql
73 |
74 | script:
75 | - luacheck src test
76 | - |
77 | cd test/dev-app
78 | if [ "$SERVER" != "openresty" ]; then
79 | sailor test -- --verbose --coverage
80 | else
81 | sailor test --resty
82 | fi
83 |
84 | after_success: |
85 | if [ "$SERVER" != "openresty" ]; then
86 | mv luacov.stats.out ../..
87 | cd ../..
88 | luacov-coveralls -c test/dev-app/.luacov
89 | fi
90 |
91 | notifications:
92 | email:
93 | on_success: change
94 | on_failure: always
95 |
--------------------------------------------------------------------------------
/docs/INSTALL_LINUX_ARCH.md:
--------------------------------------------------------------------------------
1 | ## Installation for Linux
2 | Sailor is compatible with a variety of operating systems and webservers. On this example, we will use Arch Linux and Apache 2.4.12.
3 |
4 | ### Installing Lua
5 |
6 | If you don't have it already, install Lua. Sailor is compatible with both 5.1 and 5.2.
7 |
8 | sudo pacman -Sy
9 | sudo pacman -S lua-{sec,socket}
10 |
11 | ### Installing Apache 2.4
12 |
13 | Use the following command to install Apache 2.4.x:
14 |
15 | sudo pacman -S apache
16 |
17 | Enable mod_lua:
18 |
19 | Edit httpd.conf and enable the mod_lua.so module:
20 |
21 | sudo yourtexteditor /etc/httpd/conf/httpd.conf
22 |
23 | The following line must be uncommented:
24 |
25 | LoadModule lua_module modules/mod_lua.so
26 |
27 | Change the DirectoryIndex directive to:
28 |
29 | DirectoryIndex index.lua index.html
30 |
31 | Add the SetHandler directive:
32 |
33 |
34 | SetHandler lua-script
35 |
36 |
37 | Enable Apache:
38 |
39 | systemctl enable httpd.service
40 |
41 | If it is already enabled, restart it:
42 |
43 | systemctl restart httpd.service
44 |
45 | ### Installing Sailor
46 | You can either clone it directly from the repository, download the zip containing the master branch or download and install it through LuaRocks. We will go through LuaRocks since it will also download and install almost all the required dependencies except for luasql-mysql if you want to persist your models.
47 |
48 | sudo pacman -S luarocks
49 | sudo luarocks install sailor
50 |
51 | We are almost done! You can now use `sailor` to create your web applications. In this example, we will create an app called "Hey Arnold" on the directory Apache is reading from (usually /var/www). After you're done, you can open your browser and access it on .
52 |
53 | sailor create 'Hey Arnold' /srv/http
54 |
55 | Alternatively, you can manually copy the files in the /src/sailor/blank-app directory of this repository to /srv/http/hey_arnold and access it at and if you didn't install sailor through LuaRocks, you must open .htaccess and replace {{path}} with the full path on your system to Sailor's src directory.
56 |
57 | #### Dependencies
58 | If you want to persist your models you need luasql. Sailor could work with other drivers but so far we've only tested with mysql and don't offer support for others.
59 |
60 | sudo luarocks install luasql-mysql
61 |
62 | If you installed Sailor through LuaRocks, there is no need to worry, all next dependencies will be installed with it and you can ignore the rest of this section. If you just cloned the repository or downloaded the zip, you should install these dependencies:
63 |
64 | Lua File System and valua are required.
65 |
66 | sudo luarocks install luafilesystem
67 | sudo luarocks install valua
68 |
69 | If you want to save your models in a database, you will need LuaSQL. I believe it should work with every database LuaSQL supports, but so far I have only tested with MySQL. LuaSQL-MySQL requires you to have mysql installed.
70 |
71 | sudo luarocks install LuaSQL-MySQL
72 |
73 | If you want to use our mailer module, get these rocks so we are able to send stuff via SMTP.
74 |
75 | sudo luarocks install LuaSocket
76 | sudo luarocks install LuaSec
77 |
78 | LuaSec requires OpenSSL as a dependency, if you don't have it already please install it and try getting LuaSec again. Remember to install "devel" packages, if your distro has them, to get the header files! If LuaSec can't find your OpenSSL dir, try using these flags, depending on your system's architecture (the examples below work on some Linux distros).
79 |
80 | sudo luarocks install LuaSec OPENSSL_LIBDIR=/usr/lib/x86_64-linux-gnu
81 | or
82 |
83 | sudo luarocks install LuaSec OPENSSL_LIBDIR=/usr/lib/i386-linux-gnu
84 |
--------------------------------------------------------------------------------
/sailor:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env lua
2 |
3 | --------------------------------------------------------------------------------
4 | -- sailor v0.6.2: Command line utility for sailor
5 | -- This file is a part of Sailor project
6 | -- Copyright (c) 2014 Etiene Dalcol
7 | -- License: MIT
8 | -- http://sailorproject.org
9 | --------------------------------------------------------------------------------
10 |
11 | local argparse = require "argparse"
12 | local colors = require "ansicolors"
13 | local actions = require "sailor.cli"
14 |
15 |
16 | local parser = argparse("script", colors("%{bright yellow}Sailor command line utility"))
17 | :name(string.match(arg[0], "/*(%w+)/*$")) -- this file name, usually will be "sailor"
18 | :epilog("For more info see http://sailorproject.org")
19 | :require_command(false)
20 |
21 | local create_cmd = parser:command("c create", "Generates web application in a directory.")
22 | :action(actions.create)
23 | create_cmd:usage(colors("%{bright red}Usage: sailor create NAME [PATH]"))
24 | create_cmd:argument("name", "The name of your application.")
25 | create_cmd:argument("path", "The path to where you wish your app to be created."):default(".")
26 | create_cmd:epilog(colors([[
27 | Example: %{bright red} sailor create 'Hey Arnold' /var/www %{reset}
28 | This will create your web app under /var/www/hey_arnold.]]))
29 |
30 | local test_cmd = parser:command("t test", "Runs the tests specified for an application. Must be called from the base dir of the application.")
31 | :action(actions.test)
32 | test_cmd:usage(colors"%{bright red}Usage: sailor test [--resty] [-- EXTRA_FLAGS]")
33 | test_cmd:argument("EXTRA_FLAGS", "Flags that will be passed to the Busted library."):args("*")
34 | test_cmd:flag("--resty", "Run the tests using the resty bootstrap.", false)
35 |
36 | local enable_cmd = parser:command("e enable", "Installs an extension to Sailor and copy necessary files to your app. Must be called from the base dir of the application.")
37 | :action(actions.enable)
38 | enable_cmd:usage(colors("%{bright red}Usage: sailor enable NAME"))
39 | enable_cmd:argument("name", "The name of the extension to be enabled.")
40 |
41 |
42 | local gen_cmd = parser:command("g gen", "Generates some scaffolding for your app.")
43 | gen_cmd:usage(colors("%{bright red}Usage: sailor gen COMMAND ARG"))
44 | gen_cmd:epilog(colors([[
45 | Example: %{bright red} sailor gen model users%{reset}
46 | Given a table called 'users' exist in the database, this will generate a model based on it.]]))
47 |
48 | local model_cmd = gen_cmd:command("m model", "Generates a basic model based on an existing table on the database.")
49 | :action(actions.gen_model)
50 | model_cmd:argument("table_name", "The name of the database table that the model should reflect.")
51 | model_cmd:usage(colors("%{bright red}Usage: sailor gen model TABLE_NAME"))
52 |
53 | local crud_cmd = gen_cmd:command("crud c", "Generates Create-Read-Update-Delete scaffolding for a given model name.")
54 | :action(actions.gen_crud)
55 | crud_cmd:argument("model_name", "The name of the model table that CRUD should act on.")
56 | crud_cmd:usage(colors("%{bright red}Usage: sailor gen crud MODEL_NAME"))
57 |
58 | local all_cmd = gen_cmd:command("a all", "Generates both the model and a CRUD for an existing table name.")
59 | :action(actions.gen_all)
60 | all_cmd:argument("table_name", "The name of the database table that the model and the CRUD should reflect.")
61 | all_cmd:usage(colors("%{bright red}Usage: sailor gen all TABLE_NAME"))
62 |
63 | local start_cmd = parser:command("s start", "Runs a Sailor app starting Xavante webserver.")
64 | :action(actions.start)
65 | enable_cmd:usage(colors("%{bright red}Usage: sailor start"))
66 |
67 | parser:flag("-v --version", "Show the current Sailor version installed and exit.", false):action(actions.version)
68 |
69 | parser:usage(parser:get_help())
70 |
71 | local args = parser:parse()
72 |
--------------------------------------------------------------------------------
/test/dev-app/conf/mime.types:
--------------------------------------------------------------------------------
1 |
2 | types {
3 | text/html html htm shtml;
4 | text/css css;
5 | text/xml xml;
6 | image/gif gif;
7 | image/jpeg jpeg jpg;
8 | application/javascript js;
9 | application/atom+xml atom;
10 | application/rss+xml rss;
11 |
12 | text/mathml mml;
13 | text/plain txt;
14 | text/vnd.sun.j2me.app-descriptor jad;
15 | text/vnd.wap.wml wml;
16 | text/x-component htc;
17 |
18 | image/png png;
19 | image/tiff tif tiff;
20 | image/vnd.wap.wbmp wbmp;
21 | image/x-icon ico;
22 | image/x-jng jng;
23 | image/x-ms-bmp bmp;
24 | image/svg+xml svg svgz;
25 | image/webp webp;
26 |
27 | application/font-woff woff;
28 | application/java-archive jar war ear;
29 | application/json json;
30 | application/mac-binhex40 hqx;
31 | application/msword doc;
32 | application/pdf pdf;
33 | application/postscript ps eps ai;
34 | application/rtf rtf;
35 | application/vnd.apple.mpegurl m3u8;
36 | application/vnd.ms-excel xls;
37 | application/vnd.ms-fontobject eot;
38 | application/vnd.ms-powerpoint ppt;
39 | application/vnd.wap.wmlc wmlc;
40 | application/vnd.google-earth.kml+xml kml;
41 | application/vnd.google-earth.kmz kmz;
42 | application/x-7z-compressed 7z;
43 | application/x-cocoa cco;
44 | application/x-java-archive-diff jardiff;
45 | application/x-java-jnlp-file jnlp;
46 | application/x-makeself run;
47 | application/x-perl pl pm;
48 | application/x-pilot prc pdb;
49 | application/x-rar-compressed rar;
50 | application/x-redhat-package-manager rpm;
51 | application/x-sea sea;
52 | application/x-shockwave-flash swf;
53 | application/x-stuffit sit;
54 | application/x-tcl tcl tk;
55 | application/x-x509-ca-cert der pem crt;
56 | application/x-xpinstall xpi;
57 | application/xhtml+xml xhtml;
58 | application/xspf+xml xspf;
59 | application/zip zip;
60 |
61 | application/octet-stream bin exe dll;
62 | application/octet-stream deb;
63 | application/octet-stream dmg;
64 | application/octet-stream iso img;
65 | application/octet-stream msi msp msm;
66 |
67 | application/vnd.openxmlformats-officedocument.wordprocessingml.document docx;
68 | application/vnd.openxmlformats-officedocument.spreadsheetml.sheet xlsx;
69 | application/vnd.openxmlformats-officedocument.presentationml.presentation pptx;
70 |
71 | audio/midi mid midi kar;
72 | audio/mpeg mp3;
73 | audio/ogg ogg;
74 | audio/x-m4a m4a;
75 | audio/x-realaudio ra;
76 |
77 | video/3gpp 3gpp 3gp;
78 | video/mp2t ts;
79 | video/mp4 mp4;
80 | video/mpeg mpeg mpg;
81 | video/quicktime mov;
82 | video/webm webm;
83 | video/x-flv flv;
84 | video/x-m4v m4v;
85 | video/x-mng mng;
86 | video/x-ms-asf asx asf;
87 | video/x-ms-wmv wmv;
88 | video/x-msvideo avi;
89 | }
90 |
--------------------------------------------------------------------------------
/src/sailor/blank-app/conf/mime.types:
--------------------------------------------------------------------------------
1 |
2 | types {
3 | text/html html htm shtml;
4 | text/css css;
5 | text/xml xml;
6 | image/gif gif;
7 | image/jpeg jpeg jpg;
8 | application/javascript js;
9 | application/atom+xml atom;
10 | application/rss+xml rss;
11 |
12 | text/mathml mml;
13 | text/plain txt;
14 | text/vnd.sun.j2me.app-descriptor jad;
15 | text/vnd.wap.wml wml;
16 | text/x-component htc;
17 |
18 | image/png png;
19 | image/tiff tif tiff;
20 | image/vnd.wap.wbmp wbmp;
21 | image/x-icon ico;
22 | image/x-jng jng;
23 | image/x-ms-bmp bmp;
24 | image/svg+xml svg svgz;
25 | image/webp webp;
26 |
27 | application/font-woff woff;
28 | application/java-archive jar war ear;
29 | application/json json;
30 | application/mac-binhex40 hqx;
31 | application/msword doc;
32 | application/pdf pdf;
33 | application/postscript ps eps ai;
34 | application/rtf rtf;
35 | application/vnd.apple.mpegurl m3u8;
36 | application/vnd.ms-excel xls;
37 | application/vnd.ms-fontobject eot;
38 | application/vnd.ms-powerpoint ppt;
39 | application/vnd.wap.wmlc wmlc;
40 | application/vnd.google-earth.kml+xml kml;
41 | application/vnd.google-earth.kmz kmz;
42 | application/x-7z-compressed 7z;
43 | application/x-cocoa cco;
44 | application/x-java-archive-diff jardiff;
45 | application/x-java-jnlp-file jnlp;
46 | application/x-makeself run;
47 | application/x-perl pl pm;
48 | application/x-pilot prc pdb;
49 | application/x-rar-compressed rar;
50 | application/x-redhat-package-manager rpm;
51 | application/x-sea sea;
52 | application/x-shockwave-flash swf;
53 | application/x-stuffit sit;
54 | application/x-tcl tcl tk;
55 | application/x-x509-ca-cert der pem crt;
56 | application/x-xpinstall xpi;
57 | application/xhtml+xml xhtml;
58 | application/xspf+xml xspf;
59 | application/zip zip;
60 |
61 | application/octet-stream bin exe dll;
62 | application/octet-stream deb;
63 | application/octet-stream dmg;
64 | application/octet-stream iso img;
65 | application/octet-stream msi msp msm;
66 |
67 | application/vnd.openxmlformats-officedocument.wordprocessingml.document docx;
68 | application/vnd.openxmlformats-officedocument.spreadsheetml.sheet xlsx;
69 | application/vnd.openxmlformats-officedocument.presentationml.presentation pptx;
70 |
71 | audio/midi mid midi kar;
72 | audio/mpeg mp3;
73 | audio/ogg ogg;
74 | audio/x-m4a m4a;
75 | audio/x-realaudio ra;
76 |
77 | video/3gpp 3gpp 3gp;
78 | video/mp2t ts;
79 | video/mp4 mp4;
80 | video/mpeg mpeg mpg;
81 | video/quicktime mov;
82 | video/webm webm;
83 | video/x-flv flv;
84 | video/x-m4v m4v;
85 | video/x-mng mng;
86 | video/x-ms-asf asx asf;
87 | video/x-ms-wmv wmv;
88 | video/x-msvideo avi;
89 | }
90 |
--------------------------------------------------------------------------------
/docs/manual_lua_at_client.md:
--------------------------------------------------------------------------------
1 | ##Reference Manual
2 |
3 | ###Lua at client
4 |
5 | With Sailor, you can not only write the backend of your app with Lua, but you can also write Lua code that will run on the browser. This is possible because Sailor will get this piece of code and give it to a Virtual Machine that will handle it and run Javascript behind the scenes. Sailor is compatible with different implementations of Lua-to-Javascript virtual machines. The default is starlight. In case you want to use a different VM, you will have to download the folder with the libraries, put it inside the `pub` folder of your Sailor app and edit your `conf/conf.lua` to configure your app to use this VM instead.
6 |
7 | Here is a small comparative table of the compatible VMs:
8 |
9 | | | starlight | moonshine | lua51js | luavmjs |
10 | |---------------------------------------------------------------------------|:---------------------:|:---------------------:|:------------------------:|:------------------------:|
11 | | The code is pre-processed on the server and bytecode is sent to the JS VM | | ✓ | | |
12 | | The code is sent as a string to the JS VM | ✓ | | ✓ | ✓ |
13 | | Compatible Lua version of the client written code | 5.1 | 5.1 | 5.1 | 5.2.3 |
14 | | Works with Sailor on LuaJIT based servers, such as openresty | ✓ | | ✓ | ✓ |
15 | | DOM manipulation | ✓ | ✓ | incomplete | ✓ |
16 | | Can require Lua modules | ✓ | ✓ | Only on Apache | |
17 | | Supports Lua callbacks | ✓ | ✓ | x | ✓ |
18 | | Supports Lua script tags | ✓ | x | ✓ | ✓ |
19 | | Can call JS methods like eval() from Lua | ? | ? | x | ✓ |
20 | | Supports the Lua C API | x | x | ✓ | incomplete |
21 | | How to print "hello" to the console | print("hello") | print("hello") | print("hello") | print("hello") |
22 | | How to pop an alert message with "hello" | window:alert("hello") | window:alert("hello") | js.window:alert("hello") | js.global:alert("hello") |
23 |
24 |
25 | You can find more information about them here:
26 |
27 | Starlight: Examples, Github Repo
28 |
29 | Moonshine: Official website, Github Repo
30 |
31 | Lua5.1.js: Examples, Github Repo
32 |
33 | Lua.vm.js: Examples, Official website, Github Repo
34 |
35 |
36 |
--------------------------------------------------------------------------------
/docs/CONFIG.md:
--------------------------------------------------------------------------------
1 | ##Configuring your Sailor Application
2 |
3 | You will find Sailor's config file under `conf/conf.lua`. This file contains a table with config strings for core Sailor control, database server configuration and SMTP server configuration for mailer module.
4 |
5 | ###`sailor.app_name`
6 | Used as a default title tag for your pages and can be invoked at any time from the rest of your app accessing the conf table.
7 |
8 | ###`sailor.default_static`
9 | Is about flow control. If defined, Sailor will render a specific view as defined, disabling routing. It's useful, for example, for serving a very simple page instead of a complex app or for loading a temporary maintenance page.
10 |
11 | ###`sailor.default_controller` and `default_action`
12 | Will define which action from which controller will run by default, when no route is called, a.k.a. your index.
13 |
14 | ###`sailor.theme`
15 | Will define the basic and default theme used for all pages. Sailor is integrated with [Twitter Bootstrap](http://getbootstrap.com) for an enhanced feel. You can add more themes on `/themes` and set a default here. Themes can be changed for specific pages by setting `page.theme` to something else on controller before rendering pages. It can be deactivated by setting it to nil.
16 |
17 | ###`sailor.layout`
18 | Will define the basic and default layout used for all pages. A layout is the exact .lp file inside your theme folder that will be rendered. For example, one theme can come with many possible different layouts, like front and 'inside' pages, or 1-column and 2-columns. Layout can be changed for specific pages by setting `page.layout` to something else on controller before rendering pages. It can be deactivated by setting it to nil.
19 |
20 | ###`sailor.route_parameter`
21 | Is for page routing when friendly urls are deactivated, which is done accessing a get variable, the default is 'r', but you can change it here if you wish.
22 |
23 | ###`sailor.default_error404`
24 | Sets a default view for 404 errors. It can be deactivated by setting it to nil.
25 |
26 | ###`sailor.enable_autogen`
27 | Turns Sailor's autogen on or off by setting it to true or false. The autogen is a tool to autogenerate models and CRUDs. You can find more about it under the Autogen section. The default value is false for avoiding accidental overwriting of files.
28 |
29 | ###`sailor.friendly_urls`
30 | turns friendly urls on or off by setting it to true or false. Normally, to access the view action of the article controller passing 4 as id via get variables, you would have to type in your address bar `http://your_url.com/?r=article/view&id=4`. However, when friendly urls are set to true, you can access it on `http://your_url.com/article/view/id/4` which is way cleaner. If you want to personalize it, for Xavante, you need to edit /start-server.lua and for Apache2, .htaccess.
31 |
32 | ###`sailor.max_upload`
33 | Sets, in bytes, the max size of files to be uploaded using file inputs on forms.
34 |
35 | ###`environment`
36 | Is a string with the name of your current environment. Example: 'test'.
37 |
38 | ###`hide_stack_trace`
39 | Is a boolean that if set to true will make Sailor not throw the full stack trace on errors but a default 500 Internal Server Error message.
40 |
41 | ###`db`
42 | Contains a table with your different database setups. They must contain the following fields:
43 |
44 | ####`driver`
45 | Is your database driver, example: 'mysql'.
46 |
47 | ####`host`
48 | Is your database host, example: 'localhost'.
49 |
50 | ####`user` and `db.pass`
51 | Are the login information for your database.
52 |
53 | ####`dbname`
54 | Is the database name. You can leave db configs blank if you are not persisting models.
55 |
56 | ###`smtp.server`
57 | Is the server for sending emails. You can leave smtp configs blank if you are not using your application for sending emails.
58 |
59 | ###`smtp.user` and `smtp.server`
60 | Are the login information for your smtp server.
61 |
62 | ###`smtp.from`
63 | Is the email address who is sending emails.
64 |
65 | ###`lua_at_client.vm`
66 | Is the virtual machine that will translate Lua to Javascript in case you'd like to write Lua code for the browser as well. `starlight` is the default. Other options are `moonshine`, `lua51js` and `luavmjs`. You can find more details about them on the reference manual.
67 |
68 | ###`debug.inspect`
69 | Toggles on/off the exhibition of debug messages on the bottom of the page made with `page.inspect`.
70 |
71 |
--------------------------------------------------------------------------------
/docs/tutorial_views.md:
--------------------------------------------------------------------------------
1 | ##Views
2 | Sailor's views are Lua Page files (.lp) contained inside your `/views` folder. They are valid HTML files in all aspects, except for the .lp extension and the fact that you can also use `` tags inside it to execute lua scripts.
3 |
4 | Let's create our `/views/main/index.lp`:
5 |
6 | This is valid HTML!
7 |
8 | You can:
9 |
10 | * Use regular HTML
11 | `tags`
12 |
13 | * Run Javascript on your browser
14 | ` `
15 |
16 | * Run Lua scripts from your server
17 |
18 |
21 | <%= msg %>
22 |
23 |
24 | * Intercalate Lua code with HTML
25 |
26 |
28 | This message will appear 10 times! This is number <%= i %>.
29 |
30 |
31 | * Use the page object and all its functions, for example, page:include().
32 |
33 |
34 |
35 |
36 |
37 | ###Lua at client
38 | You can also write Lua code that will run on the browser, if you want to. This is possible because Sailor will get this piece of code and give it to a Virtual Machine that will handle it and run Javascript behind the scenes. There are different Virtual Machines available, however, `starlight` is the default. Other options are `moonshine`, `lua51js` and `luavmjs`. They have slight differences on features, performance and how they handle DOM manipulation. Since starlight is the default, the following example will work on it, but also on moonshine. You can find more details about these differences on the reference manual.
39 |
40 |
41 | To write Lua code on a view that will run on the browser, you need to annotate your `` tag. Code inside `` will run on the browser, code inside `` will run on the server side, and code inside `` will run both on the server side and on the browser. Since `` is the default, it can be simply written as ``.
42 |
43 | Here are some examples of Lua code that will run on the browser using the `starlight` virtual machine:
44 |
45 | #####Manipulation of the DOM
46 |
47 |
48 |
57 |
58 |
59 | #####Accessing Javascript functions and passing callbacks
60 |
61 |
70 |
71 |
81 |
82 | #####Exporting Lua modules to the browser
83 |
84 | Remember that this code will run on the browser and some Lua modules won't make sense being used in this context! Attention: this feature is still under tests.
85 |
86 |
87 |
95 |
96 | #####Accessing Javascript modules such as JQuery
97 |
98 |
99 |
105 |
106 |
107 |
108 |
113 |
114 |
--------------------------------------------------------------------------------
/src/sailor/form.lua:
--------------------------------------------------------------------------------
1 | --------------------------------------------------------------------------------
2 | -- form.lua, v0.6: generates html for forms
3 | -- This file is a part of Sailor project
4 | -- Copyright (c) 2014 Etiene Dalcol
5 | -- License: MIT
6 | -- http://sailorproject.org
7 | --------------------------------------------------------------------------------
8 |
9 | local form = {}
10 | local tinsert, tconcat = table.insert, table.concat
11 | local model_name
12 |
13 | local meta = {}
14 | meta.__call = function(_,mname)
15 | model_name = mname
16 | return form
17 | end
18 | setmetatable(form,meta)
19 |
20 | local generic_input_types = {
21 | file = true,
22 | text = true,
23 | hidden = true,
24 | password = true,
25 | color = true,
26 | date = true,
27 | datetime = true,
28 | email = true,
29 | month = true,
30 | number = true,
31 | range = true,
32 | search = true,
33 | tel = true,
34 | time = true,
35 | url = true,
36 | week = true
37 | }
38 |
39 |
40 | local function defaults(model,attribute,html_options)
41 | local value = model[attribute] and 'value="'..tostring(model[attribute])..'"'
42 | local name = model['@name']..':'..attribute
43 | local id = 'id="'..name..'"'
44 | name = 'name="'..name..'"'
45 | html_options = html_options
46 |
47 | return name, id, html_options, value
48 | end
49 |
50 | local pack = function(...)
51 | if not table.pack then
52 | return {n=select('#',...),...}
53 | end
54 | return table.pack(...)
55 | end
56 |
57 | -- Inputs that work exactly the same changing only the type
58 | meta.__index = function(_,key)
59 | if generic_input_types[key] then
60 | return function(...)
61 | local t = pack(defaults(...))
62 | tinsert(t,1,'')
65 | return tconcat(t,' ')
66 | end
67 | end
68 | return nil
69 | end
70 |
71 | -- More form inputs
72 | function form.textarea(model,attribute,html_options)
73 | local t = pack(defaults(model,attribute,html_options))
74 | tinsert(t,1,'')
76 |
77 | return tconcat(t,' ')
78 | end
79 |
80 | function form.dropdown(model,attribute,list,prompt,html_options)
81 | local html = pack(defaults(model,attribute,html_options))
82 | local value = model[attribute]
83 | list = list or {}
84 |
85 | tinsert(html,1,'')
99 |
100 | return tconcat(html,' ')
101 | end
102 |
103 |
104 |
105 | -- layout: horizontal(default) or vertical
106 | function form.radio_list(model,attribute,list,default,layout,html_options)
107 | local _
108 | _, _, html_options = defaults(model,attribute,html_options)
109 | local value = model[attribute]
110 | list = list or {}
111 |
112 | local t = {}
113 | for k,v in pairs(list) do
114 | local html = {}
115 | tinsert(html, '')
125 | tinsert(html,v)
126 |
127 | tinsert(t,tconcat(html,' '))
128 | end
129 |
130 | if layout == 'vertical' then
131 | return tconcat(t,' ')
132 | end
133 | return tconcat(t,' ')
134 | end
135 |
136 | -- checked: boolean
137 | function form.checkbox(model,attribute,label,checked,html_options)
138 | local t = pack(defaults(model,attribute,html_options))
139 | local value = model[attribute]
140 |
141 | tinsert(t,1,'')
146 | tinsert(t,(label or attribute))
147 |
148 | return tconcat(t,' ')
149 | end
150 |
151 | function form.ify(data)
152 | local new_data = {}
153 | for k,v in pairs(data) do
154 | new_data[model_name .. ':' .. k] = v
155 | end
156 | return new_data
157 | end
158 |
159 | return form
160 |
--------------------------------------------------------------------------------
/CHANGELOG.md:
--------------------------------------------------------------------------------
1 | ## v0.5 alpha - Pluto
2 |
3 |
4 | #### Bug Fixes
5 |
6 |
7 | * **autogen** Fixes autogen page not opening ([5347acb3](https://github.com/sailorproject/sailor/commit/5347acb3))
8 | * **db** Changes query for postgres compatibility on table_exists ([85cc1f59](https://github.com/sailorproject/sailor/commit/85cc1f59))
9 | * **tests** Adds posts fixtures to dev-app tests ([e53b0646](https://github.com/sailorproject/sailor/commit/e53b0646))
10 | * **travis integration** Using a different rockspec for travis ci ([cbd48b2b](https://github.com/sailorproject/sailor/commit/cbd48b2b))
11 | * **latclient**
12 | * Updates starlight version ([ff0d6642](https://github.com/sailorproject/sailor/commit/ff0d6642))
13 | * Changes string delimiters to multiline strings ([5fe91827](https://github.com/sailorproject/sailor/commit/5fe91827))
14 | * Load latclient settings from sailor.lua ([ec058470](https://github.com/sailorproject/sailor/commit/ec058470))
15 | * Make set_application_path() simple again ([d1bc6fb7](https://github.com/sailorproject/sailor/commit/d1bc6fb7))
16 | * Add compatibility with 4 different Lua to JS VMs for lua at client ([9d772384](https://github.com/sailorproject/sailor/commit/9d772384))
17 | * Makes latclient not load the same module again ([4d7cc852](https://github.com/sailorproject/sailor/commit/4d7cc852))
18 | * **remy**
19 | * Make Lighttpd support work again ([e9190523](https://github.com/sailorproject/sailor/commit/e9190523))
20 | * Fixes openresty environment issue ([42545098](https://github.com/sailorproject/sailor/commit/42545098))
21 | * **core**
22 | * Allow hiding stack trace ([b75c9181](https://github.com/sailorproject/sailor/commit/b75c9181))
23 | * Path fixes on set_application_path and make_url. ([7d4528d5](https://github.com/sailorproject/sailor/commit/7d4528d5))
24 | * Fixing set application path ([9d9a1ab6](https://github.com/sailorproject/sailor/commit/9d9a1ab6))
25 | * Fixing route paths and status code for Xavante and Apache ([e2369138](https://github.com/sailorproject/sailor/commit/e2369138))
26 | * **blank-app** Adds test bootstraps to blank app ([eef903f9](https://github.com/sailorproject/sailor/commit/eef903f9))
27 | * **page**
28 | * Fixes typo on page.redirect ([2fe112eb](https://github.com/sailorproject/sailor/commit/2fe112eb))
29 | * Adjusts path on page.include ([27376166](https://github.com/sailorproject/sailor/commit/27376166))
30 | * Page inspect printing number of gsubs, Fixes #36 ([0c848a7c](https://github.com/sailorproject/sailor/commit/0c848a7c))
31 | * **model** Adds missing db.close on model:fild_all ([e07960fb](https://github.com/sailorproject/sailor/commit/e07960fb))
32 |
33 | #### Features
34 |
35 | * **page**
36 | * Adds page:to_browser method ([bd5d95db](https://github.com/sailorproject/sailor/commit/bd5d95db))
37 | * Adds page:tostring() function ([77c8f848](https://github.com/sailorproject/sailor/commit/77c8f848))
38 | * **transactions** Supporting transactions for major databases ([27ccf960](https://github.com/sailorproject/sailor/commit/27ccf960))
39 | * **autogen** Adds autogen compatibility with sqlite3 and postgresql ([e0417418](https://github.com/sailorproject/sailor/commit/e0417418))
40 | * **latclient**
41 | * Support Lua script tag when using starlight VM ([69402cfb](https://github.com/sailorproject/sailor/commit/69402cfb))
42 | * Improve latclient support in persistent environments ([92d5d579](https://github.com/sailorproject/sailor/commit/92d5d579))
43 | * **binary** Adds sailor enable command on binary to install extensions ([9efa2a34](https://github.com/sailorproject/sailor/commit/9efa2a34))
44 | * **controllers** Allows controller to set a custom view path ([dbddf85f](https://github.com/sailorproject/sailor/commit/dbddf85f))
45 | * **remy**
46 | * Adds suport to redirect when using openresty, Closes #47 ([ebb30c1e](https://github.com/sailorproject/sailor/commit/ebb30c1e))
47 | * Improves openresty compatibility ([3d4aebd0](https://github.com/sailorproject/sailor/commit/3d4aebd0))
48 | * **tests**
49 | * Adds openresty simulation on automated tests ([a5f4cd06](https://github.com/sailorproject/sailor/commit/a5f4cd06))
50 | * **db** Adds support to openresty internal MySQL API. ([7e0bd062](https://github.com/sailorproject/sailor/commit/7e0bd062))
51 |
52 | ### Breaking changes
53 | * `sailor` is no longer on global namespace, if you are accessing sailor attributes now you need to require
54 |
55 | ### Deprecations
56 | * sailor.make_url has been copied to page:make_url and will be removed on next versions
57 | * sailor.model has been copied to a call metamethod on the model module and will be removed on next version
58 |
--------------------------------------------------------------------------------
/docs/manual_page_object.md:
--------------------------------------------------------------------------------
1 | ##Reference Manual
2 |
3 | ###The Page object
4 | The `page` object is being passed around controllers and views (implicitly) and it encapsulates several methods and attributes that may vary upon webservers. It can be used inside the actions of a controller and inside views.
5 |
6 | ####page:render( filename [*, parms*] )
7 | Renders a view from a controller action, if there's a default layout configured, it will render the layout first and then render your view.
8 |
9 | * filename: string, filename without ".lp". The file must be inside /views/controller_name
10 | * parms: [optional] table, vars being passed ahead (env).
11 |
12 | Example: `page:render( 'index', {msg = 'hello'} )`
13 |
14 | ####page:include( path [*, parms*] )
15 | Includes a .lp file from a .lp file.
16 |
17 | * path: string, full file path
18 |
19 | * parms: [optional] table, vars being passed ahead (env).
20 |
21 | Example: `page:include( '/views/incs/_defaultmenu' )`
22 |
23 | ####page:redirect( route [*, args*] )
24 | Redirects to another action if the route string doesn't start with 'http://' or another address if it does.
25 |
26 | * route: string, "controller_name/action_name" or some website address.
27 |
28 | * args: [optional] table, vars being passed as get parameters (only for internal redirect).
29 |
30 | Example 1: `page:redirect( 'user/update', {id = 2} )`
31 |
32 | Example 2: `page:redirect( 'http://google.com' )`
33 |
34 | ####page:json( data, [*, parms*] )
35 | Serializes data as JSON and sends it to the response body.
36 |
37 | * data: any serializable value (table, string, number).
38 |
39 | * parms: [optional] table, vars being passed to the dkjson.encode function. Refer to the [dkjson documentation](http://dkolf.de/src/dkjson-lua.fsl/wiki?name=Documentation) for details. Useful parameters are (indent, keyorder, level).
40 |
41 | ####page:write( data )
42 | Writes a single string to the response body.
43 |
44 | * data: string.
45 |
46 | Example 1: `page:write( "Hello world!")`
47 |
48 | ####page:print( data )
49 | (Apache2): Sends one or more variables to the response body.
50 |
51 | (Other webservers): Does the same as page:write does and writes a single string to the response body.
52 |
53 | * data: string.
54 |
55 | Example 1: `page:print( "Hello world!")`
56 |
57 | Example 2 (Apache2): `page:print( "Hello", " world", "!")`
58 |
59 | ####page:inspect( var )
60 | Will inspect a var and print the result on the bottom of the page. It can be toggled on/off by setting conf.debug.inspect to true/false. Very useful for seeing the contents of a table, for example.
61 | * var: any type that you want to be stringfied.
62 |
63 | Example 1: `page:inspect( page.POST )`
64 |
65 | ####page:enable_cors([headers] )
66 | Sends [CORS headers](https://developer.mozilla.org/en-US/docs/Web/HTTP/Access_control_CORS#The_HTTP_response_headers) to the client.
67 |
68 | * headers: [optional] table, contains which headers to pass, if nil then `Access-Control-Allow-Origin = "*"` is used. The keys are (allow_origin, expose_headers, max_age, allow_credentials, allow_methods, allow_headers).
69 |
70 | Example 1: `page:enable_cors()`
71 |
72 | Example 2: `page:enable_cors({allow_origin = "http://sailorproject.org"})`
73 |
74 | ####page.POST
75 | * table: contains the POST data, empty table if there is no POST data.
76 |
77 | ####page.GET
78 | * table: contains the GET data, empty table if there is no GET data.
79 |
80 | ####page.title
81 | * string *writeable*: By default it is set to the same as conf.sailor.app_name, but you can modify it before rendering a page, for example.
82 |
83 | ####page.theme
84 | * string *writeable*: Sailor comes bundled with a default theme, using Bootstrap. This is the name of a folder inside /themes folder. You can modify the default theme of your application by editing conf.sailor.theme. You can modify the theme of just one page by setting page.theme to something else on the controller action before rendering your page. You can set it to nil for displaying no theme at all, like for serving a JSON, for example.
85 |
86 | ####page.layout
87 | * string *writeable*: Sailor default's theme only comes with one layout, main. This refers to a .lp file inside the theme folder. You can create multiple layouts inside one same theme, like 1-column and 2-columns, for example. You can modify the default layout of your application by editing conf.sailor.layout. You can modify the layout of just one page by setting page.layout to something else on the controller action before rendering your page.
88 |
89 | ####page.r
90 | * userdata: request_rec structure that varies according to the webserver, comes with built-in functions.
91 |
92 | (Apache2): [The request_rec structure](http://modlua.org/api/request).
93 |
--------------------------------------------------------------------------------
/docs/manual_form_module.md:
--------------------------------------------------------------------------------
1 | ##Reference Manual
2 | ###The form module
3 | This module will generate html to be used on forms that capture data for a model. It is handy and recommended. This module needs to be required on the view: `local form = require "sailor.form"`. Also please note that on views, `<%= var %>` is equal to ``.
4 | ####form.text(model,attribute,html_options)
5 | Generates a text field input.
6 |
7 | * model: object, an instantiated object from a model.
8 |
9 | * attribute: string, name of the attribute to which the value of this attribute will be sent to.
10 |
11 | * html_options: string, other things to be added inside the input tag.
12 |
13 | Example 1:
14 |
15 | <%= form.text(user, 'username', 'class="cute-form-input" width="300"') %>
16 |
17 |
18 | ####form.textarea(model,attribute,html_options)
19 | Generates a text area input.
20 |
21 | * model: object, an instantiated object from a model.
22 |
23 | * attribute: string, name of the attribute to which the value of this attribute will be sent to.
24 |
25 | * html_options: string, other things to be added inside the input tag.
26 |
27 | Example 1:
28 |
29 | <%= form.textarea(user, 'description', 'class="cute-form-input" width="300"') %>
30 |
31 | ####form.file(model,attribute,html_options)
32 | Generates a file input.
33 |
34 | * model: object, an instantiated object from a model.
35 |
36 | * attribute: string, name of the attribute to which the value of this attribute will be sent to.
37 |
38 | * html_options: string, other things to be added inside the input tag.
39 |
40 | Example 1:
41 |
42 | <%= form.file(user, 'profile_picture', 'class="cute-form-input" width="300"') %>
43 |
44 | ####form.dropdown(model,attribute,list,prompt,html_options)
45 | Generates a dropdown list.
46 |
47 | * model: object, an instantiated object from a model.
48 |
49 | * attribute: string, name of the attribute to which the value of this attribute will be sent to.
50 |
51 | * list: table, contains lists of options to be selected.
52 |
53 | * prompt: string, first option that contains a nil value.
54 |
55 | * html_options: string, other things to be added inside the select tag.
56 |
57 | Example 1:
58 |
59 | <%= form.dropdown(
60 | user,
61 | 'newsletter',
62 | { weekly = 'Receive weekly', monthly = 'Receive Monthly' },
63 | 'Please select newsletter...',
64 | 'class="cute-form-input" width="300"'
65 | )
66 | %>
67 |
68 | ####form.password(model,attribute,html_options)
69 | Generates a password input.
70 |
71 | * model: object, an instantiated object from a model.
72 |
73 | * attribute: string, name of the attribute to which the value of this attribute will be sent to.
74 |
75 | * html_options: string, other things to be added inside the input tag.
76 |
77 | Example 1:
78 |
79 | <%= form.password(user, 'password', 'class="cute-form-input" width="300"') %>
80 |
81 | ####form.radio_list(model,attribute,list,default,layout,html_options)
82 | Generates a set of radio buttons.
83 |
84 | * model: object, an instantiated object from a model.
85 |
86 | * attribute: string, name of the attribute to which the value of this attribute will be sent to.
87 |
88 | * list: table, contains lists of radios to be selected.
89 |
90 | * default: string or nil, which value should be selected by default.
91 |
92 | * layout: string or nil, 'vertical' or 'horizontal' (default when nil).
93 |
94 | * html_options: string, other things to be added inside the input tag.
95 |
96 | Example 1:
97 |
98 | <%= form.radio_list(
99 | user,
100 | 'newsletter',
101 | { weekly = 'Receive weekly', monthly = 'Receive Monthly' },
102 | 'weekly',
103 | 'vertical' ,
104 | 'class="cute-form-input" width="300"'
105 | )
106 | %>
107 |
108 | ####form.checkbox(model,attribute,label,checked,html_options)
109 | Generates a checkbox.
110 |
111 | * model: object, an instantiated object from a model.
112 |
113 | * attribute: string, name of the attribute to which the value of this attribute will be sent to.
114 |
115 | * label: string or nil, text that will go next to the checkbox, defaults to attribute name when nil.
116 |
117 | * checked: boolean, whether or not the checkbox is checked by default.
118 |
119 | * html_options: string, other things to be added inside the input tag.
120 |
121 | Example 1:
122 |
123 | <%= form.checkbox(
124 | user,
125 | 'likes_puppies',
126 | "Do you like puppies?",
127 | true,
128 | 'class="cute-checkbox"'
129 | )
130 | %>
131 |
--------------------------------------------------------------------------------
/rockspecs/sailor-0.3-1.rockspec:
--------------------------------------------------------------------------------
1 | package = "Sailor"
2 | version = "0.3-1"
3 | source = {
4 | url = "git://github.com/Etiene/sailor",
5 | tag = "v0.3"
6 | }
7 | description = {
8 | summary = "A Lua MVC Framework",
9 | detailed = [[
10 | Sailor is a web framework written in Lua that follows the MVC design pattern.
11 | ]],
12 | homepage = "http://sailorproject.org",
13 | license = "MIT"
14 | }
15 | dependencies = {
16 | "lua >= 5.1, < 5.3",
17 | 'datafile >= 0.1',
18 | 'luafilesystem >= 1.6.2',
19 | 'valua >= 0.2.2',
20 | 'lbase64 >= 20120807',
21 | 'cgilua >= 5.1.4',
22 | 'xavante >= 2.3',
23 | 'wsapi-xavante >= 1.6.1'
24 | }
25 | build = {
26 | type = "builtin",
27 | modules = {
28 | latclient = "src/latclient.lua",
29 | ['latclient.lp_handler'] = "src/latclient/lp_handler.lua",
30 | remy = "src/remy.lua",
31 | ['remy.cgilua'] = "src/remy/cgilua.lua",
32 | ['remy.mod_plua'] = "src/remy/mod_plua.lua",
33 | ['remy.nginx'] = "src/remy/nginx.lua",
34 | sailor = "src/sailor.lua",
35 | ['sailor.access'] = "src/sailor/access.lua",
36 | ['sailor.cookie'] = "src/sailor/cookie.lua",
37 | ['sailor.db'] = "src/sailor/db.lua",
38 | ['sailor.demo-app.conf.conf'] = "src/sailor/demo-app/conf/conf.lua",
39 | ['sailor.demo-app.start-server'] = "src/sailor/demo-app/start-server.lua",
40 | ['sailor.demo-app.controllers.main'] = "src/sailor/demo-app/controllers/main.lua",
41 | ['sailor.demo-app.index'] = "src/sailor/demo-app/index.lua",
42 | ['sailor.form'] = "src/sailor/form.lua",
43 | ['sailor.model'] = "src/sailor/model.lua",
44 | ['sailor.session'] = "src/sailor/session.lua",
45 | ['web_utils.lp'] = "src/web_utils/lp.lua",
46 | ['web_utils.lp_ex'] = "src/web_utils/lp_ex.lua",
47 | ['web_utils.serialize'] = "src/web_utils/serialize.lua",
48 | ['web_utils.session'] = "src/web_utils/session.lua",
49 | ['web_utils.utils'] = "src/web_utils/utils.lua"
50 | },
51 | install = {
52 | lua = {
53 | ["sailor.demo-app.htaccess"] = "src/sailor/demo-app/.htaccess",
54 | ["sailor.demo-app.conf.htaccess"] = "src/sailor/demo-app/conf/.htaccess",
55 | ["sailor.demo-app.controllers.htaccess"] = "src/sailor/demo-app/controllers/.htaccess",
56 | ["sailor.demo-app.models.htaccess"] = "src/sailor/demo-app/models/.htaccess",
57 | ["sailor.demo-app.runtime.tmp.htaccess"] = "src/sailor/demo-app/runtime/tmp/.htaccess",
58 | ["sailor.demo-app.views.main.index"] = "src/sailor/demo-app/views/main/index.lp",
59 | ["sailor.demo-app.pub.thirdparty.latclient.js.js-lua"] = "src/sailor/demo-app/pub/thirdparty/latclient/js/js-lua.js",
60 | ["sailor.demo-app.pub.thirdparty.latclient.js.latclient"] = "src/sailor/demo-app/pub/thirdparty/latclient/js/latclient.js",
61 | ["sailor.demo-app.pub.thirdparty.latclient.js.lib.lua51"] = "src/sailor/demo-app/pub/thirdparty/latclient/js/lib/lua5.1.5.min.js",
62 | ["sailor.demo-app.themes.default.css.bootstrap-theme"] = "src/sailor/demo-app/themes/default/css/bootstrap-theme.css",
63 | ["sailor.demo-app.themes.default.css.bootstrap"] = "src/sailor/demo-app/themes/default/css/bootstrap.css",
64 | ["sailor.demo-app.themes.default.css.bootstrap-thememin"] = "src/sailor/demo-app/themes/default/css/bootstrap-theme.min.css",
65 | ["sailor.demo-app.themes.default.css.bootstrapmin"] = "src/sailor/demo-app/themes/default/css/bootstrap.min.css",
66 | ["sailor.demo-app.themes.default.css.sticky-footer-navbar"] = "src/sailor/demo-app/themes/default/css/sticky-footer-navbar.css",
67 | ["sailor.demo-app.themes.default.js.jquery"] = "src/sailor/demo-app/themes/default/js/jquery-1.10.2.min.js",
68 | ["sailor.demo-app.themes.default.js.bootstrap"] = "src/sailor/demo-app/themes/default/js/bootstrap.js",
69 | ["sailor.demo-app.themes.default.js.bootstrapmin"] = "src/sailor/demo-app/themes/default/js/bootstrap.min.js",
70 | ["sailor.demo-app.themes.default.fonts.glysvg"] = "src/sailor/demo-app/themes/default/fonts/glyphicons-halflings-regular.svg",
71 | ["sailor.demo-app.themes.default.fonts.glyttf"] = "src/sailor/demo-app/themes/default/fonts/glyphicons-halflings-regular.ttf",
72 | ["sailor.demo-app.themes.default.fonts.glyeot"] = "src/sailor/demo-app/themes/default/fonts/glyphicons-halflings-regular.eot",
73 | ["sailor.demo-app.themes.default.fonts.glywoff"] = "src/sailor/demo-app/themes/default/fonts/glyphicons-halflings-regular.woff",
74 | ["sailor.demo-app.themes.default.config"] = "src/sailor/demo-app/themes/default/config.json",
75 | ["sailor.demo-app.themes.default.main"] = "src/sailor/demo-app/themes/default/main.lp",
76 | },
77 | bin = {
78 | sailor_create = "sailor_create"
79 | }
80 | }
81 | }
82 |
--------------------------------------------------------------------------------
/rockspecs/sailor-0.3-2.rockspec:
--------------------------------------------------------------------------------
1 | package = "Sailor"
2 | version = "0.3-2"
3 | source = {
4 | url = "git://github.com/Etiene/sailor",
5 | tag = "v0.3"
6 | }
7 | description = {
8 | summary = "A Lua MVC Framework",
9 | detailed = [[
10 | Sailor is a web framework written in Lua that follows the MVC design pattern.
11 | ]],
12 | homepage = "http://sailorproject.org",
13 | license = "MIT"
14 | }
15 | dependencies = {
16 | "lua >= 5.1, < 5.3",
17 | 'datafile >= 0.1',
18 | 'luafilesystem >= 1.6.2',
19 | 'valua >= 0.2.2',
20 | 'lbase64 >= 20120807',
21 | 'cgilua >= 5.1.4, < 5.2',
22 | 'xavante >= 2.3',
23 | 'wsapi-xavante >= 1.6.1'
24 | }
25 | build = {
26 | type = "builtin",
27 | modules = {
28 | latclient = "src/latclient.lua",
29 | ['latclient.lp_handler'] = "src/latclient/lp_handler.lua",
30 | remy = "src/remy.lua",
31 | ['remy.cgilua'] = "src/remy/cgilua.lua",
32 | ['remy.mod_plua'] = "src/remy/mod_plua.lua",
33 | ['remy.nginx'] = "src/remy/nginx.lua",
34 | sailor = "src/sailor.lua",
35 | ['sailor.access'] = "src/sailor/access.lua",
36 | ['sailor.cookie'] = "src/sailor/cookie.lua",
37 | ['sailor.db'] = "src/sailor/db.lua",
38 | ['sailor.demo-app.conf.conf'] = "src/sailor/demo-app/conf/conf.lua",
39 | ['sailor.demo-app.start-server'] = "src/sailor/demo-app/start-server.lua",
40 | ['sailor.demo-app.controllers.main'] = "src/sailor/demo-app/controllers/main.lua",
41 | ['sailor.demo-app.index'] = "src/sailor/demo-app/index.lua",
42 | ['sailor.form'] = "src/sailor/form.lua",
43 | ['sailor.model'] = "src/sailor/model.lua",
44 | ['sailor.session'] = "src/sailor/session.lua",
45 | ['web_utils.lp'] = "src/web_utils/lp.lua",
46 | ['web_utils.lp_ex'] = "src/web_utils/lp_ex.lua",
47 | ['web_utils.serialize'] = "src/web_utils/serialize.lua",
48 | ['web_utils.session'] = "src/web_utils/session.lua",
49 | ['web_utils.utils'] = "src/web_utils/utils.lua"
50 | },
51 | install = {
52 | lua = {
53 | ["sailor.demo-app.htaccess"] = "src/sailor/demo-app/.htaccess",
54 | ["sailor.demo-app.conf.htaccess"] = "src/sailor/demo-app/conf/.htaccess",
55 | ["sailor.demo-app.controllers.htaccess"] = "src/sailor/demo-app/controllers/.htaccess",
56 | ["sailor.demo-app.models.htaccess"] = "src/sailor/demo-app/models/.htaccess",
57 | ["sailor.demo-app.runtime.tmp.htaccess"] = "src/sailor/demo-app/runtime/tmp/.htaccess",
58 | ["sailor.demo-app.views.main.index"] = "src/sailor/demo-app/views/main/index.lp",
59 | ["sailor.demo-app.pub.thirdparty.latclient.js.js-lua"] = "src/sailor/demo-app/pub/thirdparty/latclient/js/js-lua.js",
60 | ["sailor.demo-app.pub.thirdparty.latclient.js.latclient"] = "src/sailor/demo-app/pub/thirdparty/latclient/js/latclient.js",
61 | ["sailor.demo-app.pub.thirdparty.latclient.js.lib.lua51"] = "src/sailor/demo-app/pub/thirdparty/latclient/js/lib/lua5.1.5.min.js",
62 | ["sailor.demo-app.themes.default.css.bootstrap-theme"] = "src/sailor/demo-app/themes/default/css/bootstrap-theme.css",
63 | ["sailor.demo-app.themes.default.css.bootstrap"] = "src/sailor/demo-app/themes/default/css/bootstrap.css",
64 | ["sailor.demo-app.themes.default.css.bootstrap-thememin"] = "src/sailor/demo-app/themes/default/css/bootstrap-theme.min.css",
65 | ["sailor.demo-app.themes.default.css.bootstrapmin"] = "src/sailor/demo-app/themes/default/css/bootstrap.min.css",
66 | ["sailor.demo-app.themes.default.css.sticky-footer-navbar"] = "src/sailor/demo-app/themes/default/css/sticky-footer-navbar.css",
67 | ["sailor.demo-app.themes.default.js.jquery"] = "src/sailor/demo-app/themes/default/js/jquery-1.10.2.min.js",
68 | ["sailor.demo-app.themes.default.js.bootstrap"] = "src/sailor/demo-app/themes/default/js/bootstrap.js",
69 | ["sailor.demo-app.themes.default.js.bootstrapmin"] = "src/sailor/demo-app/themes/default/js/bootstrap.min.js",
70 | ["sailor.demo-app.themes.default.fonts.glysvg"] = "src/sailor/demo-app/themes/default/fonts/glyphicons-halflings-regular.svg",
71 | ["sailor.demo-app.themes.default.fonts.glyttf"] = "src/sailor/demo-app/themes/default/fonts/glyphicons-halflings-regular.ttf",
72 | ["sailor.demo-app.themes.default.fonts.glyeot"] = "src/sailor/demo-app/themes/default/fonts/glyphicons-halflings-regular.eot",
73 | ["sailor.demo-app.themes.default.fonts.glywoff"] = "src/sailor/demo-app/themes/default/fonts/glyphicons-halflings-regular.woff",
74 | ["sailor.demo-app.themes.default.config"] = "src/sailor/demo-app/themes/default/config.json",
75 | ["sailor.demo-app.themes.default.main"] = "src/sailor/demo-app/themes/default/main.lp",
76 | },
77 | bin = {
78 | sailor_create = "sailor_create"
79 | }
80 | }
81 | }
82 |
--------------------------------------------------------------------------------
/rockspecs/sailor-0.2.1-1.rockspec:
--------------------------------------------------------------------------------
1 | package = "Sailor"
2 | version = "0.2.1-1"
3 | source = {
4 | url = "git://github.com/Etiene/sailor",
5 | tag = "v0.2.1"
6 | }
7 | description = {
8 | summary = "A Lua MVC Framework",
9 | detailed = [[
10 | Sailor is a web framework written in Lua that follows the MVC design pattern.
11 | ]],
12 | homepage = "http://sailorproject.org",
13 | license = "MIT"
14 | }
15 | dependencies = {
16 | "lua >= 5.1, < 5.3",
17 | 'datafile >= 0.1',
18 | 'luafilesystem >= 1.6.2',
19 | 'valua >= 0.2.2',
20 | 'lbase64 >= 20120807',
21 | 'cgilua >= 5.1.4',
22 | 'xavante >= 2.3',
23 | 'wsapi-xavante >= 1.6.1'
24 | }
25 | build = {
26 | type = "builtin",
27 | modules = {
28 | latclient = "src/latclient.lua",
29 | ['latclient.lp_handler'] = "src/latclient/lp_handler.lua",
30 | remy = "src/remy.lua",
31 | ['remy.cgilua'] = "src/remy/cgilua.lua",
32 | ['remy.mod_plua'] = "src/remy/mod_plua.lua",
33 | ['remy.nginx'] = "src/remy/nginx.lua",
34 | sailor = "src/sailor.lua",
35 | ['sailor.access'] = "src/sailor/access.lua",
36 | ['sailor.cookie'] = "src/sailor/cookie.lua",
37 | ['sailor.db'] = "src/sailor/db.lua",
38 | ['sailor.demo-app.conf.conf'] = "src/sailor/demo-app/conf/conf.lua",
39 | ['sailor.demo-app.start-server'] = "src/sailor/demo-app/start-server.lua",
40 | ['sailor.demo-app.controllers.main'] = "src/sailor/demo-app/controllers/main.lua",
41 | ['sailor.demo-app.index'] = "src/sailor/demo-app/index.lua",
42 | ['sailor.form'] = "src/sailor/form.lua",
43 | ['sailor.model'] = "src/sailor/model.lua",
44 | ['sailor.session'] = "src/sailor/session.lua",
45 | ['web_utils.lp'] = "src/web_utils/lp.lua",
46 | ['web_utils.lp_ex'] = "src/web_utils/lp_ex.lua",
47 | ['web_utils.serialize'] = "src/web_utils/serialize.lua",
48 | ['web_utils.session'] = "src/web_utils/session.lua",
49 | ['web_utils.utils'] = "src/web_utils/utils.lua"
50 | },
51 | install = {
52 | lua = {
53 | ["sailor.demo-app.htaccess"] = "src/sailor/demo-app/.htaccess",
54 | ["sailor.demo-app.conf.htaccess"] = "src/sailor/demo-app/conf/.htaccess",
55 | ["sailor.demo-app.controllers.htaccess"] = "src/sailor/demo-app/controllers/.htaccess",
56 | ["sailor.demo-app.models.htaccess"] = "src/sailor/demo-app/models/.htaccess",
57 | ["sailor.demo-app.runtime.tmp.htaccess"] = "src/sailor/demo-app/runtime/tmp/.htaccess",
58 | ["sailor.demo-app.views.main.index"] = "src/sailor/demo-app/views/main/index.lp",
59 | ["sailor.demo-app.pub.thirdparty.latclient.js.js-lua"] = "src/sailor/demo-app/pub/thirdparty/latclient/js/js-lua.js",
60 | ["sailor.demo-app.pub.thirdparty.latclient.js.latclient"] = "src/sailor/demo-app/pub/thirdparty/latclient/js/latclient.js",
61 | ["sailor.demo-app.pub.thirdparty.latclient.js.lib.lua51"] = "src/sailor/demo-app/pub/thirdparty/latclient/js/lib/lua5.1.5.min.js",
62 | ["sailor.demo-app.layouts.default.css.bootstrap-theme"] = "src/sailor/demo-app/layouts/default/css/bootstrap-theme.css",
63 | ["sailor.demo-app.layouts.default.css.bootstrap"] = "src/sailor/demo-app/layouts/default/css/bootstrap.css",
64 | ["sailor.demo-app.layouts.default.css.bootstrap-thememin"] = "src/sailor/demo-app/layouts/default/css/bootstrap-theme.min.css",
65 | ["sailor.demo-app.layouts.default.css.bootstrapmin"] = "src/sailor/demo-app/layouts/default/css/bootstrap.min.css",
66 | ["sailor.demo-app.layouts.default.css.sticky-footer-navbar"] = "src/sailor/demo-app/layouts/default/css/sticky-footer-navbar.css",
67 | ["sailor.demo-app.layouts.default.js.jquery"] = "src/sailor/demo-app/layouts/default/js/jquery-1.10.2.min.js",
68 | ["sailor.demo-app.layouts.default.js.bootstrap"] = "src/sailor/demo-app/layouts/default/js/bootstrap.js",
69 | ["sailor.demo-app.layouts.default.js.bootstrapmin"] = "src/sailor/demo-app/layouts/default/js/bootstrap.min.js",
70 | ["sailor.demo-app.layouts.default.fonts.glysvg"] = "src/sailor/demo-app/layouts/default/fonts/glyphicons-halflings-regular.svg",
71 | ["sailor.demo-app.layouts.default.fonts.glyttf"] = "src/sailor/demo-app/layouts/default/fonts/glyphicons-halflings-regular.ttf",
72 | ["sailor.demo-app.layouts.default.fonts.glyeot"] = "src/sailor/demo-app/layouts/default/fonts/glyphicons-halflings-regular.eot",
73 | ["sailor.demo-app.layouts.default.fonts.glywoff"] = "src/sailor/demo-app/layouts/default/fonts/glyphicons-halflings-regular.woff",
74 | ["sailor.demo-app.layouts.default.config"] = "src/sailor/demo-app/layouts/default/config.json",
75 | ["sailor.demo-app.layouts.default.index"] = "src/sailor/demo-app/layouts/default/index.lp",
76 | },
77 | bin = {
78 | sailor_create = "sailor_create"
79 | }
80 | }
81 | }
82 |
--------------------------------------------------------------------------------
/rockspecs/sailor-0.2.1-2.rockspec:
--------------------------------------------------------------------------------
1 | package = "Sailor"
2 | version = "0.2.1-2"
3 | source = {
4 | url = "git://github.com/sailorproject/sailor",
5 | tag = "v0.2.1"
6 | }
7 | description = {
8 | summary = "A Lua MVC Framework",
9 | detailed = [[
10 | Sailor is a web framework written in Lua that follows the MVC design pattern.
11 | ]],
12 | homepage = "http://sailorproject.org",
13 | license = "MIT"
14 | }
15 | dependencies = {
16 | "lua >= 5.1, < 5.3",
17 | 'datafile >= 0.1',
18 | 'luafilesystem >= 1.6.2',
19 | 'valua >= 0.2.2',
20 | 'lbase64 >= 20120807',
21 | 'cgilua >= 5.1.4',
22 | 'xavante >= 2.3',
23 | 'wsapi-xavante >= 1.6.1'
24 | }
25 | build = {
26 | type = "builtin",
27 | modules = {
28 | latclient = "src/latclient.lua",
29 | ['latclient.lp_handler'] = "src/latclient/lp_handler.lua",
30 | remy = "src/remy.lua",
31 | ['remy.cgilua'] = "src/remy/cgilua.lua",
32 | ['remy.mod_plua'] = "src/remy/mod_plua.lua",
33 | ['remy.nginx'] = "src/remy/nginx.lua",
34 | sailor = "src/sailor.lua",
35 | ['sailor.access'] = "src/sailor/access.lua",
36 | ['sailor.cookie'] = "src/sailor/cookie.lua",
37 | ['sailor.db'] = "src/sailor/db.lua",
38 | ['sailor.demo-app.conf.conf'] = "src/sailor/demo-app/conf/conf.lua",
39 | ['sailor.demo-app.start-server'] = "src/sailor/demo-app/start-server.lua",
40 | ['sailor.demo-app.controllers.main'] = "src/sailor/demo-app/controllers/main.lua",
41 | ['sailor.demo-app.index'] = "src/sailor/demo-app/index.lua",
42 | ['sailor.form'] = "src/sailor/form.lua",
43 | ['sailor.model'] = "src/sailor/model.lua",
44 | ['sailor.session'] = "src/sailor/session.lua",
45 | ['web_utils.lp'] = "src/web_utils/lp.lua",
46 | ['web_utils.lp_ex'] = "src/web_utils/lp_ex.lua",
47 | ['web_utils.serialize'] = "src/web_utils/serialize.lua",
48 | ['web_utils.session'] = "src/web_utils/session.lua",
49 | ['web_utils.utils'] = "src/web_utils/utils.lua"
50 | },
51 | install = {
52 | lua = {
53 | ["sailor.demo-app.htaccess"] = "src/sailor/demo-app/.htaccess",
54 | ["sailor.demo-app.conf.htaccess"] = "src/sailor/demo-app/conf/.htaccess",
55 | ["sailor.demo-app.controllers.htaccess"] = "src/sailor/demo-app/controllers/.htaccess",
56 | ["sailor.demo-app.models.htaccess"] = "src/sailor/demo-app/models/.htaccess",
57 | ["sailor.demo-app.runtime.tmp.htaccess"] = "src/sailor/demo-app/runtime/tmp/.htaccess",
58 | ["sailor.demo-app.views.main.index"] = "src/sailor/demo-app/views/main/index.lp",
59 | ["sailor.demo-app.pub.thirdparty.latclient.js.js-lua"] = "src/sailor/demo-app/pub/thirdparty/latclient/js/js-lua.js",
60 | ["sailor.demo-app.pub.thirdparty.latclient.js.latclient"] = "src/sailor/demo-app/pub/thirdparty/latclient/js/latclient.js",
61 | ["sailor.demo-app.pub.thirdparty.latclient.js.lib.lua51"] = "src/sailor/demo-app/pub/thirdparty/latclient/js/lib/lua5.1.5.min.js",
62 | ["sailor.demo-app.layouts.default.css.bootstrap-theme"] = "src/sailor/demo-app/layouts/default/css/bootstrap-theme.css",
63 | ["sailor.demo-app.layouts.default.css.bootstrap"] = "src/sailor/demo-app/layouts/default/css/bootstrap.css",
64 | ["sailor.demo-app.layouts.default.css.bootstrap-thememin"] = "src/sailor/demo-app/layouts/default/css/bootstrap-theme.min.css",
65 | ["sailor.demo-app.layouts.default.css.bootstrapmin"] = "src/sailor/demo-app/layouts/default/css/bootstrap.min.css",
66 | ["sailor.demo-app.layouts.default.css.sticky-footer-navbar"] = "src/sailor/demo-app/layouts/default/css/sticky-footer-navbar.css",
67 | ["sailor.demo-app.layouts.default.js.jquery"] = "src/sailor/demo-app/layouts/default/js/jquery-1.10.2.min.js",
68 | ["sailor.demo-app.layouts.default.js.bootstrap"] = "src/sailor/demo-app/layouts/default/js/bootstrap.js",
69 | ["sailor.demo-app.layouts.default.js.bootstrapmin"] = "src/sailor/demo-app/layouts/default/js/bootstrap.min.js",
70 | ["sailor.demo-app.layouts.default.fonts.glysvg"] = "src/sailor/demo-app/layouts/default/fonts/glyphicons-halflings-regular.svg",
71 | ["sailor.demo-app.layouts.default.fonts.glyttf"] = "src/sailor/demo-app/layouts/default/fonts/glyphicons-halflings-regular.ttf",
72 | ["sailor.demo-app.layouts.default.fonts.glyeot"] = "src/sailor/demo-app/layouts/default/fonts/glyphicons-halflings-regular.eot",
73 | ["sailor.demo-app.layouts.default.fonts.glywoff"] = "src/sailor/demo-app/layouts/default/fonts/glyphicons-halflings-regular.woff",
74 | ["sailor.demo-app.layouts.default.config"] = "src/sailor/demo-app/layouts/default/config.json",
75 | ["sailor.demo-app.layouts.default.index"] = "src/sailor/demo-app/layouts/default/index.lp",
76 | },
77 | bin = {
78 | sailor_create = "sailor_create"
79 | }
80 | }
81 | }
82 |
--------------------------------------------------------------------------------
/src/sailor/cli.lua:
--------------------------------------------------------------------------------
1 | --------------------------------------------------------------------------------
2 | -- cli.lua v0.1.2: Functions for sailor's command line utility
3 | -- This file is a part of Sailor project
4 | -- Copyright (c) 2014 Etiene Dalcol
5 | -- License: MIT
6 | -- http://sailorproject.org
7 | --------------------------------------------------------------------------------
8 |
9 | local lfs = require "lfs"
10 |
11 | local cli = {}
12 |
13 | local function get_sailor_path(current_dir)
14 | local sailor_path = ((debug.getinfo(1).source):match("^@?(.-)/sailor$"))
15 |
16 | local f = sailor_path and io.open(sailor_path.."/src/sailor.lua", "r")
17 | if not f then
18 | local datafile = require("datafile")
19 | sailor_path = datafile.path("sailor/cookie.lua"):match("^@?(.-)/sailor/cookie.lua$")
20 | else
21 | f:close()
22 | if sailor_path == '.' then
23 | sailor_path = current_dir.."/src"
24 | elseif sailor_path:match("^.") then
25 | local path = sailor_path:match(".(.-)")
26 | sailor_path = current_dir.."/sailor"..tostring(path).."/src"
27 | elseif not sailor_path:match("^/") then
28 | sailor_path = current_dir.."/src/"..sailor_path
29 | else
30 | sailor_path = sailor_path.."/src"
31 | end
32 | end
33 | return sailor_path
34 | end
35 |
36 | function cli.create(args, _)
37 | local name = string.gsub(args.name:lower(),' ','_')
38 | local current_dir = lfs.currentdir()
39 | local destiny = args.path or current_dir
40 |
41 | local sailor_path = get_sailor_path(current_dir)
42 |
43 | local raw_app = sailor_path.."/sailor/blank-app"
44 | local new_app = destiny.."/"..name
45 | assert(os.execute("cp -a '"..raw_app.."' '"..new_app.."'"))
46 |
47 | local htaccess = assert(io.open (new_app.."/.htaccess" , "r"))
48 | local src = htaccess:read("*a")
49 | htaccess:close()
50 |
51 | htaccess = assert(io.open (new_app.."/.htaccess" , "w"))
52 | src = string.gsub(src,"{{path}}",sailor_path)
53 | htaccess:write(src)
54 | htaccess:close()
55 |
56 | local conf = assert(io.open (new_app.."/conf/conf.lua" , "r"))
57 | src = conf:read("*a")
58 | conf:close()
59 | conf = assert(io.open (new_app.."/conf/conf.lua" , "w"))
60 | src = string.gsub(src,"Sailor! A Lua MVC Framework", args.name)
61 | conf:write(src)
62 | conf:close()
63 |
64 | print("done!")
65 | os.exit(0)
66 | end
67 |
68 | function cli.enable(args, _)
69 | local name = 'sailor-'..args.name
70 | local current_dir = lfs.currentdir()
71 | local sailor_path = get_sailor_path(current_dir)
72 |
73 | assert(os.execute('luarocks install '..name))
74 |
75 | local ext_app = sailor_path.."/sailor/"..name.."/app"
76 | assert(os.execute("mkdir -p extensions"))
77 | local err = assert(os.execute("cp -a '"..ext_app.."' extensions/"..name))
78 | if err == 0 then
79 | local index_file = assert(io.open ("index.lua" , "r"))
80 | local src = index_file:read("*a")
81 | index_file:close()
82 |
83 | local package_path = "package.path = base_dir..'extensions/"..name.."/?.lua;'..package.path"
84 | src = string.gsub(src,"\nlocal sailor",package_path.."\n\nlocal sailor")
85 | index_file = assert(io.open ("index.lua" , "w"))
86 | index_file:write(src)
87 | index_file:close()
88 | print("New files:")
89 | print("extensions/"..name.."/*\n")
90 | print("Files modified:")
91 | print("index.lua\n")
92 | print("done!")
93 | os.exit(0)
94 | end
95 | end
96 |
97 | function cli.gen_all(args)
98 | local model = require "sailor.model"
99 | model.generate_model(args.table_name)
100 | model.generate_crud(args.table_name)
101 | end
102 |
103 | function cli.gen_crud(args)
104 | local model = require "sailor.model"
105 | model.generate_crud(args.model_name)
106 | end
107 |
108 | function cli.gen_model(args)
109 | local model = require "sailor.model"
110 | model.generate_model(args.table_name)
111 | end
112 |
113 | function cli.start()
114 | local ok, _ = pcall(require, "start-server")
115 | if not ok then
116 | print("Start script not found. Please run this command from the root dir of your Sailor app.")
117 | os.exit(1, true)
118 | end
119 | end
120 |
121 | function cli.test(args, _)
122 | local ok
123 |
124 | local flags = table.concat(args.EXTRA_FLAGS, " ")
125 |
126 | if args.resty then
127 | ok = os.execute('resty tests/bootstrap_resty.lua')
128 | else
129 | ok = os.execute('busted --helper=tests/bootstrap.lua '..flags..' tests/unit/* tests/functional/*')
130 | end
131 |
132 | if type(ok) == "number" then return ok end -- Lua 5.1 just returns the status code
133 | local exit_code = ok and 0 or 1 -- don't care about actual value
134 |
135 | if exit_code and exit_code ~= 0 then
136 | -- exit code sometimes is > 255 and fails to be propagated
137 | os.exit(1, true)
138 | end
139 | end
140 |
141 | function cli.version()
142 | print("Sailor: version " .. require "sailor.version")
143 | os.exit(0)
144 | end
145 |
146 | return cli
147 |
--------------------------------------------------------------------------------
/rockspecs/sailor-0.3-3.rockspec:
--------------------------------------------------------------------------------
1 | package = "Sailor"
2 | version = "0.3-3"
3 | source = {
4 | url = "git://github.com/Etiene/sailor",
5 | tag = "v0.3"
6 | }
7 | description = {
8 | summary = "A Lua MVC Framework",
9 | detailed = [[
10 | Sailor is a web framework written in Lua that follows the MVC design pattern.
11 | ]],
12 | homepage = "http://sailorproject.org",
13 | license = "MIT"
14 | }
15 | dependencies = {
16 | "lua >= 5.1, < 5.3",
17 | 'datafile >= 0.1',
18 | 'luafilesystem >= 1.6.2',
19 | 'valua >= 0.2.2',
20 | 'lbase64 >= 20120807',
21 | 'cgilua >= 5.1.4, < 5.2',
22 | 'xavante >= 2.3',
23 | 'wsapi-xavante >= 1.6.1'
24 | }
25 | build = {
26 | type = "builtin",
27 | modules = {
28 | latclient = "src/latclient.lua",
29 | ['latclient.lp_handler'] = "src/latclient/lp_handler.lua",
30 | remy = "src/remy.lua",
31 | ['remy.cgilua'] = "src/remy/cgilua.lua",
32 | ['remy.mod_plua'] = "src/remy/mod_plua.lua",
33 | ['remy.mod_magnet'] = "src/remy/mod_magnet.lua",
34 | ['remy.lwan'] = "src/remy/lwan.lua",
35 | ['remy.nginx'] = "src/remy/nginx.lua",
36 | sailor = "src/sailor.lua",
37 | ['sailor.access'] = "src/sailor/access.lua",
38 | ['sailor.autogen'] = "src/sailor/autogen.lua",
39 | ['sailor.cookie'] = "src/sailor/cookie.lua",
40 | ['sailor.db'] = "src/sailor/db.lua",
41 | ['sailor.demo-app.conf.conf'] = "src/sailor/demo-app/conf/conf.lua",
42 | ['sailor.demo-app.start-server'] = "src/sailor/demo-app/start-server.lua",
43 | ['sailor.demo-app.controllers.main'] = "src/sailor/demo-app/controllers/main.lua",
44 | ['sailor.demo-app.index'] = "src/sailor/demo-app/index.lua",
45 | ['sailor.demo-app.index-magnet'] = "src/sailor/demo-app/index-magnet.lua",
46 | ['sailor.form'] = "src/sailor/form.lua",
47 | ['sailor.model'] = "src/sailor/model.lua",
48 | ['sailor.session'] = "src/sailor/session.lua",
49 | ['web_utils.lp'] = "src/web_utils/lp.lua",
50 | ['web_utils.lp_ex'] = "src/web_utils/lp_ex.lua",
51 | ['web_utils.serialize'] = "src/web_utils/serialize.lua",
52 | ['web_utils.session'] = "src/web_utils/session.lua",
53 | ['web_utils.utils'] = "src/web_utils/utils.lua"
54 | },
55 | install = {
56 | lua = {
57 | ["sailor.demo-app.htaccess"] = "src/sailor/demo-app/.htaccess",
58 | ["sailor.demo-app.conf.htaccess"] = "src/sailor/demo-app/conf/.htaccess",
59 | ["sailor.demo-app.controllers.htaccess"] = "src/sailor/demo-app/controllers/.htaccess",
60 | ["sailor.demo-app.models.htaccess"] = "src/sailor/demo-app/models/.htaccess",
61 | ["sailor.demo-app.runtime.tmp.htaccess"] = "src/sailor/demo-app/runtime/tmp/.htaccess",
62 | ["sailor.demo-app.views.main.index"] = "src/sailor/demo-app/views/main/index.lp",
63 | ["sailor.demo-app.pub.thirdparty.latclient.js.js-lua"] = "src/sailor/demo-app/pub/thirdparty/latclient/js/js-lua.js",
64 | ["sailor.demo-app.pub.thirdparty.latclient.js.latclient"] = "src/sailor/demo-app/pub/thirdparty/latclient/js/latclient.js",
65 | ["sailor.demo-app.pub.thirdparty.latclient.js.lib.lua51"] = "src/sailor/demo-app/pub/thirdparty/latclient/js/lib/lua5.1.5.min.js",
66 | ["sailor.demo-app.themes.default.css.bootstrap-theme"] = "src/sailor/demo-app/themes/default/css/bootstrap-theme.css",
67 | ["sailor.demo-app.themes.default.css.bootstrap"] = "src/sailor/demo-app/themes/default/css/bootstrap.css",
68 | ["sailor.demo-app.themes.default.css.bootstrap-thememin"] = "src/sailor/demo-app/themes/default/css/bootstrap-theme.min.css",
69 | ["sailor.demo-app.themes.default.css.bootstrapmin"] = "src/sailor/demo-app/themes/default/css/bootstrap.min.css",
70 | ["sailor.demo-app.themes.default.css.sticky-footer-navbar"] = "src/sailor/demo-app/themes/default/css/sticky-footer-navbar.css",
71 | ["sailor.demo-app.themes.default.js.jquery"] = "src/sailor/demo-app/themes/default/js/jquery-1.10.2.min.js",
72 | ["sailor.demo-app.themes.default.js.bootstrap"] = "src/sailor/demo-app/themes/default/js/bootstrap.js",
73 | ["sailor.demo-app.themes.default.js.bootstrapmin"] = "src/sailor/demo-app/themes/default/js/bootstrap.min.js",
74 | ["sailor.demo-app.themes.default.fonts.glysvg"] = "src/sailor/demo-app/themes/default/fonts/glyphicons-halflings-regular.svg",
75 | ["sailor.demo-app.themes.default.fonts.glyttf"] = "src/sailor/demo-app/themes/default/fonts/glyphicons-halflings-regular.ttf",
76 | ["sailor.demo-app.themes.default.fonts.glyeot"] = "src/sailor/demo-app/themes/default/fonts/glyphicons-halflings-regular.eot",
77 | ["sailor.demo-app.themes.default.fonts.glywoff"] = "src/sailor/demo-app/themes/default/fonts/glyphicons-halflings-regular.woff",
78 | ["sailor.demo-app.themes.default.config"] = "src/sailor/demo-app/themes/default/config.json",
79 | ["sailor.demo-app.themes.default.main"] = "src/sailor/demo-app/themes/default/main.lp",
80 | },
81 | bin = {
82 | sailor_create = "sailor_create"
83 | }
84 | }
85 | }
86 |
--------------------------------------------------------------------------------
/rockspecs/sailor-0.3-4.rockspec:
--------------------------------------------------------------------------------
1 | package = "Sailor"
2 | version = "0.3-4"
3 | source = {
4 | url = "git://github.com/sailorproject/sailor",
5 | tag = "v0.3"
6 | }
7 | description = {
8 | summary = "A Lua MVC Framework",
9 | detailed = [[
10 | Sailor is a web framework written in Lua that follows the MVC design pattern.
11 | ]],
12 | homepage = "http://sailorproject.org",
13 | license = "MIT"
14 | }
15 | dependencies = {
16 | "lua >= 5.1, < 5.3",
17 | 'datafile >= 0.1',
18 | 'luafilesystem >= 1.6.2',
19 | 'valua >= 0.2.2',
20 | 'lbase64 >= 20120807',
21 | 'cgilua >= 5.1.4, < 5.2',
22 | 'xavante >= 2.3',
23 | 'wsapi-xavante >= 1.6.1'
24 | }
25 | build = {
26 | type = "builtin",
27 | modules = {
28 | latclient = "src/latclient.lua",
29 | ['latclient.lp_handler'] = "src/latclient/lp_handler.lua",
30 | remy = "src/remy.lua",
31 | ['remy.cgilua'] = "src/remy/cgilua.lua",
32 | ['remy.mod_plua'] = "src/remy/mod_plua.lua",
33 | ['remy.mod_magnet'] = "src/remy/mod_magnet.lua",
34 | ['remy.lwan'] = "src/remy/lwan.lua",
35 | ['remy.nginx'] = "src/remy/nginx.lua",
36 | sailor = "src/sailor.lua",
37 | ['sailor.access'] = "src/sailor/access.lua",
38 | ['sailor.autogen'] = "src/sailor/autogen.lua",
39 | ['sailor.cookie'] = "src/sailor/cookie.lua",
40 | ['sailor.db'] = "src/sailor/db.lua",
41 | ['sailor.demo-app.conf.conf'] = "src/sailor/demo-app/conf/conf.lua",
42 | ['sailor.demo-app.start-server'] = "src/sailor/demo-app/start-server.lua",
43 | ['sailor.demo-app.controllers.main'] = "src/sailor/demo-app/controllers/main.lua",
44 | ['sailor.demo-app.index'] = "src/sailor/demo-app/index.lua",
45 | ['sailor.demo-app.index-magnet'] = "src/sailor/demo-app/index-magnet.lua",
46 | ['sailor.form'] = "src/sailor/form.lua",
47 | ['sailor.model'] = "src/sailor/model.lua",
48 | ['sailor.session'] = "src/sailor/session.lua",
49 | ['web_utils.lp'] = "src/web_utils/lp.lua",
50 | ['web_utils.lp_ex'] = "src/web_utils/lp_ex.lua",
51 | ['web_utils.serialize'] = "src/web_utils/serialize.lua",
52 | ['web_utils.session'] = "src/web_utils/session.lua",
53 | ['web_utils.utils'] = "src/web_utils/utils.lua"
54 | },
55 | install = {
56 | lua = {
57 | ["sailor.demo-app.htaccess"] = "src/sailor/demo-app/.htaccess",
58 | ["sailor.demo-app.conf.htaccess"] = "src/sailor/demo-app/conf/.htaccess",
59 | ["sailor.demo-app.controllers.htaccess"] = "src/sailor/demo-app/controllers/.htaccess",
60 | ["sailor.demo-app.models.htaccess"] = "src/sailor/demo-app/models/.htaccess",
61 | ["sailor.demo-app.runtime.tmp.htaccess"] = "src/sailor/demo-app/runtime/tmp/.htaccess",
62 | ["sailor.demo-app.views.main.index"] = "src/sailor/demo-app/views/main/index.lp",
63 | ["sailor.demo-app.pub.thirdparty.latclient.js.js-lua"] = "src/sailor/demo-app/pub/thirdparty/latclient/js/js-lua.js",
64 | ["sailor.demo-app.pub.thirdparty.latclient.js.latclient"] = "src/sailor/demo-app/pub/thirdparty/latclient/js/latclient.js",
65 | ["sailor.demo-app.pub.thirdparty.latclient.js.lib.lua51"] = "src/sailor/demo-app/pub/thirdparty/latclient/js/lib/lua5.1.5.min.js",
66 | ["sailor.demo-app.themes.default.css.bootstrap-theme"] = "src/sailor/demo-app/themes/default/css/bootstrap-theme.css",
67 | ["sailor.demo-app.themes.default.css.bootstrap"] = "src/sailor/demo-app/themes/default/css/bootstrap.css",
68 | ["sailor.demo-app.themes.default.css.bootstrap-thememin"] = "src/sailor/demo-app/themes/default/css/bootstrap-theme.min.css",
69 | ["sailor.demo-app.themes.default.css.bootstrapmin"] = "src/sailor/demo-app/themes/default/css/bootstrap.min.css",
70 | ["sailor.demo-app.themes.default.css.sticky-footer-navbar"] = "src/sailor/demo-app/themes/default/css/sticky-footer-navbar.css",
71 | ["sailor.demo-app.themes.default.js.jquery"] = "src/sailor/demo-app/themes/default/js/jquery-1.10.2.min.js",
72 | ["sailor.demo-app.themes.default.js.bootstrap"] = "src/sailor/demo-app/themes/default/js/bootstrap.js",
73 | ["sailor.demo-app.themes.default.js.bootstrapmin"] = "src/sailor/demo-app/themes/default/js/bootstrap.min.js",
74 | ["sailor.demo-app.themes.default.fonts.glysvg"] = "src/sailor/demo-app/themes/default/fonts/glyphicons-halflings-regular.svg",
75 | ["sailor.demo-app.themes.default.fonts.glyttf"] = "src/sailor/demo-app/themes/default/fonts/glyphicons-halflings-regular.ttf",
76 | ["sailor.demo-app.themes.default.fonts.glyeot"] = "src/sailor/demo-app/themes/default/fonts/glyphicons-halflings-regular.eot",
77 | ["sailor.demo-app.themes.default.fonts.glywoff"] = "src/sailor/demo-app/themes/default/fonts/glyphicons-halflings-regular.woff",
78 | ["sailor.demo-app.themes.default.config"] = "src/sailor/demo-app/themes/default/config.json",
79 | ["sailor.demo-app.themes.default.main"] = "src/sailor/demo-app/themes/default/main.lp",
80 | },
81 | bin = {
82 | sailor_create = "sailor_create"
83 | }
84 | }
85 | }
86 |
--------------------------------------------------------------------------------
/docs/INSTALL_MAC.md:
--------------------------------------------------------------------------------
1 | ## Installation for Mac
2 |
3 | Sailor is compatible with a variety of operating systems and webservers. On this example, we will use OS X 10.10 Yosemite
4 |
5 | ### Basic installation through LuaRocks (Xavante web server)
6 |
7 | For the purpose of this guide, it will be assumed that you already have Homebrew installed. Sailor is compatible with both Lua 5.1 and Lua 5.2 and either of them can be installed through brew.
8 |
9 | Let's begin by installing Lua (by default brew will install the version 5.1) and LuaRocks. LuaRocks is a package manager for Lua modules and if you don't have it already you will find it very useful. If you already have these, you may skip this step.
10 |
11 | brew update
12 | brew install lua luarocks
13 |
14 |
15 | Now we need to install Sailor:
16 |
17 | luarocks install sailor
18 |
19 | When installing Sailor through LuaRocks most of the dependencies will be installed with it, including Xavante, a lightweight webserver also written in Lua. However, libraries for manipulating data on a database will not be installed automatically because which database to use when developing a web application will be up to the developer. Once you have installed and configured your database of choice, you must also install the apropriate LuaSQL driver to allow your Sailor apps to communicate with it. So, supposed you are using MySQL, you must install LuaSQL-MySQL
20 |
21 | luarocks install luasql-mysql
22 |
23 | Now everything is ready to create and run your app!
24 |
25 | sailor create "My app"
26 | cd my_app
27 | lua start-server.lua
28 |
29 | You can view your app by opening your browser and navigating to `http://localhost:8080`.
30 |
31 | If you wish to use different web servers, please, read on.
32 |
33 |
34 | ### Alternative setup with Apache 2.4 and mod_lua
35 |
36 | This guide assumes that you have already completed Sailor's basic installation through LuaRocks. Now we need Apache, that can be installed view homebrew. The default apache build however, does not come with Lua module by default, so we must edit the brew install file. Also, Apache is not in the default repository of Homebrew formulas, nor are some dependencies, so we use the "brew tap" command to add other formula repositories.
37 |
38 | brew tap djl/homebrew-apache2
39 | brew install djl/apache2/apache24
40 | brew edit apache24
41 |
42 | Find the list of enabled flags, after `args = [`, add `--enable-lua` and save the file. You can add other flags to the argument list if necessary. The file is ususally localted at "/usr/local/Library/Taps/djl/homebrew-apache2/apache24.rb".
43 |
44 | brew install apache24
45 |
46 | Alternatively, if you are having issues downloading Apache via homebrew, you can download it directly from [apache.org](http://apache.org) and compile your own build. Remember to add the `--enable-lua` flag when running `./configure` along with other flags you may wish.
47 |
48 | Now, you need to enable `mod_lua` in Apache's configuration file. The file will probably be located at `/usr/local/etc/apache2/httpd.conf`. Add or uncomment the following directive:
49 |
50 | LoadModule lua_module modules/mod_lua.so
51 |
52 | Change the DirectoryIndex directive to:
53 |
54 | DirectoryIndex index.lua index.html
55 |
56 | Add the SetHandler directive:
57 |
58 |
59 | SetHandler lua-script
60 |
61 |
62 | It's also necessary to allow `.htaccess` files. Look for the `AllowOverride` directive in the configuration file and change from `None` (the default) to `All`. Now you can either add a VirtualHost for Apache to read from the directory of your previously created app or simply create your apps inside the directory Apache is reading from (for example /usr/local/var/www/htdocs). It is also necessary to
63 |
64 | sailor create "My app" /usr/local/var/www/htdocs
65 |
66 | Now, you should start Apache. You can use the following command for that:
67 |
68 | sudo apachectl start
69 |
70 | You can view your app by opening your browser and navigating to `http://localhost/my_app`.
71 |
72 | Keep in mind that this guide was made with a specific version of Apache (2.4.12) and in future releases some details might change. Other details like the location of apache's configuration files might also change according to the installation method used. It is recommended to always install the latest version of Apache.
73 |
74 |
75 | ### Alternative setup using Nginx and [OpenResty](http://openresty.org/)
76 |
77 | This guide assumes that you have already completed Sailor's basic installation through LuaRocks. Now we need OpenResty. Please follow the guide at [openresty.org](http://openresty.org/#Download) to download and install it. It is recommended to always install the latest version.
78 |
79 | Additionally, it might be necessary to add nginx binary to the PATH:
80 |
81 | PATH=/usr/local/openresty/nginx/sbin/:$PATH
82 |
83 | Then you can create your app and run it!
84 |
85 | sailor create "My app"
86 | cd my_app
87 | nginx -p `pwd`/ -c conf/nginx.conf
88 |
89 | And a small useful information, if you want to restart the server, run this same last comment but with an additional reload command:
90 |
91 | nginx -p `pwd`/ -c conf/nginx.conf -s reload
92 |
93 |
--------------------------------------------------------------------------------
/docs/INSTALL_WIN.md:
--------------------------------------------------------------------------------
1 | ##Installation for Windows
2 |
3 | ### Installing Lua
4 |
5 | First, download and install Lua for Windows. You can get it from:
6 |
7 |
8 |
9 | Copy the files in the `src` directory of this repository to C:/Program Files/Lua/5.1/lua/.
10 |
11 | You will also need the LuaSec's ssl library, which is included in this ZIP:
12 |
13 |
14 |
15 | Unzip it and copy the `ssl.dll` file in the bin\clibs directory of the archive to C:/Program Files/Lua/5.1/clibs/.
16 |
17 | Copy the `ssl.lua` file and the `ssl` subdir in the lualibs directory to C:/Program Files/Lua/5.1/lua/.
18 |
19 | Alternatively, you may want to try to install it via luarocks:
20 |
21 | luarocks install LuaSec
22 |
23 | ###Installation for Apache 2
24 |
25 | Download Apache 2.4 according to your Windows version:
26 |
27 | Windows 7, 8/8.1, Vista, Server 2008, Server 2012 -
28 |
29 | Windows XP -
30 |
31 | Unzip the package (eg: httpd-2.4.9-win32.zip) to `C:\Apache24\`.
32 |
33 | Copy the files in the `src/sailor/blank-app` directory of this repository to C:/Apache24/htdocs/sailor/.
34 |
35 | ####Configuring mod_lua
36 |
37 | Edit `\conf\httpd.conf` and uncomment the following line to enable mod_lua:
38 |
39 | LoadModule lua_module modules/mod_lua.so
40 |
41 | Change the DirectoryIndex directive to:
42 |
43 | DirectoryIndex index.lua index.html
44 |
45 | Add the SetHandler directive:
46 |
47 |
48 | SetHandler lua-script
49 |
50 |
51 | Optionally, tweak mod_lua for high performance:
52 |
53 | LuaScope thread
54 | LuaCodeCache stat
55 |
56 | Add the LuaPackage* directives:
57 |
58 |
59 | LuaPackageCPath "C:/Program Files/Lua/5.1/clibs/?.dll"
60 | LuaPackagePath "C:/Program Files/Lua/5.1/lua/?.lua"
61 | LuaPackagePath "C:/Program Files/Lua/5.1/lua/?/init.lua"
62 | LuaPackagePath "C:/Apache24/htdocs/sailor/?.lua"
63 | LuaPackagePath "C:/Apache24/htdocs/sailor/?/init.lua"
64 |
65 |
66 | ####Alternative Installation with mod_plua
67 |
68 | Download mod_plua from .
69 |
70 | Install and configure it as explained at .
71 |
72 | ####Alternative Installation with CGILua
73 |
74 | TODO
75 |
76 | ####Done!
77 |
78 | Run bin\httpd.exe in the Apache24 directory.
79 |
80 | Now go to in your browser. You should see the default Sailor page.
81 |
82 | ###Installation for Nginx
83 |
84 | Download the latest Nginx version from:
85 |
86 |
87 |
88 | If you've not done it yet, you may need to install the Visual C++ Redistributable Setup:
89 |
90 |
91 |
92 | Unzip the nginx ZIP to a directory of your choice.
93 |
94 | Copy the `lua5.1.dll` and `lua51.dll` files from C:/Program Files/Lua/5.1/ to the root of the nginx directory, replacing lua51.dll from the original package.
95 |
96 | Copy the files in the `src/sailor/blank-app` directory of this repository to the html/sailor directory of the nginx dir.
97 |
98 | ####Configuring Nginx
99 |
100 | Rename the `conf\nginx-win.conf` file to `nginx.conf`.
101 |
102 | Open the nginx.conf file and add to the http block:
103 |
104 | lua_package_path 'C:/Program Files/Lua/5.1/lua/?.lua;html/sailor/?.lua;';
105 | lua_package_cpath 'C:/Program Files/Lua/5.1/clibs/?.dll;';
106 |
107 | You must also add to the server block:
108 |
109 | location ~ ^/sailor/(.+) {
110 | lua_need_request_body on;
111 | lua_code_cache off;
112 | content_by_lua_file html/sailor/$1;
113 | index index.lua index.lp;
114 | }
115 | location ~* ^.+\.(?:css|eot|js|json|png|svg|ttf|woff)$ { }
116 |
117 | ####Done!
118 |
119 | Now run nginx.exe and go to in your browser.
120 |
121 | ###Installation for Lighttpd
122 |
123 | Download the latest Lighttpd from:
124 |
125 |
126 |
127 | Unzip the Lighttpd ZIP to a directory of your choice.
128 |
129 | Copy the files in the `src/sailor/blank-app` directory of this repository to the htdocs/sailor directory of the Lighttpd dir.
130 |
131 | ####Configuring Lighttpd
132 |
133 | Open the `conf\lighttpd.conf` file, uncomment mod_magnet in server.modules, and add the following lines right after index-file.names:
134 |
135 | $HTTP["url"] =~ "^/sailor/index.lua" {
136 | magnet.attract-physical-path-to = ( server_root + "/htdocs/sailor/index-magnet.lua")
137 | }
138 | $HTTP["url"] =~ "^/sailor/(conf|controllers|models|runtime|views)/" {
139 | url.access-deny = ("")
140 | dir-listing.activate = "disable"
141 | }
142 | $HTTP["url"] =~ "^/sailor/themes/" {
143 | url.access-deny = (".lp")
144 | dir-listing.activate = "disable"
145 | }
146 |
147 | ####Done!
148 |
149 | Now run LightTPD.exe and go to in your browser.
150 |
--------------------------------------------------------------------------------