mirror of
https://github.com/openwrt/luci
synced 2025-01-05 10:37:19 +08:00
* new project: ff-luci - Freifunk Lua Configuration Interface
This commit is contained in:
commit
3f5de3273c
5
.buildpath
Normal file
5
.buildpath
Normal file
@ -0,0 +1,5 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<buildpath>
|
||||
<buildpathentry kind="src" path="src"/>
|
||||
<buildpathentry kind="con" path="org.eclipse.dltk.launching.INTERPRETER_CONTAINER"/>
|
||||
</buildpath>
|
12
.project
Normal file
12
.project
Normal file
@ -0,0 +1,12 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<projectDescription>
|
||||
<name>ffluci</name>
|
||||
<comment></comment>
|
||||
<projects>
|
||||
</projects>
|
||||
<buildSpec>
|
||||
</buildSpec>
|
||||
<natures>
|
||||
<nature>org.eclipse.dltk.lua.core.nature</nature>
|
||||
</natures>
|
||||
</projectDescription>
|
201
LICENSE
Normal file
201
LICENSE
Normal file
@ -0,0 +1,201 @@
|
||||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
APPENDIX: How to apply the Apache License to your work.
|
||||
|
||||
To apply the Apache License to your work, attach the following
|
||||
boilerplate notice, with the fields enclosed by brackets "[]"
|
||||
replaced with your own identifying information. (Don't include
|
||||
the brackets!) The text should be enclosed in the appropriate
|
||||
comment syntax for the file format. We also recommend that a
|
||||
file or class name and description of purpose be included on the
|
||||
same "printed page" as the copyright notice for easier
|
||||
identification within third-party archives.
|
||||
|
||||
Copyright [yyyy] [name of copyright owner]
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
40
Makefile
Normal file
40
Makefile
Normal file
@ -0,0 +1,40 @@
|
||||
LUAC = luac
|
||||
LUAC_OPTIONS = -s
|
||||
|
||||
FILES = ffluci/config.lua
|
||||
|
||||
CFILES = ffluci/util.lua ffluci/http.lua \
|
||||
ffluci/fs.lua ffluci/i18n.lua ffluci/model/uci.lua \
|
||||
ffluci/template.lua ffluci/dispatcher.lua ffluci/menu.lua ffluci/init.lua
|
||||
|
||||
DIRECTORIES = dist/ffluci/model dist/ffluci/controller/public dist/ffluci/controller/admin dist/ffluci/i18n dist/ffluci/view
|
||||
|
||||
INFILES = $(CFILES:%=src/%)
|
||||
OUTFILE = ffluci/init.lua
|
||||
|
||||
all: compile
|
||||
|
||||
dist-compile: compile examples
|
||||
dist-source: source examples
|
||||
|
||||
examples:
|
||||
cp src/ffluci/controller/public/* dist/ffluci/controller/public/
|
||||
cp src/ffluci/controller/admin/* dist/ffluci/controller/admin/
|
||||
cp src/ffluci/i18n/* dist/ffluci/i18n/
|
||||
cp src/ffluci/view/* dist/ffluci/view/ -R
|
||||
|
||||
compile:
|
||||
mkdir -p $(DIRECTORIES)
|
||||
$(LUAC) $(LUAC_OPTIONS) -o dist/$(OUTFILE) $(INFILES)
|
||||
for i in $(CFILES); do [ -f dist/$$i ] || ln -s `dirname $$i | cut -s -d / -f 2- | sed -e 's/[^/]*\/*/..\//g'``basename $(OUTFILE)` dist/$$i; done
|
||||
for i in $(FILES); do cp src/$$i dist/$$i; done
|
||||
|
||||
source:
|
||||
mkdir -p $(DIRECTORIES)
|
||||
for i in $(CFILES); do cp src/$$i dist/$$i; done
|
||||
for i in $(FILES); do cp src/$$i dist/$$i; done
|
||||
|
||||
|
||||
.PHONY: clean
|
||||
clean:
|
||||
rm dist -rf
|
56
README
Normal file
56
README
Normal file
@ -0,0 +1,56 @@
|
||||
FFLuCI - Freifunk Lua Configuration Interface
|
||||
|
||||
This is a leightweight MVC-Webframework for small embedded device.
|
||||
It uses the the Lua programming language and relies on Haserl.
|
||||
|
||||
It consists of several parts:
|
||||
|
||||
MVC Dispatcher
|
||||
Simple PATH_INFO based dispatching mechanism using Lua modules
|
||||
|
||||
> See src/ffluci/dispatcher.lua for a detailed description
|
||||
> See src/ffluci/controller for example controllers
|
||||
|
||||
|
||||
Template engine
|
||||
Support for plain and compiled templates, on-demand compiling support
|
||||
Short markups:
|
||||
<% Lua-Code %>
|
||||
<%= Lua-Code with return value %>
|
||||
<%:i18nkey default translation%>
|
||||
<%+template-to-be-included%>
|
||||
<%~uci.short.cut%>
|
||||
|
||||
Predefined variables for controller dir and media dir
|
||||
|
||||
> See src/ffluci/template.lua for details
|
||||
> See src/view/ for examples
|
||||
|
||||
|
||||
i18n Translation support
|
||||
Simple multi-language per-module internationalization support
|
||||
|
||||
> See src/ffluci/i18n.lua for details
|
||||
> See src/i18n/ for examples
|
||||
|
||||
|
||||
UCI wrapper support
|
||||
Lua UCI-Wrapper adapting the CLI of the uci binary
|
||||
|
||||
> See src/model/uci.lua for details
|
||||
|
||||
|
||||
Menu Building support
|
||||
Supports menu building for modules and exported actions
|
||||
|
||||
> See src/ffluci/menu.lua for details
|
||||
> See src/ffluci/view/menu.htm, src/ffluci/controller for examples
|
||||
|
||||
|
||||
HTTP-Abstraction and Formvalue validation support
|
||||
HTTP-Redirect, Statuscode, Content-Type abstraction
|
||||
Dynamic formvalue validation support including varaible type and
|
||||
value range validation
|
||||
|
||||
> See src/ffluci/http.lua for details
|
||||
> See src/ffluci/controller/public/example-action.lua for examples
|
5
contrib/ffluci
Executable file
5
contrib/ffluci
Executable file
@ -0,0 +1,5 @@
|
||||
#!/usr/bin/haserl --shell=luac
|
||||
package.path = "/usr/lib/lua/?.lua;/usr/lib/lua/?/init.lua;" .. package.path
|
||||
package.cpath = "/usr/lib/lua/?.so;" .. package.cpath
|
||||
require("ffluci").dispatch()
|
||||
|
3
contrib/index.cgi
Executable file
3
contrib/index.cgi
Executable file
@ -0,0 +1,3 @@
|
||||
#!/usr/bin/haserl --shell=luac
|
||||
print("Status: 302 Found")
|
||||
print("Location: /cgi-bin/ffluci\n")
|
43
contrib/package/ffluci/Makefile
Normal file
43
contrib/package/ffluci/Makefile
Normal file
@ -0,0 +1,43 @@
|
||||
include $(TOPDIR)/rules.mk
|
||||
|
||||
PKG_NAME:=ffluci
|
||||
PKG_VERSION:=0.1
|
||||
PKG_RELEASE:=1
|
||||
|
||||
PKG_BUILD_DIR:=$(BUILD_DIR)/$(PKG_NAME)-$(PKG_VERSION)
|
||||
PKG_INSTALL_DIR:=$(PKG_BUILD_DIR)/ipkg-install
|
||||
|
||||
MAKE_ACTION:=dist-source
|
||||
|
||||
include $(INCLUDE_DIR)/package.mk
|
||||
|
||||
define Package/ffluci
|
||||
SECTION:=admin
|
||||
CATEGORY:=Administration
|
||||
TITLE:=FFLuCI
|
||||
DEPENDS:=+liblua +luafilesystem +haserl
|
||||
MAINTAINER:=Steven Barth <steven-at-midlink-dot-org>
|
||||
endef
|
||||
|
||||
define Build/Prepare
|
||||
mkdir -p $(PKG_BUILD_DIR)
|
||||
$(CP) ./src/* $(PKG_BUILD_DIR)/ -R
|
||||
endef
|
||||
|
||||
define Build/Configure
|
||||
endef
|
||||
|
||||
define Build/Compile
|
||||
$(MAKE) -C $(PKG_BUILD_DIR) dist-source
|
||||
endef
|
||||
|
||||
define Package/ffluci/install
|
||||
$(INSTALL_DIR) $(1)/usr/lib/lua
|
||||
$(INSTALL_DIR) $(1)/www/cgi-bin
|
||||
$(CP) $(PKG_BUILD_DIR)/dist/* $(1)/usr/lib/lua/ -R
|
||||
$(INSTALL_BIN) $(PKG_BUILD_DIR)/contrib/ffluci $(1)/www/cgi-bin
|
||||
$(INSTALL_BIN) $(PKG_BUILD_DIR)/contrib/index.cgi $(1)/www/cgi-bin
|
||||
$(CP) -a ./ipkg/ffluci.postinst $(1)/CONTROL/postinst
|
||||
endef
|
||||
|
||||
$(eval $(call BuildPackage,ffluci))
|
4
contrib/package/ffluci/ipkg/ffluci.postinst
Executable file
4
contrib/package/ffluci/ipkg/ffluci.postinst
Executable file
@ -0,0 +1,4 @@
|
||||
#!/bin/sh
|
||||
PATTERN='/cgi-bin/ffluci/admin:root:$p$root'
|
||||
grep $PATTERN ${IPKG_INSTROOT}/etc/httpd.conf >/dev/null 2>/dev/null || echo $PATTERN >> ${IPKG_INSTROOT}/etc/httpd.conf
|
||||
[ -z ${IPKG_INSTROOT} ] && /etc/init.d/httpd restart
|
1
contrib/package/ffluci/src
Symbolic link
1
contrib/package/ffluci/src
Symbolic link
@ -0,0 +1 @@
|
||||
../../..
|
39
contrib/package/haserl-devel/Makefile
Normal file
39
contrib/package/haserl-devel/Makefile
Normal file
@ -0,0 +1,39 @@
|
||||
#
|
||||
# Copyright (C) 2006 OpenWrt.org
|
||||
#
|
||||
# This is free software, licensed under the GNU General Public License v2.
|
||||
# See /LICENSE for more information.
|
||||
#
|
||||
# $Id$
|
||||
|
||||
include $(TOPDIR)/rules.mk
|
||||
|
||||
PKG_NAME:=haserl
|
||||
PKG_VERSION:=0.9.22
|
||||
PKG_RELEASE:=1
|
||||
|
||||
PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.gz
|
||||
PKG_SOURCE_URL:=@SF/haserl
|
||||
PKG_MD5SUM:=b791150f2e5704d03b1fb698f4edc6c0
|
||||
|
||||
|
||||
include $(INCLUDE_DIR)/package.mk
|
||||
|
||||
define Package/haserl
|
||||
SECTION:=utils
|
||||
CATEGORY:=Utilities
|
||||
TITLE:=A CGI wrapper to embed shell scripts in HTML documents
|
||||
URL:=http://haserl.sourceforge.net/
|
||||
DEPENDS:=+liblua
|
||||
endef
|
||||
|
||||
CONFIGURE_ARGS += \
|
||||
--with-lua
|
||||
|
||||
define Package/haserl/install
|
||||
$(INSTALL_DIR) $(1)/usr/bin
|
||||
$(STRIP) $(PKG_BUILD_DIR)/src/haserl
|
||||
$(INSTALL_BIN) $(PKG_BUILD_DIR)/src/haserl $(1)/usr/bin/
|
||||
endef
|
||||
|
||||
$(eval $(call BuildPackage,haserl))
|
44
contrib/package/luafilesystem/Makefile
Normal file
44
contrib/package/luafilesystem/Makefile
Normal file
@ -0,0 +1,44 @@
|
||||
include $(TOPDIR)/rules.mk
|
||||
|
||||
PKG_NAME:=luafilesystem
|
||||
PKG_VERSION:=1.4.0
|
||||
PKG_RELEASE:=1
|
||||
|
||||
PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.gz
|
||||
PKG_SOURCE_URL:=http://luaforge.net/frs/download.php/3158
|
||||
PKG_MD5SUM:=6f3d247f27820b8f045431ad81bcd3ad
|
||||
|
||||
PKG_BUILD_DIR:=$(BUILD_DIR)/$(PKG_NAME)-$(PKG_VERSION)
|
||||
PKG_INSTALL_DIR:=$(PKG_BUILD_DIR)/ipkg-install
|
||||
|
||||
include $(INCLUDE_DIR)/package.mk
|
||||
|
||||
define Package/luafilesystem
|
||||
SECTION:=lib
|
||||
CATEGORY:=Libraries
|
||||
TITLE:=Lua FS library
|
||||
URL:=http://www.keplerproject.org/luafilesystem/
|
||||
DEPENDS:=+liblua
|
||||
MAINTAINER:=Steven Barth <steven-at-midlink-dot-org>
|
||||
endef
|
||||
|
||||
define Build/Configure
|
||||
endef
|
||||
|
||||
define Build/Compile
|
||||
$(MAKE) -C $(PKG_BUILD_DIR) \
|
||||
CC="$(TARGET_CROSS)gcc" \
|
||||
LD="$(TARGET_CROSS)ld" \
|
||||
AR="$(TARGET_CROSS)ar rcu" \
|
||||
RANLIB="$(TARGET_CROSS)ranlib" \
|
||||
INSTALL_ROOT=/usr \
|
||||
LUA_INC=$(STAGING_DIR)/usr/include
|
||||
endef
|
||||
|
||||
define Package/luafilesystem/install
|
||||
$(INSTALL_DIR) $(1)/usr/lib/lua
|
||||
$(STRIP) $(PKG_BUILD_DIR)/src/lfs.so
|
||||
$(INSTALL_BIN) $(PKG_BUILD_DIR)/src/lfs.so $(1)/usr/lib/lua
|
||||
endef
|
||||
|
||||
$(eval $(call BuildPackage,luafilesystem))
|
37
src/ffluci/config.lua
Normal file
37
src/ffluci/config.lua
Normal file
@ -0,0 +1,37 @@
|
||||
--[[
|
||||
FFLuCI - Configuration
|
||||
|
||||
Description:
|
||||
Some FFLuCI configuration values
|
||||
|
||||
ToDo:
|
||||
Port over to UCI
|
||||
|
||||
FileId:
|
||||
$Id$
|
||||
|
||||
License:
|
||||
Copyright 2008 Steven Barth <steven@midlink.org>
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
|
||||
]]--
|
||||
|
||||
module("ffluci.config", package.seeall)
|
||||
|
||||
-- This is where stylesheets and images go
|
||||
mediaurlbase = "/ffluci/media"
|
||||
|
||||
-- Does anybody think about browser autodetect here?
|
||||
-- Too bad busybox doesn't populate HTTP_ACCEPT_LANGUAGE
|
||||
lang = "de"
|
15
src/ffluci/controller/admin/index.lua
Normal file
15
src/ffluci/controller/admin/index.lua
Normal file
@ -0,0 +1,15 @@
|
||||
module(..., package.seeall)
|
||||
|
||||
function dispatcher(request)
|
||||
require("ffluci.template").render("header")
|
||||
print("Hello there, Mr. Administrator")
|
||||
require("ffluci.template").render("footer")
|
||||
end
|
||||
|
||||
menu = {
|
||||
descr = "Administrative",
|
||||
order = 10,
|
||||
entries = {
|
||||
{action = "index", descr = "Hello"}
|
||||
}
|
||||
}
|
49
src/ffluci/controller/public/example-action.lua
Normal file
49
src/ffluci/controller/public/example-action.lua
Normal file
@ -0,0 +1,49 @@
|
||||
-- This example demonstrates the action dispatcher which invokes
|
||||
-- an appropriate action function named action_"action"
|
||||
|
||||
-- This example consists of:
|
||||
-- ffluci/controller/index/example-action.lua (this file)
|
||||
|
||||
-- Try the following address(es) in your browser:
|
||||
-- ffluci/index/example-action
|
||||
-- ffluci/index/example-action/sp
|
||||
-- ffluci/index/example-action/redir
|
||||
|
||||
module(..., package.seeall)
|
||||
|
||||
dispatcher = require("ffluci.dispatcher").action
|
||||
|
||||
menu = {
|
||||
descr = "Example Action",
|
||||
order = 30,
|
||||
entries = {
|
||||
{action = "index", descr = "Action-Dispatcher Example"},
|
||||
{action = "sp", descr = "Simple View Template Stealing"},
|
||||
{action = "redir", descr = "Hello World Redirector"}
|
||||
}
|
||||
}
|
||||
|
||||
function action_index()
|
||||
require("ffluci.template").render("header")
|
||||
local formvalue = require("ffluci.http").formvalue
|
||||
|
||||
local x = formvalue("x", nil, true)
|
||||
|
||||
print(x and "x*x: "..tostring(x*x) or "Set ?x= any number")
|
||||
require("ffluci.template").render("footer")
|
||||
end
|
||||
|
||||
function action_sp()
|
||||
require("ffluci.http")
|
||||
require("ffluci.i18n")
|
||||
require("ffluci.config")
|
||||
require("ffluci.template")
|
||||
|
||||
-- Try uncommenting the next line
|
||||
-- ffluci.i18n.loadc("example-simpleview")
|
||||
ffluci.template.render("example-simpleview/index")
|
||||
end
|
||||
|
||||
function action_redir()
|
||||
require("ffluci.http").request_redirect("public", "index", "foobar")
|
||||
end
|
27
src/ffluci/controller/public/example-simpleview.lua
Normal file
27
src/ffluci/controller/public/example-simpleview.lua
Normal file
@ -0,0 +1,27 @@
|
||||
-- This example demonstrates the simple view dispatcher which is the
|
||||
-- most simple way to provide content as it directly renders the
|
||||
-- associated template
|
||||
|
||||
-- This example consists of:
|
||||
-- ffluci/controller/index/example-simpleview.lua (this file)
|
||||
-- ffluci/view/example-simpleview/index.htm (the template for action "index")
|
||||
-- ffluci/view/example-simpleview/foo.htm (the template for action "foo")
|
||||
-- ffluci/i18n/example-simpleview.de (the german language file for this module)
|
||||
|
||||
-- Try the following address(es) in your browser:
|
||||
-- ffluci/index/example-simpleview
|
||||
-- ffluci/index/example-simpleview/index
|
||||
-- ffluci/index/example-simpleview/foo
|
||||
|
||||
module(..., package.seeall)
|
||||
|
||||
dispatcher = require("ffluci.dispatcher").simpleview
|
||||
|
||||
menu = {
|
||||
descr = "Example Simpleview",
|
||||
order = 20,
|
||||
entries = {
|
||||
{action = "index", descr = "Simpleview Index"},
|
||||
{action = "foo", descr = "Simpleview Foo"}
|
||||
}
|
||||
}
|
32
src/ffluci/controller/public/index.lua
Normal file
32
src/ffluci/controller/public/index.lua
Normal file
@ -0,0 +1,32 @@
|
||||
-- This is a very simple example Hello World FFLuCI controller
|
||||
-- See the other examples for more automated controllers
|
||||
|
||||
-- Initialise Lua module system
|
||||
module(..., package.seeall)
|
||||
|
||||
-- This is the module dispatcher. It implements the last step of the
|
||||
-- dispatching process.
|
||||
function dispatcher(request)
|
||||
require("ffluci.template").render("header")
|
||||
print("<h2>Hello World!</h2>")
|
||||
for k,v in pairs(request) do
|
||||
print("<div>" .. k .. ": " .. v .. "</div>")
|
||||
end
|
||||
require("ffluci.template").render("footer")
|
||||
end
|
||||
|
||||
-- The following part is optional it could be useful for menu generators
|
||||
-- An example menu generator is implemented in the template "menu"
|
||||
|
||||
menu = {
|
||||
-- This is the menu item description
|
||||
descr = "Hello World",
|
||||
|
||||
-- This is the order level of the menu entry (lowest goes first)
|
||||
order = 10,
|
||||
|
||||
-- A list of menu entries in the form action => "description"
|
||||
entries = {
|
||||
{action = "index", descr = "Hello World"},
|
||||
}
|
||||
}
|
175
src/ffluci/dispatcher.lua
Normal file
175
src/ffluci/dispatcher.lua
Normal file
@ -0,0 +1,175 @@
|
||||
--[[
|
||||
FFLuCI - Dispatcher
|
||||
|
||||
Description:
|
||||
The request dispatcher and module dispatcher generators
|
||||
|
||||
|
||||
The dispatching process:
|
||||
For a detailed explanation of the dispatching process we assume:
|
||||
You have installed the FFLuCI CGI-Dispatcher in /cgi-bin/ffluci
|
||||
|
||||
To enforce a higher level of security only the CGI-Dispatcher
|
||||
resides inside the web server's document root, everything else
|
||||
stays inside an external directory, we assume this is /lua/ffluci
|
||||
for this explanation.
|
||||
|
||||
All controllers and action are reachable as sub-objects of /cgi-bin/ffluci
|
||||
as if they were virtual folders and files
|
||||
e.g.: /cgi-bin/ffluci/public/info/about
|
||||
/cgi-bin/ffluci/admin/network/interfaces
|
||||
and so on.
|
||||
|
||||
The PATH_INFO variable holds the dispatch path and
|
||||
will be split into three parts: /category/module/action
|
||||
|
||||
Category: This is the category in which modules are stored in
|
||||
By default there are two categories:
|
||||
"public" - which is the default public category
|
||||
"admin" - which is the default protected category
|
||||
|
||||
As FFLuCI itself does not implement authentication
|
||||
you should make sure that "admin" and other sensitive
|
||||
categories are protected by the webserver.
|
||||
|
||||
E.g. for busybox add a line like:
|
||||
/cgi-bin/ffluci/admin:root:$p$root
|
||||
to /etc/httpd.conf to protect the "admin" category
|
||||
|
||||
|
||||
Module: This is the controller which will handle the request further
|
||||
It is always a submodule of ffluci.controller, so a module
|
||||
called "helloworld" will be stored in
|
||||
/lua/ffluci/controller/helloworld.lua
|
||||
You are free to submodule your controllers any further.
|
||||
|
||||
Action: This is action that will be invoked after loading the module.
|
||||
The kind of how the action will be dispatched depends on
|
||||
the module dispatcher that is defined in the controller.
|
||||
See the description of the default module dispatcher down
|
||||
on this page for some examples.
|
||||
|
||||
|
||||
The main dispatcher at first searches for the module by trying to
|
||||
include ffluci.controller.category.module
|
||||
(where "category" is the category name and "module" is the module name)
|
||||
If this fails a 404 status code will be send to the client and FFLuCI exits
|
||||
|
||||
Then the main dispatcher calls the module dispatcher
|
||||
ffluci.controller.category.module.dispatcher with the request object
|
||||
as the only argument. The module dispatcher is then responsible
|
||||
for the further dispatching process.
|
||||
|
||||
|
||||
FileId:
|
||||
$Id$
|
||||
|
||||
License:
|
||||
Copyright 2008 Steven Barth <steven@midlink.org>
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
|
||||
]]--
|
||||
|
||||
module("ffluci.dispatcher", package.seeall)
|
||||
require("ffluci.http")
|
||||
require("ffluci.template")
|
||||
|
||||
|
||||
-- Dispatches the "request"
|
||||
function dispatch(req)
|
||||
request = req
|
||||
local m = "ffluci.controller." .. request.category .. "." .. request.module
|
||||
local stat, module = pcall(require, m)
|
||||
if not stat then
|
||||
return error404()
|
||||
else
|
||||
module.request = request
|
||||
setfenv(module.dispatcher, module)
|
||||
return module.dispatcher(request)
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
-- Sends a 404 error code and renders the "error404" template if available
|
||||
function error404(message)
|
||||
message = message or "Not Found"
|
||||
|
||||
ffluci.http.status(404, "Not Found")
|
||||
|
||||
if not pcall(ffluci.template.render, "error404") then
|
||||
ffluci.http.textheader()
|
||||
print(message)
|
||||
end
|
||||
return false
|
||||
end
|
||||
|
||||
-- Sends a 500 error code and renders the "error500" template if available
|
||||
function error500(message)
|
||||
ffluci.http.status(500, "Internal Server Error")
|
||||
|
||||
if not pcall(ffluci.template.render, "error500") then
|
||||
ffluci.http.textheader()
|
||||
print(message)
|
||||
end
|
||||
return false
|
||||
end
|
||||
|
||||
|
||||
-- Dispatches a request depending on the PATH_INFO variable
|
||||
function httpdispatch()
|
||||
local pathinfo = os.getenv("PATH_INFO") or ""
|
||||
local parts = pathinfo:gmatch("/[%w-]+")
|
||||
|
||||
local sanitize = function(s, default)
|
||||
return s and s:sub(2) or default
|
||||
end
|
||||
|
||||
local cat = sanitize(parts(), "public")
|
||||
local mod = sanitize(parts(), "index")
|
||||
local act = sanitize(parts(), "index")
|
||||
|
||||
dispatch({category=cat, module=mod, action=act})
|
||||
end
|
||||
|
||||
-- The Simple View Dispatcher directly renders the template
|
||||
-- which is placed in ffluci/views/"request.module"/"request.action"
|
||||
function simpleview(request)
|
||||
local i18n = require("ffluci.i18n")
|
||||
local tmpl = require("ffluci.template")
|
||||
local conf = require("ffluci.config")
|
||||
local disp = require("ffluci.dispatcher")
|
||||
|
||||
pcall(i18n.load, request.module .. "." .. conf.lang)
|
||||
if not pcall(tmpl.get, request.module .. "/" .. request.action) then
|
||||
disp.error404()
|
||||
else
|
||||
tmpl.render(request.module .. "/" .. request.action)
|
||||
end
|
||||
end
|
||||
|
||||
-- The Action Dispatcher searches the module for any function called
|
||||
-- action_"request.action" and calls it
|
||||
function action(request)
|
||||
local i18n = require("ffluci.i18n")
|
||||
local conf = require("ffluci.config")
|
||||
local disp = require("ffluci.dispatcher")
|
||||
|
||||
pcall(i18n.load, request.module .. "." .. conf.lang)
|
||||
local action = getfenv()["action_" .. request.action:gsub("-", "_")]
|
||||
if action then
|
||||
action()
|
||||
else
|
||||
disp.error404()
|
||||
end
|
||||
end
|
71
src/ffluci/fs.lua
Normal file
71
src/ffluci/fs.lua
Normal file
@ -0,0 +1,71 @@
|
||||
--[[
|
||||
FFLuCI - Filesystem tools
|
||||
|
||||
Description:
|
||||
A module offering often needed filesystem manipulation functions
|
||||
|
||||
FileId:
|
||||
$Id$
|
||||
|
||||
License:
|
||||
Copyright 2008 Steven Barth <steven@midlink.org>
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
|
||||
]]--
|
||||
|
||||
module("ffluci.fs", package.seeall)
|
||||
|
||||
require("lfs")
|
||||
|
||||
-- Returns the content of file
|
||||
function readfile(filename)
|
||||
local fp = io.open(filename)
|
||||
if fp == nil then
|
||||
error("Unable to open file for reading: " .. filename)
|
||||
end
|
||||
local data = fp:read("*a")
|
||||
fp:close()
|
||||
return data
|
||||
end
|
||||
|
||||
-- Writes given data to a file
|
||||
function writefile(filename, data)
|
||||
local fp = io.open(filename, "w")
|
||||
if fp == nil then
|
||||
error("Unable to open file for writing: " .. filename)
|
||||
end
|
||||
fp:write(data)
|
||||
fp:close()
|
||||
end
|
||||
|
||||
-- Returns the file modification date/time of "path"
|
||||
function mtime(path)
|
||||
return lfs.attributes(path, "modification")
|
||||
end
|
||||
|
||||
-- Simplified dirname function
|
||||
function dirname(file)
|
||||
return string.gsub(file, "[^/]+$", "")
|
||||
end
|
||||
|
||||
-- Diriterator - alias for lfs.dir - filter . and ..
|
||||
function dir(path)
|
||||
local e = {}
|
||||
for entry in lfs.dir(path) do
|
||||
if not(entry == "." or entry == "..") then
|
||||
table.insert(e, entry)
|
||||
end
|
||||
end
|
||||
return e
|
||||
end
|
118
src/ffluci/http.lua
Normal file
118
src/ffluci/http.lua
Normal file
@ -0,0 +1,118 @@
|
||||
--[[
|
||||
FFLuCI - HTTP-Interaction
|
||||
|
||||
Description:
|
||||
HTTP-Header manipulator and form variable preprocessor
|
||||
|
||||
FileId:
|
||||
$Id$
|
||||
|
||||
ToDo:
|
||||
- Cookie handling
|
||||
|
||||
License:
|
||||
Copyright 2008 Steven Barth <steven@midlink.org>
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
|
||||
]]--
|
||||
|
||||
module("ffluci.http", package.seeall)
|
||||
|
||||
require("ffluci.util")
|
||||
|
||||
-- Sets HTTP-Status-Header
|
||||
function status(code, message)
|
||||
print("Status: " .. tostring(code) .. " " .. message)
|
||||
end
|
||||
|
||||
|
||||
-- Asks the browser to redirect to "url"
|
||||
function redirect(url)
|
||||
status(302, "Found")
|
||||
print("Location: " .. url .. "\n")
|
||||
end
|
||||
|
||||
|
||||
-- Same as redirect but accepts category, module and action for internal use
|
||||
function request_redirect(category, module, action)
|
||||
category = category or "public"
|
||||
module = module or "index"
|
||||
action = action or "index"
|
||||
|
||||
local pattern = os.getenv("SCRIPT_NAME") .. "/%s/%s/%s"
|
||||
redirect(pattern:format(category, module, action))
|
||||
end
|
||||
|
||||
-- Form validation function:
|
||||
-- Gets a form variable "key".
|
||||
-- If it does not exist: return "default"
|
||||
-- If cast_number is true and "key" is not a number: return "default"
|
||||
-- If valid is a table and "key" is not in it: return "default"
|
||||
-- If valid is a function and returns nil: return "default"
|
||||
-- Else return the value of "key"
|
||||
--
|
||||
-- Examples:
|
||||
-- Get a form variable "foo" and return "bar" if it is not set
|
||||
-- = formvalue("foo", "bar")
|
||||
--
|
||||
-- Get "foo" and make sure it is either "bar" or "baz"
|
||||
-- = formvalue("foo", nil, nil, {"bar", "baz"})
|
||||
--
|
||||
-- Get "foo", make sure its a number and below 10 else return 5
|
||||
-- = formvalue("foo", 5, true, function(a) return a < 10 and a or nil end)
|
||||
function formvalue(key, default, cast_number, valid, table)
|
||||
table = table or formvalues()
|
||||
|
||||
if table[key] == nil then
|
||||
return default
|
||||
else
|
||||
local value = table[key]
|
||||
|
||||
value = cast_number and tonumber(value) or not cast_number and nil
|
||||
|
||||
if type(valid) == "function" then
|
||||
value = valid(value)
|
||||
elseif type(valid) == "table" then
|
||||
if not ffluci.util.contains(valid, value) then
|
||||
value = nil
|
||||
end
|
||||
end
|
||||
|
||||
return value or default
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
-- Returns a table of all COOKIE, GET and POST Parameters
|
||||
function formvalues()
|
||||
return FORM
|
||||
end
|
||||
|
||||
|
||||
-- Prints plaintext content-type header
|
||||
function textheader()
|
||||
print("Content-Type: text/plain\n")
|
||||
end
|
||||
|
||||
|
||||
-- Prints html content-type header
|
||||
function htmlheader()
|
||||
print("Content-Type: text/html\n")
|
||||
end
|
||||
|
||||
|
||||
-- Prints xml content-type header
|
||||
function xmlheader()
|
||||
print("Content-Type: text/xml\n")
|
||||
end
|
61
src/ffluci/i18n.lua
Normal file
61
src/ffluci/i18n.lua
Normal file
@ -0,0 +1,61 @@
|
||||
--[[
|
||||
FFLuCI - Internationalisation
|
||||
|
||||
Description:
|
||||
A very minimalistic but yet effective internationalisation module
|
||||
|
||||
FileId:
|
||||
$Id$
|
||||
|
||||
License:
|
||||
Copyright 2008 Steven Barth <steven@midlink.org>
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
|
||||
]]--
|
||||
|
||||
module("ffluci.i18n", package.seeall)
|
||||
|
||||
require("ffluci.fs")
|
||||
require("ffluci.util")
|
||||
require("ffluci.config")
|
||||
|
||||
table = {}
|
||||
i18ndir = ffluci.fs.dirname(ffluci.util.__file__()) .. "i18n/"
|
||||
|
||||
-- Clears the translation table
|
||||
function clear()
|
||||
table = {}
|
||||
end
|
||||
|
||||
-- Loads a translation and copies its data into the global translation table
|
||||
function load(file)
|
||||
local f = loadfile(i18ndir .. file)
|
||||
if f then
|
||||
setfenv(f, table)
|
||||
f()
|
||||
return true
|
||||
else
|
||||
return false
|
||||
end
|
||||
end
|
||||
|
||||
-- Same as load but autocompletes the filename with .LANG from config.lang
|
||||
function loadc(file)
|
||||
return load(file .. "." .. ffluci.config.lang)
|
||||
end
|
||||
|
||||
-- Returns the i18n-value defined by "key" or if there is no such: "default"
|
||||
function translate(key, default)
|
||||
return table[key] or default
|
||||
end
|
6
src/ffluci/i18n/example-simpleview.de
Normal file
6
src/ffluci/i18n/example-simpleview.de
Normal file
@ -0,0 +1,6 @@
|
||||
descr = [[Dies ist das Simple View-Beispiel.<br />
|
||||
Dieses Template ist: ffluci/view/example-simpleview/index.htm und gehoert
|
||||
zur Aktion "index".<br />
|
||||
Diese Uebersetzung ist: ffluci/i18n/example-simpleview.de]]
|
||||
|
||||
lan = "Die LAN IP-Adresse des Routers lautet:"
|
33
src/ffluci/init.lua
Normal file
33
src/ffluci/init.lua
Normal file
@ -0,0 +1,33 @@
|
||||
--[[
|
||||
FFLuCI - Freifunk Lua Configuration Interface
|
||||
|
||||
Description:
|
||||
This is the init file
|
||||
|
||||
FileId:
|
||||
$Id$
|
||||
|
||||
License:
|
||||
Copyright 2008 Steven Barth <steven@midlink.org>
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
|
||||
]]--
|
||||
module("ffluci", package.seeall)
|
||||
|
||||
__version__ = "0.1"
|
||||
__appname__ = "FFLuCI"
|
||||
|
||||
dispatch = require("ffluci.dispatcher").httpdispatch
|
||||
env = ENV
|
||||
form = FORM
|
124
src/ffluci/menu.lua
Normal file
124
src/ffluci/menu.lua
Normal file
@ -0,0 +1,124 @@
|
||||
--[[
|
||||
FFLuCI - Menu Builder
|
||||
|
||||
Description:
|
||||
Collects menu building information from controllers
|
||||
|
||||
FileId:
|
||||
$Id$
|
||||
|
||||
License:
|
||||
Copyright 2008 Steven Barth <steven@midlink.org>
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
|
||||
]]--
|
||||
module("ffluci.menu", package.seeall)
|
||||
|
||||
require("ffluci.fs")
|
||||
require("ffluci.util")
|
||||
require("ffluci.template")
|
||||
|
||||
ctrldir = ffluci.fs.dirname(ffluci.util.__file__()) .. "controller/"
|
||||
modelpath = ffluci.fs.dirname(ffluci.util.__file__()) .. "model/menudata.lua"
|
||||
|
||||
-- Cache menudata into a Luafile instead of recollecting it at every pageload
|
||||
-- Warning: Make sure the menudata cache gets deleted everytime you update
|
||||
-- the menu information of any module or add or remove a module
|
||||
builder_enable_cache = false
|
||||
|
||||
|
||||
-- Builds the menudata file
|
||||
function build()
|
||||
local data = collect()
|
||||
ffluci.fs.writefile(modelpath, dump(data, "m"))
|
||||
return data
|
||||
end
|
||||
|
||||
|
||||
-- Collect all menu information provided in the controller modules
|
||||
function collect()
|
||||
local m = {}
|
||||
for k,cat in pairs(ffluci.fs.dir(ctrldir)) do
|
||||
m[cat] = {}
|
||||
for k,con in pairs(ffluci.fs.dir(ctrldir .. "/" .. cat)) do
|
||||
if con:sub(-4) == ".lua" then
|
||||
con = con:sub(1, con:len()-4)
|
||||
local mod = require("ffluci.controller." .. cat .. "." .. con)
|
||||
if mod.menu and mod.menu.descr
|
||||
and mod.menu.entries and mod.menu.order then
|
||||
local entry = {}
|
||||
entry[".descr"] = mod.menu.descr
|
||||
entry[".order"] = mod.menu.order
|
||||
entry[".contr"] = con
|
||||
for k,v in pairs(mod.menu.entries) do
|
||||
entry[k] = v
|
||||
end
|
||||
local i = 0
|
||||
for k,v in ipairs(m[cat]) do
|
||||
if v[".order"] > entry[".order"] then
|
||||
break
|
||||
end
|
||||
i = k
|
||||
end
|
||||
table.insert(m[cat], i+1, entry)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
return m
|
||||
end
|
||||
|
||||
|
||||
-- Dumps a table into a string of Lua code
|
||||
function dump(tbl, name)
|
||||
local src = name .. "={}\n"
|
||||
for k,v in pairs(tbl) do
|
||||
if type(k) == "string" then
|
||||
k = ffluci.util.escape(k)
|
||||
k = "'" .. ffluci.util.escape(k, "'") .. "'"
|
||||
end
|
||||
if type(v) == "string" then
|
||||
v = ffluci.util.escape(v)
|
||||
v = ffluci.util.escape(v, "'")
|
||||
src = src .. name .. "[" .. k .. "]='" .. v .. "'\n"
|
||||
elseif type(v) == "number" then
|
||||
src = src .. name .. "[" .. k .. "]=" .. v .. "\n"
|
||||
elseif type(v) == "table" then
|
||||
src = src .. dump(v, name .. "[" .. k .. "]")
|
||||
end
|
||||
end
|
||||
return src
|
||||
end
|
||||
|
||||
-- Returns the menu information
|
||||
function get()
|
||||
if builder_enable_cache then
|
||||
local cachemt = ffluci.fs.mtime(modelpath)
|
||||
local data = nil
|
||||
|
||||
if cachemt == nil then
|
||||
data = build()
|
||||
else
|
||||
local fenv = {}
|
||||
local f = loadfile(modelpath)
|
||||
setfenv(f, fenv)
|
||||
f()
|
||||
data = fenv.m
|
||||
end
|
||||
|
||||
return data
|
||||
else
|
||||
return collect()
|
||||
end
|
||||
end
|
139
src/ffluci/model/uci.lua
Normal file
139
src/ffluci/model/uci.lua
Normal file
@ -0,0 +1,139 @@
|
||||
--[[
|
||||
FFLuCI - UCI wrapper library
|
||||
|
||||
Description:
|
||||
Wrapper for the /sbin/uci application, syntax of implemented functions
|
||||
is comparable to the syntax of the uci application
|
||||
|
||||
Any return value of false or nil can be interpreted as an error
|
||||
|
||||
FileId:
|
||||
$Id$
|
||||
|
||||
License:
|
||||
Copyright 2008 Steven Barth <steven@midlink.org>
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
|
||||
]]--
|
||||
module("ffluci.model.uci", package.seeall)
|
||||
require("ffluci.util")
|
||||
|
||||
ucicmd = "uci"
|
||||
|
||||
-- Wrapper for "uci add"
|
||||
function add(config, section_type)
|
||||
return _uci("add " .. _path(config) .. " " .. _path(section_type))
|
||||
end
|
||||
|
||||
|
||||
-- Wrapper for "uci changes"
|
||||
function changes(config)
|
||||
return _uci3("changes " .. _path(config))
|
||||
end
|
||||
|
||||
|
||||
-- Wrapper for "uci commit"
|
||||
function commit(config)
|
||||
return _uci2("commit " .. _path(config))
|
||||
end
|
||||
|
||||
|
||||
-- Wrapper for "uci get"
|
||||
function get(config, section, option)
|
||||
return _uci("get " .. _path(config, section, option))
|
||||
end
|
||||
|
||||
|
||||
-- Wrapper for "uci revert"
|
||||
function revert(config)
|
||||
return _uci2("revert " .. _path(config))
|
||||
end
|
||||
|
||||
|
||||
-- Wrapper for "uci show"
|
||||
function show(config)
|
||||
return _uci3("show " .. _path(config))
|
||||
end
|
||||
|
||||
|
||||
-- Wrapper for "uci set"
|
||||
function set(config, section, option, value)
|
||||
return _uci2("set " .. _path(config, section, option, value))
|
||||
end
|
||||
|
||||
|
||||
-- Internal functions --
|
||||
|
||||
function _uci(cmd)
|
||||
local res = ffluci.util.exec(ucicmd .. " 2>/dev/null " .. cmd)
|
||||
|
||||
if res:len() == 0 then
|
||||
return nil
|
||||
else
|
||||
return res:sub(1, res:len()-1)
|
||||
end
|
||||
end
|
||||
|
||||
function _uci2(cmd)
|
||||
local res = ffluci.util.exec(ucicmd .. " 2>&1 " .. cmd)
|
||||
|
||||
if res:len() > 0 then
|
||||
return false, res
|
||||
else
|
||||
return true
|
||||
end
|
||||
end
|
||||
|
||||
function _uci3(cmd)
|
||||
local res = ffluci.util.exec(ucicmd .. " 2>&1 " .. cmd, true)
|
||||
if res[1]:sub(1, ucicmd:len() + 1) == ucicmd .. ":" then
|
||||
return nil, res[1]
|
||||
end
|
||||
|
||||
table = {}
|
||||
|
||||
for k,line in pairs(res) do
|
||||
c, s, t = line:match("^([^.]-)%.([^.]-)=(.-)$")
|
||||
if c then
|
||||
table[c] = table[c] or {}
|
||||
table[c][s] = {}
|
||||
table[c][s][".type"] = t
|
||||
end
|
||||
|
||||
c, s, o, v = line:match("^([^.]-)%.([^.]-)%.([^.]-)=(.-)$")
|
||||
if c then
|
||||
table[c][s][o] = v
|
||||
end
|
||||
end
|
||||
|
||||
return table
|
||||
end
|
||||
|
||||
-- Build path (config.section.option=value) and prevent command injection
|
||||
function _path(...)
|
||||
local result = ""
|
||||
|
||||
-- Not using ipairs because it is not reliable in case of nil arguments
|
||||
arg.n = nil
|
||||
for k,v in pairs(arg) do
|
||||
if k == 1 then
|
||||
result = "'" .. v:gsub("['.]", "") .. "'"
|
||||
elseif k < 4 then
|
||||
result = result .. ".'" .. v:gsub("['.]", "") .. "'"
|
||||
elseif k == 4 then
|
||||
result = result .. "='" .. v:gsub("'", "") .. "'"
|
||||
end
|
||||
end
|
||||
return result
|
||||
end
|
189
src/ffluci/template.lua
Normal file
189
src/ffluci/template.lua
Normal file
@ -0,0 +1,189 @@
|
||||
--[[
|
||||
FFLuCI - Template Parser
|
||||
|
||||
Description:
|
||||
A template parser supporting includes, translations, Lua code blocks
|
||||
and more. It can be used either as a compiler or as an interpreter.
|
||||
|
||||
FileId: $Id$
|
||||
|
||||
License:
|
||||
Copyright 2008 Steven Barth <steven@midlink.org>
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
|
||||
]]--
|
||||
module("ffluci.template", package.seeall)
|
||||
|
||||
require("ffluci.config")
|
||||
require("ffluci.util")
|
||||
require("ffluci.fs")
|
||||
require("ffluci.i18n")
|
||||
require("ffluci.model.uci")
|
||||
|
||||
viewdir = ffluci.fs.dirname(ffluci.util.__file__()) .. "view/"
|
||||
|
||||
|
||||
-- Compile modes:
|
||||
-- none: Never compile, only render precompiled
|
||||
-- memory: Always compile, do not save compiled files, ignore precompiled
|
||||
-- always: Same as "memory" but also saves compiled files
|
||||
-- smart: Compile on demand, save compiled files, update precompiled
|
||||
compiler_mode = "smart"
|
||||
|
||||
|
||||
-- This applies to compiler modes "always" and "smart"
|
||||
--
|
||||
-- Produce compiled lua code rather than lua sourcecode
|
||||
-- WARNING: Increases template size heavily!!!
|
||||
-- This produces the same bytecode as luac but does not have a strip option
|
||||
compiler_enable_bytecode = false
|
||||
|
||||
|
||||
-- Define the namespace for template modules
|
||||
viewns = {
|
||||
translate = ffluci.i18n.translate,
|
||||
config = ffluci.model.uci.get,
|
||||
controller = os.getenv("SCRIPT_NAME"),
|
||||
media = ffluci.config.mediaurlbase,
|
||||
include = function(name) return render(name, getfenv(2)) end,
|
||||
write = io.write
|
||||
}
|
||||
|
||||
|
||||
-- Compiles and builds a given template
|
||||
function build(template, compiled)
|
||||
local template = compile(ffluci.fs.readfile(template))
|
||||
|
||||
if compiled then
|
||||
ffluci.fs.writefile(compiled, template)
|
||||
end
|
||||
|
||||
return template
|
||||
end
|
||||
|
||||
|
||||
-- Compiles a given template into an executable Lua module
|
||||
function compile(template)
|
||||
-- Search all <% %> expressions (remember: Lua table indexes begin with #1)
|
||||
local function expr_add(command)
|
||||
table.insert(expr, command)
|
||||
return "<%" .. tostring(#expr) .. "%>"
|
||||
end
|
||||
|
||||
-- As "expr" should be local, we have to assign it to the "expr_add" scope
|
||||
local expr = {}
|
||||
ffluci.util.extfenv(expr_add, "expr", expr)
|
||||
|
||||
-- Save all expressiosn to table "expr"
|
||||
template = template:gsub("<%%(.-)%%>", expr_add)
|
||||
|
||||
local function sanitize(s)
|
||||
s = ffluci.util.escape(s)
|
||||
s = ffluci.util.escape(s, "'")
|
||||
s = ffluci.util.escape(s, "\n")
|
||||
return s
|
||||
end
|
||||
|
||||
-- Escape and sanitize all the template (all non-expressions)
|
||||
template = sanitize(template)
|
||||
|
||||
-- Template module header/footer declaration
|
||||
local header = "write('"
|
||||
local footer = "')"
|
||||
|
||||
template = header .. template .. footer
|
||||
|
||||
-- Replacements
|
||||
local r_include = "')\ninclude('%s')\nwrite('"
|
||||
local r_i18n = "'..translate('%1','%2')..'"
|
||||
local r_uci = "'..config('%1','%2','%3')..'"
|
||||
local r_pexec = "'..%s..'"
|
||||
local r_exec = "')\n%s\nwrite('"
|
||||
|
||||
-- Parse the expressions
|
||||
for k,v in pairs(expr) do
|
||||
local p = v:sub(1, 1)
|
||||
local re = nil
|
||||
if p == "+" then
|
||||
re = r_include:format(sanitize(string.sub(v, 2)))
|
||||
elseif p == ":" then
|
||||
re = sanitize(v):gsub(":(.-) (.+)", r_i18n)
|
||||
elseif p == "~" then
|
||||
re = sanitize(v):gsub("~(.-)%.(.-)%.(.+)", r_uci)
|
||||
elseif p == "=" then
|
||||
re = r_pexec:format(string.sub(v, 2))
|
||||
else
|
||||
re = r_exec:format(v)
|
||||
end
|
||||
template = template:gsub("<%%"..tostring(k).."%%>", re)
|
||||
end
|
||||
|
||||
if compiler_enable_bytecode then
|
||||
tf = loadstring(template)
|
||||
template = string.dump(tf)
|
||||
end
|
||||
|
||||
return template
|
||||
end
|
||||
|
||||
|
||||
-- Returns and builds the template for "name" depending on the compiler mode
|
||||
function get(name)
|
||||
local templatefile = viewdir .. name .. ".htm"
|
||||
local compiledfile = viewdir .. name .. ".lua"
|
||||
local template = nil
|
||||
|
||||
if compiler_mode == "smart" then
|
||||
local tplmt = ffluci.fs.mtime(templatefile)
|
||||
local commt = ffluci.fs.mtime(compiledfile)
|
||||
|
||||
-- Build if there is no compiled file or if compiled file is outdated
|
||||
if ((commt == nil) and not (tplmt == nil))
|
||||
or (not (commt == nil) and not (tplmt == nil) and commt < tplmt) then
|
||||
template = loadstring(build(templatefile, compiledfile))
|
||||
else
|
||||
template = loadfile(compiledfile)
|
||||
end
|
||||
|
||||
elseif compiler_mode == "none" then
|
||||
template = loadfile(compiledfile)
|
||||
|
||||
elseif compiler_mode == "memory" then
|
||||
template = loadstring(build(templatefile))
|
||||
|
||||
elseif compiler_mode == "always" then
|
||||
template = loadstring(build(templatefile, compiledfile))
|
||||
|
||||
else
|
||||
error("Invalid compiler mode: " .. compiler_mode)
|
||||
|
||||
end
|
||||
|
||||
return template or error("Unable to load template: " .. name)
|
||||
end
|
||||
|
||||
-- Renders a template
|
||||
function render(name, scope)
|
||||
scope = scope or getfenv(2)
|
||||
|
||||
-- Our template module
|
||||
local view = get(name)
|
||||
|
||||
-- Put our predefined objects in the scope of the template
|
||||
ffluci.util.updfenv(view, scope)
|
||||
ffluci.util.updfenv(view, viewns)
|
||||
|
||||
-- Now finally render the thing
|
||||
return view()
|
||||
end
|
102
src/ffluci/util.lua
Normal file
102
src/ffluci/util.lua
Normal file
@ -0,0 +1,102 @@
|
||||
--[[
|
||||
FFLuCI - Utility library
|
||||
|
||||
Description:
|
||||
Several common useful Lua functions
|
||||
|
||||
FileId:
|
||||
$Id$
|
||||
|
||||
License:
|
||||
Copyright 2008 Steven Barth <steven@midlink.org>
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
|
||||
]]--
|
||||
|
||||
module("ffluci.util", package.seeall)
|
||||
|
||||
-- Checks whether a table has an object "value" in it
|
||||
function contains(table, value)
|
||||
for k,v in pairs(table) do
|
||||
if value == v then
|
||||
return true
|
||||
end
|
||||
end
|
||||
return false
|
||||
end
|
||||
|
||||
|
||||
-- Dumps a table to stdout (useful for testing and debugging)
|
||||
function dumptable(t, i)
|
||||
i = i or 0
|
||||
for k,v in pairs(t) do
|
||||
print(string.rep("\t", i) .. k, v)
|
||||
if type(v) == "table" then
|
||||
dumptable(v, i+1)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
-- Escapes all occurences of c in s
|
||||
function escape(s, c)
|
||||
c = c or "\\"
|
||||
return s:gsub(c, "\\" .. c)
|
||||
end
|
||||
|
||||
|
||||
-- Runs "command" and returns its output
|
||||
function exec(command, return_array)
|
||||
local pp = io.popen(command)
|
||||
local data = nil
|
||||
|
||||
if return_array then
|
||||
local line = ""
|
||||
data = {}
|
||||
|
||||
while true do
|
||||
line = pp:read()
|
||||
if (line == nil) then break end
|
||||
table.insert(data, line)
|
||||
end
|
||||
pp:close()
|
||||
else
|
||||
data = pp:read("*a")
|
||||
pp:close()
|
||||
end
|
||||
|
||||
return data
|
||||
end
|
||||
|
||||
-- Populate obj in the scope of f as key
|
||||
function extfenv(f, key, obj)
|
||||
local scope = getfenv(f)
|
||||
scope[key] = obj
|
||||
setfenv(f, scope)
|
||||
end
|
||||
|
||||
|
||||
-- Updates the scope of f with "extscope"
|
||||
function updfenv(f, extscope)
|
||||
local scope = getfenv(f)
|
||||
for k, v in pairs(extscope) do
|
||||
scope[k] = v
|
||||
end
|
||||
setfenv(f, scope)
|
||||
end
|
||||
|
||||
-- Returns the filename of the calling script
|
||||
function __file__()
|
||||
return debug.getinfo(2, 'S').source:sub(2)
|
||||
end
|
3
src/ffluci/view/example-simpleview/foo.htm
Executable file
3
src/ffluci/view/example-simpleview/foo.htm
Executable file
@ -0,0 +1,3 @@
|
||||
<%+header%>
|
||||
<h1>bar</h1>
|
||||
<%+footer%>
|
6
src/ffluci/view/example-simpleview/index.htm
Executable file
6
src/ffluci/view/example-simpleview/index.htm
Executable file
@ -0,0 +1,6 @@
|
||||
<%+header%>
|
||||
<p><%:descr This is the Simple View-Example.<br />
|
||||
This template is ffluci/view/example-simpleview/index.htm and belongs
|
||||
to the index-Action.%></p>
|
||||
<p><%:lan The router's LAN IP-Address is:%> <%~network.lan.ipaddr%></p>
|
||||
<%+footer%>
|
3
src/ffluci/view/footer.htm
Normal file
3
src/ffluci/view/footer.htm
Normal file
@ -0,0 +1,3 @@
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
9
src/ffluci/view/header.htm
Normal file
9
src/ffluci/view/header.htm
Normal file
@ -0,0 +1,9 @@
|
||||
<% require("ffluci.http").htmlheader() %>
|
||||
<html>
|
||||
<head>
|
||||
<title>FFLuCI Examples</title>
|
||||
</head>
|
||||
<body>
|
||||
<h1>FFLuCI</h1>
|
||||
<%+menu%>
|
||||
<div id="content">
|
1
src/ffluci/view/hello.htm
Normal file
1
src/ffluci/view/hello.htm
Normal file
@ -0,0 +1 @@
|
||||
A very little Hello <%=muh%>
|
25
src/ffluci/view/menu.htm
Normal file
25
src/ffluci/view/menu.htm
Normal file
@ -0,0 +1,25 @@
|
||||
<%
|
||||
local req = require("ffluci.dispatcher").request
|
||||
local menu = require("ffluci.menu").get()[req.category]
|
||||
local menu_module = nil
|
||||
require("ffluci.i18n").loadc("default")
|
||||
%>
|
||||
<div id="menu" style="font-size: 0.8em; padding-bottom: 20px">
|
||||
<div id="menu_categories">
|
||||
<span style="<% if "public" == req.category then write("font-weight: bold") end %>"><a href="<%=controller%>/public"><%:public Public%></a></span>
|
||||
<span style="<% if "admin" == req.category then write("font-weight: bold") end %>"><a href="<%=controller%>/admin"><%:admin Admin%></a></span>
|
||||
</div>
|
||||
<div id="menu_modules">
|
||||
<% for k,v in pairs(menu) do
|
||||
if v[".contr"] == req.module then menu_module = v end %>
|
||||
<span style="<% if v[".contr"] == req.module then write("font-weight: bold") end %>"><a href="<%=controller.."/"..req.category.."/"..v[".contr"]%>"><%=translate(v[".contr"], v[".descr"])%></a></span>
|
||||
<% end %>
|
||||
</div>
|
||||
<% if menu_module then %>
|
||||
<div id="menu_actions">
|
||||
<% for k,v in ipairs(menu_module) do %>
|
||||
<span style="<% if v.action == req.action then write("font-weight: bold") end %>"><a href="<%=controller.."/"..req.category.."/"..req.module.."/"..v.action%>"><%=translate(v.action, v.descr)%></a></span>
|
||||
<% end %>
|
||||
</div>
|
||||
<% end %>
|
||||
</div>
|
Loading…
Reference in New Issue
Block a user