lesli_audit 1.0.1 → 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.
Files changed (119) hide show
  1. checksums.yaml +4 -4
  2. data/app/assets/images/lesli_audit/audit-logo.svg +1 -72
  3. data/app/controllers/lesli_audit/dashboards_controller.rb +0 -2
  4. data/app/controllers/lesli_audit/logs_controller.rb +25 -0
  5. data/app/controllers/lesli_audit/requests_controller.rb +1 -1
  6. data/app/controllers/lesli_audit/users_controller.rb +2 -1
  7. data/app/controllers/lesli_audit/visitors_controller.rb +14 -0
  8. data/app/helpers/lesli_audit/{analytics_helper.rb → logs_helper.rb} +1 -1
  9. data/app/helpers/lesli_audit/user_journals_helper.rb +4 -0
  10. data/app/interfaces/lesli_audit/logger_interface.rb +53 -25
  11. data/app/models/lesli_audit/account.rb +7 -1
  12. data/app/models/lesli_audit/account_device.rb +5 -0
  13. data/app/models/lesli_audit/account_log.rb +11 -0
  14. data/app/models/lesli_audit/dashboard.rb +1 -2
  15. data/app/models/lesli_audit/user_journal.rb +7 -0
  16. data/app/models/lesli_audit/user_log.rb +7 -0
  17. data/app/models/lesli_audit/user_request.rb +1 -1
  18. data/app/{assets/config/lesli_audit_manifest.js → services/lesli_audit/log_service.rb} +14 -8
  19. data/app/services/lesli_audit/request_service.rb +1 -2
  20. data/app/services/lesli_audit/user_service.rb +146 -2
  21. data/app/services/lesli_audit/visitor_service.rb +239 -0
  22. data/app/views/lesli_audit/dashboards/_component-calendar.html.erb +0 -0
  23. data/app/views/lesli_audit/dashboards/show.html.erb +1 -1
  24. data/app/views/lesli_audit/logs/index.html.erb +23 -0
  25. data/app/views/lesli_audit/logs/show.html.erb +10 -0
  26. data/app/views/lesli_audit/partials/_navigation.html.erb +4 -5
  27. data/app/views/lesli_audit/requests/index.html.erb +1 -1
  28. data/app/views/lesli_audit/users/index.html.erb +66 -5
  29. data/app/views/lesli_audit/visitors/index.html.erb +118 -0
  30. data/config/routes.rb +8 -27
  31. data/{lib/vue/apps/dashboards/components/users.vue → db/migrate/v1.0/0501110110_create_lesli_audit_account_logs.rb} +20 -38
  32. data/{lib/vue/stores/users.js → db/migrate/v1.0/0501110210_create_lesli_audit_account_devices.rb} +18 -28
  33. data/{lib/vue/apps/dashboards/components/roles.vue → db/migrate/v1.0/0501120110_create_lesli_audit_user_logs.rb} +28 -45
  34. data/db/migrate/v1.0/{0503050110_create_lesli_audit_dashboards.rb → 0501120210_create_lesli_audit_user_journals.rb} +12 -4
  35. data/db/migrate/v1.0/{0503110010_create_lesli_audit_user_requests.rb → 0501120310_create_lesli_audit_user_requests.rb} +4 -3
  36. data/db/seed/devices.rb +76 -0
  37. data/db/seed/users.rb +117 -0
  38. data/db/seeds.rb +3 -2
  39. data/db/version_structure.rb +53 -0
  40. data/lib/lesli_audit/engine.rb +1 -0
  41. data/lib/lesli_audit/version.rb +2 -2
  42. data/readme.md +78 -25
  43. metadata +46 -94
  44. data/app/controllers/lesli_audit/analytics_controller.rb +0 -26
  45. data/app/helpers/lesli_audit/dashboard/components_helper.rb +0 -4
  46. data/app/models/lesli_audit/account/request.rb +0 -4
  47. data/app/models/lesli_audit/analytic.rb +0 -4
  48. data/app/models/lesli_audit/dashboard/component.rb +0 -18
  49. data/app/models/lesli_audit/request.rb +0 -4
  50. data/app/models/lesli_audit/user.rb +0 -4
  51. data/app/services/lesli_audit/account/activity_services.rb +0 -69
  52. data/app/services/lesli_audit/analytic_service.rb +0 -130
  53. data/app/services/lesli_audit/analytics/trend_services.rb +0 -84
  54. data/app/services/lesli_audit/analytics/visitor_service.rb +0 -172
  55. data/app/services/lesli_audit/users/activity_services.rb +0 -61
  56. data/app/services/lesli_audit/users/log_services.rb +0 -62
  57. data/app/services/lesli_audit/users/registration_services.rb +0 -62
  58. data/app/services/lesli_audit/users/role_services.rb +0 -61
  59. data/app/services/lesli_audit/users/working_hour_services.rb +0 -78
  60. data/app/views/lesli_audit/accounts/_account.html.erb +0 -2
  61. data/app/views/lesli_audit/accounts/_form.html.erb +0 -17
  62. data/app/views/lesli_audit/accounts/edit.html.erb +0 -10
  63. data/app/views/lesli_audit/accounts/index.html.erb +0 -14
  64. data/app/views/lesli_audit/accounts/new.html.erb +0 -9
  65. data/app/views/lesli_audit/accounts/show.html.erb +0 -10
  66. data/app/views/lesli_audit/analytics/_analytic.html.erb +0 -2
  67. data/app/views/lesli_audit/analytics/_form.html.erb +0 -17
  68. data/app/views/lesli_audit/analytics/edit.html.erb +0 -10
  69. data/app/views/lesli_audit/analytics/index.html.erb +0 -42
  70. data/app/views/lesli_audit/analytics/new.html.erb +0 -9
  71. data/app/views/lesli_audit/analytics/show.html.erb +0 -10
  72. data/app/views/lesli_audit/dashboard/components/_component.html.erb +0 -2
  73. data/app/views/lesli_audit/dashboard/components/_form.html.erb +0 -17
  74. data/app/views/lesli_audit/dashboard/components/edit.html.erb +0 -1
  75. data/app/views/lesli_audit/dashboard/components/index.html.erb +0 -14
  76. data/app/views/lesli_audit/dashboard/components/new.html.erb +0 -9
  77. data/app/views/lesli_audit/dashboard/components/show.html.erb +0 -1
  78. data/app/views/lesli_audit/dashboards/_dashboard.html.erb +0 -2
  79. data/app/views/lesli_audit/dashboards/_form.html.erb +0 -17
  80. data/app/views/lesli_audit/requests/_form.html.erb +0 -17
  81. data/app/views/lesli_audit/requests/_request.html.erb +0 -2
  82. data/app/views/lesli_audit/requests/edit.html.erb +0 -10
  83. data/app/views/lesli_audit/requests/new.html.erb +0 -9
  84. data/app/views/lesli_audit/requests/show.html.erb +0 -10
  85. data/app/views/lesli_audit/users/_form.html.erb +0 -17
  86. data/app/views/lesli_audit/users/_user.html.erb +0 -2
  87. data/app/views/lesli_audit/users/edit.html.erb +0 -10
  88. data/app/views/lesli_audit/users/new.html.erb +0 -9
  89. data/app/views/lesli_audit/users/show.html.erb +0 -10
  90. data/lib/scss/application.scss +0 -31
  91. data/lib/vue/application.js +0 -146
  92. data/lib/vue/apps/accounts/activities.vue +0 -48
  93. data/lib/vue/apps/analytics/index.vue +0 -56
  94. data/lib/vue/apps/analytics/trends.vue +0 -148
  95. data/lib/vue/apps/dashboards/show.vue +0 -8
  96. data/lib/vue/apps/requests/index.vue +0 -125
  97. data/lib/vue/apps/security/passwords.vue +0 -52
  98. data/lib/vue/apps/security/sessions.vue +0 -63
  99. data/lib/vue/apps/users/activities.vue +0 -49
  100. data/lib/vue/apps/users/index.vue +0 -89
  101. data/lib/vue/apps/users/logs.vue +0 -49
  102. data/lib/vue/apps/users/registrations.vue +0 -73
  103. data/lib/vue/apps/users/roles.vue +0 -70
  104. data/lib/vue/apps/users/workingHours.vue +0 -52
  105. data/lib/vue/components/requests.vue +0 -63
  106. data/lib/vue/components/visitors.vue +0 -76
  107. data/lib/vue/stores/accounts/activities.js +0 -87
  108. data/lib/vue/stores/analytics.js +0 -127
  109. data/lib/vue/stores/request.js +0 -70
  110. data/lib/vue/stores/security/password.js +0 -75
  111. data/lib/vue/stores/security/session.js +0 -78
  112. data/lib/vue/stores/translations.json +0 -162
  113. data/lib/vue/stores/users/activities.js +0 -76
  114. data/lib/vue/stores/users/logs.js +0 -74
  115. data/lib/vue/stores/users/registrations.js +0 -61
  116. data/lib/vue/stores/users/roles.js +0 -52
  117. data/lib/vue/stores/users/working_hours.js +0 -92
  118. /data/db/migrate/v1.0/{0503000110_create_lesli_audit_accounts.rb → 0501000110_create_lesli_audit_accounts.rb} +0 -0
  119. /data/db/migrate/v1.0/{0503100010_create_lesli_audit_account_requests.rb → 0501110310_create_lesli_audit_account_requests.rb} +0 -0
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 243d721faa43b0cdba37a620455872fd0f515bbae81e18fc6bf49c4490c3e5aa
4
- data.tar.gz: 983e1c3c7f1c44d2cea04996ca5f1060d797092c24c3e45c396fc1159ee8fda5
3
+ metadata.gz: 6a84c6870b0006a5609054e1c8a311a0b9d57a5220dc8c75c7841eae7ffd1e8c
4
+ data.tar.gz: 882412cf089844f7c36bb58d492396c521e673374e2a13da8dcd466c23a5dc7f
5
5
  SHA512:
