backframe 0.0.0 → 0.0.1
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.
- 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
|