loggable_activity 0.2.1c → 0.5.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.rubocop.yml +29 -42
- data/.vscode/commands.json +2 -2
- data/.vscode/terminals.json +8 -8
- data/CHANGELOG.md +0 -3
- data/CHEAT_SHEET.md +31 -0
- data/MIT-LICENSE +21 -0
- data/README.md +31 -45
- data/Rakefile +6 -4
- data/app/assets/config/loggable_activity_manifest.js +4 -0
- data/app/assets/javascripts/loggable_activity/application.js +2 -0
- data/app/assets/stylesheets/loggable_activity/application.scss +20 -0
- data/app/controllers/concerns/.keep +0 -0
- data/app/controllers/loggable_activity/activities_controller.rb +12 -0
- data/app/controllers/loggable_activity/application_controller.rb +6 -0
- data/app/helpers/loggable_activity/activities_helper.rb +17 -0
- data/app/helpers/loggable_activity/application_helper.rb +6 -0
- data/app/jobs/loggable_activity/application_job.rb +6 -0
- data/app/mailers/loggable_activity/application_mailer.rb +8 -0
- data/app/models/loggable_activity/application_record.rb +7 -0
- data/app/views/kaminari/kaminari-turbo-bootstrap/_first_page.html.erb +14 -0
- data/app/views/kaminari/kaminari-turbo-bootstrap/_gap.html.erb +8 -0
- data/app/views/kaminari/kaminari-turbo-bootstrap/_last_page.html.erb +13 -0
- data/app/views/kaminari/kaminari-turbo-bootstrap/_next_page.html.erb +13 -0
- data/app/views/kaminari/kaminari-turbo-bootstrap/_page.html.erb +14 -0
- data/app/views/kaminari/kaminari-turbo-bootstrap/_paginator.html.erb +27 -0
- data/app/views/kaminari/kaminari-turbo-bootstrap/_prev_page.html.erb +14 -0
- data/app/views/layouts/loggable_activity/application.html.erb +19 -0
- data/app/views/loggable_activity/activities/_activities.html.erb +56 -0
- data/app/views/loggable_activity/activities/index.html.erb +7 -0
- data/app/views/loggable_activity/activities/show.html.erb +2 -0
- data/config/initializers/kaminari_config.rb +14 -0
- data/config/routes.rb +7 -0
- data/{lib/generators/loggable_activity/templates/create_loggable_activities.rb → db/migrate/20240702092648_create_loggable_activity_tables.rb} +18 -10
- data/git-org/HEAD +1 -0
- data/git-org/config +7 -0
- data/git-org/description +1 -0
- data/git-org/hooks/applypatch-msg.sample +15 -0
- data/git-org/hooks/commit-msg.sample +24 -0
- data/git-org/hooks/fsmonitor-watchman.sample +174 -0
- data/git-org/hooks/post-update.sample +8 -0
- data/git-org/hooks/pre-applypatch.sample +14 -0
- data/git-org/hooks/pre-commit.sample +49 -0
- data/git-org/hooks/pre-merge-commit.sample +13 -0
- data/git-org/hooks/pre-push.sample +53 -0
- data/git-org/hooks/pre-rebase.sample +169 -0
- data/git-org/hooks/pre-receive.sample +24 -0
- data/git-org/hooks/prepare-commit-msg.sample +42 -0
- data/git-org/hooks/push-to-checkout.sample +78 -0
- data/git-org/hooks/update.sample +128 -0
- data/git-org/info/exclude +6 -0
- data/lib/loggable_activity/activity.rb +3 -3
- data/lib/{schemas → loggable_activity}/config_schema.json +3 -3
- data/lib/loggable_activity/configuration.rb +51 -74
- data/lib/loggable_activity/data_owner.rb +0 -1
- data/lib/loggable_activity/encryption.rb +16 -7
- data/lib/loggable_activity/encryption_key.rb +4 -7
- data/lib/loggable_activity/engine.rb +27 -0
- data/lib/loggable_activity/error.rb +0 -10
- data/lib/loggable_activity/hooks.rb +10 -5
- data/lib/loggable_activity/payload.rb +8 -11
- data/lib/loggable_activity/sanitizer.rb +6 -2
- data/lib/loggable_activity/services/base_payloads_builder.rb +14 -5
- data/lib/loggable_activity/services/destroy_payloads_builder.rb +2 -1
- data/lib/loggable_activity/services/payloads_builder.rb +9 -2
- data/lib/loggable_activity/services/update_payloads_builder.rb +30 -2
- data/lib/loggable_activity/version.rb +1 -1
- data/lib/loggable_activity.rb +51 -14
- data/lib/tasks/loggable_activity_tasks.rake +6 -0
- metadata +126 -114
- data/.document +0 -1
- data/.nojekyll +0 -1
- data/.rspec +0 -3
- data/CONSIDERTIONS.md +0 -129
- data/GETTING-STARTED.md +0 -119
- data/LICENSE.txt +0 -21
- data/PAYLOAD_EXAMPLE.md +0 -63
- data/ROADMAP.md +0 -23
- data/docs/LoggableActivity/Activity.html +0 -555
- data/docs/LoggableActivity/Configuration.html +0 -330
- data/docs/LoggableActivity/ConfigurationError.html +0 -148
- data/docs/LoggableActivity/DataOwner.html +0 -138
- data/docs/LoggableActivity/Encryption.html +0 -234
- data/docs/LoggableActivity/EncryptionError.html +0 -145
- data/docs/LoggableActivity/EncryptionKey.html +0 -351
- data/docs/LoggableActivity/Error.html +0 -145
- data/docs/LoggableActivity/Hooks.html +0 -759
- data/docs/LoggableActivity/Payload.html +0 -432
- data/docs/LoggableActivity/Services/BasePayloadsBuilder.html +0 -442
- data/docs/LoggableActivity/Services/DestroyPayloadsBuilder.html +0 -395
- data/docs/LoggableActivity/Services/PayloadsBuilder.html +0 -342
- data/docs/LoggableActivity/Services/UpdatePayloadsBuilder.html +0 -490
- data/docs/LoggableActivity/Services.html +0 -93
- data/docs/LoggableActivity.html +0 -102
- data/docs/created.rid +0 -14
- data/docs/css/fonts.css +0 -167
- data/docs/css/rdoc.css +0 -687
- data/docs/fonts/Lato-Light.ttf +0 -0
- data/docs/fonts/Lato-LightItalic.ttf +0 -0
- data/docs/fonts/Lato-Regular.ttf +0 -0
- data/docs/fonts/Lato-RegularItalic.ttf +0 -0
- data/docs/fonts/SourceCodePro-Bold.ttf +0 -0
- data/docs/fonts/SourceCodePro-Regular.ttf +0 -0
- data/docs/images/add.png +0 -0
- data/docs/images/arrow_up.png +0 -0
- data/docs/images/brick.png +0 -0
- data/docs/images/brick_link.png +0 -0
- data/docs/images/bug.png +0 -0
- data/docs/images/bullet_black.png +0 -0
- data/docs/images/bullet_toggle_minus.png +0 -0
- data/docs/images/bullet_toggle_plus.png +0 -0
- data/docs/images/date.png +0 -0
- data/docs/images/delete.png +0 -0
- data/docs/images/find.png +0 -0
- data/docs/images/loadingAnimation.gif +0 -0
- data/docs/images/macFFBgHack.png +0 -0
- data/docs/images/package.png +0 -0
- data/docs/images/page_green.png +0 -0
- data/docs/images/page_white_text.png +0 -0
- data/docs/images/page_white_width.png +0 -0
- data/docs/images/plugin.png +0 -0
- data/docs/images/ruby.png +0 -0
- data/docs/images/tag_blue.png +0 -0
- data/docs/images/tag_green.png +0 -0
- data/docs/images/transparent.png +0 -0
- data/docs/images/wrench.png +0 -0
- data/docs/images/wrench_orange.png +0 -0
- data/docs/images/zoom.png +0 -0
- data/docs/index.html +0 -99
- data/docs/js/darkfish.js +0 -97
- data/docs/js/navigation.js +0 -105
- data/docs/js/navigation.js.gz +0 -0
- data/docs/js/search.js +0 -110
- data/docs/js/search_index.js +0 -1
- data/docs/js/search_index.js.gz +0 -0
- data/docs/js/searcher.js +0 -229
- data/docs/js/searcher.js.gz +0 -0
- data/docs/table_of_contents.html +0 -617
- data/help/loggable_activity_help.txt +0 -19
- data/lib/generators/.DS_Store +0 -0
- data/lib/generators/loggable_activity/.DS_Store +0 -0
- data/lib/generators/loggable_activity/install_generator.rb +0 -109
- data/lib/generators/loggable_activity/templates/.DS_Store +0 -0
- data/lib/generators/loggable_activity/templates/binary_ids/create_loggable_activities.rb +0 -30
- data/lib/generators/loggable_activity/templates/config/locales/loggable_activity.en.yml +0 -36
- data/lib/generators/loggable_activity/templates/config/loggable_activity.yaml +0 -29
- data/lib/generators/loggable_activity/templates/loggable_activity.en.yaml +0 -36
- data/pkg/loggable_activity-0.1.35.gem +0 -0
- data/sig/loggable_activity.rbs +0 -4
- /data/{.rspec_status → app/assets/images/loggable_activity/.keep} +0 -0
- /data/lib/{generators/loggable_activity/templates → loggable_activity/concerns}/current_user.rb +0 -0
@@ -0,0 +1,78 @@
|
|
1
|
+
#!/bin/sh
|
2
|
+
|
3
|
+
# An example hook script to update a checked-out tree on a git push.
|
4
|
+
#
|
5
|
+
# This hook is invoked by git-receive-pack(1) when it reacts to git
|
6
|
+
# push and updates reference(s) in its repository, and when the push
|
7
|
+
# tries to update the branch that is currently checked out and the
|
8
|
+
# receive.denyCurrentBranch configuration variable is set to
|
9
|
+
# updateInstead.
|
10
|
+
#
|
11
|
+
# By default, such a push is refused if the working tree and the index
|
12
|
+
# of the remote repository has any difference from the currently
|
13
|
+
# checked out commit; when both the working tree and the index match
|
14
|
+
# the current commit, they are updated to match the newly pushed tip
|
15
|
+
# of the branch. This hook is to be used to override the default
|
16
|
+
# behaviour; however the code below reimplements the default behaviour
|
17
|
+
# as a starting point for convenient modification.
|
18
|
+
#
|
19
|
+
# The hook receives the commit with which the tip of the current
|
20
|
+
# branch is going to be updated:
|
21
|
+
commit=$1
|
22
|
+
|
23
|
+
# It can exit with a non-zero status to refuse the push (when it does
|
24
|
+
# so, it must not modify the index or the working tree).
|
25
|
+
die () {
|
26
|
+
echo >&2 "$*"
|
27
|
+
exit 1
|
28
|
+
}
|
29
|
+
|
30
|
+
# Or it can make any necessary changes to the working tree and to the
|
31
|
+
# index to bring them to the desired state when the tip of the current
|
32
|
+
# branch is updated to the new commit, and exit with a zero status.
|
33
|
+
#
|
34
|
+
# For example, the hook can simply run git read-tree -u -m HEAD "$1"
|
35
|
+
# in order to emulate git fetch that is run in the reverse direction
|
36
|
+
# with git push, as the two-tree form of git read-tree -u -m is
|
37
|
+
# essentially the same as git switch or git checkout that switches
|
38
|
+
# branches while keeping the local changes in the working tree that do
|
39
|
+
# not interfere with the difference between the branches.
|
40
|
+
|
41
|
+
# The below is a more-or-less exact translation to shell of the C code
|
42
|
+
# for the default behaviour for git's push-to-checkout hook defined in
|
43
|
+
# the push_to_deploy() function in builtin/receive-pack.c.
|
44
|
+
#
|
45
|
+
# Note that the hook will be executed from the repository directory,
|
46
|
+
# not from the working tree, so if you want to perform operations on
|
47
|
+
# the working tree, you will have to adapt your code accordingly, e.g.
|
48
|
+
# by adding "cd .." or using relative paths.
|
49
|
+
|
50
|
+
if ! git update-index -q --ignore-submodules --refresh
|
51
|
+
then
|
52
|
+
die "Up-to-date check failed"
|
53
|
+
fi
|
54
|
+
|
55
|
+
if ! git diff-files --quiet --ignore-submodules --
|
56
|
+
then
|
57
|
+
die "Working directory has unstaged changes"
|
58
|
+
fi
|
59
|
+
|
60
|
+
# This is a rough translation of:
|
61
|
+
#
|
62
|
+
# head_has_history() ? "HEAD" : EMPTY_TREE_SHA1_HEX
|
63
|
+
if git cat-file -e HEAD 2>/dev/null
|
64
|
+
then
|
65
|
+
head=HEAD
|
66
|
+
else
|
67
|
+
head=$(git hash-object -t tree --stdin </dev/null)
|
68
|
+
fi
|
69
|
+
|
70
|
+
if ! git diff-index --quiet --cached --ignore-submodules $head --
|
71
|
+
then
|
72
|
+
die "Working directory has staged changes"
|
73
|
+
fi
|
74
|
+
|
75
|
+
if ! git read-tree -u -m "$commit"
|
76
|
+
then
|
77
|
+
die "Could not update working tree to new HEAD"
|
78
|
+
fi
|
@@ -0,0 +1,128 @@
|
|
1
|
+
#!/bin/sh
|
2
|
+
#
|
3
|
+
# An example hook script to block unannotated tags from entering.
|
4
|
+
# Called by "git receive-pack" with arguments: refname sha1-old sha1-new
|
5
|
+
#
|
6
|
+
# To enable this hook, rename this file to "update".
|
7
|
+
#
|
8
|
+
# Config
|
9
|
+
# ------
|
10
|
+
# hooks.allowunannotated
|
11
|
+
# This boolean sets whether unannotated tags will be allowed into the
|
12
|
+
# repository. By default they won't be.
|
13
|
+
# hooks.allowdeletetag
|
14
|
+
# This boolean sets whether deleting tags will be allowed in the
|
15
|
+
# repository. By default they won't be.
|
16
|
+
# hooks.allowmodifytag
|
17
|
+
# This boolean sets whether a tag may be modified after creation. By default
|
18
|
+
# it won't be.
|
19
|
+
# hooks.allowdeletebranch
|
20
|
+
# This boolean sets whether deleting branches will be allowed in the
|
21
|
+
# repository. By default they won't be.
|
22
|
+
# hooks.denycreatebranch
|
23
|
+
# This boolean sets whether remotely creating branches will be denied
|
24
|
+
# in the repository. By default this is allowed.
|
25
|
+
#
|
26
|
+
|
27
|
+
# --- Command line
|
28
|
+
refname="$1"
|
29
|
+
oldrev="$2"
|
30
|
+
newrev="$3"
|
31
|
+
|
32
|
+
# --- Safety check
|
33
|
+
if [ -z "$GIT_DIR" ]; then
|
34
|
+
echo "Don't run this script from the command line." >&2
|
35
|
+
echo " (if you want, you could supply GIT_DIR then run" >&2
|
36
|
+
echo " $0 <ref> <oldrev> <newrev>)" >&2
|
37
|
+
exit 1
|
38
|
+
fi
|
39
|
+
|
40
|
+
if [ -z "$refname" -o -z "$oldrev" -o -z "$newrev" ]; then
|
41
|
+
echo "usage: $0 <ref> <oldrev> <newrev>" >&2
|
42
|
+
exit 1
|
43
|
+
fi
|
44
|
+
|
45
|
+
# --- Config
|
46
|
+
allowunannotated=$(git config --type=bool hooks.allowunannotated)
|
47
|
+
allowdeletebranch=$(git config --type=bool hooks.allowdeletebranch)
|
48
|
+
denycreatebranch=$(git config --type=bool hooks.denycreatebranch)
|
49
|
+
allowdeletetag=$(git config --type=bool hooks.allowdeletetag)
|
50
|
+
allowmodifytag=$(git config --type=bool hooks.allowmodifytag)
|
51
|
+
|
52
|
+
# check for no description
|
53
|
+
projectdesc=$(sed -e '1q' "$GIT_DIR/description")
|
54
|
+
case "$projectdesc" in
|
55
|
+
"Unnamed repository"* | "")
|
56
|
+
echo "*** Project description file hasn't been set" >&2
|
57
|
+
exit 1
|
58
|
+
;;
|
59
|
+
esac
|
60
|
+
|
61
|
+
# --- Check types
|
62
|
+
# if $newrev is 0000...0000, it's a commit to delete a ref.
|
63
|
+
zero=$(git hash-object --stdin </dev/null | tr '[0-9a-f]' '0')
|
64
|
+
if [ "$newrev" = "$zero" ]; then
|
65
|
+
newrev_type=delete
|
66
|
+
else
|
67
|
+
newrev_type=$(git cat-file -t $newrev)
|
68
|
+
fi
|
69
|
+
|
70
|
+
case "$refname","$newrev_type" in
|
71
|
+
refs/tags/*,commit)
|
72
|
+
# un-annotated tag
|
73
|
+
short_refname=${refname##refs/tags/}
|
74
|
+
if [ "$allowunannotated" != "true" ]; then
|
75
|
+
echo "*** The un-annotated tag, $short_refname, is not allowed in this repository" >&2
|
76
|
+
echo "*** Use 'git tag [ -a | -s ]' for tags you want to propagate." >&2
|
77
|
+
exit 1
|
78
|
+
fi
|
79
|
+
;;
|
80
|
+
refs/tags/*,delete)
|
81
|
+
# delete tag
|
82
|
+
if [ "$allowdeletetag" != "true" ]; then
|
83
|
+
echo "*** Deleting a tag is not allowed in this repository" >&2
|
84
|
+
exit 1
|
85
|
+
fi
|
86
|
+
;;
|
87
|
+
refs/tags/*,tag)
|
88
|
+
# annotated tag
|
89
|
+
if [ "$allowmodifytag" != "true" ] && git rev-parse $refname > /dev/null 2>&1
|
90
|
+
then
|
91
|
+
echo "*** Tag '$refname' already exists." >&2
|
92
|
+
echo "*** Modifying a tag is not allowed in this repository." >&2
|
93
|
+
exit 1
|
94
|
+
fi
|
95
|
+
;;
|
96
|
+
refs/heads/*,commit)
|
97
|
+
# branch
|
98
|
+
if [ "$oldrev" = "$zero" -a "$denycreatebranch" = "true" ]; then
|
99
|
+
echo "*** Creating a branch is not allowed in this repository" >&2
|
100
|
+
exit 1
|
101
|
+
fi
|
102
|
+
;;
|
103
|
+
refs/heads/*,delete)
|
104
|
+
# delete branch
|
105
|
+
if [ "$allowdeletebranch" != "true" ]; then
|
106
|
+
echo "*** Deleting a branch is not allowed in this repository" >&2
|
107
|
+
exit 1
|
108
|
+
fi
|
109
|
+
;;
|
110
|
+
refs/remotes/*,commit)
|
111
|
+
# tracking branch
|
112
|
+
;;
|
113
|
+
refs/remotes/*,delete)
|
114
|
+
# delete tracking branch
|
115
|
+
if [ "$allowdeletebranch" != "true" ]; then
|
116
|
+
echo "*** Deleting a tracking branch is not allowed in this repository" >&2
|
117
|
+
exit 1
|
118
|
+
fi
|
119
|
+
;;
|
120
|
+
*)
|
121
|
+
# Anything else (is there anything else?)
|
122
|
+
echo "*** Update hook: unknown type of update to ref $refname of type $newrev_type" >&2
|
123
|
+
exit 1
|
124
|
+
;;
|
125
|
+
esac
|
126
|
+
|
127
|
+
# --- Finished
|
128
|
+
exit 0
|
@@ -5,7 +5,6 @@ require 'active_record'
|
|
5
5
|
module LoggableActivity
|
6
6
|
# Represents one action in the activity log.
|
7
7
|
class Activity < ActiveRecord::Base
|
8
|
-
self.table_name = 'loggable_activities'
|
9
8
|
# Associations
|
10
9
|
has_many :payloads, class_name: '::LoggableActivity::Payload', dependent: :destroy
|
11
10
|
belongs_to :actor, polymorphic: true, optional: true
|
@@ -33,7 +32,7 @@ module LoggableActivity
|
|
33
32
|
'belongs_to_payload' => 'belongs_to',
|
34
33
|
'belongs_to_destroy_payload' => 'belongs_to',
|
35
34
|
'belongs_to_update_payload' => 'belongs_to'
|
36
|
-
}
|
35
|
+
}.freeze
|
37
36
|
|
38
37
|
# Returns an array of hashes, each representing an activity's attributes and its associated relations. The structure and relations to include are specified in 'config/loggable_activity.yaml'. This format is designed for UI display purposes.
|
39
38
|
#
|
@@ -72,7 +71,8 @@ module LoggableActivity
|
|
72
71
|
route: payload.payload_route,
|
73
72
|
record_display_name: payload.record_display_name,
|
74
73
|
current_payload: payload.current_payload,
|
75
|
-
data_owner: payload.data_owner
|
74
|
+
data_owner: payload.data_owner,
|
75
|
+
public_attrs: payload.public_attrs
|
76
76
|
}
|
77
77
|
end
|
78
78
|
end
|
@@ -5,7 +5,7 @@
|
|
5
5
|
"current_user_model_name": {
|
6
6
|
"type": "string"
|
7
7
|
},
|
8
|
-
"
|
8
|
+
"current_user_name": {
|
9
9
|
"type": "string"
|
10
10
|
},
|
11
11
|
"task_for_sanitization": {
|
@@ -13,7 +13,7 @@
|
|
13
13
|
}
|
14
14
|
},
|
15
15
|
"patternProperties": {
|
16
|
-
"^(?!current_user_model_name$|
|
16
|
+
"^(?!current_user_model_name$|current_user_name$|task_for_sanitization)[A-Za-z0-9_:]+$": {
|
17
17
|
"type": "object",
|
18
18
|
"properties": {
|
19
19
|
"data_owner": {
|
@@ -91,6 +91,6 @@
|
|
91
91
|
"additionalProperties": false,
|
92
92
|
"required": [
|
93
93
|
"current_user_model_name",
|
94
|
-
"
|
94
|
+
"current_user_name"
|
95
95
|
]
|
96
96
|
}
|
@@ -4,91 +4,68 @@ require 'json-schema'
|
|
4
4
|
require 'json'
|
5
5
|
|
6
6
|
module LoggableActivity
|
7
|
-
# This class is used to load the configuration file located at config/loggable_activity.yml
|
8
|
-
class ConfigurationError < StandardError
|
9
|
-
def initialize(msg = '')
|
10
|
-
# https://api.loggable_activity.com/msg
|
11
|
-
puts '---------------- LOGGABLE ACTIVITY -----------------'
|
12
|
-
puts msg
|
13
|
-
puts '----------------------------------------------------'
|
14
|
-
super(msg)
|
15
|
-
end
|
16
|
-
end
|
17
|
-
|
18
7
|
# This class is used to load the configuration file located at config/loggable_activity.yml
|
19
8
|
# When the LoggableActivity::Hook is included in a model
|
20
9
|
# it takes the model's name and find the configuration for that model in the configuration file.
|
21
10
|
class Configuration
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
end
|
29
|
-
|
30
|
-
# Loads the schema file for the configuration file
|
31
|
-
def self.load_schema
|
32
|
-
schema_path = File.join(__dir__, '..', 'schemas', 'config_schema.json')
|
33
|
-
JSON.parse(File.read(schema_path))
|
34
|
-
end
|
35
|
-
|
36
|
-
# Validates the configuration file againss the schema
|
37
|
-
def self.validate_config_file
|
38
|
-
schema = load_schema
|
39
|
-
errors = JSON::Validator.fully_validate(schema, @config_data)
|
40
|
-
return unless errors.any?
|
11
|
+
class << self
|
12
|
+
# Loads the schema file for the configuration file
|
13
|
+
def load_schema
|
14
|
+
schema_path = File.join(__dir__, 'config_schema.json')
|
15
|
+
JSON.parse(File.read(schema_path))
|
16
|
+
end
|
41
17
|
|
42
|
-
|
43
|
-
|
44
|
-
|
18
|
+
# Loads the configuration file, and store it as a hash
|
19
|
+
def config_data
|
20
|
+
@config_data ||= YAML.load_file(LoggableActivity.config_file_path)
|
21
|
+
end
|
45
22
|
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
23
|
+
# Validates the configuration file againss the schema
|
24
|
+
def validate_config_file
|
25
|
+
schema = load_schema
|
26
|
+
errors = JSON::Validator.fully_validate(schema, config_data)
|
27
|
+
return true unless errors.any?
|
50
28
|
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
attr_reader :config_data
|
55
|
-
end
|
29
|
+
raise ConfigurationError,
|
30
|
+
"config/loggable_activity.yaml is invalid: #{errors.join(', ')}"
|
31
|
+
end
|
56
32
|
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
33
|
+
# Returns the configuration data for the given class
|
34
|
+
#
|
35
|
+
# Example:
|
36
|
+
# ::LoggableActivity::Configuration.for_class('User')
|
37
|
+
# Returns:
|
38
|
+
# {
|
39
|
+
# "fetch_record_name_from": "full_name",
|
40
|
+
# "loggable_attrs": [
|
41
|
+
# "first_name",
|
42
|
+
# "last_name",
|
43
|
+
# ],
|
44
|
+
# "auto_log": [
|
45
|
+
# "create",
|
46
|
+
# "update",
|
47
|
+
# "destroy"
|
48
|
+
# ],
|
49
|
+
# ....
|
50
|
+
# }
|
51
|
+
def for_class(class_name)
|
52
|
+
config_data[class_name]
|
53
|
+
end
|
78
54
|
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
55
|
+
# Returns the name of the field or method to use for the actor's display name.
|
56
|
+
def current_user_name
|
57
|
+
config_data['current_user_name']
|
58
|
+
end
|
83
59
|
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
60
|
+
# Returns the name of the model to use for the current user.
|
61
|
+
def current_user_model_name
|
62
|
+
config_data['current_user_model_name']
|
63
|
+
end
|
88
64
|
|
89
|
-
|
90
|
-
|
91
|
-
|
65
|
+
# Returns whatever models should be sanitized on delete.
|
66
|
+
def task_for_sanitization
|
67
|
+
config_data['task_for_sanitization']
|
68
|
+
end
|
92
69
|
end
|
93
70
|
end
|
94
71
|
end
|
@@ -6,7 +6,6 @@ module LoggableActivity
|
|
6
6
|
# This class represends an additional data owner for a record.
|
7
7
|
# For it to kick in, the data_owner configuration has to be set to true in the loggable_activity.yaml file.
|
8
8
|
class DataOwner < ActiveRecord::Base
|
9
|
-
self.table_name = 'loggable_data_owners'
|
10
9
|
belongs_to :record, polymorphic: true, optional: true
|
11
10
|
belongs_to :encryption_key, class_name: '::LoggableActivity::EncryptionKey'
|
12
11
|
|
@@ -20,7 +20,10 @@ module LoggableActivity
|
|
20
20
|
return nil if data.nil?
|
21
21
|
|
22
22
|
encryption_key = Base64.decode64(secret_key)
|
23
|
-
|
23
|
+
unless encryption_key.bytesize == 32
|
24
|
+
raise EncryptionError,
|
25
|
+
"Encryption failed: Invalid encoded_key length #{encryption_key.bytesize}"
|
26
|
+
end
|
24
27
|
|
25
28
|
cipher = OpenSSL::Cipher.new('AES-256-CBC').encrypt
|
26
29
|
cipher.key = encryption_key
|
@@ -42,11 +45,14 @@ module LoggableActivity
|
|
42
45
|
# "my secret data"
|
43
46
|
#
|
44
47
|
def self.decrypt(data, secret_key)
|
45
|
-
return I18n.t('
|
48
|
+
return I18n.t('loggable_activity.activity.deleted') if secret_key.nil?
|
46
49
|
return '' if data.blank?
|
47
50
|
|
48
51
|
encryption_key = Base64.decode64(secret_key)
|
49
|
-
|
52
|
+
unless encryption_key.bytesize == 32
|
53
|
+
raise EncryptionError,
|
54
|
+
"Decryption failed: Invalid encoded_key length: #{encryption_key.bytesize}"
|
55
|
+
end
|
50
56
|
|
51
57
|
cipher = OpenSSL::Cipher.new('AES-256-CBC').decrypt
|
52
58
|
cipher.key = encryption_key
|
@@ -58,11 +64,14 @@ module LoggableActivity
|
|
58
64
|
|
59
65
|
decrypted_data.force_encoding('UTF-8')
|
60
66
|
rescue OpenSSL::Cipher::CipherError => e
|
61
|
-
|
62
|
-
'
|
67
|
+
Rails.logger.error "CipherError Decryption failed: #{e.message}"
|
68
|
+
I18n.t('loggable_activity.decryption.failed')
|
63
69
|
rescue EncryptionError => e
|
64
|
-
|
65
|
-
'
|
70
|
+
Rails.logger.error "EncryptionError: #{e.message}"
|
71
|
+
I18n.t('loggable_activity.decryption.failed')
|
72
|
+
rescue ArgumentError => e
|
73
|
+
Rails.logger.error "ArgumentError Decryption failed: #{e.message}"
|
74
|
+
I18n.t('loggable_activity.decryption.failed')
|
66
75
|
end
|
67
76
|
|
68
77
|
# Returns true if the given value is blank
|
@@ -6,15 +6,13 @@ module LoggableActivity
|
|
6
6
|
# This class represents the encryption key used to unlock the data for one payload.
|
7
7
|
# When deleted, only the encryption_key field is deleted.
|
8
8
|
class EncryptionKey < ActiveRecord::Base
|
9
|
-
self.table_name = 'loggable_encryption_keys'
|
10
|
-
|
11
9
|
# Associations
|
12
10
|
belongs_to :record, polymorphic: true, optional: true
|
13
11
|
# belongs_to :payload, class_name: '::LoggableActivity::Payload', optional: true
|
14
12
|
# belongs_to :parent_key, class_name: '::LoggableActivity::EncryptionKey', optional: true,
|
15
13
|
# foreign_key: 'parent_key_id'
|
16
14
|
|
17
|
-
# Prepare the record for deletion
|
15
|
+
# Prepare the record for deletion
|
18
16
|
def mark_as_deleted!
|
19
17
|
LoggableActivity::Configuration.task_for_sanitization ? update(delete_at: DateTime.now + 1.month) : delete
|
20
18
|
end
|
@@ -25,17 +23,16 @@ module LoggableActivity
|
|
25
23
|
end
|
26
24
|
|
27
25
|
# Delete the encryption key by updating the key to nil.
|
26
|
+
# Nullify the delete_at field, so the key is not deleted when the sanitization task runs.
|
28
27
|
def delete
|
29
|
-
update(secret_key: nil, delete_at: nil)
|
28
|
+
update(secret_key: nil, delete_at: nil)
|
30
29
|
end
|
31
30
|
|
32
31
|
# Restores the encryption key by updating the delete_at field to nil.
|
33
32
|
def restore!
|
34
|
-
update(delete_at: nil) if delete_at &&
|
33
|
+
update(delete_at: nil) if delete_at && DateTime.now < delete_at
|
35
34
|
end
|
36
35
|
|
37
|
-
|
38
|
-
|
39
36
|
# Returns an encryption key for a record by its type and ID, optionally using a parent key.
|
40
37
|
#
|
41
38
|
# @param record_type [String] The type of the record.
|
@@ -0,0 +1,27 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module LoggableActivity
|
4
|
+
# Engine
|
5
|
+
#
|
6
|
+
# This module defines the LoggableActivity engine for use within a Rails application.
|
7
|
+
# It leverages Rails::Engine to create an isolated namespace, ensuring that the components
|
8
|
+
# of the LoggableActivity engine (such as models, controllers, and views) do not interfere
|
9
|
+
# with those of the host application or other engines.
|
10
|
+
#
|
11
|
+
# Example Usage:
|
12
|
+
# In a Rails application, you can mount this engine to make its functionality available:
|
13
|
+
#
|
14
|
+
# mount LoggableActivity::Engine, at: "/loggable_activity"
|
15
|
+
#
|
16
|
+
# This will allow the application to utilize the features provided by the LoggableActivity engine
|
17
|
+
# under the specified mount path.
|
18
|
+
#
|
19
|
+
class Engine < ::Rails::Engine
|
20
|
+
isolate_namespace LoggableActivity
|
21
|
+
|
22
|
+
# initializer 'loggable_activity.assets.precompile' do |app|
|
23
|
+
# app.config.assets.precompile += %w( loggable_activity/application.css )
|
24
|
+
# app.config.assets.precompile += %w( loggable_activity/bootstrap.css )
|
25
|
+
# end
|
26
|
+
end
|
27
|
+
end
|
@@ -4,9 +4,6 @@ module LoggableActivity
|
|
4
4
|
# Error class for loggable activity.
|
5
5
|
class Error < StandardError
|
6
6
|
def initialize(msg = '')
|
7
|
-
puts '---------------- LOGGABLE ACTIVITY -----------------'
|
8
|
-
puts msg
|
9
|
-
puts '----------------------------------------------------'
|
10
7
|
super(msg)
|
11
8
|
end
|
12
9
|
end
|
@@ -14,9 +11,6 @@ module LoggableActivity
|
|
14
11
|
# Error class for encryption.
|
15
12
|
class EncryptionError < StandardError
|
16
13
|
def initialize(msg = '')
|
17
|
-
puts '---------------- LOGGABLE ACTIVITY -----------------'
|
18
|
-
puts msg
|
19
|
-
puts '----------------------------------------------------'
|
20
14
|
super(msg)
|
21
15
|
end
|
22
16
|
end
|
@@ -24,10 +18,6 @@ module LoggableActivity
|
|
24
18
|
# This class is used to load the configuration file located at config/loggable_activity.yml
|
25
19
|
class ConfigurationError < StandardError
|
26
20
|
def initialize(msg = '')
|
27
|
-
# https://api.loggable_activity.com/msg
|
28
|
-
puts '---------------- LOGGABLE ACTIVITY -----------------'
|
29
|
-
puts msg
|
30
|
-
puts '----------------------------------------------------'
|
31
21
|
super(msg)
|
32
22
|
end
|
33
23
|
end
|
@@ -24,6 +24,7 @@ module LoggableActivity
|
|
24
24
|
|
25
25
|
# Initializes attributes based on configuration.
|
26
26
|
self.loggable_attrs = config&.fetch('loggable_attrs', []) || []
|
27
|
+
self.public_attrs = config&.fetch('public_attrs', []) || []
|
27
28
|
self.relations = config&.fetch('relations', []) || []
|
28
29
|
self.auto_log = config&.fetch('auto_log', []) || []
|
29
30
|
self.fetch_record_name_from = config&.fetch('fetch_record_name_from', nil)
|
@@ -60,6 +61,10 @@ module LoggableActivity
|
|
60
61
|
end
|
61
62
|
end
|
62
63
|
|
64
|
+
def disable_hooks!
|
65
|
+
self.disable_hooks = true
|
66
|
+
end
|
67
|
+
|
63
68
|
private
|
64
69
|
|
65
70
|
# Logs an activity for the current action.
|
@@ -134,6 +139,7 @@ module LoggableActivity
|
|
134
139
|
# Logs a create activity automatically if configured.
|
135
140
|
def log_create_activity
|
136
141
|
return unless hooks_enabled?
|
142
|
+
return if id.nil?
|
137
143
|
|
138
144
|
log(:create) if self.class.auto_log.include?('create')
|
139
145
|
end
|
@@ -159,13 +165,13 @@ module LoggableActivity
|
|
159
165
|
|
160
166
|
# Returns the encrypted name of the actor.
|
161
167
|
def encrypted_actor_name
|
162
|
-
name = @actor.send(
|
168
|
+
name = @actor.send(current_user_name)
|
163
169
|
::LoggableActivity::Encryption.encrypt(name, actor_secret_key)
|
164
170
|
end
|
165
171
|
|
166
172
|
# Reads the field to feetch the record name from.
|
167
|
-
def
|
168
|
-
::LoggableActivity::Configuration.
|
173
|
+
def current_user_name
|
174
|
+
::LoggableActivity::Configuration.current_user_name
|
169
175
|
end
|
170
176
|
|
171
177
|
# Returns the action key for the current action.
|
@@ -200,13 +206,12 @@ module LoggableActivity
|
|
200
206
|
|
201
207
|
class_methods do
|
202
208
|
# The loggable_attrs attribute is used read the configuration for the model that included LoggableActivity::Hooks.
|
203
|
-
attr_accessor :loggable_attrs, :relations, :auto_log, :fetch_record_name_from, :route
|
209
|
+
attr_accessor :loggable_attrs, :relations, :auto_log, :fetch_record_name_from, :route, :public_attrs
|
204
210
|
|
205
211
|
# Convert the model name and name space in to 'base_action'.
|
206
212
|
def base_action
|
207
213
|
name.downcase.gsub('::', '/')
|
208
214
|
end
|
209
|
-
|
210
215
|
end
|
211
216
|
end
|
212
217
|
end
|