6
- metadata.gz: 24214a6c519ed8554cc81df0fdd045eae85a7195e7057fa20a87620d1af56c43eaf43d9dd7f638ef85c3edc14fa0c7232e1efbaf2a8120516ea6b6a24f69642b
7
- data.tar.gz: f16f44e3ac62f688ce7aea3db2290ba5546175ce33cf511307382f22095af22d74cd0eafd93a253e9c63a22406fd77689de1fc0de38c1f061a0d33ec2bdf8c7c
6
+ metadata.gz: f3d60b2ebcd66549072ace0988c2c4ca40b832c2c50173960b9db99b9c4184d4c65488197633718aacaa568b10144d592d842f667430732cc57d8665e1055fc9
7
+ data.tar.gz: 7f2c3f56961cb0aaf60dab530de6a7fd30eaf29a64cfafbc84623ee96c50e7162581c9728adf5894fd68f1d290946f49e1136456a913c00cf80cd8ebe4128fd4
@@ -1,72 +1 @@
1
- <?xml version="1.0" encoding="UTF-8" standalone="no"?>
2
- <svg
3
- xmlns:dc="http://purl.org/dc/elements/1.1/"
4
- xmlns:cc="http://creativecommons.org/ns#"
5
- xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
6
- xmlns:svg="http://www.w3.org/2000/svg"
7
- xmlns="http://www.w3.org/2000/svg"
8
- xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
9
- xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
10
- inkscape:version="1.0 (4035a4f, 2020-05-01)"
11
- height="48.025002"
12
- width="43.825001"
13
- sodipodi:docname="iconfinder_186_2508414.svg"
14
- xml:space="preserve"
15
- viewBox="0 0 43.825001 48.025002"
16
- version="1.1"
17
- id="Layer_1"
18
- enable-background="new 0 0 48 48"><metadata
19
- id="metadata860"><rdf:RDF><cc:Work
20
- rdf:about=""><dc:format>image/svg+xml</dc:format><dc:type
21
- rdf:resource="http://purl.org/dc/dcmitype/StillImage" /></cc:Work></rdf:RDF></metadata><defs
22
- id="defs858" /><sodipodi:namedview
23
- inkscape:current-layer="Layer_1"
24
- inkscape:window-maximized="1"
25
- inkscape:window-y="23"
26
- inkscape:window-x="0"
27
- inkscape:cy="24"
28
- inkscape:cx="18.731461"
29
- inkscape:zoom="9.7781858"
30
- showgrid="false"
31
- id="namedview856"
32
- inkscape:window-height="953"
33
- inkscape:window-width="1680"
34
- inkscape:pageshadow="2"
35
- inkscape:pageopacity="0"
36
- guidetolerance="10"
37
- gridtolerance="10"
38
- objecttolerance="10"
39
- borderopacity="1"
40
- bordercolor="#666666"
41
- pagecolor="#ffffff" /><g
42
- transform="translate(-2.1)"
43
- id="g853"><g
44
- id="g837"><path
45
- id="path833"
46
- fill="#e6e6e5"
47
- d="M 26.4,0 H 6.5 C 4.1,0 2.1,2 2.1,4.4 v 39 c 0,2.4 2,4.4 4.4,4.4 h 30.7 c 2.4,0 4.4,-2 4.4,-4.4 V 15.3 C 36.7,10.3 30.3,3.9 26.4,0 Z" /><path
48
- id="path835"
49
- fill="#98d0f1"
50
- d="m 26.4,0 v 10.8 c 0,2.4 2,4.4 4.4,4.4 H 41.6 C 37.6,11.3 31.2,4.9 26.4,0 Z" /></g><g
51
- id="g841"><path
52
- id="path839"
53
- fill="#ec7b72"
54
- d="m 21.2,40.7 c -0.2,0 -0.4,-0.2 -0.5,-0.4 l -5.1,-21.4 -4.1,8.4 c -0.1,0.2 -0.3,0.3 -0.4,0.3 h -8 c -0.3,0 -0.5,-0.2 -0.5,-0.5 0,-0.3 0.2,-0.5 0.5,-0.5 h 7.7 l 4.6,-9.4 c 0.1,-0.2 0.3,-0.3 0.5,-0.3 0.2,0 0.4,0.2 0.4,0.4 l 5,20.7 2.6,-11.1 c 0.1,-0.2 0.3,-0.4 0.5,-0.4 h 4.1 l 1.7,-4.4 c 0.1,-0.2 0.3,-0.3 0.5,-0.3 0.2,0 0.4,0.2 0.5,0.4 l 3.5,12 L 36,27 c 0,-0.2 0.2,-0.4 0.5,-0.4 h 4.3 c 0.3,0 0.5,0.2 0.5,0.5 0,0.3 -0.2,0.5 -0.5,0.5 h -3.9 l -1.6,8.9 c 0,0.2 -0.2,0.4 -0.5,0.4 -0.2,0 -0.4,-0.1 -0.5,-0.4 l -3.7,-12.6 -1.3,3.4 c -0.1,0.2 -0.3,0.3 -0.5,0.3 h -4 l -3,12.8 c -0.1,0.1 -0.3,0.3 -0.6,0.3 z" /></g><g
55
- id="g851"><rect
56
- id="rect843"
57
- y="33.900002"
58
- x="33.700001"
59
- width="2.5"
60
- transform="matrix(0.7071,-0.7071,0.7071,0.7071,-15.9478,35.568)"
61
- height="6.3000002"
62
- fill="#333333" /><path
63
- id="path845"
64
- fill="#525252"
65
- d="m 18.5,20.6 c -4.2,4.2 -4.2,11 0,15.1 4.2,4.1 11,4.2 15.1,0 4.2,-4.2 4.2,-10.9 0,-15.1 -4.2,-4.2 -10.9,-4.2 -15.1,0 z m 13.2,13.2 c -3.1,3.1 -8.2,3.1 -11.3,0 -3.1,-3.1 -3.1,-8.2 0,-11.4 3.1,-3.1 8.2,-3.1 11.3,0 3.2,3.2 3.2,8.3 0,11.4 z" /><path
66
- id="path847"
67
- opacity="0.25"
68
- fill="#ffffff"
69
- d="m 30.6,23.9 c -2.4,-2.4 -6.3,-2.4 -8.7,0 0,0 0,0 0,0 l 1.7,1.7 c 0,0 0,0 0,0 2.1,-2.1 5.6,-2.1 7.7,0 0.4,0.4 0.8,0.9 1,1.4 -0.3,-1.1 -0.9,-2.2 -1.7,-3.1 z" /><path
70
- id="path849"
71
- fill="#ffcc67"
72
- d="m 37.5,34.5 c -0.3,-0.3 -0.8,-0.3 -1.1,0 v 0 l -4,4 v 0 c -0.3,0.3 -0.3,0.8 0,1.1 0.3,0.3 0.8,0.3 1.1,0 l 7.6,7.6 c 1.1,1.1 2.9,1.1 4,0 1.1,-1.1 1.1,-2.9 0,-4 l -7.6,-7.6 c 0.3,-0.3 0.3,-0.8 0,-1.1 z" /></g></g></svg>
1
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 43.8 48.09" fill="#0d52bf"><path stroke="#000" stroke-miterlimit="10" stroke-width=".25" d="M36.5 12.29c-4.3-4.3-9-9.1-12.2-12.2 3.7 3.8 8.4 8.5 12.2 12.2Z"/><path d="m19.2 38.09.1-.3q-.1 0-.2-.1z"/><path stroke="#000" stroke-miterlimit="10" stroke-width=".25" d="m39.5 15.29-3-3z"/><path d="m33.3 35.89.1-.4-.2.2z"/><path d="M31.26 40.61c-.13.04-.27.05-.41.05-.41 0-.79-.16-1.08-.45s-.44-.67-.44-1.08c0-.39.15-.75.4-1.03a11.2 11.2 0 0 1-5.7 1.55c-1.31 0-2.62-.24-3.88-.68l-.35 1.61c-.1.1-.3.3-.6.3-.2 0-.4-.2-.5-.4l-.56-2.45c-.8-.47-1.57-1.04-2.26-1.72a11.17 11.17 0 0 1-3.38-7.98c-.01-2.25.62-4.4 1.82-6.25l-.72-3.01-4.1 8.4c-.1.2-.3.3-.4.3H1c-.3 0-.5-.2-.5-.5s.2-.5.5-.5h7.7l4.6-9.4c.1-.2.3-.3.5-.3s.4.2.4.4l.86 3.58c.25-.31.52-.62.81-.91 4.45-4.46 11.7-4.46 16.16 0 1.82 1.82 2.95 4.14 3.27 6.63h3.4c.3 0 .5.2.5.5s-.2.5-.5.5h-3.32c0 .15.02.3.02.45 0 2.07-.57 4.06-1.61 5.81.6-.58 1.55-.58 2.14.01.29.29.44.67.44 1.08 0 .14-.02.28-.05.41l3.18 3.18V15.39l-.1-.1H28.7c-2.4 0-4.4-2-4.4-4.4V.09H4.4C2 .09 0 2.09 0 4.49v39c0 2.4 2 4.4 4.4 4.4h30.7c.95 0 1.82-.32 2.55-.89z"/><path d="m29.718 35.787 1.768-1.768 4.454 4.455-1.767 1.768z"/><path d="M16.37 20.66c-4.2 4.2-4.2 11 0 15.1s11 4.2 15.1 0c4.2-4.2 4.2-10.9 0-15.1s-10.9-4.2-15.1 0m13.2 13.2c-3.1 3.1-8.2 3.1-11.3 0s-3.1-8.2 0-11.4c3.1-3.1 8.2-3.1 11.3 0 3.2 3.2 3.2 8.3 0 11.4"/><path d="M28.47 23.96c-2.4-2.4-6.3-2.4-8.7 0l1.7 1.7c2.1-2.1 5.6-2.1 7.7 0 .4.4.8.9 1 1.4-.3-1.1-.9-2.2-1.7-3.1" style="isolation:isolate"/><path d="M35.37 34.56c-.3-.3-.8-.3-1.1 0l-4 4c-.3.3-.3.8 0 1.1s.8.3 1.1 0l7.6 7.6c1.1 1.1 2.9 1.1 4 0s1.1-2.9 0-4l-7.6-7.6c.3-.3.3-.8 0-1.1"/></svg>
@@ -32,7 +32,5 @@ Building a better future, one line of code at a time.
32
32
 
