backframe 0.0.0 → 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/Gemfile +3 -1
- data/backframe.gemspec +2 -0
- data/lib/backframe/acts_as_orderable.rb +38 -0
- data/lib/backframe/acts_as_status.rb +52 -0
- data/lib/backframe/acts_as_user.rb +101 -0
- data/lib/backframe/api/page.rb +27 -32
- data/lib/backframe/filter_sort.rb +56 -0
- data/lib/backframe/migration.rb +19 -0
- data/lib/backframe/railtie.rb +14 -0
- data/lib/backframe/version.rb +1 -1
- data/lib/backframe.rb +10 -0
- metadata +35 -1
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: b82eb2645a15741b2dfda3c0fea9ae60c1d90ed8
|
4
|
+
data.tar.gz: 32f108b39fe6a99f90b936e4d47964cf9b25f2b2
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: e6176bfbbef7a17bdf19d1cefb6bd55f7b015a7b8dba667b2d89a85677612795c99c63503443f7a9874a2a2a3bc141990fa199d5d7a5db49e4623d47527142aa
|
7
|
+
data.tar.gz: 02130ecd29e535126f3714f75d43b78bf6ccd204399fd80c928b56a874f072c793b06bb1a854cdae6e12065cfb5467b22daf393f5dcc4cf14d5944b6243106ef
|
data/Gemfile
CHANGED
data/backframe.gemspec
CHANGED
@@ -16,6 +16,8 @@ Gem::Specification.new do |gem|
|
|
16
16
|
gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
|
17
17
|
gem.require_paths = ["lib"]
|
18
18
|
|
19
|
+
gem.add_runtime_dependency 'write_xlsx', '~> 0.83.0'
|
20
|
+
gem.add_runtime_dependency 'activerecord', '~> 4.0'
|
19
21
|
gem.add_runtime_dependency 'activesupport', '~> 4.0'
|
20
22
|
gem.add_runtime_dependency 'active_model_serializers', '>= 0.10.0.rc4'
|
21
23
|
gem.add_runtime_dependency 'kaminari', '~> 0.16'
|
@@ -0,0 +1,38 @@
|
|
1
|
+
module Backframe
|
2
|
+
module ActsAsOrderable
|
3
|
+
extend ActiveSupport::Concern
|
4
|
+
|
5
|
+
def self.included(base)
|
6
|
+
base.send :extend, ClassMethods
|
7
|
+
end
|
8
|
+
|
9
|
+
module ClassMethods
|
10
|
+
|
11
|
+
def acts_as_orderable(field, args = {})
|
12
|
+
|
13
|
+
class_eval <<-EOV
|
14
|
+
validates_presence_of :#{field}
|
15
|
+
|
16
|
+
before_validation :set_#{field}, :on => :create
|
17
|
+
after_destroy :reorder_#{field}
|
18
|
+
|
19
|
+
default_scope -> { order(:#{field} => :asc) }
|
20
|
+
|
21
|
+
def set_#{field}
|
22
|
+
self.#{field} ||= (self.#{args[:on]}.#{self.name.tableize}.any?) ? self.#{args[:on]}.#{self.name.tableize}.maximum(:#{field}) + 1 : 0
|
23
|
+
end
|
24
|
+
|
25
|
+
def reorder_#{field}
|
26
|
+
self.#{args[:on]}.#{self.name.tableize}.order(:#{field} => :asc).each_with_index do |item, index|
|
27
|
+
item.update_column(:#{field}, index)
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
EOV
|
32
|
+
|
33
|
+
end
|
34
|
+
|
35
|
+
end
|
36
|
+
|
37
|
+
end
|
38
|
+
end
|
@@ -0,0 +1,52 @@
|
|
1
|
+
module Backframe
|
2
|
+
module ActsAsStatus
|
3
|
+
extend ActiveSupport::Concern
|
4
|
+
|
5
|
+
def self.included(base)
|
6
|
+
base.send :extend, ClassMethods
|
7
|
+
end
|
8
|
+
|
9
|
+
module ClassMethods
|
10
|
+
|
11
|
+
def acts_as_status(*args)
|
12
|
+
|
13
|
+
field = args[0]
|
14
|
+
arguments = args[1]
|
15
|
+
|
16
|
+
if arguments.key?(:default)
|
17
|
+
after_initialize :init_status, :if => Proc.new { |d| d.new_record? }
|
18
|
+
end
|
19
|
+
|
20
|
+
if arguments.key?(:required)
|
21
|
+
validates_presence_of field
|
22
|
+
end
|
23
|
+
|
24
|
+
if arguments.key?(:in)
|
25
|
+
validates_inclusion_of field, :in => arguments[:in]
|
26
|
+
end
|
27
|
+
|
28
|
+
if arguments.key?(:in)
|
29
|
+
arguments[:in].each do |status|
|
30
|
+
class_eval <<-EOV
|
31
|
+
scope :#{status}, -> { where(:status => '#{status}') }
|
32
|
+
|
33
|
+
def #{status}?
|
34
|
+
self.#{field} == '#{status}'
|
35
|
+
end
|
36
|
+
EOV
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
if arguments.key?(:default)
|
41
|
+
class_eval <<-EOV
|
42
|
+
def init_status
|
43
|
+
self.#{field} ||= '#{arguments[:default]}'
|
44
|
+
end
|
45
|
+
EOV
|
46
|
+
end
|
47
|
+
|
48
|
+
end
|
49
|
+
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
@@ -0,0 +1,101 @@
|
|
1
|
+
module Backframe
|
2
|
+
module ActsAsUser
|
3
|
+
extend ActiveSupport::Concern
|
4
|
+
|
5
|
+
def self.included(base)
|
6
|
+
base.send :extend, ClassMethods
|
7
|
+
end
|
8
|
+
|
9
|
+
module ClassMethods
|
10
|
+
|
11
|
+
def acts_as_user
|
12
|
+
|
13
|
+
attr_accessor :password, :change_password, :set_password, :old_password, :new_password, :confirm_password, :confirm_email
|
14
|
+
|
15
|
+
has_many :activations, :dependent => :destroy
|
16
|
+
has_many :resets, :dependent => :destroy
|
17
|
+
|
18
|
+
after_validation :set_new_password, :if => Proc.new { |u| u.new_password.present? }
|
19
|
+
after_create :activate
|
20
|
+
after_save :update_activities, :if => Proc.new { |u| u.first_name_changed? || u.last_name_changed? }
|
21
|
+
|
22
|
+
validates_presence_of :first_name, :last_name, :email
|
23
|
+
validates_uniqueness_of :email
|
24
|
+
validate :validate_password, :if => Proc.new { |u| u.change_password.present? || u.set_password.present? }
|
25
|
+
|
26
|
+
class_eval <<-EOV
|
27
|
+
def full_name
|
28
|
+
self.first_name+' '+self.last_name
|
29
|
+
end
|
30
|
+
|
31
|
+
def rfc822
|
32
|
+
self.full_name+' <'+self.email+'>'
|
33
|
+
end
|
34
|
+
|
35
|
+
def locked_out?
|
36
|
+
self.signin_locked_at.present? && self.signin_locked_at > Time.now.ago(5.minutes)
|
37
|
+
end
|
38
|
+
|
39
|
+
def signin(status)
|
40
|
+
if status == :success
|
41
|
+
self.signin_locked_at = nil
|
42
|
+
self.signin_attempts = 0
|
43
|
+
elsif status == :failed
|
44
|
+
self.signin_attempts += 1
|
45
|
+
if self.signin_attempts >= 5
|
46
|
+
self.signin_attempts = 0
|
47
|
+
self.signin_locked_at = Time.now
|
48
|
+
end
|
49
|
+
end
|
50
|
+
self.save
|
51
|
+
end
|
52
|
+
|
53
|
+
def authenticate(password)
|
54
|
+
self.password_hash == BCrypt::Engine.hash_secret(password, self.password_salt)
|
55
|
+
end
|
56
|
+
|
57
|
+
def reset
|
58
|
+
self.resets.create
|
59
|
+
end
|
60
|
+
|
61
|
+
def activate
|
62
|
+
self.activations.create
|
63
|
+
end
|
64
|
+
|
65
|
+
def password=(password)
|
66
|
+
@password = password
|
67
|
+
self.password_salt = BCrypt::Engine.generate_salt
|
68
|
+
self.password_hash = BCrypt::Engine.hash_secret(password, self.password_salt)
|
69
|
+
end
|
70
|
+
|
71
|
+
def password
|
72
|
+
@password
|
73
|
+
end
|
74
|
+
|
75
|
+
def validate_password
|
76
|
+
if self.change_password && self.old_password.blank?
|
77
|
+
return self.errors.add(:old_password, I18n.t('activerecord.errors.messages.blank'))
|
78
|
+
elsif self.change_password && !authenticate(self.old_password)
|
79
|
+
return self.errors.add(:old_password, I18n.t(:user_invalid_old_password))
|
80
|
+
elsif self.new_password.blank? || self.confirm_password.blank?
|
81
|
+
return self.errors.add(:new_password, I18n.t(:user_unconfirmed_password))
|
82
|
+
elsif self.confirm_password != self.new_password
|
83
|
+
return self.errors.add(:new_password, I18n.t(:user_unmatching_passwords))
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
def set_new_password
|
88
|
+
self.password = self.new_password
|
89
|
+
end
|
90
|
+
|
91
|
+
def update_activities
|
92
|
+
Activity.where(:#{self.name.downcase}_id => self.id).update_all(:updated_at => Time.zone.now)
|
93
|
+
end
|
94
|
+
|
95
|
+
EOV
|
96
|
+
|
97
|
+
end
|
98
|
+
|
99
|
+
end
|
100
|
+
end
|
101
|
+
end
|
data/lib/backframe/api/page.rb
CHANGED
@@ -104,49 +104,44 @@ module Backframe
|
|
104
104
|
end
|
105
105
|
|
106
106
|
def collection_to_xls(collection, serializer, fields)
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
line << '<Cell><Data ss:Type="String">'+key+'</Data></Cell>'
|
107
|
+
filename = SecureRandom.hex(32).to_s.upcase[0,16]
|
108
|
+
workbook = WriteXLSX.new(filename)
|
109
|
+
worksheet = workbook.add_worksheet
|
110
|
+
row = 0
|
111
|
+
col = 0
|
112
|
+
fields.each_with_index do |key, col|
|
113
|
+
worksheet.write(row, col, key)
|
115
114
|
end
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
fields.each do |fullkey|
|
115
|
+
collection.all.each_with_index do |record, index|
|
116
|
+
row = index + 1
|
117
|
+
serialized = serializer.new(record).attributes
|
118
|
+
fields.each_with_index do |fullkey, col|
|
121
119
|
value = serialized
|
122
120
|
fullkey.to_s.split(".").each do |key|
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
value = OpenStruct.new(value)
|
127
|
-
end
|
121
|
+
key = key.to_sym
|
122
|
+
if value.is_a?(Hash) && value.key?(key)
|
123
|
+
value = value[key]
|
128
124
|
else
|
129
125
|
value = nil
|
130
126
|
end
|
131
127
|
end
|
132
|
-
if value.is_a?(
|
133
|
-
|
134
|
-
elsif value.is_a?(Time)
|
135
|
-
line << '<Cell><Data ss:Type="String">'+value.strftime("%F %T")+'</Data></Cell>'
|
128
|
+
if value.is_a?(Time)
|
129
|
+
value = value.strftime("%F %T")
|
136
130
|
elsif value.is_a?(Date)
|
137
|
-
|
138
|
-
elsif value.is_a?(
|
139
|
-
|
140
|
-
|
141
|
-
|
131
|
+
value = value.strftime("%F")
|
132
|
+
elsif value.is_a?(TrueClass)
|
133
|
+
value = 'true'
|
134
|
+
elsif value.is_a?(FalseClass)
|
135
|
+
value = 'false'
|
142
136
|
end
|
137
|
+
value = (!value.is_a?(String)) ? '' : value
|
138
|
+
worksheet.write(row, col, value)
|
143
139
|
end
|
144
|
-
rows << "<Row>"+line.join+"</Row>"
|
145
140
|
end
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
141
|
+
workbook.close
|
142
|
+
data = open(filename).read
|
143
|
+
File.unlink(filename)
|
144
|
+
data
|
150
145
|
end
|
151
146
|
|
152
147
|
def pagination_links(collection, per_page, page)
|
@@ -0,0 +1,56 @@
|
|
1
|
+
module Backframe
|
2
|
+
module FilterSort
|
3
|
+
extend ActiveSupport::Concern
|
4
|
+
|
5
|
+
class_methods do
|
6
|
+
def filter_query(relation, filters, fields)
|
7
|
+
if filters.key?(:q)
|
8
|
+
conditions = []
|
9
|
+
params = []
|
10
|
+
fields.each do |field|
|
11
|
+
conditions << "LOWER(#{field}::VARCHAR) LIKE ?"
|
12
|
+
params << '%'+filters[:q].downcase+'%'
|
13
|
+
end
|
14
|
+
args = params.unshift(conditions.join(' OR '))
|
15
|
+
relation = relation.where(args)
|
16
|
+
end
|
17
|
+
relation
|
18
|
+
end
|
19
|
+
|
20
|
+
def filter_range(relation, filters, start_date, end_date = nil)
|
21
|
+
end_date ||= start_date
|
22
|
+
if filters.key?(:start_date) && filters.key?(:end_date)
|
23
|
+
relation = relation.where("#{self.table_name}.#{start_date} <= ? AND #{self.table_name}.#{end_date} >= ?", filters[:end_date], filters[:start_date])
|
24
|
+
end
|
25
|
+
relation
|
26
|
+
end
|
27
|
+
|
28
|
+
def filter_boolean(relation, filters, field)
|
29
|
+
if filters.key?(field)
|
30
|
+
relation = relation.where(:field => true) if filters[field] == 1
|
31
|
+
relation = relation.where(:field => false) if filters[field] == 0
|
32
|
+
end
|
33
|
+
relation
|
34
|
+
end
|
35
|
+
|
36
|
+
def sort(relation, key = nil, order = nil)
|
37
|
+
self._sort(relation, key, order, 'created_at', 'desc', [self])
|
38
|
+
end
|
39
|
+
|
40
|
+
def _sort(relation, key, order, default_key = 'created_at', default_order = 'desc', included = nil)
|
41
|
+
sortfields = {}
|
42
|
+
included ||= [self]
|
43
|
+
included.each do |model|
|
44
|
+
model.columns.each do |column|
|
45
|
+
sortkey = (model == self) ? column.name : "#{model.table_name.singularize}.#{column.name}"
|
46
|
+
sortfields[sortkey] = "\"#{model.table_name}\".\"#{column.name}\""
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
key = (key.present? && sortfields.has_key?(key)) ? key : default_key
|
51
|
+
order = (order.present?) ? order : default_order
|
52
|
+
relation.order("#{sortfields[key]} #{order}")
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
module Backframe
|
2
|
+
module Migration
|
3
|
+
extend ActiveSupport::Concern
|
4
|
+
|
5
|
+
class_methods do
|
6
|
+
|
7
|
+
def add_foreign_key_index(from, to, column)
|
8
|
+
add_foreign_key(from, to, :column => column)
|
9
|
+
add_index(from, column)
|
10
|
+
end
|
11
|
+
|
12
|
+
def remove_foreign_key_index(from, column)
|
13
|
+
add_index(from, column)
|
14
|
+
add_foreign_key(from, :column => column)
|
15
|
+
end
|
16
|
+
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,14 @@
|
|
1
|
+
module Backframe
|
2
|
+
class Railtie < ::Rails::Railtie
|
3
|
+
initializer 'backframe' do |_app|
|
4
|
+
ActionController::Base.send(:include, Backframe::API)
|
5
|
+
ActionController::Base.send(:include, Backframe::Resource)
|
6
|
+
ActiveRecord::Base.send(:include, Backframe::FilterSort)
|
7
|
+
ActiveRecord::Base.send(:include, Backframe::ActsAsOrderable)
|
8
|
+
ActiveRecord::Base.send(:include, Backframe::ActsAsUser)
|
9
|
+
ActiveRecord::Base.send(:include, Backframe::ActsAsStatus)
|
10
|
+
ActiveRecord::Migration.send(:include, Backframe::Migration)
|
11
|
+
Backframe::Mime.register_types
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
data/lib/backframe/version.rb
CHANGED
data/lib/backframe.rb
CHANGED
@@ -1,6 +1,12 @@
|
|
1
1
|
require 'backframe/api'
|
2
2
|
require 'backframe/mime'
|
3
3
|
require 'backframe/resource'
|
4
|
+
require 'backframe/filter_sort'
|
5
|
+
require 'backframe/acts_as_orderable'
|
6
|
+
require 'backframe/acts_as_status'
|
7
|
+
require 'backframe/acts_as_user'
|
8
|
+
require 'backframe/migration'
|
9
|
+
require 'write_xlsx'
|
4
10
|
|
5
11
|
module Backframe
|
6
12
|
module Exceptions
|
@@ -8,3 +14,7 @@ module Backframe
|
|
8
14
|
class Unauthorized < StandardError; end
|
9
15
|
end
|
10
16
|
end
|
17
|
+
|
18
|
+
if defined? Rails
|
19
|
+
require 'backframe/railtie'
|
20
|
+
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: backframe
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Greg Kops
|
@@ -11,6 +11,34 @@ bindir: bin
|
|
11
11
|
cert_chain: []
|
12
12
|
date: 2016-04-28 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: write_xlsx
|
16
|
+
requirement: !ruby/object:Gem::Requirement
|
17
|
+
requirements:
|
18
|
+
- - "~>"
|
19
|
+
- !ruby/object:Gem::Version
|
20
|
+
version: 0.83.0
|
21
|
+
type: :runtime
|
22
|
+
prerelease: false
|
23
|
+
version_requirements: !ruby/object:Gem::Requirement
|
24
|
+
requirements:
|
25
|
+
- - "~>"
|
26
|
+
- !ruby/object:Gem::Version
|
27
|
+
version: 0.83.0
|
28
|
+
- !ruby/object:Gem::Dependency
|
29
|
+
name: activerecord
|
30
|
+
requirement: !ruby/object:Gem::Requirement
|
31
|
+
requirements:
|
32
|
+
- - "~>"
|
33
|
+
- !ruby/object:Gem::Version
|
34
|
+
version: '4.0'
|
35
|
+
type: :runtime
|
36
|
+
prerelease: false
|
37
|
+
version_requirements: !ruby/object:Gem::Requirement
|
38
|
+
requirements:
|
39
|
+
- - "~>"
|
40
|
+
- !ruby/object:Gem::Version
|
41
|
+
version: '4.0'
|
14
42
|
- !ruby/object:Gem::Dependency
|
15
43
|
name: activesupport
|
16
44
|
requirement: !ruby/object:Gem::Requirement
|
@@ -66,12 +94,18 @@ files:
|
|
66
94
|
- Rakefile
|
67
95
|
- backframe.gemspec
|
68
96
|
- lib/backframe.rb
|
97
|
+
- lib/backframe/acts_as_orderable.rb
|
98
|
+
- lib/backframe/acts_as_status.rb
|
99
|
+
- lib/backframe/acts_as_user.rb
|
69
100
|
- lib/backframe/api.rb
|
70
101
|
- lib/backframe/api/adapter.rb
|
71
102
|
- lib/backframe/api/errors.rb
|
72
103
|
- lib/backframe/api/headers.rb
|
73
104
|
- lib/backframe/api/page.rb
|
105
|
+
- lib/backframe/filter_sort.rb
|
106
|
+
- lib/backframe/migration.rb
|
74
107
|
- lib/backframe/mime.rb
|
108
|
+
- lib/backframe/railtie.rb
|
75
109
|
- lib/backframe/resource.rb
|
76
110
|
- lib/backframe/resource/actions.rb
|
77
111
|
- lib/backframe/version.rb
|