egalite 1.0.0 → 1.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
data/README.md CHANGED
@@ -2,11 +2,19 @@
2
2
 
3
3
  Egaliteは、Ruby用のウェブアプリケーションフレームワークです。自社用に使っているフレームワークですが、使う人の利便性などを考えてオープンソースにしてgemで公開しています。
4
4
 
5
+ 添付ライブラリ等の説明:
6
+ * [メール送信ライブラリ](sendmail.md)
7
+ * [管理画面作成ツール](htmlbuilder.md)
8
+
5
9
  ## 概要
6
10
 
7
11
  いわゆるMVC構造のフレームワークです。O/RマッパーとしてはSequelを使うことを想定しています。モデルはSequelをそのまま使いますので、本ドキュメントでは言及しません。
8
12
 
9
- ビューは独自のテンプレートエンジンを使用しており、HTMLからコードをなるべく廃するという思想で作っています。
13
+ ビューは、独自のテンプレートエンジンを使用しており、HTMLからコードをなるべく廃するという思想で作っています。
14
+
15
+ コントローラは、メソッドの戻り値のみによって結果を返すようになっており、HTTPに対する処理の流れとして違和感がない作りになっています。
16
+
17
+ 自動でXSSやCSRFを防ぐための機構を持っています。
10
18
 
11
19
  ## コントローラーの基本
12
20
 
