rails-gdpr-export 1.0.2 → 2.0.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/Gemfile.lock +1 -1
- data/README.md +32 -20
- data/lib/gdpr_exporter.rb +47 -12
- data/lib/gdpr_exporter/version.rb +1 -1
- data/rails-gdpr-export.gemspec +1 -1
- metadata +4 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 515a04ae4fb4dd29c34348f8bd828d42d7c3513b508d6b5b1ad8838345486a72
|
4
|
+
data.tar.gz: 74f1a74077474a84843b4e20aa4d4740b3ea7c88b339dca8e47b62c7dc75cb11
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 10783ce78e34b5133a026578e1df08446f1b33d65f3c9f67ce878e6b904c340dcde63ede49deee486771b092acc7d122d15f198171ed2758cec3c0a3fc78ee22
|
7
|
+
data.tar.gz: d8eb588eeb5c2e9b0ace0a79b1a2eb970a6d8cbc8a0d4acd6cd3a8b2e9f8a5d751df32670aa373b01a1a7a17e2dd061495cb42381661f87b25c98b6900a354c9
|
data/Gemfile.lock
CHANGED
data/README.md
CHANGED
@@ -24,43 +24,55 @@ This gem allows you to specify fields that you want to retrieve from your models
|
|
24
24
|
|
25
25
|
### Initialization
|
26
26
|
|
27
|
-
|
28
|
-
|
29
|
-
```ruby
|
30
|
-
ActiveRecord::Base.send :include, GdprExporter
|
31
|
-
```
|
27
|
+
First start by importing `gdpr_exporter` into your application, i.e., add `require "gdpr_exporter"` to your `Application.rb` file.
|
32
28
|
|
33
29
|
### Data collection
|
34
30
|
|
35
|
-
In order to specify the fields you want to
|
31
|
+
In order to specify the fields you want to collect you need to call `gdpr_collect`.
|
36
32
|
The call target is a rails model and its arguments are:
|
37
33
|
* a set of simple fields, i.e. fields that will be output as is,
|
38
34
|
* followed by a hash of params:
|
35
|
+
|
39
36
|
```ruby
|
40
|
-
{user_id: <the field in the model used as alias for the user_id field>
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
37
|
+
{ user_id: <the field in the model used as alias for the user_id field>
|
38
|
+
renamed_fields: { <field_from_db> => <field_name_in_output> }
|
39
|
+
table_name: <the new table name in output>
|
40
|
+
description: <a comment>
|
41
|
+
joins: [<an array of associations>] }
|
45
42
|
```
|
46
43
|
|
44
|
+
When `joins` is specified, the fields of an association should be defined as `<association_name> <field_name>`.
|
45
|
+
|
46
|
+
For `user_id`, you can also use a string with a chain of associations. For instance, if my model is indirectly linked to user through an `belongs_to: :account` association, you can specify `user_id: "account user_id"`. Currently, the gem support only to levels of nested associations.
|
47
|
+
|
47
48
|
#### Example
|
48
49
|
|
50
|
+
Suppose you have a `User` model, then in its class you should `include Gdprexporter` and call `gdpr_collect`.
|
51
|
+
And you should do something similar for all other models you are interested in in your application.
|
52
|
+
|
49
53
|
```ruby
|
50
|
-
User
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
54
|
+
class User
|
55
|
+
include GdprExporter
|
56
|
+
|
57
|
+
gdpr_collect :email, :last_sign_in_at, :type, :forward_mailbox,
|
58
|
+
"program title",
|
59
|
+
{ user_id: :id,
|
60
|
+
renamed_fields: { sign_in_count: "sign in count",
|
61
|
+
current_sign_in_at: "time of current sign in",
|
62
|
+
chosen_program_id: "chosen program",
|
63
|
+
current_sign_in_ip: "current IP address",
|
64
|
+
last_sign_in_ip: "previously used IP address" },
|
65
|
+
joins: [:program] }
|
66
|
+
end
|
57
67
|
```
|
58
68
|
|
59
|
-
|
69
|
+
Here from your `User` model, you want to retrieve the values of the fields `email, last_sign_in_at,
|
60
70
|
type, forward_mailbox`, in addition to the fields `sign_in_count, current_sign_in_at, chosen_program_id, current_sign_in_ip, last_sign_in_ip`. However for the latter you want their csv header to be renamed. And the field representing the user in the `User` model is `id`.
|
71
|
+
`User` has also an association with `program` and you want to value of its field `title` (hence the presence of `"program title"` in the list of fields).
|
61
72
|
|
62
73
|
### Data export
|
63
|
-
|
74
|
+
|
75
|
+
Finally, call `GdprExporter.export(<user_id>)` (from a controller in your application) to return a csv formatted output of all the fields you specified previously.
|
64
76
|
|
65
77
|
|
66
78
|
## Contributing
|
data/lib/gdpr_exporter.rb
CHANGED
@@ -1,11 +1,12 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
require "gdpr_exporter/version"
|
4
|
-
require
|
4
|
+
require "csv"
|
5
|
+
require "set"
|
5
6
|
|
6
7
|
module GdprExporter
|
7
8
|
# Stores all the classes that have been tagged for gdpr collection
|
8
|
-
@@klasses = []
|
9
|
+
@@klasses = Set[]
|
9
10
|
|
10
11
|
def self.get_klasses
|
11
12
|
@@klasses
|
@@ -18,7 +19,7 @@ module GdprExporter
|
|
18
19
|
# Collects data through all the tagged models and generates a csv
|
19
20
|
# formatted output
|
20
21
|
def self.export(user_id)
|
21
|
-
CSV.generate do |csv|
|
22
|
+
CSV.generate(force_quotes: true) do |csv|
|
22
23
|
get_klasses.each do |klass|
|
23
24
|
rows = klass.gdpr_query(user_id)
|
24
25
|
klass.gdpr_export(rows, csv)
|
@@ -57,11 +58,11 @@ module GdprExporter
|
|
57
58
|
end
|
58
59
|
|
59
60
|
unless hash_params.class == Hash
|
60
|
-
raise "Gdpr fields collection error: last argument must be a hash!"
|
61
|
+
raise ArgumentError.new("Gdpr fields collection error: last argument must be a hash!")
|
61
62
|
end
|
62
63
|
|
63
64
|
unless hash_params.key?(:user_id)
|
64
|
-
raise "Gdpr fields collection error: the field aliasing user_id is not declared for '#{self}'!"
|
65
|
+
raise ArgumentError.new("Gdpr fields collection error: the field aliasing user_id is not declared for '#{self}'!")
|
65
66
|
end
|
66
67
|
|
67
68
|
# Adds the eigen class to the set of classes eligible for gdpr data collection.
|
@@ -91,12 +92,29 @@ module GdprExporter
|
|
91
92
|
# Adds the class method 'gdpr_query' to the eigenclass.
|
92
93
|
# It will execute the query.
|
93
94
|
self.define_singleton_method(:gdpr_query) do |_user_id|
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
95
|
+
decomposed_user_id_field = user_id_field.to_s.split(" ")
|
96
|
+
result = case
|
97
|
+
when decomposed_user_id_field.size == 3
|
98
|
+
self
|
99
|
+
.includes(decomposed_user_id_field.first.to_sym => decomposed_user_id_field.second.to_sym)
|
100
|
+
.where(decomposed_user_id_field.second.pluralize.to_sym => { decomposed_user_id_field.last.to_sym => _user_id })
|
101
|
+
when decomposed_user_id_field.size == 2
|
102
|
+
self
|
103
|
+
.includes(decomposed_user_id_field.first.to_sym)
|
104
|
+
.where(decomposed_user_id_field.first.pluralize.to_sym => { decomposed_user_id_field.last.to_sym => _user_id })
|
105
|
+
else
|
106
|
+
self.where(user_id_field => _user_id)
|
107
|
+
end
|
108
|
+
|
109
|
+
# When there are multiple joins defined, just keep calling 'joins'
|
110
|
+
# for each association.
|
111
|
+
if hash_params[:joins]
|
112
|
+
result = hash_params[:joins].inject(result) do | query, assoc |
|
113
|
+
query.send(:joins, assoc)
|
114
|
+
end
|
99
115
|
end
|
116
|
+
|
117
|
+
result
|
100
118
|
end
|
101
119
|
|
102
120
|
# Adds a method to export to csv to the eigenclass.
|
@@ -105,11 +123,28 @@ module GdprExporter
|
|
105
123
|
|
106
124
|
csv << (hash_params[:table_name] ? [hash_params[:table_name]] :
|
107
125
|
[self.to_s])
|
126
|
+
|
127
|
+
if hash_params[:desc]
|
128
|
+
csv << ['Description:', hash_params[:desc]]
|
129
|
+
end
|
130
|
+
|
108
131
|
csv << csv_headers
|
109
132
|
rows.each do |r|
|
110
|
-
csv << query_fields.map
|
133
|
+
csv << query_fields.map do |f|
|
134
|
+
f_splitted = f.to_s.split(' ')
|
135
|
+
if (f_splitted.size == 2)
|
136
|
+
# field f is coming from an assoc, i.e. field has been defined
|
137
|
+
# as "<tablename> <field>" in gdpr_collect then to get its value
|
138
|
+
# do r.<tablename>.<field>
|
139
|
+
f_splitted.inject(r) { |result, method| result.send(method) }
|
140
|
+
elsif (f_splitted.size > 2)
|
141
|
+
raise ArgumentError.new("Field #{f} is made of more than 2 words!?")
|
142
|
+
else
|
143
|
+
# No association involved, simply retrieve the field value.
|
144
|
+
r.send(f)
|
145
|
+
end
|
146
|
+
end
|
111
147
|
end
|
112
|
-
csv << ['Comment:', hash_params[:desc]] if hash_params[:desc]
|
113
148
|
csv << []
|
114
149
|
end
|
115
150
|
end
|
data/rails-gdpr-export.gemspec
CHANGED
@@ -9,7 +9,7 @@ Gem::Specification.new do |spec|
|
|
9
9
|
spec.authors = ["Chrislain Razafimahefa"]
|
10
10
|
spec.email = ["razafima@gmail.com"]
|
11
11
|
|
12
|
-
spec.summary = %q{A gem to export personal data in compliance with GDPR.}
|
12
|
+
spec.summary = %q{A rails gem to export personal data in compliance with GDPR.}
|
13
13
|
spec.homepage = "https://github.com/epfl-exts/rails-gdpr-export"
|
14
14
|
spec.license = "MIT"
|
15
15
|
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: rails-gdpr-export
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version:
|
4
|
+
version: 2.0.4
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Chrislain Razafimahefa
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2021-03-22 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -92,8 +92,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
92
92
|
version: '0'
|
93
93
|
requirements: []
|
94
94
|
rubyforge_project:
|
95
|
-
rubygems_version: 2.7.6
|
95
|
+
rubygems_version: 2.7.6.2
|
96
96
|
signing_key:
|
97
97
|
specification_version: 4
|
98
|
-
summary: A gem to export personal data in compliance with GDPR.
|
98
|
+
summary: A rails gem to export personal data in compliance with GDPR.
|
99
99
|
test_files: []
|