33
33
  module LesliAudit
34
34
  class DashboardsController < Lesli::Shared::DashboardsController
35
- def show
36
- end
37
35
  end
38
36
  end
@@ -0,0 +1,25 @@
1
+ module LesliAudit
2
+ class LogsController < ApplicationController
3
+ before_action :set_log, only: %i[ show ]
4
+
5
+ # GET /logs
6
+ def index
7
+ @logs = respond_with_pagination(LesliAudit::LogService.new(current_user, query).index)
8
+ end
9
+
10
+ # GET /logs/1
11
+ def show
12
+ end
13
+
14
+ private
15
+
16
+ def set_log
17
+ @log = Log.find(params.expect(:id))
18
+ end
19
+
20
+ # Only allow a list of trusted parameters through.
21
+ def log_params
22
+ params.fetch(:log, {})
23
+ end
24
+ end
25
+ end
@@ -35,7 +35,7 @@ module LesliAudit
35
35
 
36
36
  # GET /requests
37
37
  def index
38
- @requests = respond_as_pagination(LesliAudit::RequestService.new(current_user, query).index)
38
+ @requests = respond_with_pagination(LesliAudit::RequestService.new(current_user, query).index)
39
39
  end
40
40
  end
41
41
  end
@@ -34,7 +34,8 @@ module LesliAudit
34
34
 