@@ -91,20 +99,28 @@ URL以外で引き渡されるパラメーター(クエリパラメータやPOST
91
99
 
92
100
  ## セキュリティ対応
93
101
 
102
+ ### 自動XSS対策機能
103
+
104
+ テンプレートエンジンは、与えられた文字列を自動でエスケープします。もしエスケープして欲しくないときは、文字列をNonEscapeStringという型にキャストしてからテンプレートエンジンに渡します。
105
+
106
+ コントローラ内では、このキャストはraw(string)というメソッドで行えます。
107
+
94
108
  ### 自動CSRF対策機能
95
109
 
96
110
  egaliteには自動でCSRF対策のチェック値を埋め込む機能が付いています。この機能を有効にすると自動でCSRF対策を行うことができます。
97
111
 
98
- 【注意】外部のサイトにフォームを送信するときにセッション情報が送られてしまいますので、外部のサイトにフォームを送る必要があるシステムでは絶対に使わないでください。(そのうち改善します)
112
+ テンプレートエンジンが勝手にformタグを見つけて、勝手にcsrf情報を埋め込むhiddenタグが付与されます。
99
113
 
100
- 有効にする方法は以下の通りです。
114
+ 【注意】外部のサイトにフォームを送信するときにセッション情報が送られてしまいますので、外部のサイトにフォームを送るときは、<form>タグを<form :nocsrf action='hoge' method='POST'>のように記述してください。
101
115
 
102
- egalite = Egalite::Handler.new(
103
- :db => db,
104
- :template_engine => Egalite::CSRFTemplate
105
- )
116
+ 有効にする方法は以下の通りです。
106
117
 
107
- class Pages < Egalite::CSRFController
108
- end
118
+ egalite = Egalite::Handler.new(
119
+ :db => db,
120
+ :template_engine => Egalite::CSRFTemplate
121
+ )
122
+
123
+ class Pages < Egalite::CSRFController
124
+ end
109
125
 
110
126
 
data/htmlbuilder.md ADDED
@@ -0,0 +1,62 @@
1
+
2
+ # 管理画面作成ツール
3
+
4
+ Egaliteでは、HTMLを書かずとも、簡単な管理画面のためのテーブルやフォームを作成するためのライブラリを備えています。
5
+
6
+ この機能を使えば、いちいちページごとにHTMLを書かずとも、20行程度のコードで簡単な管理画面を作成することができますので、生産性・メンテナンス性が大きく改善されます。
7
+
8
+ ただし、あまり複雑なページにこれを使うと、コードがぐちゃぐちゃになりますので、どっかのタイミングで諦めてHTMLに移行するほうが無難です。
9
+
10
+ ## テーブル作成ツール
11
+
12
+ recs = User.map { |rec| [rec.id, rec.name, rec.email] }
13
+ table_by_array(["番号","氏名","メールアドレス"],recs)
14
+
15
+ とするだけで、ユーザ一覧のテーブルが生成できます。これをひな形となるテンプレートの一部分に投入すれば、それだけで一覧画面が完成します。
16
+
17
+ ## フォーム作成ツール
18
+
19
+ rec = User[id]
20
+ fm = form(rec) # FormHelperインスタンスを取得します
21
+ fm.text(:name) # => "<input type='text' name='name' value='#{rec.user}'/>"
22
+ fm.password(:password) # => "<input type='password' name='password'/>"
23
+ fm.hidden(:foo) # => "<input type='hidden' name='foo' value='#{rec.foo}'/>"
24
+ fm.checkbox(:cb) # => "<input type='checkbox' name='cb' value='true' #{rec.cb ? 'checked' : ''}/>"
25
+ fm.radio(:rd, "foo") # => "<input type='checkbox' name='rd' value='foo' #{rec.rd == 'foo' ? 'selected' : ''}/>"
26
+ fm.textarea(:ta) # => <textarea name='ta'>#{rec.ta}</textarea>
27
+ fm.file(:file) # => <input type='file' name='file'/>
28
+ fm.submit("登録") # => <input type='submit' value='登録'/>
29
+
30
+ これで作成したフォームを以下のように組むことで、フォームのテーブルが作れます。
31
+
32
+ left = ["名前","メールアドレス"]
33
+ right = [fm.text(:name), fm.text(:email)]
34
+ table_by_array(nil, left.zip(right))
35
+
36
+ ## タグ作成ツール
37
+
38
+ ### 単独タグ作成
39
+
40
+ tags.br # => <br/>
41
+
42
+ brとhrが使えます。
43
+
44
+ ### 囲みタグ作成
45
+
46
+ tags.p("ほげ") # => "<p>ほげ</p>"
47
+
48
+ h1 h2 h3 h4 b i p html bodyなどがこのように作れます。
49
+
50
+ ### リンク
51
+
52
+ tags.a("http://example.com","ほげ") # => <a href="http://example.com">ほげ</a>
53
+
54
+ ### liタグ
55
+
56
+ tags.li(["foo","bar"]) # => <li>foo</li><li>bar</li>
57
+
58
+ ### リストタグ作成
59
+
60
+ tags.ul(["foo","bar"]) # => <ul><li>foo</li><li>bar</li></ul>
61
+
62
+ ulとolが使えます。
@@ -0,0 +1,85 @@
1
+
2
+ =begin
3
+ キャッシュテーブルのデータ定義:
4
+
5
+ CREATE TABLE controller_cache (
6
+ id SERIAL PRIMARY KEY,
7
+ inner_path TEXT UNIQUE NOT NULL,
8
+ language TEXT,
9
+ updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
10
+ content TEXT NOT NULL
11
+ );
12
+ =end
13
+
14
+ module Egalite
15
+ module ControllerCache
16
+ class <<self
17
+ attr_accessor :table
18
+
19
+ def create_table(db, opts = {})
20
+ table = opts[:table_name] || :controller_cache
21
+
22
+ db.create_table(table) {
23
+ primary_key :id, :integer, :auto_increment => true
24
+ column :inner_path, :varchar
25
+ column :language, :varchar
26
+ column :updated_at, :timestamp
27
+ column :content, :varchar
28
+ }
29
+ end
30
+ end
31
+ module ClassMethods
32
+ attr_reader :controller_cache_actions
33
+ def cache_action(action, options)
34
+ @controller_cache_actions ||= {}
35
+ @controller_cache_actions[action.to_s] = options
36
+ end
37
+ end
38
+ def self.included(base)
39
+ base.extend(ClassMethods)
40
+ end
41
+ def __controller_cache__dataset
42
+ table = Egalite::ControllerCache.table
43
+ dataset = table.filter(:inner_path => req.inner_path)
44
+ if req.language
45
+ dataset = dataset.filter(:language => req.language)
46
+ end
47
+ dataset
48
+ end
49
+ def before_filter
50
+ cache = self.class.controller_cache_actions[req.action_method]
51
+ if cache
52
+ result = super
53
+ if result != true
54
+ return result
55
+ end
56
+ dataset = __controller_cache__dataset
57
+ record = dataset.first
58
+ return true unless record
59
+ return true if record[:updated_at] < (Time.now - cache[:expire])
60
+ record[:content]
61
+ else
62
+ super
63
+ end
64
+ end
65
+ def after_filter_html(html)
66
+ html = super(html)
67
+ if self.class.controller_cache_actions[req.action_method]
68
+ dataset = __controller_cache__dataset
69
+ data = {
70
+ :inner_path => req.inner_path,
71
+ :language => req.language,
72
+ :updated_at => Time.now,
73
+ :content => html,
74
+ }
75
+ if dataset.count > 0
76
+ dataset.update(data)
77
+ else
78
+ Egalite::ControllerCache.table.insert(data)
79
+ end
80
+ end
81
+ return html
82
+ end
83
+ end
84
+ end
85
+
data/lib/egalite/m17n.rb CHANGED
@@ -15,6 +15,7 @@ module Egalite
15
15
  end
16
16
  @lang ||= Translation.lang(Translation.user_default_lang)
17
17
  @lang ||= Translation.lang('ja')
18
+ req.language = @lang
18
19
 
19
20
  super
20
21
  end
@@ -1,6 +1,7 @@
1
1
 
2
2
  require 'nkf'
3
3
  require 'time'
4
+ require 'net/smtp'
4
5
 
5
6
  # mailheaders
6
7
  # {
@@ -264,7 +264,7 @@ class CSRFTemplate < HTMLTemplate
264
264
  csrf = nil
265
265
  if attrs[":nocsrf"]
266
266
  attrs.delete(":nocsrf")
267
- elsif attrs["method"] =~ /\APOST\Z/i
267
+ elsif attrs["method"].upcase == "POST"
268
268
  csrf = params["csrf"]
269
269
  csrf = "<input type='hidden' name='csrf' value='#{escapeHTML(csrf)}'/>"
270
270
  end
@@ -1,3 +1,3 @@
1
1
  module Egalite
2
- VERSION = "1.0.0"
2
+ VERSION = "1.1.0"
3
3
  end
data/lib/egalite.rb CHANGED
@@ -519,6 +519,7 @@ class Handler
519
519
  before_filter_result = controller.before_filter
520
520
  if before_filter_result != true
521
521
  return before_filter_result if before_filter_result.is_a?(Array)
522
+ return [200,{'Content-Type' => "text/html"},[before_filter_result]] if before_filter_result.is_a?(String)
522
523
  return forbidden unless before_filter_result.respond_to?(:command)
523
524
  response = case before_filter_result.command
524
525
  when :delegate
@@ -561,7 +562,8 @@ class Handler
561
562
  elsif values.is_a?(Array)
562
563
  values
563
564
  elsif values.is_a?(String)
564
- [200,{'Content-Type' => "text/html"},[values]]
565
+ html = controller.after_filter_html(values)
566
+ [200,{'Content-Type' => "text/html"},[html]]
565
567
  elsif values.is_a?(Rack::Response)
566
568
  values.to_a
567
569
  elsif values == nil
@@ -627,9 +629,6 @@ class Handler
627
629
  req.path_params = path_params
628
630
  req.path_info = path_params.join('/')
629
631
 
630
- # todo: language handling (by pathinfo?)
631
- # todo: session handling (by pathinfo?)
632
-
633
632
  res = run_controller(controller, action, req)
634
633
 
635
634
  if first_call
data/sendmail.md ADDED
@@ -0,0 +1,54 @@
1
+
2
+ # Egalite メール送信ライブラリ
3
+
4
+ Egaliteにはシンプルなメール送信ライブラリが付属しています。
5
+
6
+ require 'rubygems'
7
+ require 'egalite'
8
+ require 'egalite/sendmail'
9
+
10
+ 多バイト文字によるメール送信に対応しており、簡単にメールを送ることができます。デフォルトではUTF8エンコーディングでメールを送信します。
11
+
12
+ HTMLメールや添付ファイルには現在は対応しておりません。
13
+
14
+ SMTPの凝った機能(認証や暗号化等)には対応しておりませんし、今後も対応するつもりはありません。必要であれば、ローカルのメールサーバー(Postfix等)の設定で対応してください。
15
+
16
+ ## メールを送信する
17
+
18
+ Sendmail.send(
19
+ body, # メール本文
20
+ {:from => "from@example.com",
21
+ :reply_to => "replyto@example.com", # 省略可
22
+ :to => { "James Dean" => "james@example.com",
23
+ "新井太郎" => "foo@example.com" },
24
+ :cc => "",
25
+ :bcc => "",
26
+ :subject => "お打ち合わせについて"
27
+ }, # その他、メールヘッダに入れたいものは何でも入れられます
28
+ "localhost" # メールサーバのアドレス (省略可)
29
+ )
30
+
31
+ メールの宛先や送信人などについては、メールアドレスだけを記載することもできますし、Hash形式で名前とメールアドレスの両方を指定することもできます。
32
+
33
+ ## テンプレートを使ってメールを送信する
34
+
35
+ Sendmail.send_with_template(
36
+ "mailtext.txt", # メールテンプレート (HTMLテンプレートとほぼ同様)
37
+ {
38
+ :from => "from@example.com",
39
+ :to => "to@example.com",
40
+ :name => "新井 太郎",
41
+ :price => "3,000円",
42
+ }, # メールヘッダと、テンプレートに埋め込む内容を入れます
43
+ "localhost" # メールサーバのアドレス (省略可)
44
+ )
45
+
46
+ ## メール送信をテストする
47
+
48
+ Sendmail.mock = true
49
+
50
+ とすると、メールを送信する代わりに内部に記録しておくようになります。影響はグローバルに及びます。
51
+
52
+ (text, envelope_from, to, host) = Sendmail.lastmail
53
+
54
+ とすることで、送信したメールの取得ができます。これもグローバル変数です。
data/test/cache.html ADDED
@@ -0,0 +1,8 @@
1
+ <html>
2
+ <body>
3
+ cache:<include :action='cache'/>
4
+ <br/>
5
+ nocache:<include :action='nocache'/>
6
+ <br/>
7
+ </body>
8
+ </html>
@@ -0,0 +1 @@
1
+ &=time;
@@ -0,0 +1 @@
1
+ &=time;
@@ -0,0 +1,130 @@
1
+ $LOAD_PATH << File.dirname(__FILE__)
2
+ $LOAD_PATH << File.join(File.dirname(__FILE__), '..')
3
+
4
+ require 'rubygems'
5
+ require 'sequel'
6
+ require 'test/unit'
7
+ require 'egalite'
8
+ require 'egalite/cache'
9
+
10
+ require 'rack'
11
+ require 'rack/test'
12
+
13
+ require 'setup'
14
+
15
+ class TestCacheController < Egalite::Controller
16
+ include Egalite::ControllerCache
17
+
18
+ cache_action :get, :expire => 1
19
+
20
+ def get
21
+ "#{Time.now.to_i}.#{Time.now.usec}"
22
+ end
23
+ def nocache
24
+ "#{Time.now.to_i}.#{Time.now.usec}"
25
+ end
26
+ end
27
+
28
+ class CacheController < Egalite::Controller
29
+ include Egalite::ControllerCache
30
+
31
+ cache_action :cache, :expire => 1
32
+
33
+ def get
34
+ {}
35
+ end
36
+ def cache
37
+ {:time => "#{Time.now.to_i}.#{Time.now.usec}"}
38
+ end
39
+ def nocache
40
+ {:time => "#{Time.now.to_i}.#{Time.now.usec}"}
41
+ end
42
+ end
43
+
44
+ class T_Cache < Test::Unit::TestCase
45
+ include Rack::Test::Methods
46
+
47
+ def app
48
+ db = Sequel.sqlite
49
+ Egalite::ControllerCache.create_table(db)
50
+ Egalite::ControllerCache.table = db[:controller_cache]
51
+ Egalite::Handler.new
52
+ end
53
+ def test_cache
54
+ # test cache is not working
55
+ get "/test/cache/nocache"
56
+ a = last_response.body
57
+ sleep 0.1
58
+ get "/test/cache/nocache"
59
+ b = last_response.body
60
+ assert_not_equal a,b
61
+
62
+ # test cache is working
63
+ get "/test/cache/"
64
+ a = last_response.body
65
+ sleep 0.1
66
+ get "/test/cache/"
67
+ b = last_response.body
68
+ assert_equal a,b
69
+ sleep 2
70
+ get "/test/cache/"
71
+ c = last_response.body
72
+ assert_not_equal a,c
73
+
74
+ # test cache is not working for different url
75
+ get "/test/cache/1"
76
+ a = last_response.body
77
+ sleep 0.1
78
+ get "/test/cache/2"
79
+ b = last_response.body
80
+ assert_not_equal a,b
81
+ end
82
+ end
83
+
84
+ # テンプレートでのテスト
85
+ class T_CacheTemplate < Test::Unit::TestCase
86
+ include Rack::Test::Methods
87
+
88
+ def app
89
+ db = Sequel.sqlite
90
+ Egalite::ControllerCache.create_table(db)
91
+ Egalite::ControllerCache.table = db[:controller_cache]
92
+ Egalite::Handler.new(:template_path => File.dirname(__FILE__))
93
+ end
94
+ def test_cache
95
+ # test cache is not working
96
+ get "/cache/"
97
+ last_response.body =~ /nocache:(.+?)\n/
98
+ a = $1
99
+ sleep 0.1
100
+ get "/cache/"
101
+ last_response.body =~ /nocache:(.+?)\n/
102
+ b = $1
103
+ assert_not_equal a,b
104
+
105
+ # test cache is working
106
+ get "/cache/"
107
+ last_response.body =~ /\ncache:(.+?)\n/
108
+ a = $1
109
+ sleep 0.1
110
+ get "/cache/"
111
+ last_response.body =~ /\ncache:(.+?)\n/
112
+ b = $1
113
+ assert_equal a,b
114
+ sleep 2
115
+ get "/cache/"
116
+ last_response.body =~ /\ncache:(.+?)\n/
117
+ c = $1
118
+ assert_not_equal a,c
119
+
120
+ # test cache is not working for different url
121
+ get "/cache?1"
122
+ last_response.body =~ /\ncache:(.+?)\n/
123
+ a = $1
124
+ sleep 0.1
125
+ get "/cache?2"
126
+ last_response.body =~ /\ncache:(.+?)\n/
127
+ a = $1
128
+ assert_not_equal a,b
129
+ end
130
+ end
metadata CHANGED
@@ -1,13 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: egalite
3
3
  version: !ruby/object:Gem::Version
4
- hash: 23
4
+ hash: 19
5
5
  prerelease:
6
6
  segments:
7
7
  - 1
8
+ - 1
8
9
  - 0
9
- - 0
10
- version: 1.0.0
10
+ version: 1.1.0
11
11
  platform: ruby
12
12
  authors:
13
13
  - Shunichi Arai
@@ -15,7 +15,7 @@ autorequire:
15
15
  bindir: bin
16
16
  cert_chain: []
17
17
 
18
- date: 2013-08-07 00:00:00 Z
18
+ date: 2014-04-18 00:00:00 Z
19
19
  dependencies:
20
20
  - !ruby/object:Gem::Dependency
21
21
  name: bundler
@@ -82,9 +82,11 @@ files:
82
82
  - examples/simple/run_webrick.rb
83
83
  - examples/simple_db/example_db.rb
84
84
  - examples/simple_db/pages/edit.html
85
+ - htmlbuilder.md
85
86
  - lib/egalite.rb
86
87
  - lib/egalite/auth/basic.rb
87
88
  - lib/egalite/blank.rb
89
+ - lib/egalite/cache.rb
88
90
  - lib/egalite/errorconsole.rb
89
91
  - lib/egalite/helper.rb
90
92
  - lib/egalite/keitai/keitai.rb
@@ -110,7 +112,11 @@ files:
110
112
  - lib/egalite/support.rb
111
113
  - lib/egalite/template.rb
112
114
  - lib/egalite/version.rb
115
+ - sendmail.md
113
116
  - test.bat
117
+ - test/cache.html
118
+ - test/cache_cache.html
119
+ - test/cache_nocache.html
114
120
  - test/french.html
115
121
  - test/french_msg.html
116
122
  - test/m17n.txt
@@ -122,6 +128,7 @@ files:
122
128
  - test/template_innerparam.html
123
129
  - test/test_auth.rb
124
130
  - test/test_blank.rb
131
+ - test/test_cache.rb
125
132
  - test/test_csrf.rb
126
133
  - test/test_errorconsole.rb
127
134
  - test/test_handler.rb
@@ -167,6 +174,9 @@ signing_key:
167
174
  specification_version: 3
168
175
  summary: Egalite - yet another web application framework.
169
176
  test_files:
177
+ - test/cache.html
178
+ - test/cache_cache.html
179
+ - test/cache_nocache.html
170
180
  - test/french.html
171
181
  - test/french_msg.html
172
182
  - test/m17n.txt
@@ -178,6 +188,7 @@ test_files:
178
188
  - test/template_innerparam.html
179
189
  - test/test_auth.rb
180
190
  - test/test_blank.rb
191
+ - test/test_cache.rb
181
192
  - test/test_csrf.rb
182
193
  - test/test_errorconsole.rb
183
194
  - test/test_handler.rb