loggable_activity 0.2.1 → 0.5.4
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 +4 -4
- data/.rubocop.yml +29 -42
- data/.vscode/commands.json +2 -2
- data/.vscode/terminals.json +8 -8
- data/CHANGELOG.md +9 -0
- data/CHEAT_SHEET.md +31 -0
- data/MIT-LICENSE +21 -0
- data/README.md +1 -1
- data/Rakefile +6 -4
- data/app/assets/config/loggable_activity_manifest.js +2 -0
- data/app/assets/javascripts/loggable_activity/application.js +1 -0
- data/app/assets/stylesheets/loggable_activity/activities.scss +25 -0
- data/app/assets/stylesheets/loggable_activity/application.scss +16 -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/pico/_first_page.html.erb +13 -0
- data/app/views/kaminari/pico/_gap.html.erb +8 -0
- data/app/views/kaminari/pico/_last_page.html.erb +12 -0
- data/app/views/kaminari/pico/_next_page.html.erb +13 -0
- data/app/views/kaminari/pico/_page.html.erb +14 -0
- data/app/views/kaminari/pico/_paginator.html.erb +27 -0
- data/app/views/kaminari/pico/_prev_page.html.erb +14 -0
- data/app/views/layouts/loggable_activity/application.html.slim +20 -0
- data/app/views/loggable_activity/activities/_activities.html.slim +28 -0
- data/app/views/loggable_activity/activities/index.html.erb +6 -0
- data/app/views/loggable_activity/bootstrap/kaminari/_first_page.html.erb +13 -0
- data/app/views/loggable_activity/bootstrap/kaminari/_gap.html.erb +8 -0
- data/app/views/loggable_activity/bootstrap/kaminari/_last_page.html.erb +13 -0
- data/app/views/loggable_activity/bootstrap/kaminari/_next_page.html.erb +13 -0
- data/app/views/loggable_activity/bootstrap/kaminari/_page.html.erb +14 -0
- data/app/views/loggable_activity/bootstrap/kaminari/_paginator.html.erb +27 -0
- data/app/views/loggable_activity/bootstrap/kaminari/_prev_page.html.erb +13 -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 +4 -3
- data/lib/{schemas → loggable_activity}/config_schema.json +3 -10
- data/lib/loggable_activity/configuration.rb +48 -77
- 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 +22 -0
- data/lib/loggable_activity/error.rb +0 -10
- data/lib/loggable_activity/hooks.rb +10 -15
- 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 +12 -5
- data/lib/loggable_activity/services/update_payloads_builder.rb +34 -6
- data/lib/loggable_activity/version.rb +1 -1
- data/lib/loggable_activity.rb +51 -14
- data/lib/tasks/loggable_activity_tasks.rake +6 -0
- data/loggable_activity-0.5.0.gem +0 -0
- metadata +129 -109
- 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,42 @@
|
|
|
1
|
+
#!/bin/sh
|
|
2
|
+
#
|
|
3
|
+
# An example hook script to prepare the commit log message.
|
|
4
|
+
# Called by "git commit" with the name of the file that has the
|
|
5
|
+
# commit message, followed by the description of the commit
|
|
6
|
+
# message's source. The hook's purpose is to edit the commit
|
|
7
|
+
# message file. If the hook fails with a non-zero status,
|
|
8
|
+
# the commit is aborted.
|
|
9
|
+
#
|
|
10
|
+
# To enable this hook, rename this file to "prepare-commit-msg".
|
|
11
|
+
|
|
12
|
+
# This hook includes three examples. The first one removes the
|
|
13
|
+
# "# Please enter the commit message..." help message.
|
|
14
|
+
#
|
|
15
|
+
# The second includes the output of "git diff --name-status -r"
|
|
16
|
+
# into the message, just before the "git status" output. It is
|
|
17
|
+
# commented because it doesn't cope with --amend or with squashed
|
|
18
|
+
# commits.
|
|
19
|
+
#
|
|
20
|
+
# The third example adds a Signed-off-by line to the message, that can
|
|
21
|
+
# still be edited. This is rarely a good idea.
|
|
22
|
+
|
|
23
|
+
COMMIT_MSG_FILE=$1
|
|
24
|
+
COMMIT_SOURCE=$2
|
|
25
|
+
SHA1=$3
|
|
26
|
+
|
|
27
|
+
/usr/bin/perl -i.bak -ne 'print unless(m/^. Please enter the commit message/..m/^#$/)' "$COMMIT_MSG_FILE"
|
|
28
|
+
|
|
29
|
+
# case "$COMMIT_SOURCE,$SHA1" in
|
|
30
|
+
# ,|template,)
|
|
31
|
+
# /usr/bin/perl -i.bak -pe '
|
|
32
|
+
# print "\n" . `git diff --cached --name-status -r`
|
|
33
|
+
# if /^#/ && $first++ == 0' "$COMMIT_MSG_FILE" ;;
|
|
34
|
+
# *) ;;
|
|
35
|
+
# esac
|
|
36
|
+
|
|
37
|
+
# SOB=$(git var GIT_COMMITTER_IDENT | sed -n 's/^\(.*>\).*$/Signed-off-by: \1/p')
|
|
38
|
+
# git interpret-trailers --in-place --trailer "$SOB" "$COMMIT_MSG_FILE"
|
|
39
|
+
# if test -z "$COMMIT_SOURCE"
|
|
40
|
+
# then
|
|
41
|
+
# /usr/bin/perl -i.bak -pe 'print "\n" if !$first_line++' "$COMMIT_MSG_FILE"
|
|
42
|
+
# fi
|
|
@@ -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
|
|
@@ -135,6 +135,7 @@ module LoggableActivity
|
|
|
135
135
|
return I18n.t('loggable.activity.deleted') if actor_deleted?
|
|
136
136
|
|
|
137
137
|
::LoggableActivity::Encryption.decrypt(encrypted_actor_name, actor_secret_key)
|
|
138
|
+
|
|
138
139
|
end
|
|
139
140
|
|
|
140
141
|
# Returns a list of activities for a given actor.
|
|
@@ -2,10 +2,7 @@
|
|
|
2
2
|
"$schema": "http://json-schema.org/draft-06/schema#",
|
|
3
3
|
"type": "object",
|
|
4
4
|
"properties": {
|
|
5
|
-
"
|
|
6
|
-
"type": "string"
|
|
7
|
-
},
|
|
8
|
-
"fetch_current_user_name_from": {
|
|
5
|
+
"fetch_actor_name_from": {
|
|
9
6
|
"type": "string"
|
|
10
7
|
},
|
|
11
8
|
"task_for_sanitization": {
|
|
@@ -13,7 +10,7 @@
|
|
|
13
10
|
}
|
|
14
11
|
},
|
|
15
12
|
"patternProperties": {
|
|
16
|
-
"^(?!
|
|
13
|
+
"^(?!fetch_actor_name_from$|task_for_sanitization)[A-Za-z0-9_:]+$": {
|
|
17
14
|
"type": "object",
|
|
18
15
|
"properties": {
|
|
19
16
|
"data_owner": {
|
|
@@ -72,9 +69,6 @@
|
|
|
72
69
|
"route": {
|
|
73
70
|
"type": "string",
|
|
74
71
|
"minLength": 1
|
|
75
|
-
},
|
|
76
|
-
"fetch_record_name_from": {
|
|
77
|
-
"type": "string"
|
|
78
72
|
}
|
|
79
73
|
},
|
|
80
74
|
"required": [
|
|
@@ -90,7 +84,6 @@
|
|
|
90
84
|
},
|
|
91
85
|
"additionalProperties": false,
|
|
92
86
|
"required": [
|
|
93
|
-
"
|
|
94
|
-
"fetch_current_user_name_from"
|
|
87
|
+
"fetch_actor_name_from"
|
|
95
88
|
]
|
|
96
89
|
}
|
|
@@ -2,94 +2,65 @@
|
|
|
2
2
|
|
|
3
3
|
require 'json-schema'
|
|
4
4
|
require 'json'
|
|
5
|
-
require 'awesome_print'
|
|
6
5
|
|
|
7
6
|
module LoggableActivity
|
|
8
|
-
# This class is used to load the configuration file located at config/loggable_activity.yml
|
|
9
|
-
class ConfigurationError < StandardError
|
|
10
|
-
def initialize(msg = '')
|
|
11
|
-
# https://api.loggable_activity.com/msg
|
|
12
|
-
puts '---------------- LOGGABLE ACTIVITY -----------------'
|
|
13
|
-
puts msg
|
|
14
|
-
puts '----------------------------------------------------'
|
|
15
|
-
super(msg)
|
|
16
|
-
end
|
|
17
|
-
end
|
|
18
|
-
|
|
19
7
|
# This class is used to load the configuration file located at config/loggable_activity.yml
|
|
20
8
|
# When the LoggableActivity::Hook is included in a model
|
|
21
9
|
# it takes the model's name and find the configuration for that model in the configuration file.
|
|
22
10
|
class Configuration
|
|
23
|
-
# Loads the configuration file
|
|
24
|
-
def self.load_config_file(config_file_path)
|
|
25
|
-
@config_data = YAML.load_file(config_file_path)
|
|
26
|
-
validate_config_file
|
|
27
|
-
rescue Errno::ENOENT
|
|
28
|
-
raise ConfigurationError, 'config/loggable_activity.yaml not found'
|
|
29
|
-
end
|
|
30
|
-
|
|
31
|
-
# Loads the schema file for the configuration file
|
|
32
|
-
def self.load_schema
|
|
33
|
-
schema_path = File.join(__dir__, '..', 'schemas', 'config_schema.json')
|
|
34
|
-
JSON.parse(File.read(schema_path))
|
|
35
|
-
end
|
|
36
|
-
|
|
37
|
-
# Validates the configuration file againss the schema
|
|
38
|
-
def self.validate_config_file
|
|
39
|
-
schema = load_schema
|
|
40
|
-
errors = JSON::Validator.fully_validate(schema, @config_data)
|
|
41
|
-
return unless errors.any?
|
|
42
|
-
|
|
43
|
-
raise ConfigurationError,
|
|
44
|
-
"config/loggable_activity.yaml is invalid: #{errors.join(', ')}"
|
|
45
|
-
end
|
|
46
|
-
|
|
47
|
-
# Returns true if the configuration file has been loaded
|
|
48
|
-
def self.loaded?
|
|
49
|
-
!@config_data.nil?
|
|
50
|
-
end
|
|
51
|
-
|
|
52
|
-
# Returns the configuration data
|
|
53
11
|
class << self
|
|
54
|
-
#
|
|
55
|
-
|
|
56
|
-
|
|
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
|
|
57
17
|
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
# Returns:
|
|
63
|
-
# {
|
|
64
|
-
# "fetch_record_name_from": "full_name",
|
|
65
|
-
# "loggable_attrs": [
|
|
66
|
-
# "first_name",
|
|
67
|
-
# "last_name",
|
|
68
|
-
# ],
|
|
69
|
-
# "auto_log": [
|
|
70
|
-
# "create",
|
|
71
|
-
# "update",
|
|
72
|
-
# "destroy"
|
|
73
|
-
# ],
|
|
74
|
-
# ....
|
|
75
|
-
# }
|
|
76
|
-
def self.for_class(class_name)
|
|
77
|
-
@config_data[class_name]
|
|
78
|
-
end
|
|
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
|
|
79
22
|
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
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?
|
|
84
28
|
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
29
|
+
raise ConfigurationError,
|
|
30
|
+
"config/loggable_activity.yaml is invalid: #{errors.join(', ')}"
|
|
31
|
+
end
|
|
32
|
+
|
|
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
|
|
89
54
|
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
55
|
+
# Returns the name of the field or method to use for the actor's display name.
|
|
56
|
+
def fetch_actor_name_from
|
|
57
|
+
config_data['fetch_actor_name_from']
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
# Returns whatever models should be sanitized on delete.
|
|
61
|
+
def task_for_sanitization
|
|
62
|
+
config_data['task_for_sanitization']
|
|
63
|
+
end
|
|
93
64
|
end
|
|
94
65
|
end
|
|
95
66
|
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,22 @@
|
|
|
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
|
+
end
|
|
22
|
+
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
|