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 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: []