35
35
  # GET /users
36
36
  def index
37
- @users = respond_as_successful(UserService.new(current_user, query).registrations)
37
+ @users = UserService.new(current_user, query).users
38
+ @working_hours = UserService.new(current_user, query).working_hours
38
39
  end
39
40
  end
40
41
  end
@@ -0,0 +1,14 @@
1
+ module LesliAudit
2
+ class VisitorsController < ApplicationController
3
+
4
+ # GET /analytics
5
+ def index
6
+ @visits = VisitorService.new(current_user, query).visits
7
+ @visitors = VisitorService.new(current_user, query).visitors
8
+ @requests = VisitorService.new(current_user, query).requests
9
+ @browsers = VisitorService.new(current_user, query).browsers
10
+ @devices = VisitorService.new(current_user, query).devices
11
+ @os = VisitorService.new(current_user, query).os
12
+ end
13
+ end
14
+ end
@@ -1,4 +1,4 @@
1
1
  module LesliAudit
2
- module AnalyticsHelper
2
+ module LogsHelper
3
3
  end
4
4
  end
@@ -0,0 +1,4 @@
1
+ module LesliAudit
2
+ module UserJournalsHelper
3
+ end
4
+ end
@@ -29,40 +29,32 @@ Building a better future, one line of code at a time.
29
29
  // · ~·~ ~·~ ~·~ ~·~ ~·~ ~·~ ~·~ ~·~ ~·~
