sinatra-hexacta 0.0.2 → 0.3.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/lib/sinatra/extensions/antiquity.rb +34 -0
- data/lib/sinatra/extensions/date.rb +49 -0
- data/lib/sinatra/extensions/generalmail.rb +26 -0
- data/lib/sinatra/extensions/init.rb +8 -0
- data/lib/sinatra/extensions/mail.rb +35 -0
- data/lib/sinatra/extensions/mailbuilder.rb +38 -0
- data/lib/sinatra/extensions/mailsender.rb +88 -0
- data/lib/sinatra/extensions/notification.rb +44 -0
- data/lib/sinatra/handlers/errors.rb +11 -4
- data/lib/sinatra/handlers/init.rb +3 -1
- data/lib/sinatra/handlers/notifications.rb +17 -28
- data/lib/sinatra/handlers/params.rb +26 -0
- data/lib/sinatra/handlers/reports.rb +28 -1
- data/lib/sinatra/helpers/alerts.rb +27 -0
- data/lib/sinatra/helpers/cas.rb +92 -0
- data/lib/sinatra/helpers/charts.rb +21 -5
- data/lib/sinatra/helpers/init.rb +4 -0
- data/lib/sinatra/helpers/inputs.rb +3 -3
- data/lib/sinatra/helpers/libraries.rb +3 -3
- data/lib/sinatra/helpers/reports.rb +27 -0
- data/lib/sinatra/helpers/schedule.rb +68 -0
- data/lib/sinatra/helpers/subscriptions.rb +1 -1
- data/lib/sinatra/hexacta.rb +15 -9
- data/lib/sinatra/public/css/app.min.1.css +132 -6
- data/lib/sinatra/public/js/app.js +49 -42
- data/lib/sinatra/public/vendors/chartist/chartist-plugin-legend.js +237 -0
- data/lib/sinatra/public/vendors/typeahead.js/typeahead.bundle.min.js +1 -2
- data/lib/sinatra/views/alerts/empty.slim +7 -0
- data/lib/sinatra/views/alerts/error.slim +7 -0
- data/lib/sinatra/views/alerts/info.slim +7 -0
- data/lib/sinatra/views/alerts/warning.slim +7 -0
- data/lib/sinatra/views/charts/bar.slim +56 -0
- data/lib/sinatra/views/charts/gauge.slim +30 -0
- data/lib/sinatra/views/charts/{simple_line.slim → line.slim} +7 -8
- data/lib/sinatra/views/charts/pie.slim +34 -0
- data/lib/sinatra/views/charts/stacked_bar.slim +36 -0
- data/lib/sinatra/views/inputs/multiple_select.slim +4 -0
- data/lib/sinatra/views/inputs/select.slim +3 -0
- data/lib/sinatra/views/libraries/include_js_after.slim +0 -24
- data/lib/sinatra/views/libraries/include_js_before.slim +1 -0
- data/lib/sinatra/views/notifications.slim +37 -31
- data/lib/sinatra/views/notifications/form.slim +4 -4
- data/lib/sinatra/views/notifications/new.slim +4 -4
- data/lib/sinatra/views/notifications/widget.slim +9 -5
- data/lib/sinatra/views/reports/pick_date.slim +14 -0
- data/lib/sinatra/views/reports/pick_dates.slim +16 -0
- data/lib/sinatra/views/reports/pick_month.slim +14 -0
- data/lib/sinatra/views/reports/pick_year.slim +14 -0
- metadata +30 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: a6fb503a8966bb24d1526acd9e44a6b8f798967193f7b5c465c61b86c4eb4d76
|
4
|
+
data.tar.gz: 1896cd47708d90de659d4e7d5253d3588331fd2372234c7c1bc152783bbd75ff
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 2cbd2de133ebff3475d3d8f398d6588d264d6d310194b150e45a061a7d094f03dfe7288ef5b27bc1d9cecf663504fd793e0d0da9c9d47852ce327f04c5fc1e0b
|
7
|
+
data.tar.gz: ff26fc925028c9a03ca3af480c9292ed8a6ba6f463180d39625fb5a6ed896d13570f41e786a9d4038235ddfd950234e0e1ef402ee8be17085e8a8eb3670319c4
|
@@ -0,0 +1,34 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
class Antiquity
|
3
|
+
|
4
|
+
def initialize(periods)
|
5
|
+
@periods = periods.sort { |a,b| a.start_date <=> b.start_date }
|
6
|
+
end
|
7
|
+
|
8
|
+
def days
|
9
|
+
@periods.inject(0) { |total, period| total + period.days }
|
10
|
+
end
|
11
|
+
|
12
|
+
def months
|
13
|
+
@periods.inject(0) { |total, period| total + period.months }
|
14
|
+
end
|
15
|
+
|
16
|
+
def years
|
17
|
+
months.divmod(12).first
|
18
|
+
end
|
19
|
+
|
20
|
+
def to_s
|
21
|
+
date = (@periods.last && @periods.last.end_date) || Date.today
|
22
|
+
result = ""
|
23
|
+
return result if @periods.empty?
|
24
|
+
if date >= @periods.first.start_date
|
25
|
+
result += years > 1 ? "#{years} años" : "#{years} año" unless years == 0
|
26
|
+
result += ", " if years >= 1 && !(months.modulo(12).eql?(0))
|
27
|
+
result += months.modulo(12) > 1 ? "#{months.modulo(12)} meses" : "#{months.modulo(12)} mes" unless months.modulo(12) == 0
|
28
|
+
result += "#{(date - @periods.last.start_date).to_i} dias" if months.modulo(12) == 0 && years == 0 && date > @periods.last.start_date
|
29
|
+
result += "Hoy!" if months.modulo(12) == 0 && date == @periods.last.start_date
|
30
|
+
end
|
31
|
+
result += "En unos días..." if date < @periods.first.start_date
|
32
|
+
result
|
33
|
+
end
|
34
|
+
end
|
@@ -0,0 +1,49 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
class Date
|
3
|
+
|
4
|
+
def self.year(year=Date.today.year)
|
5
|
+
Date.new(year)
|
6
|
+
end
|
7
|
+
|
8
|
+
def january(day=nil)
|
9
|
+
day.nil?? self.change(month: 1) : self.change(month: 1, day: day)
|
10
|
+
end
|
11
|
+
|
12
|
+
def october(day=nil)
|
13
|
+
day.nil?? self.change(month: 10) : self.change(month: 10, day: day)
|
14
|
+
end
|
15
|
+
|
16
|
+
def december(day=nil)
|
17
|
+
day.nil?? self.change(month: 12) : self.change(month: 12, day: day)
|
18
|
+
end
|
19
|
+
|
20
|
+
def monday
|
21
|
+
self - (self.wday - 1) % 7
|
22
|
+
end
|
23
|
+
|
24
|
+
def weekend?
|
25
|
+
self.wday == 0 || self.wday == 6
|
26
|
+
end
|
27
|
+
|
28
|
+
def display
|
29
|
+
"#{Configuration::DAYS[self.wday]} #{self.day} de #{Configuration::MONTHS[self.month-1]} #{self.year == Date.today.year ? '' : self.year}"
|
30
|
+
end
|
31
|
+
|
32
|
+
def short_display
|
33
|
+
self.strftime('%d/%m/%Y')
|
34
|
+
end
|
35
|
+
|
36
|
+
def next_working_date
|
37
|
+
add_working_days(1)
|
38
|
+
end
|
39
|
+
|
40
|
+
def prev_working_date
|
41
|
+
add_working_days(-1)
|
42
|
+
end
|
43
|
+
|
44
|
+
def first_monday_before
|
45
|
+
return self if self.monday?
|
46
|
+
(self - 1).first_monday_before
|
47
|
+
end
|
48
|
+
|
49
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
class GeneralMail < Mail
|
3
|
+
|
4
|
+
def initialize(args)
|
5
|
+
super(args)
|
6
|
+
@subject = args[:subject]
|
7
|
+
@description = args[:description]
|
8
|
+
@link = args[:link]
|
9
|
+
end
|
10
|
+
|
11
|
+
def template
|
12
|
+
'general'
|
13
|
+
end
|
14
|
+
|
15
|
+
def subject
|
16
|
+
@subject
|
17
|
+
end
|
18
|
+
|
19
|
+
def values
|
20
|
+
data = {}
|
21
|
+
data["{description}"] = @description
|
22
|
+
data["{link}"] = @link
|
23
|
+
data
|
24
|
+
end
|
25
|
+
|
26
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
class Mail
|
3
|
+
|
4
|
+
def initialize(args)
|
5
|
+
@receivers = args[:to]
|
6
|
+
@sender = args[:from]
|
7
|
+
end
|
8
|
+
|
9
|
+
def template
|
10
|
+
raise Exception, "You have to override 'template' method in #{self.class}"
|
11
|
+
end
|
12
|
+
|
13
|
+
def subject
|
14
|
+
raise Exception, "You have to override 'subject' method in #{self.class}"
|
15
|
+
end
|
16
|
+
|
17
|
+
def values
|
18
|
+
raise Exception, "You have to override 'values' method in #{self.class}"
|
19
|
+
end
|
20
|
+
|
21
|
+
def to
|
22
|
+
_receivers = {}
|
23
|
+
@receivers.each { |user| _receivers[user.full_name] = "Persons" }
|
24
|
+
_receivers
|
25
|
+
end
|
26
|
+
|
27
|
+
def from
|
28
|
+
@sender ||= "apps@hexacta.com"
|
29
|
+
end
|
30
|
+
|
31
|
+
def send
|
32
|
+
MailSender.perform_async(self)
|
33
|
+
end
|
34
|
+
|
35
|
+
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
class MailBuilder
|
3
|
+
|
4
|
+
def to(receivers)
|
5
|
+
@to = receivers
|
6
|
+
return self
|
7
|
+
end
|
8
|
+
|
9
|
+
def from(sender)
|
10
|
+
@from = "#{sender.hxt_id}@hexacta.com"
|
11
|
+
return self
|
12
|
+
end
|
13
|
+
|
14
|
+
def subject(a_subject)
|
15
|
+
@subject = a_subject
|
16
|
+
return self
|
17
|
+
end
|
18
|
+
|
19
|
+
def description(a_description)
|
20
|
+
@description = a_description
|
21
|
+
return self
|
22
|
+
end
|
23
|
+
|
24
|
+
def link(a_link)
|
25
|
+
@link = a_link
|
26
|
+
return self
|
27
|
+
end
|
28
|
+
|
29
|
+
def send
|
30
|
+
@from ||= "apps@hexacta.com"
|
31
|
+
GeneralMail.new({ :to => @to,
|
32
|
+
:from => @from,
|
33
|
+
:subject => @subject,
|
34
|
+
:description => @description,
|
35
|
+
:link => @link
|
36
|
+
}).send
|
37
|
+
end
|
38
|
+
end
|
@@ -0,0 +1,88 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
require 'singleton'
|
3
|
+
require 'sucker_punch'
|
4
|
+
|
5
|
+
class MailSender
|
6
|
+
include SuckerPunch::Job
|
7
|
+
|
8
|
+
attr_reader :access_token, :expire, :refresh_token
|
9
|
+
|
10
|
+
def _do_connect(uri, form={},token=nil)
|
11
|
+
url = URI.parse("#{uri}")
|
12
|
+
http = Net::HTTP.new(url.host, url.port)
|
13
|
+
http.read_timeout = 1000
|
14
|
+
http.use_ssl = (url.scheme == 'https')
|
15
|
+
http.verify_mode = OpenSSL::SSL::VERIFY_NONE
|
16
|
+
header = { 'Content-Type' => 'application/x-www-form-urlencoded' }
|
17
|
+
header["Authorization"] = "Bearer #{token}" unless token.nil?
|
18
|
+
request = Net::HTTP::Post.new(url, header)
|
19
|
+
request.form_data = form
|
20
|
+
http.start { |http| http.request(request) }
|
21
|
+
end
|
22
|
+
|
23
|
+
def _authorize_mail
|
24
|
+
params = [ [ "grant_type", "password" ], [ "client_id", "MailApp" ], [ "client_secret", "MailAppPRD2018!" ] ]
|
25
|
+
response = _do_connect("https://comunicacion.hexacta.com:4443/apptoken",params)
|
26
|
+
if( response.is_a?( Net::HTTPSuccess ) )
|
27
|
+
token = JSON.parse(response.body)
|
28
|
+
@access_token = token["access_token"]
|
29
|
+
@refresh_token = token["refresh_token"]
|
30
|
+
@expire = DateTime.parse(token[".expires"])
|
31
|
+
else
|
32
|
+
NotificationSender.instance.send_error(nil,'Authorize mail failed',response.body)
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
def _build_map_values(mail_values)
|
37
|
+
values = []
|
38
|
+
for key in mail_values.keys
|
39
|
+
index = mail_values.keys.index(key)
|
40
|
+
values << ["MailValues[#{index}].Key", key]
|
41
|
+
values << ["MailValues[#{index}].Value", mail_values[key]]
|
42
|
+
end
|
43
|
+
values
|
44
|
+
end
|
45
|
+
|
46
|
+
def _build_to_map(to_map)
|
47
|
+
values = []
|
48
|
+
for key in to_map.keys
|
49
|
+
index = to_map.keys.index(key)
|
50
|
+
values << ["ResourcesRequest[#{index}].TypeGroup", to_map[key]]
|
51
|
+
values << ["ResourcesRequest[#{index}].Name", key]
|
52
|
+
end
|
53
|
+
values
|
54
|
+
end
|
55
|
+
|
56
|
+
def _expired?
|
57
|
+
expire.nil? || DateTime.now < expire
|
58
|
+
end
|
59
|
+
|
60
|
+
def do_send(mail)
|
61
|
+
begin
|
62
|
+
if _expired?
|
63
|
+
_authorize_mail
|
64
|
+
end
|
65
|
+
|
66
|
+
params = [ [ "ApplicationCode", 2009 ], [ "Name", mail.template ], [ "Subject", mail.subject ], [ "EmailAddress", mail.from ] ]
|
67
|
+
params = params + _build_map_values(mail.values) + _build_to_map(mail.to)
|
68
|
+
|
69
|
+
response = _do_connect("https://comunicacion.hexacta.com:4444/api/app/TemplateNotification/SendMail",params,@access_token)
|
70
|
+
|
71
|
+
if( !response.is_a?( Net::HTTPSuccess ) )
|
72
|
+
NotificationSender.instance.send_error(nil,'Send mail failed',response.body)
|
73
|
+
end
|
74
|
+
rescue StandardError => error
|
75
|
+
message = error.backtrace.join(',');
|
76
|
+
NotificationSender.instance.send_error(nil,"Mail send error",message)
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
def send(mail)
|
81
|
+
run(mail) #Async call
|
82
|
+
end
|
83
|
+
|
84
|
+
#For async method call
|
85
|
+
def perform(mail)
|
86
|
+
do_send(mail)
|
87
|
+
end
|
88
|
+
end
|
@@ -0,0 +1,44 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
require 'singleton'
|
3
|
+
|
4
|
+
class NotificationSender
|
5
|
+
include Singleton
|
6
|
+
|
7
|
+
def send_to(user,creator,title,message,label,link=nil)
|
8
|
+
notification = Notification.find_or_create(:user_id => user.id,
|
9
|
+
:creator_id => creator.id,
|
10
|
+
:title => title,
|
11
|
+
:message => message,
|
12
|
+
:label => label,
|
13
|
+
:link => link,
|
14
|
+
:creation_date => Date.today)
|
15
|
+
if link.nil?
|
16
|
+
notification.link = "/notifications/#{notification.id}"
|
17
|
+
notification.save
|
18
|
+
end
|
19
|
+
notification
|
20
|
+
end
|
21
|
+
|
22
|
+
def send_to_subscriptors(creator,title,message,label,link=nil)
|
23
|
+
Subscription.where(:label => label).all.each do |subscription|
|
24
|
+
notification = send_to(subscription.user,creator,title,message,label,link)
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
def send_error(creator,title,message)
|
29
|
+
Subscription.where(:label => 'error').all.each do |subscription|
|
30
|
+
creator = subscription.user if creator.nil?
|
31
|
+
notification = Notification.find(:user_id => subscription.user_id,
|
32
|
+
:creator_id => creator.id,
|
33
|
+
:title => title,
|
34
|
+
:message => message,
|
35
|
+
:label => 'error',
|
36
|
+
:read_date => nil)
|
37
|
+
if notification.nil?
|
38
|
+
notification = send_to(subscription.user,creator,title,message,'error')
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
end
|
43
|
+
|
44
|
+
end
|
@@ -3,20 +3,27 @@ module Sinatra
|
|
3
3
|
module ErrorHandler
|
4
4
|
extend Hexacta
|
5
5
|
|
6
|
+
def enable_errors
|
7
|
+
p "Enabling errors..."
|
8
|
+
ErrorHandler.setup_dir("/app/views/#{Hexacta::GEM_FILE_DIR}/errors")
|
9
|
+
|
10
|
+
error_template(404)
|
11
|
+
error_template(403)
|
12
|
+
error_template(500)
|
13
|
+
end
|
14
|
+
|
6
15
|
def error_template(code)
|
7
|
-
ErrorHandler.
|
16
|
+
ErrorHandler.copy_file("/lib/sinatra/views/errors/#{code}.slim","/app/views/#{Hexacta::GEM_FILE_DIR}/errors/#{code}.slim")
|
8
17
|
error code do
|
9
18
|
if code == 500
|
10
19
|
title = env['sinatra.error'].message.split(':')[0].gsub('#<','');
|
11
20
|
message = (["in #{request.url}"] + env['sinatra.error'].backtrace).join(',');
|
12
|
-
|
21
|
+
NotificationSender.instance.send_error(authenticated(User),title,message)
|
13
22
|
end
|
14
23
|
slim "#{Hexacta::GEM_FILE_DIR}/errors/#{code}".to_sym, locals: { :params => params }
|
15
24
|
end
|
16
25
|
end
|
17
26
|
|
18
|
-
p "Setting up errors directory..."
|
19
|
-
setup_dir("/app/views/#{Hexacta::GEM_FILE_DIR}/errors")
|
20
27
|
end
|
21
28
|
|
22
29
|
register ErrorHandler
|
@@ -3,71 +3,60 @@ module Sinatra
|
|
3
3
|
module NotificationHandler
|
4
4
|
extend Hexacta
|
5
5
|
|
6
|
-
def
|
6
|
+
def enable_notifications
|
7
|
+
p "Enabling notifications..."
|
8
|
+
NotificationHandler.setup_dir("/app/views/#{Hexacta::GEM_FILE_DIR}/notifications")
|
9
|
+
NotificationHandler.copy_file("/lib/sinatra/views/notifications.slim","/app/views/#{Hexacta::GEM_FILE_DIR}/notifications.slim")
|
10
|
+
NotificationHandler.copy_all_files("/lib/sinatra/views/notifications","/app/views/#{Hexacta::GEM_FILE_DIR}/notifications")
|
11
|
+
|
7
12
|
post '/notification' do
|
8
|
-
if params[
|
9
|
-
|
13
|
+
if params[:user_ids].blank?
|
14
|
+
NotificationSender.instance.send_to_subscriptors(authenticated(User),params[:title],params[:message],params[:label])
|
10
15
|
else
|
11
|
-
for id in params[
|
12
|
-
|
16
|
+
for id in params[:user_ids]
|
17
|
+
NotificationSender.instance.send_to(User.find(:id => id),authenticated(User),params[:title],params[:message],params[:label])
|
13
18
|
end
|
14
19
|
end
|
15
20
|
redirect back
|
16
21
|
end
|
17
|
-
end
|
18
22
|
|
19
|
-
def edit_notification
|
20
23
|
post '/notifications/:id' do |id|
|
21
24
|
Notification.where(:user_id => authenticated(User).id, :id => id).update(:read_date => Date.today)
|
22
25
|
200
|
23
26
|
end
|
24
|
-
end
|
25
27
|
|
26
|
-
def read_notifications
|
27
28
|
post '/notifications' do
|
28
|
-
Notification.where(:user_id => authenticated(User).id, :id => params[
|
29
|
+
Notification.where(:user_id => authenticated(User).id, :id => params[:ids]).update(:read_date => Date.today)
|
29
30
|
redirect back
|
30
31
|
end
|
31
|
-
end
|
32
32
|
|
33
|
-
def get_notification
|
34
33
|
get '/notifications/:id' do |id|
|
35
34
|
notification = Notification.find(:id => id)
|
36
35
|
redirect "/notifications" if notification.nil?
|
37
36
|
slim "#{Hexacta::GEM_FILE_DIR}/notifications/view".to_sym, locals: { :notification => notification }
|
38
37
|
end
|
39
|
-
end
|
40
38
|
|
41
|
-
def delete_notification
|
42
39
|
delete '/notifications/:id' do |id|
|
43
40
|
Notification.find(:user_id => authenticated(User).id, :id => id).destroy.to_hash.to_json.to_s
|
44
41
|
end
|
45
|
-
end
|
46
42
|
|
47
|
-
def delete_notifications
|
48
43
|
delete '/notifications' do
|
49
|
-
Notification.where(:user_id => authenticated(User).id, :id => params[
|
44
|
+
Notification.where(:user_id => authenticated(User).id, :id => params[:ids]).destroy.to_s
|
50
45
|
end
|
51
|
-
end
|
52
46
|
|
53
|
-
def get_notifications
|
54
47
|
get '/notifications' do
|
55
48
|
filters = params.select { |attribute| Notification.columns.include?(attribute.to_sym) }
|
56
|
-
params[
|
57
|
-
params[
|
58
|
-
limit = params[
|
59
|
-
offset = params[
|
49
|
+
params[:limit] = "20" if params[:limit].to_i < 20
|
50
|
+
params[:limit] = "100" if params[:limit].to_i > 100
|
51
|
+
limit = params[:limit].to_i
|
52
|
+
offset = params[:offset].to_i
|
60
53
|
|
61
|
-
query = Notification.where(:user_id => authenticated(User).id).where(filters.to_filter).order(
|
54
|
+
query = Notification.where(:user_id => authenticated(User).id).where(filters.to_filter).order(Sequel.desc(:id))
|
62
55
|
|
63
56
|
slim "#{Hexacta::GEM_FILE_DIR}/notifications".to_sym, locals: { :notifications => query.limit(limit).offset(offset*limit).all, :total => query.count, :filters => params, :query => query }
|
64
57
|
end
|
65
58
|
end
|
66
59
|
|
67
|
-
p "Setting up notifications directory..."
|
68
|
-
setup_dir("/app/views/#{Hexacta::GEM_FILE_DIR}/notifications")
|
69
|
-
symlink("/lib/sinatra/views/notifications.slim","/app/views/#{Hexacta::GEM_FILE_DIR}/notifications.slim")
|
70
|
-
symlink_all("/lib/sinatra/views/notifications","/app/views/#{Hexacta::GEM_FILE_DIR}/notifications")
|
71
60
|
end
|
72
61
|
|
73
62
|
register NotificationHandler
|