synerma-audits1984 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.
- checksums.yaml +7 -0
- data/MIT-LICENSE +20 -0
- data/README.md +77 -0
- data/Rakefile +19 -0
- data/app/assets/config/audits1984_manifest.js +2 -0
- data/app/assets/stylesheets/audits1984/application.css +15 -0
- data/app/assets/stylesheets/audits1984/bulma.min.css +1 -0
- data/app/assets/stylesheets/audits1984/forms.css +3 -0
- data/app/assets/stylesheets/audits1984/sessions.css +5 -0
- data/app/controllers/audits1984/application_controller.rb +25 -0
- data/app/controllers/audits1984/audits_controller.rb +43 -0
- data/app/controllers/audits1984/filtered_sessions_controller.rb +15 -0
- data/app/controllers/audits1984/filtered_sessions_scoped.rb +14 -0
- data/app/controllers/audits1984/sessions_controller.rb +16 -0
- data/app/helpers/audits1984/application_helper.rb +38 -0
- data/app/javascript/audits1984/application.js +2 -0
- data/app/jobs/audits1984/application_job.rb +4 -0
- data/app/mailers/audits1984/application_mailer.rb +6 -0
- data/app/models/audits1984/application_record.rb +5 -0
- data/app/models/audits1984/audit.rb +10 -0
- data/app/models/audits1984/current.rb +3 -0
- data/app/models/audits1984/filtered_sessions.rb +30 -0
- data/app/models/audits1984/session/auditable.rb +13 -0
- data/app/models/audits1984/session/iterable.rb +23 -0
- data/app/views/audits1984/sessions/_audit_form.html.erb +26 -0
- data/app/views/audits1984/sessions/_executed_code.html.erb +26 -0
- data/app/views/audits1984/sessions/_filter.html.erb +34 -0
- data/app/views/audits1984/sessions/_header.html.erb +14 -0
- data/app/views/audits1984/sessions/_session.html.erb +25 -0
- data/app/views/audits1984/sessions/_summary.html.erb +5 -0
- data/app/views/audits1984/sessions/index.html.erb +6 -0
- data/app/views/audits1984/sessions/show.html.erb +10 -0
- data/app/views/layouts/audits1984/_flash.html.erb +10 -0
- data/app/views/layouts/audits1984/application.html.erb +24 -0
- data/config/importmap.rb +2 -0
- data/config/routes.rb +9 -0
- data/db/migrate/20210810092639_create_auditing_tables.rb +12 -0
- data/lib/audits1984/engine.rb +46 -0
- data/lib/audits1984/version.rb +3 -0
- data/lib/audits1984.rb +13 -0
- data/lib/tasks/audits1984_tasks.rake +4 -0
- metadata +324 -0
@@ -0,0 +1,38 @@
|
|
1
|
+
require "rouge"
|
2
|
+
|
3
|
+
module Audits1984
|
4
|
+
module ApplicationHelper
|
5
|
+
include Audits1984::Engine.routes.url_helpers
|
6
|
+
def auditor_name_for(auditor)
|
7
|
+
if auditor == Audits1984::Current.auditor
|
8
|
+
"You"
|
9
|
+
else
|
10
|
+
auditor.public_send(Audits1984.auditor_name_attribute)
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
def format_date(date)
|
15
|
+
# <time datetime="2016-1-1">11:09 PM - 1 Jan 2016</time>
|
16
|
+
date.strftime("%Y-%m-%d")
|
17
|
+
end
|
18
|
+
|
19
|
+
def format_date_and_time(date)
|
20
|
+
# <time datetime="2016-1-1">11:09 PM - 1 Jan 2016</time>
|
21
|
+
date.strftime("%Y-%m-%d at %I:%m %P")
|
22
|
+
end
|
23
|
+
|
24
|
+
def highlighted_code_from(commands)
|
25
|
+
highlight_code commands.collect(&:statements).collect(&:strip).filter(&:present?).join("\n")
|
26
|
+
end
|
27
|
+
|
28
|
+
def highlight_code(source)
|
29
|
+
formatter = Rouge::Formatters::HTMLLinewise.new(Rouge::Formatters::HTML.new)
|
30
|
+
lexer = Rouge::Lexers::Ruby.new
|
31
|
+
formatter.format(lexer.lex(source)).html_safe
|
32
|
+
end
|
33
|
+
|
34
|
+
def sensitive_session_decoration(session)
|
35
|
+
"*" if session.sensitive?
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
@@ -0,0 +1,10 @@
|
|
1
|
+
module Audits1984
|
2
|
+
class Audit < Console1984::Base
|
3
|
+
belongs_to :session, class_name: "Console1984::Session", touch: true
|
4
|
+
belongs_to :auditor, class_name: Audits1984.auditor_class
|
5
|
+
|
6
|
+
enum :status, %i[ pending approved flagged ]
|
7
|
+
|
8
|
+
encrypts :notes
|
9
|
+
end
|
10
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
module Audits1984
|
2
|
+
class FilteredSessions
|
3
|
+
include ActiveModel::Model
|
4
|
+
include ActiveModel::Attributes
|
5
|
+
|
6
|
+
attribute :from_date, :date
|
7
|
+
attribute :to_date, :date
|
8
|
+
attribute :sensitive_only, :boolean
|
9
|
+
|
10
|
+
def self.resume(attributes)
|
11
|
+
new attributes&.with_indifferent_access&.slice(*attribute_names)
|
12
|
+
end
|
13
|
+
|
14
|
+
def to_h
|
15
|
+
attributes.compact.transform_values(&:to_s)
|
16
|
+
end
|
17
|
+
|
18
|
+
def all
|
19
|
+
sessions = Console1984::Session.order(created_at: :desc, id: :desc)
|
20
|
+
sessions = sessions.sensitive if sensitive_only
|
21
|
+
sessions = sessions.where("console1984_sessions.created_at >= ?", from_date.beginning_of_day) if from_date.present?
|
22
|
+
sessions = sessions.where("console1984_sessions.created_at <= ?", to_date.end_of_day) if to_date.present?
|
23
|
+
sessions
|
24
|
+
end
|
25
|
+
|
26
|
+
def pending_session_after(session)
|
27
|
+
all.pending.where("console1984_sessions.created_at < ? OR console1984_sessions.id < ?", session.created_at, session.id).first
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
module Audits1984::Session::Auditable
|
2
|
+
extend ActiveSupport::Concern
|
3
|
+
|
4
|
+
included do
|
5
|
+
has_many :audits, dependent: :destroy, class_name: "Audits1984::Audit"
|
6
|
+
|
7
|
+
scope :sensitive, -> { joins(:sensitive_accesses).distinct }
|
8
|
+
scope :reviewed, -> { joins(:audits).distinct }
|
9
|
+
scope :approved, -> { reviewed.where("audits.status": :approved) }
|
10
|
+
scope :flagged, -> { reviewed.where("audits.status": :flagged) }
|
11
|
+
scope :pending, -> { where.not(id: reviewed.distinct(false)) }
|
12
|
+
end
|
13
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
module Audits1984::Session::Iterable
|
2
|
+
extend ActiveSupport::Concern
|
3
|
+
|
4
|
+
# Loops through all the session commands in order, yielding lists grouped by
|
5
|
+
# its sensitive access record, or its absence
|
6
|
+
def each_batch_of_commands_grouped_by_sensitive_access
|
7
|
+
group = []
|
8
|
+
current_sensitive_access = nil
|
9
|
+
commands.includes(:sensitive_access).sorted_chronologically.each.with_index do |command, index|
|
10
|
+
current_sensitive_access = command.sensitive_access if index == 0
|
11
|
+
if index > 0 && command.sensitive_access != current_sensitive_access
|
12
|
+
yield current_sensitive_access, group
|
13
|
+
group = []
|
14
|
+
current_sensitive_access = command.sensitive_access
|
15
|
+
end
|
16
|
+
group << command
|
17
|
+
end
|
18
|
+
|
19
|
+
if group.present?
|
20
|
+
yield current_sensitive_access, group
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
<article class="panel mt-5">
|
2
|
+
<p class="panel-heading">
|
3
|
+
Your review
|
4
|
+
</p>
|
5
|
+
|
6
|
+
<div class="panel-block">
|
7
|
+
<%= form_with model: [session, audit], authenticity_token: true do |form| %>
|
8
|
+
<div class="field">
|
9
|
+
<div class="control is-fullwidth">
|
10
|
+
<%= form.label :from_date, "Notes" %>
|
11
|
+
<%= form.text_area :notes, class: "textarea", placeholder: "Enter optional comments..." %>
|
12
|
+
</div>
|
13
|
+
</div>
|
14
|
+
<div class="field is-grouped">
|
15
|
+
<div class="control">
|
16
|
+
<%= form.button name: "audit[status]", value: :approved, class: "button is-primary" do %>
|
17
|
+
Approve
|
18
|
+
<% end %>
|
19
|
+
<%= form.button name: "audit[status]", value: :flagged, class: "button is-danger" do %>
|
20
|
+
Flag as inappropriate
|
21
|
+
<% end %>
|
22
|
+
</div>
|
23
|
+
</div>
|
24
|
+
<% end %>
|
25
|
+
</div>
|
26
|
+
</article>
|
@@ -0,0 +1,26 @@
|
|
1
|
+
<style>
|
2
|
+
<%= Rouge::Theme.find('github').render(scope: '.highlight') %>
|
3
|
+
</style>
|
4
|
+
|
5
|
+
<% session.each_batch_of_commands_grouped_by_sensitive_access do |sensitive_access, commands| %>
|
6
|
+
<div class="card">
|
7
|
+
<div class="card-content">
|
8
|
+
<div class="media">
|
9
|
+
<div class="media-content">
|
10
|
+
<% if sensitive_access %>
|
11
|
+
<p class="title is-4">Sensitive access *</p>
|
12
|
+
<p class="subtitle is-6"><%= Rinku.auto_link(sensitive_access.justification).html_safe %></p>
|
13
|
+
<% else %>
|
14
|
+
<p class="title is-4">Protected access</p>
|
15
|
+
<% end %>
|
16
|
+
</div>
|
17
|
+
</div>
|
18
|
+
|
19
|
+
<div class="content">
|
20
|
+
<pre class="highlight">
|
21
|
+
<%= highlighted_code_from commands %>
|
22
|
+
</pre>
|
23
|
+
</div>
|
24
|
+
</div>
|
25
|
+
</div>
|
26
|
+
<% end %>
|
@@ -0,0 +1,34 @@
|
|
1
|
+
<nav class="panel">
|
2
|
+
<p class="panel-heading">
|
3
|
+
Filter console sessions
|
4
|
+
</p>
|
5
|
+
<div class="panel-block">
|
6
|
+
|
7
|
+
<%= form_with model: filtered_sessions, url: filtered_sessions_path, method: :put, authenticity_token: true do |form| %>
|
8
|
+
<div class="field is-grouped">
|
9
|
+
<div class="control">
|
10
|
+
<%= form.label :from_date, "From" %>
|
11
|
+
<%= form.date_field :from_date, class: "input" %>
|
12
|
+
</div>
|
13
|
+
|
14
|
+
<div class="control">
|
15
|
+
<%= form.label :to_date, "To" %>
|
16
|
+
<%= form.date_field :to_date, class: "input" %>
|
17
|
+
</div>
|
18
|
+
</div>
|
19
|
+
|
20
|
+
<div class="field">
|
21
|
+
<div class="control">
|
22
|
+
<%= form.label :sensitive_only, "Only with sensitive access", class: "checkbox" %>
|
23
|
+
<%= form.check_box :sensitive_only %>
|
24
|
+
</div>
|
25
|
+
</div>
|
26
|
+
|
27
|
+
<div class="field is-grouped">
|
28
|
+
<div class="control">
|
29
|
+
<%= form.submit "Filter", class: "button is-link" %>
|
30
|
+
</div>
|
31
|
+
</div>
|
32
|
+
<% end %>
|
33
|
+
</div>
|
34
|
+
</nav>
|
@@ -0,0 +1,14 @@
|
|
1
|
+
<h2 class="title"><%= Rinku.auto_link(session.reason).html_safe %> <%= sensitive_session_decoration(session) %></h2>
|
2
|
+
<h3 class="subtitle">by <%= session.user.username %>
|
3
|
+
<br> <%= format_date_and_time(session.created_at) %></h3>
|
4
|
+
|
5
|
+
<% if session.audits.any? %>
|
6
|
+
<ul class="mb-6">
|
7
|
+
<% session.audits.except(&:new_record?).each do |audit| %>
|
8
|
+
<li> <%= audit.status.humanize %>
|
9
|
+
by <%= auditor_name_for(audit.auditor) %>
|
10
|
+
on <%= format_date_and_time(audit.created_at) %>
|
11
|
+
</li>
|
12
|
+
<% end %>
|
13
|
+
</ul>
|
14
|
+
<% end %>
|
@@ -0,0 +1,25 @@
|
|
1
|
+
<%= link_to session_path(session) do %>
|
2
|
+
<article class="session media">
|
3
|
+
<div class="media-left">
|
4
|
+
<%= format_date session.created_at %>
|
5
|
+
</div>
|
6
|
+
<div class="media-content">
|
7
|
+
<div class="content">
|
8
|
+
<p>
|
9
|
+
<strong class="session__reason"><%= session.reason %></strong>
|
10
|
+
<%= sensitive_session_decoration(session) %>
|
11
|
+
<br>
|
12
|
+
by <%= session.user.username %>
|
13
|
+
</p>
|
14
|
+
</div>
|
15
|
+
</div>
|
16
|
+
|
17
|
+
<div class="session__status media-right">
|
18
|
+
<% if session.audits.any? %>
|
19
|
+
<%= session.audits.pluck(:status).collect(&:humanize).join(", ") %>
|
20
|
+
<% else %>
|
21
|
+
Pending
|
22
|
+
<% end %>
|
23
|
+
</div>
|
24
|
+
</article>
|
25
|
+
<% end %>
|
@@ -0,0 +1,6 @@
|
|
1
|
+
<%= render "audits1984/sessions/filter", filtered_sessions: @filtered_sessions %>
|
2
|
+
<%= render "audits1984/sessions/summary", sessions: @sessions %>
|
3
|
+
|
4
|
+
<div class="sessions">
|
5
|
+
<%= render partial: "audits1984/sessions/session", collection: @sessions, cached: true %>
|
6
|
+
</div>
|
@@ -0,0 +1,10 @@
|
|
1
|
+
<nav class="breadcrumb">
|
2
|
+
<ul>
|
3
|
+
<li><%= link_to "Sessions", sessions_path %></li>
|
4
|
+
<li class="is-active"><a href="#" aria-current="page">Session <%= @session.id %> by <%= @session.user.username %></a></li>
|
5
|
+
</ul>
|
6
|
+
</nav>
|
7
|
+
|
8
|
+
<%= render "audits1984/sessions/header", session: @session, audit: @audit %>
|
9
|
+
<%= render "audits1984/sessions/executed_code", session: @session %>
|
10
|
+
<%= render "audits1984/sessions/audit_form", session: @session, audit: @audit %>
|
@@ -0,0 +1,24 @@
|
|
1
|
+
<!DOCTYPE html>
|
2
|
+
<html>
|
3
|
+
<head>
|
4
|
+
<meta charset="utf-8">
|
5
|
+
<title><%= @title || "Audits1984" %></title>
|
6
|
+
<meta name="viewport" content="width=device-width, initial-scale=1">
|
7
|
+
|
8
|
+
<%= csrf_meta_tags %>
|
9
|
+
|
10
|
+
<%= stylesheet_link_tag "audits1984/bulma.min" %>
|
11
|
+
<%= javascript_importmap_tags "application", importmap: Audits1984.importmap %>
|
12
|
+
<%= stylesheet_link_tag "audits1984/application", media: :all, data: { turbo_track: :reload } %>
|
13
|
+
</head>
|
14
|
+
|
15
|
+
<body>
|
16
|
+
|
17
|
+
<section class="section">
|
18
|
+
<div class="container">
|
19
|
+
<%= render "layouts/audits1984/flash" %>
|
20
|
+
<%= yield %>
|
21
|
+
</div>
|
22
|
+
</section>
|
23
|
+
</body>
|
24
|
+
</html>
|
data/config/importmap.rb
ADDED
data/config/routes.rb
ADDED
@@ -0,0 +1,12 @@
|
|
1
|
+
class CreateAuditingTables < ActiveRecord::Migration[7.0]
|
2
|
+
def change
|
3
|
+
create_table :audits1984_audits do |t|
|
4
|
+
t.integer :status, default: 0, null: false
|
5
|
+
t.text :notes
|
6
|
+
t.references :session, null: false
|
7
|
+
t.references :auditor, null: false
|
8
|
+
|
9
|
+
t.timestamps
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end
|
@@ -0,0 +1,46 @@
|
|
1
|
+
require "console1984"
|
2
|
+
require "importmap-rails"
|
3
|
+
require "turbo-rails"
|
4
|
+
require "rinku"
|
5
|
+
|
6
|
+
module Audits1984
|
7
|
+
class Engine < ::Rails::Engine
|
8
|
+
isolate_namespace Audits1984
|
9
|
+
|
10
|
+
initializer "audits1984.middleware" do |app|
|
11
|
+
if app.config.api_only
|
12
|
+
app.middleware.use ActionDispatch::Flash
|
13
|
+
app.middleware.use ::Rack::MethodOverride
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
config.audits1984 = ActiveSupport::OrderedOptions.new
|
18
|
+
|
19
|
+
initializer "audits1984.config" do
|
20
|
+
config.audits1984.each do |key, value|
|
21
|
+
Audits1984.send("#{key}=", value)
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
initializer "audits1984.session" do
|
26
|
+
ActiveSupport.on_load(:console_1984_session) do
|
27
|
+
include Audits1984::Session::Auditable, Audits1984::Session::Iterable
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
initializer "audits1984.assets" do |app|
|
32
|
+
app.config.assets.paths << root.join("app/assets/stylesheets")
|
33
|
+
app.config.assets.paths << root.join("app/javascript")
|
34
|
+
app.config.assets.precompile << "audits1984_manifest.js"
|
35
|
+
end
|
36
|
+
|
37
|
+
initializer "audits1984.importmap", after: "importmap" do |app|
|
38
|
+
Audits1984.importmap.draw(root.join("config/importmap.rb"))
|
39
|
+
Audits1984.importmap.cache_sweeper(watches: root.join("app/javascript"))
|
40
|
+
|
41
|
+
ActiveSupport.on_load(:action_controller_base) do
|
42
|
+
before_action { Audits1984.importmap.cache_sweeper.execute_if_updated }
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
data/lib/audits1984.rb
ADDED
@@ -0,0 +1,13 @@
|
|
1
|
+
require "audits1984/version"
|
2
|
+
require "audits1984/engine"
|
3
|
+
|
4
|
+
require "zeitwerk"
|
5
|
+
loader = Zeitwerk::Loader.for_gem
|
6
|
+
loader.setup
|
7
|
+
|
8
|
+
module Audits1984
|
9
|
+
mattr_accessor :auditor_class, default: "::User"
|
10
|
+
mattr_accessor :auditor_name_attribute, default: :name
|
11
|
+
mattr_accessor :base_controller_class, default: "::ApplicationController"
|
12
|
+
mattr_accessor :importmap, default: Importmap::Map.new
|
13
|
+
end
|