30
30
  // ·
31
31
  =end
32
-
32
+ require 'device_detector'
33
33
  module LesliAudit
34
34
  module LoggerInterface
35
35
  def get_user_agent(as_string=true)
36
36
 
37
- http_user_agent = request.env["HTTP_USER_AGENT"]
38
-
39
37
  # parse user agent
40
- user_agent = UserAgent.parse(http_user_agent)
38
+ user_agent = DeviceDetector.new(request.env["HTTP_USER_AGENT"])
41
39
 
42
- user_agent_version = user_agent.version.to_a.first(2).join(".")
40
+ #user_agent_version = user_agent.version.to_a.first(2).join(".")
43
41
 
44
42
  # return user agent as object
45
- if as_string == false
46
- return {
47
- platform: user_agent.platform,
48
- os: user_agent.os,
49
- browser: user_agent.browser,
50
- version: user_agent_version
51
- }
52
- end
53
-
54
- # return user agent info as string
55
- "#{user_agent.platform} #{user_agent.os} - #{user_agent.browser} #{user_agent_version}"
43
+ {
44
+ platform: user_agent.os_name,
45
+ browser: user_agent.name,
46
+ device: user_agent.device_type
47
+ }
56
48
  end
57
49
 
58
50
  def log_requests
59
51
  log_account_requests
