base-project 0.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.
Files changed (39) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +37 -0
  3. data/.travis.yml +5 -0
  4. data/CODE_OF_CONDUCT.md +74 -0
  5. data/Gemfile +6 -0
  6. data/Gemfile.lock +196 -0
  7. data/README.md +43 -0
  8. data/Rakefile +6 -0
  9. data/base-project.gemspec +38 -0
  10. data/bin/console +14 -0
  11. data/bin/setup +8 -0
  12. data/lib/base/project.rb +7 -0
  13. data/lib/base/project/app/controllers/concerns/base_crud_controller.rb +104 -0
  14. data/lib/base/project/app/helpers/base_helper.rb +128 -0
  15. data/lib/base/project/app/helpers/button_helper.rb +101 -0
  16. data/lib/base/project/app/helpers/localizable_helper.rb +51 -0
  17. data/lib/base/project/app/helpers/panel_helper.rb +8 -0
  18. data/lib/base/project/app/models/concerns/addressable.rb +93 -0
  19. data/lib/base/project/app/models/concerns/base_user_concern.rb +39 -0
  20. data/lib/base/project/app/models/concerns/image_concern.rb +16 -0
  21. data/lib/base/project/app/models/concerns/localizable.rb +50 -0
  22. data/lib/base/project/app/models/concerns/scope_concern.rb +14 -0
  23. data/lib/base/project/app/validators/image_validator.rb +14 -0
  24. data/lib/base/project/app/views/_flash_messages.html.erb +12 -0
  25. data/lib/base/project/app/views/_menu.html.erb +16 -0
  26. data/lib/base/project/app/views/forms/_buttons.html.erb +4 -0
  27. data/lib/base/project/app/views/indexes/_buttons.html.erb +11 -0
  28. data/lib/base/project/app/views/indexes/_header.html.erb +10 -0
  29. data/lib/base/project/app/views/menu/_header_menu.html.erb +25 -0
  30. data/lib/base/project/app/views/menu/_sidebar.html.erb +44 -0
  31. data/lib/base/project/app/views/panels/_panel.html.erb +15 -0
  32. data/lib/base/project/app/views/versions/_model_dates.html.erb +12 -0
  33. data/lib/base/project/config/locales/error_pages.pt-BR.yml +9 -0
  34. data/lib/base/project/config/locales/pt-BR.yml +269 -0
  35. data/lib/base/project/config/locales/simple_form.pt-BR.yml +76 -0
  36. data/lib/base/project/lib/console_say.rb +17 -0
  37. data/lib/base/project/lib/string_sanitizer.rb +54 -0
  38. data/lib/base/project/version.rb +5 -0
  39. metadata +277 -0
