rails-gdpr-export 1.0.2 → 2.0.4

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: c0db6f0772529c9ff00bc550f978c2a1130e3a0c26bee3ed7ae885d2edb03ac4
4
- data.tar.gz: 7e759a11d04018a00cb3873560ecda0a93999e60a1fcaa1113bfd04b2a5c3ba3
3
+ metadata.gz: 515a04ae4fb4dd29c34348f8bd828d42d7c3513b508d6b5b1ad8838345486a72
4
+ data.tar.gz: 74f1a74077474a84843b4e20aa4d4740b3ea7c88b339dca8e47b62c7dc75cb11
5
5
  SHA512:
6
- metadata.gz: e09269397d19fd581611e99566fd6e3e6e37bef7c9c1a0e3c5c706151913a0c3d37bea7a27e655acc7f37d0dc1bbcc5762453a441b5c3653c867b5b425205b21
7
- data.tar.gz: 87f8158262f3a001f0dbb5fc5fb16c71278a19bff6226f89a16fd5704e0c4fd408055d8bfc6d6db6c6a90c8e9fcf484d1fa2d8838eab5cbcf727322bd39c085b
6
+ metadata.gz: 10783ce78e34b5133a026578e1df08446f1b33d65f3c9f67ce878e6b904c340dcde63ede49deee486771b092acc7d122d15f198171ed2758cec3c0a3fc78ee22
7
+ data.tar.gz: d8eb588eeb5c2e9b0ace0a79b1a2eb970a6d8cbc8a0d4acd6cd3a8b2e9f8a5d751df32670aa373b01a1a7a17e2dd061495cb42381661f87b25c98b6900a354c9
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- rails-gdpr-export (1.0.2)
4
+ rails-gdpr-export (2.0.4)
5
5
 
6
6
  GEM
7
7
  remote: https://rubygems.org/
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
- To initialize the gem usage, loads the GdprExporter module into activerecord classes. Do this at initialization time through an initializer. E.g. create a initializers/gdpr.rb file and add the following:
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 return to the user you need to call `gdpr_collect`.
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
- renamed_fields: {<field_from_db> => <field_name_in_output>}
42
- table_name: <the new table name in output>
43
- description: <a comment>
44
- join: <an association>}
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.gdpr_collect :email, :last_sign_in_at, :type, :forward_mailbox,
51
- {user_id: :id,
52
- renamed_fields: {sign_in_count: "sign in count",
53
- current_sign_in_at: "time of current sign in",
54
- chosen_program_id: "chosen program",
55
- current_sign_in_ip: "current IP address",
56
- last_sign_in_ip: "previously used IP address"}}
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
- From your `User` model, you want to retrieve the values of the fields `email, last_sign_in_at,
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
- Finally, call `GdprExporter.export(<user_id>)` to return a csv formatted output of all the fields you specified previously.
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 'csv'
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
- if hash_params[:join]
95
- self.select(query_fields).where(user_id_field => _user_id).
96
- joins(hash_params[:join])
97
- else
98
- self.select(query_fields).where(user_id_field => _user_id)
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{ |f| r.send(f) }
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
@@ -1,5 +1,5 @@
1
1
  module Exts
2
2
  module Gdpr
3
- VERSION = "1.0.2"
3
+ VERSION = "2.0.4"
4
4
  end
5
5
  end
@@ -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: 1.0.2
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: 2018-05-16 00:00:00.000000000 Z
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: []