60
52
  log_user_requests
53
+ log_devices
61
54
  end
62
55
 
63
56
  def log_account_requests
64
- return unless Lesli.config.security.dig(:enable_analytics)
65
- return unless defined?(LesliAudit)
57
+ return unless Lesli.config.audit.dig(:enable_analytics)
66
58
  return unless current_user
67
59
 
68
60
  # Try to save a unique record for this request configuration
@@ -85,11 +77,10 @@ module LesliAudit
85
77
  # Track all user activity
86
78
  # this is disabled by default in the settings file
87
79
  def log_user_requests
88
- return unless Lesli.config.security.dig(:enable_analytics)
89
- return unless defined?(LesliAudit)
90
80
  return unless current_user
91
81
  return unless session[:user_session_id]
92
-
82
+ return unless Lesli.config.audit.dig(:enable_analytics)
83
+
93
84
  # Try to save a unique record for this request configuration
94
85
  current_user.account.audit.user_requests.upsert(
95
86
  {
@@ -97,18 +88,55 @@ module LesliAudit
97
88
  request_action: action_name,
98
89
  session_id: session[:user_session_id],
99
90
  user_id: current_user.id,
100
- request_count: 1,
101
- created_at: Date2.new.date.to_s
91
+ date: Date2.new.date.to_s,
92
+ request_count: 1
102
93
  },
103
94
 
104
95
  # group of columns to consider a request as unique
105
- unique_by: %i[request_controller request_action created_at user_id session_id],
96
+ unique_by: %i[request_controller request_action date user_id session_id],
97
+
98
+ # if request id is not unique
99
+ # - increase the counter for this configuration
100
+ # - update the datetime of the last request
101
+ on_duplicate: Arel.sql(
102
+ "request_count = lesli_audit_user_requests.request_count + 1,updated_at = #{LesliDate::Compatibility.db_now}"
103
+ )
104
+ )
105
+
106
+ return unless Lesli.config.audit.dig(:enable_journals)
107
+ current_user.account.audit.user_journals.create({
108
+ request_controller: controller_path,
109
+ request_action: action_name,
110
+ session_id: session[:user_session_id],
111
+ user_id: current_user.id,
112
+ date: Date2.new.date.to_s
113
+ })
114
+ end
115
+
116
+ def log_devices
117
+ return unless Lesli.config.audit.dig(:enable_analytics)
118
+ return unless current_user
119
+
120
+ user_agent = get_user_agent(false)
121
+
122
+ # Try to save a unique record for this request configuration
123
+ current_user.account.audit.account_devices.upsert(
124
+ {
125
+ :created_at => Date2.new.date.to_s,
126
+ :agent_platform => user_agent&.dig(:platform) || "unknown",
127
+ :agent_browser => user_agent&.dig(:browser) || "unknown",
128
+ :agent_device => user_agent&.dig(:device) || "unknown",
129
+ :agent_count => 1
130
+ },
131
+
132
+ # group of columns to consider a request as unique
133
+ unique_by: %i[agent_platform agent_browser agent_device created_at account_id],
106
134
 
107
135
  # if request id is not unique
108
136
  # - increase the counter for this configuration
109
137
  # - update the datetime of the last request
110
138
  on_duplicate: Arel.sql(
111
- 'request_count = lesli_audit_user_requests.request_count + 1'
139
+ 'agent_count = lesli_audit_account_devices.agent_count + 1'
112
140
  )
113
141
  )
114
142
  end
@@ -1,9 +1,15 @@
1
1
  module LesliAudit
2
2
  class Account < ApplicationRecord
3
3
  belongs_to :account, class_name: "Lesli::Account"
4
+ has_many :dashboards
5
+
6
+ has_many :account_logs
7
+ has_many :account_devices
4
8
  has_many :account_requests
9
+
10
+ has_many :user_logs
11
+ has_many :user_journals
5
12
  has_many :user_requests
6
- has_many :dashboards
7
13
 
8
14
  after_create :initialize_account
9
15
 