@@ -0,0 +1,39 @@
1
+
2
+ module Base::Project::App::Models::Concerns::BaseUserConcern
3
+ extend ActiveSupport::Concern
4
+
5
+ included do
6
+ # Include default devise modules. Others available are:
7
+ # :confirmable, :lockable, :timeoutable and :omniauthable
8
+ devise :database_authenticatable, :registerable,
9
+ :recoverable, :rememberable, :trackable, :validatable
10
+
11
+ before_save :check_password_changed
12
+
13
+ normalize_attributes :cpf, with: :remove_punctuation, if: ->(_attr) { cpf.present? }
14
+ validates_cpf_format_of :cpf, if: ->(_attr) { cpf.present? }
15
+
16
+ validates :cpf, allow_blank: true, uniqueness: true
17
+ validates :name, presence: true, uniqueness: false
18
+ validates :email, presence: true, uniqueness: true, format: { with: Devise.email_regexp }
19
+ validates :updated_password, inclusion: { in: [true, false] }
20
+
21
+ scope :by_cpf, ->(cpf) { where("#{table_name}.cpf ILIKE ?", "%#{Base::Project::Lib::StringSanitizer.remove_punctuation(cpf)}%") }
22
+ scope :by_email, ->(email) { where("#{table_name}.email ILIKE ?", "%#{email}%") }
23
+ scope :by_name, ->(name) { where("unaccent(#{table_name}.name) ILIKE ?", "%#{name}%") }
24
+
25
+ def password_required?
26
+ new_record? ? false : super
27
+ end
28
+
29
+ private
30
+
31
+ def check_password_changed
32
+ if changed.include?('encrypted_password')
33
+ self.updated_password = attributes['encrypted_password'] != encrypted_password_was
34
+ end
35
+
36
+ nil
37
+ end
38
+ end
39
+ end
@@ -0,0 +1,16 @@
1
+
2
+ module Base::Project::App::Models::Concerns::ImageConcern
3
+ extend ActiveSupport::Concern
4
+
5
+ included do
6
+ has_attached_file :image, default_url: ':style/missing.png',
7
+ path: ':class/:id/:style.:extension',
8
+ styles: { regular: ['250x250#', :png],
9
+ big: ['500x500#', :png],
10
+ medium: ['300x300#', :png],
11
+ small: ['150x150#', :png],
12
+ thumb: ['50x50#', :png] }
13
+
14
+ validates_attachment :image, content_type: { content_type: /\Aimage\/.*\Z/ }, size: { less_than: 2.megabytes }
15
+ end
16
+ end
@@ -0,0 +1,50 @@
1
+ module Base::Project::App::Models::Concerns::Localizable
2
+ extend ActiveSupport::Concern
3
+
4
+ included do
5
+ scope :by_coord, ->(latitude, longitude) { near(latitude, longitude, 1) }
6
+
7
+ scope :near, ->(lat, lng, radius) {
8
+ d = ->(b) { destination_point(lat, lng, b, radius) }
9
+
10
+ where(['latitude BETWEEN ? AND ? AND longitude BETWEEN ? AND ?', d[180][:lat],
11
+ d[0][:lat],
12
+ d[270][:lng],
13
+ d[90][:lng]])
14
+ .where(['COALESCE(DISTANCE(?, ?, latitude, longitude), 0) < ?', lat, lng, radius])
15
+ .order(:id)
16
+ }
17
+ end
18
+
19
+ def coordinates
20
+ [longitude, latitude] if latitude && longitude
21
+ end
22
+
23
+ module ClassMethods
24
+ # Return destination point given distance and bearing from start point
25
+ def destination_point(lat, lng, initial_bearing, distance)
26
+ d2r = ->(x) { x * Math::PI / 180 }
27
+ r2d = ->(x) { x * 180 / Math::PI }
28
+
29
+ lat ||= 0
30
+ lng ||= 0
31
+
32
+ angular_distance = distance / 6371.0
33
+
34
+ lat1 = d2r.call(lat)
35
+ lng1 = d2r.call(lng)
36
+ bearing = d2r.call(initial_bearing)
37
+
38
+ lat2 = Math.asin(Math.sin(lat1) *
39
+ Math.cos(angular_distance) +
40
+ Math.cos(lat1) *
41
+ Math.sin(angular_distance) *
42
+ Math.cos(bearing))
43
+
44
+ lng2 = lng1 + Math.atan2(Math.sin(bearing) * Math.sin(angular_distance) * Math.cos(lat1),
45
+ Math.cos(angular_distance) - Math.sin(lat1) * Math.sin(lat2))
46
+
47
+ { lat: r2d.call(lat2).round(7), lng: r2d.call(lng2).round(7) }
48
+ end
49
+ end
50
+ end
@@ -0,0 +1,14 @@
1
+
2
+ module Base::Project::App::Models::Concerns::ScopeConcern
3
+ extend ActiveSupport::Concern
4
+
5
+ included do
6
+ scope :created_since, ->(time) { where("#{table_name}.created_at >= ?", Date.parse(time).beginning_of_day) }
7
+ scope :created_until, ->(time) { where("#{table_name}.created_at <= ?", Date.parse(time).end_of_day) }
8
+ scope :created_between, ->(from, to) { created_since(from).created_until(to) }
9
+
10
+ scope :updated_since, ->(time) { where("#{table_name}.updated_at >= ?", Date.parse(time).beginning_of_day) }
11
+ scope :updated_until, ->(time) { where("#{table_name}.updated_at <= ?", Date.parse(time).end_of_day) }
12
+ scope :updated_between, ->(from, to) { updated_since(from).updated_until(to) }
13
+ end
14
+ end
@@ -0,0 +1,14 @@
1
+
2
+
3
+ class Base::Project::App::Validators::ImageValidator < ActiveModel::EachValidator
4
+ def validate_each(record, attribute, value)
5
+ return if value.queued_for_write.blank? || value.queued_for_write[:original].blank?
6
+
7
+ dimensions = Paperclip::Geometry.from_file(value.queued_for_write[:original].path)
8
+ width = options[:width]
9
+ height = options[:height]
10
+
11
+ record.errors.add(attribute, I18n.t('activerecord.errors.image.width', value: width)) if dimensions.width > width
12
+ record.errors.add(attribute, I18n.t('activerecord.errors.image.height', value: height)) if dimensions.height > height
13
+ end
14
+ end
@@ -0,0 +1,12 @@
1
+ <div class="col-xs-12 m-0 p-0" id="alert-location">
2
+ <% flash.each do |type, message| %>
3
+ <% if message.kind_of?(Array) %>
4
+ <% message.each do |text| %>
5
+ <%= show_flash( type, text ) %>
6
+ <% end %>
7
+
8
+ <% else %>
9
+ <%= show_flash( type, message ) %>
10
+ <% end %>
11
+ <% end %>
12
+ </div>
@@ -0,0 +1,16 @@
1
+ <nav class="navbar navbar-default navbar-static-top" role="navigation" style="margin-bottom: 0">
2
+ <div class="navbar-header">
3
+ <button type="button" class="navbar-toggle" data-toggle="collapse" data-target=".navbar-collapse">
4
+ <span class="sr-only"><%= t('toggle_menu') %></span>
5
+ <span class="icon-bar"></span>
6
+ <span class="icon-bar"></span>
7
+ <span class="icon-bar"></span>
8
+ </button>
9
+
10
+ <%= image_tag 'android-icon-48x48', class: 'pull-left' %>
11
+ <%= brand_link %>
12
+ </div>
13
+
14
+ <%= render 'shared/menu/header_menu' %>
15
+ <%= render 'shared/menu/sidebar' %>
16
+ </nav>
@@ -0,0 +1,4 @@
1
+ <div class="col-xs-12 p-0 m-0 m-t-10">
2
+ <%= cancel_link(cancel_link) %>
3
+ <%= submit_link %>
4
+ </div>
@@ -0,0 +1,11 @@
1
+ <h2>
2
+ <div class="col-xs-12">
3
+ <%= round_icon_link button: 'btn-default', class: 'pull-left', icon: 'fa-arrow-left', path: back_link, title:t('simple_form.back') %>
4
+
5
+ <% if defined?(new_link) %>
6
+ <%= round_icon_link button: 'btn-default', class: 'pull-right m-l-5', icon: 'fa-plus', path: new_link, title: new_title %>
7
+ <% end %>
8
+
9
+ <%= round_icon_button type: :button, button: 'btn-info', icon: 'fa-filter', class: 'display-filters pull-right', title: t('filters.open_button') %>
10
+ </div>
11
+ </h2>
@@ -0,0 +1,10 @@
1
+ <h1 class="page-header">
2
+ <%= name %>
3
+
4
+ <% if defined?(parent) && parent %>
5
+ |
6
+ <span class="additional-page-header">
7
+ <%= link_to parent.name, url_for(parent), class: 'no-link' %>
8
+ </span>
9
+ <% end %>
10
+ </h1>
@@ -0,0 +1,25 @@
1
+ <ul class="nav navbar-top-links navbar-right">
2
+
3
+ <% if current_user %>
4
+ <li class="dropdown">
5
+ <a class="dropdown-toggle" data-toggle="dropdown" href="#">
6
+ <i class="fa fa-user fa-fw"></i>
7
+ <i class="fa fa-caret-down"></i>
8
+ </a>
9
+
10
+ <ul class="dropdown-menu dropdown-user">
11
+ <li>
12
+ <%= edit_profile_button %>
13
+ </li>
14
+
15
+ <% if current_user.updated_password %>
16
+ <li class="divider"></li>
17
+ <li>
18
+ <%= logout_button %>
19
+ </li>
20
+ <% end %>
21
+ </ul>
22
+ </li>
23
+ <% end %>
24
+
25
+ </ul>
@@ -0,0 +1,44 @@
1
+ <div class="navbar-default sidebar" role="navigation">
2
+ <div class="sidebar-nav navbar-collapse">
3
+
4
+ <% if current_user && current_user.updated_password %>
5
+ <ul class="nav in" id="side-menu">
6
+ <li class="sidebar-search">
7
+ <div class="input-group custom-search-form">
8
+ <input class="form-control" placeholder="<%= t('search_menu') %>" type="text">
9
+
10
+ <span class="input-group-btn">
11
+ <button class="btn btn-default" type="button">
12
+ <i class="fa fa-search"></i>
13
+ </button>
14
+ </span>
15
+ </div>
16
+ </li>
17
+
18
+ <% with_permission('dashboard|index') do %>
19
+ <li>
20
+ <%= icon_link(authenticated_user_path, 'fa fa-dashboard fa-fw', t('activerecord.models.dashboards.other')) %>
21
+ </li>
22
+ <% end %>
23
+
24
+ <% with_permission('user_type|index') do %>
25
+ <li>
26
+ <%= icon_link(user_types_path, 'fa fa-users fa-fw', t('activerecord.models.user_types.other')) %>
27
+ </li>
28
+ <% end %>
29
+
30
+ <% with_permission('employer|index') do %>
31
+ <li>
32
+ <%= icon_link(employers_path, 'fa fa-building-o fa-fw', t('activerecord.models.employers.other')) %>
33
+ </li>
34
+ <% end %>
35
+
36
+ <% with_permission('user|index') do %>
37
+ <li>
38
+ <%= icon_link(users_path, 'fa fa-users fa-fw', t('activerecord.models.users.other')) %>
39
+ </li>
40
+ <% end %>
41
+ </ul>
42
+ <% end %>
43
+ </div>
44
+ </div>
@@ -0,0 +1,15 @@
1
+ <div class="panel <%= color %>">
2
+ <div class="panel-heading">
3
+ <h4 class="panel-title">
4
+ <a data-toggle="collapse" href="#<%= panel_id %>" aria-expanded="true" class="">
5
+ <%= title %>
6
+ </a>
7
+ </h4>
8
+ </div>
9
+
10
+ <div id="<%= panel_id %>" class="panel-collapse collapse in" aria-expanded="true" style="">
11
+ <div class="panel-body">
12
+ <%= capture(&block) %>
13
+ </div>
14
+ </div>
15
+ </div>
@@ -0,0 +1,12 @@
1
+ <% if form.object.persisted? %>
2
+ <%= form.input :created_at, as: :string, wrapper_html: { class: 'col-xs-4' }, input_html: {disabled: true, value: localize(form.object.created_at, format: :small)} %>
3
+ <%= form.input :updated_at, as: :string, wrapper_html: { class: 'col-xs-4' }, input_html: {disabled: true, value: localize(form.object.updated_at, format: :small)} %>
4
+
5
+ <div class="form-group string optional client_whodunnit col-xs-4">
6
+ <label class="control-label string optional" for="client_whodunnit">
7
+ <%= t('activerecord.attributes.version.whodunnit') %>
8
+ </label>
9
+
10
+ <input class="form-control string optional" value="<%= form.object.versions.last.whodunnit%>" name="client[whodunnit]" id="client_whodunnit" type="text" disabled>
11
+ </div>
12
+ <% end %>
@@ -0,0 +1,9 @@
1
+ pt-BR:
2
+ error_pages:
3
+ code: Status %{code}
4
+ 401: Você não possui permissão para essa ação
5
+ 404: Infelizmente, não foi possível encontrar o recurso
6
+ 422: Não foi possível realizar a ação desejada
7
+ 500: Aconteceu um erro inesperado!
8
+ 503: O sistema está indisponível no momento
9
+ additional: Por favor, contate o Administrador do Sistema
@@ -0,0 +1,269 @@
1
+
2
+ pt-BR:
3
+ application_name: Envlab - Atmosférico
4
+ toggle_menu: Abre menu
5
+ search_menu: Pesquisar...
6
+ visualize_button: Visualizar
7
+
8
+ date:
9
+ abbr_day_names:
10
+ - Dom
11
+ - Seg
12
+ - Ter
13
+ - Qua
14
+ - Qui
15
+ - Sex
16
+ - Sáb
17
+
18
+ abbr_month_names:
19
+ -
20
+ - Jan
21
+ - Fev
22
+ - Mar
23
+ - Abr
24
+ - Mai
25
+ - Jun
26
+ - Jul
27
+ - Ago
28
+ - Set
29
+ - Out
30
+ - Nov
31
+ - Dez
32
+
33
+ day_names:
34
+ - Domingo
35
+ - Segunda-feira
36
+ - Terça-feira
37
+ - Quarta-feira
38
+ - Quinta-feira
39
+ - Sexta-feira
40
+ - Sábado
41
+
42
+ formats:
43
+ default: "%d/%m/%Y"
44
+ long: "%d de %B de %Y"
45
+ short: "%d de %B"
46
+ short_month: "%B %Y"
47
+
48
+ month_names:
49
+ -
50
+ - Janeiro
51
+ - Fevereiro
52
+ - Março
53
+ - Abril
54
+ - Maio
55
+ - Junho
56
+ - Julho
57
+ - Agosto
58
+ - Setembro
59
+ - Outubro
60
+ - Novembro
61
+ - Dezembro
62
+
63
+ order:
64
+ - :day
65
+ - :month
66
+ - :year
67
+
68
+ datetime:
69
+ distance_in_words:
70
+ about_x_hours:
71
+ one: aproximadamente 1 hora
72
+ other: aproximadamente %{count} horas
73
+
74
+ about_x_months:
75
+ one: aproximadamente 1 mês
76
+ other: aproximadamente %{count} meses
77
+
78
+ about_x_years:
79
+ one: aproximadamente 1 ano
80
+ other: aproximadamente %{count} anos
81
+
82
+ almost_x_years:
83
+ one: quase 1 ano
84
+ other: quase %{count} anos
85
+
86
+ half_a_minute: meio minuto
87
+
88
+ less_than_x_minutes:
89
+ one: menos de um minuto
90
+ other: menos de %{count} minutos
91
+
92
+ less_than_x_seconds:
93
+ one: menos de 1 segundo
94
+ other: menos de %{count} segundos
95
+
96
+ over_x_years:
97
+ one: mais de 1 ano
98
+ other: mais de %{count} anos
99
+
100
+ x_days:
101
+ one: 1 dia
102
+ other: "%{count} dias"
103
+
104
+ x_minutes:
105
+ one: 1 minuto
106
+ other: "%{count} minutos"
107
+
108
+ x_months:
109
+ one: 1 mês
110
+ other: "%{count} meses"
111
+
112
+ x_seconds:
113
+ one: 1 segundo
114
+ other: "%{count} segundos"
115
+
116
+ prompts:
117
+ day: Dia
118
+ hour: Hora
119
+ minute: Minuto
120
+ month: Mês
121
+ second: Segundo
122
+ year: Ano
123
+
124
+ errors:
125
+ connection_refused: Conexão recusada
126
+ format: "%{attribute} %{message}"
127
+
128
+ messages:
129
+ accepted: deve ser aceito
130
+ blank: não pode ficar em branco
131
+ present: deve ficar em branco
132
+ confirmation: não é igual a %{attribute}
133
+ empty: não pode ficar vazio
134
+ equal_to: deve ser igual a %{count}
135
+ even: deve ser par
136
+ exclusion: não está disponível
137
+ greater_than: deve ser maior que %{count}
138
+ greater_than_or_equal_to: deve ser maior ou igual a %{count}
139
+ in_between: "deve ter entre %{min} e %{max}"
140
+ inclusion: não está incluído na lista
141
+ invalid: não é válido
142
+ less_than: deve ser menor que %{count}
143
+ less_than_or_equal_to: deve ser menor ou igual a %{count}
144
+ model_invalid: 'A validação falhou: %{errors}'
145
+ not_a_number: não é um número
146
+ not_an_integer: não é um número inteiro
147
+ odd: deve ser ímpar
148
+ required: deve existir
149
+ spoofed_media_type: "tem uma extensão que não corresponde ao seu conteúdo"
150
+ taken: já está em uso
151
+
152
+ too_long:
153
+ one: 'é muito longo (máximo: 1 caracter)'
154
+ other: 'é muito longo (máximo: %{count} caracteres)'
155
+
156
+ too_short:
157
+ one: 'é muito curto (mínimo: 1 caracter)'
158
+ other: 'é muito curto (mínimo: %{count} caracteres)'
159
+
160
+ wrong_length:
161
+ one: não possui o tamanho esperado (1 caracter)
162
+ other: não possui o tamanho esperado (%{count} caracteres)
163
+
164
+ other_than: deve ser diferente de %{count}
165
+
166
+ template:
167
+ body: 'Por favor, verifique o(s) seguinte(s) campo(s):'
168
+
169
+ header:
170
+ one: 'Não foi possível gravar %{model}: 1 erro'
171
+ other: 'Não foi possível gravar %{model}: %{count} erros'
172
+
173
+ helpers:
174
+ select:
175
+ prompt: Por favor selecione
176
+
177
+ submit:
178
+ create: Criar %{model}
179
+ submit: Salvar %{model}
180
+ update: Atualizar %{model}
181
+
182
+ number:
183
+ currency:
184
+ format:
185
+ delimiter: "."
186
+ format: "%u %n"
187
+ precision: 2
188
+ separator: ","
189
+ significant: false
190
+ strip_insignificant_zeros: false
191
+ unit: R$
192
+
193
+ format:
194
+ delimiter: "."
195
+ precision: 3
196
+ separator: ","
197
+ significant: false
198
+ strip_insignificant_zeros: false
199
+
200
+ human:
201
+ decimal_units:
202
+ format: "%n %u"
203
+ units:
204
+ billion:
205
+ one: bilhão
206
+ other: bilhões
207
+
208
+ million:
209
+ one: milhão
210
+ other: milhões
211
+
212
+ quadrillion:
213
+ one: quatrilhão
214
+ other: quatrilhões
215
+
216
+ thousand: mil
217
+
218
+ trillion:
219
+ one: trilhão
220
+ other: trilhões
221
+
222
+ unit: ''
223
+
224
+ format:
225
+ delimiter: "."
226
+ precision: 2
227
+ significant: true
228
+ strip_insignificant_zeros: true
229
+
230
+ storage_units:
231
+ format: "%n %u"
232
+
233
+ units:
234
+ byte:
235
+ one: Byte
236
+ other: Bytes
237
+
238
+ gb: GB
239
+ kb: KB
240
+ mb: MB
241
+ tb: TB
242
+
243
+ percentage:
244
+ format:
245
+ delimiter: "."
246
+ format: "%n%"
247
+
248
+ precision:
249
+ format:
250
+ delimiter: "."
251
+
252
+ support:
253
+ array:
254
+ last_word_connector: " e "
255
+ two_words_connector: " e "
256
+ words_connector: ", "
257
+
258
+ time:
259
+ am: ''
260
+
261
+ formats:
262
+ default: "%a, %d de %B de %Y, %H:%M:%S %z"
263
+ long: "%d de %B de %Y, %H:%M"
264
+ short: "%d de %B, %H:%M"
265
+ small: "%d/%m/%y, %H:%M"
266
+
267
+ pm: ''
268
+
269
+ confirmation: 'Você tem certeza?'