@@ -0,0 +1,5 @@
1
+ module LesliAudit
2
+ class AccountDevice < ApplicationRecord
3
+ belongs_to :account, class_name: 'Lesli::Account'
4
+ end
5
+ end
@@ -0,0 +1,11 @@
1
+ module LesliAudit
2
+ class AccountLog < ApplicationRecord
3
+ belongs_to :account, optional: true
4
+ belongs_to :user, class_name: "Lesli::User", optional: true
5
+
6
+ enum :operation, {
7
+ :account_creation => 'account_creation',
8
+ :account_initialization => 'account_initialization'
9
+ }
10
+ end
11
+ end
@@ -1,6 +1,5 @@
1
1
  module LesliAudit
2
2
  class Dashboard < Lesli::Shared::Dashboard
3
- self.table_name = "lesli_audit_dashboards"
4
- belongs_to :account
3
+ COMPONENTS = %i[calendar]
5
4
  end
6
5
  end
@@ -0,0 +1,7 @@
1
+ module LesliAudit
2
+ class UserJournal < ApplicationRecord
3
+ belongs_to :account
4
+ belongs_to :user, class_name: "Lesli::User"
5
+ belongs_to :session, class_name: "LesliShield::User::Session"
6
+ end
7
+ end
@@ -0,0 +1,7 @@
1
+ module LesliAudit
2
+ class UserLog < ApplicationRecord
3
+ belongs_to :account, optional: true
4
+ belongs_to :user, class_name: "Lesli::User"
5
+ belongs_to :session, class_name: "LesliShield::User::Session", optional: true
6
+ end
7
+ end
@@ -2,6 +2,6 @@ module LesliAudit
2
2
  class UserRequest < ApplicationRecord
3
3
  belongs_to :account
4
4
  belongs_to :user, class_name: "Lesli::User"
5
- belongs_to :session, class_name: "Lesli::User::Session"
5
+ belongs_to :session, class_name: "LesliShield::User::Session"
6
6
  end
7
7
  end
@@ -1,4 +1,4 @@
1
- /*
1
+ =begin
2
2
 
3
3
  Lesli
4
4
 
@@ -28,10 +28,16 @@ Building a better future, one line of code at a time.
28
28
 
29
29
  // · ~·~ ~·~ ~·~ ~·~ ~·~ ~·~ ~·~ ~·~ ~·~
30
30
  // ·
31
- */
32
-
33
- //= link_tree ../images/lesli_audit .png
34
- //= link_tree ../images/lesli_audit .jpg
35
- //= link_tree ../images/lesli_audit .svg
36
-
37
- //= link lesli_audit/application.css
31
+ =end
32
+
33
+ module LesliAudit
34
+ class LogService < Lesli::ApplicationLesliService
35
+
36
+ def index
37
+ current_user.logs.all
38
+ .order(created_at: :desc)
39
+ .page(query[:pagination][:page])
40
+ .per(query[:pagination][:perPage])
41
+ end
42
+ end
43
+ end
@@ -41,9 +41,8 @@ module LesliAudit
41
41
  def index
42
42
 
43
43
 
44
- requests = Account::Request.all
44
+ requests = current_user.requests
45
45
  .order(created_at: :desc)
46
- .order(request_count: :desc)
47
46
  .page(query[:pagination][:page])
48
47
  .per(query[:pagination][:perPage])
49
48
 
@@ -33,6 +33,143 @@ Building a better future, one line of code at a time.
33
33
  module LesliAudit
34
34
  class UserService < Lesli::ApplicationLesliService
35
35
 
36
+ def users
37
+ users = current_user.account.users
38
+
39
+ now = Time.current
40
+ last_30_days = 30.days.ago
41
+
42
+ stats = users.pick(
43
+ # total users
44
+ Arel.sql("COUNT(*)"),
45
+
46
+ # total deactivated users
47
+ Arel.sql("SUM(CASE WHEN active = 0 AND deleted_at IS NULL THEN 1 ELSE 0 END)"),
48
+
49
+ # total locked users
50
+ Arel.sql(
51
+ "SUM(CASE WHEN (
52
+ locked_at IS NOT NULL
53
+ OR locked_until > #{ActiveRecord::Base.connection.quote(Time.current)}
54
+ ) AND deleted_at IS NULL THEN 1 ELSE 0 END)"
55
+ ),
56
+
57
+ # total not confirmed users
58
+ Arel.sql("SUM(CASE WHEN confirmed_at IS NULL AND deleted_at IS NULL THEN 1 ELSE 0 END)"),
59
+
60
+ # total deleted users
61
+ Arel.sql("SUM(CASE WHEN deleted_at IS NOT NULL THEN 1 ELSE 0 END)"),
62
+
63
+ # users that never signed in
64
+ Arel.sql("SUM(CASE WHEN last_sign_in_at IS NULL AND deleted_at IS NULL THEN 1 ELSE 0 END)"),
65
+
66
+ # total active users for the last 30 days
67
+ Arel.sql("SUM(CASE WHEN last_sign_in_at >= #{ActiveRecord::Base.connection.quote(last_30_days)} AND deleted_at IS NULL THEN 1 ELSE 0 END)"),
68
+
69
+ # users with failed logins
70
+ Arel.sql("SUM(CASE WHEN failed_attempts > 0 AND deleted_at IS NULL THEN 1 ELSE 0 END)"),
71
+ )
72
+
73
+ summary = {
74
+ total_users: stats[0].to_i,
75
+ total_users_deactivated: stats[1].to_i,
76
+ total_users_locked: stats[2].to_i,
77
+ total_users_unconfirmed: stats[3].to_i,
78
+ total_users_deleted: stats[4].to_i,
79
+
80
+ total_users_never_signed_in: stats[5].to_i,
81
+ total_users_active_last_30_days: stats[6].to_i,
82
+ total_users_with_failed_attempts: stats[7].to_i
83
+ }
84
+
85
+ {
86
+ overview: [{
87
+ label: "Total users",
88
+ value: summary[:total_users],
89
+ percentage: 100,
90
+ color: "info"
91
+ }, {
92
+ label: "Deactivated users",
93
+ value: summary[:total_users_deactivated],
94
+ percentage: percentage(summary[:total_users_deactivated], summary[:total_users]),
95
+ color: "warning"
96
+ }, {
97
+ label: "Locked users",
98
+ value: summary[:total_users_locked],
99
+ percentage: percentage(summary[:total_users_locked], summary[:total_users]),
100
+ color: "danger"
101
+ }, {
102
+ label: "Unconfirmed users",
103
+ value: summary[:total_users_unconfirmed],
104
+ percentage: percentage(summary[:total_users_unconfirmed], summary[:total_users]),
105
+ color: "warning",
106
+ }, {
107
+ label: "Deleted users",
108
+ value: summary[:total_users_deleted],
109
+ percentage: percentage(summary[:total_users_deleted], summary[:total_users]),
110
+ color: "danger"
111
+ }],
112
+ attention_needed: [{
113
+ label: "Unconfirmed users",
114
+ value: summary[:total_users_unconfirmed],
115
+ color: "info",
116
+ icon: "user-add-line"
117
+ }, {
118
+ label: "Never signed in",
119
+ value: summary[:total_users_never_signed_in],
120
+ color: "warning",
121
+ icon: "time-line"
122
+ }, {
123
+ label: "Failed login attempts",
124
+ value: summary[:total_users_with_failed_attempts],
125
+ color: "danger",
126
+ icon: "shield-keyhole-line"
127
+ }, {
128
+ label: "Locked users",
129
+ value: summary[:total_users_locked],
130
+ color: "danger",
131
+ icon: "lock-line"
132
+ }]
133
+ }
134
+ end
135
+
136
+ def working_hours
137
+
138
+ group = 'day'
139
+
140
+ group_by = "DATE_TRUNC('month', lesli_audit_user_requests.date)" if group == 'month'
141
+ group_by = "DATE_TRUNC('week', lesli_audit_user_requests.date)" if group == 'week'
142
+ group_by = "DATE_TRUNC('day', lesli_audit_user_requests.date)" if group == 'day'
143
+
144
+ # compatibility for SQLite
145
+ if ActiveRecord::Base.connection.adapter_name == "SQLite"
146
+ group_by = "strftime('%Y-%m-%d', lesli_audit_user_requests.date)"
147
+ end
148
+
149
+ user_requests = current_user.account.users.joins(:requests)
150
+
151
+ user_requests = user_requests.select(
152
+ :id,
153
+ "lesli_users.id as user_id",
154
+ "lesli_users.email as user_email",
155
+ "#{group_by} date",
156
+ "min(lesli_audit_user_requests.created_at) as first_activity",
157
+ "max(lesli_audit_user_requests.updated_at) as last_activity",
158
+ "count(lesli_audit_user_requests.id) resources",
159
+ "sum(lesli_audit_user_requests.request_count) requests"
160
+ )
161
+
162
+ user_requests = user_requests.group(:user_id, group_by)
163
+
164
+ user_requests.map do |request|
165
+ request[:first_activity] = Date2.new(request[:first_activity]).time
166
+ request[:last_activity] = Date2.new(request[:last_activity]).time
167
+ request
168
+ end
169
+
170
+ user_requests.reverse
171
+ end
172
+
36
173
  def registrations
37
174
 
38
175
  #Get filters from the request
@@ -59,13 +196,20 @@ module LesliAudit
59
196
  .group(group_by)
60
197
  .count.map do |request|
61
198
  {
62
- :date => request[0],
63
- :count => request[1]
199
+ :xaxiskey => request[0],
200
+ :yaxiskey => request[1]
64
201
  }
65
202
  end
66
203
  end
67
204
 
68
205
  registrations
69
206
  end
207
+
208
+ private
209
+
210
+ def percentage(value, total)
211
+ return 0 if total.to_i.zero?
212
+ ((value.to_f / total) * 100).round
213
+ end
70
214
  end
71
215
  end