{"id":23765794,"url":"https://github.com/solidusio-contrib/solidus_gdpr","last_synced_at":"2025-09-05T09:33:01.937Z","repository":{"id":38086241,"uuid":"202151516","full_name":"solidusio-contrib/solidus_gdpr","owner":"solidusio-contrib","description":"A Solidus extension for implementing GDPR in your store.","archived":false,"fork":false,"pushed_at":"2024-03-18T15:48:43.000Z","size":143,"stargazers_count":9,"open_issues_count":1,"forks_count":5,"subscribers_count":11,"default_branch":"main","last_synced_at":"2024-12-20T14:33:02.416Z","etag":null,"topics":["extension","gdpr","solidus","user-rights"],"latest_commit_sha":null,"homepage":"","language":"Ruby","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"bsd-3-clause","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/solidusio-contrib.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2019-08-13T13:33:16.000Z","updated_at":"2022-06-10T13:16:02.000Z","dependencies_parsed_at":"2022-09-17T20:51:38.129Z","dependency_job_id":null,"html_url":"https://github.com/solidusio-contrib/solidus_gdpr","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/solidusio-contrib%2Fsolidus_gdpr","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/solidusio-contrib%2Fsolidus_gdpr/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/solidusio-contrib%2Fsolidus_gdpr/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/solidusio-contrib%2Fsolidus_gdpr/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/solidusio-contrib","download_url":"https://codeload.github.com/solidusio-contrib/solidus_gdpr/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":232034913,"owners_count":18463363,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["extension","gdpr","solidus","user-rights"],"created_at":"2024-12-31T23:17:44.918Z","updated_at":"2024-12-31T23:17:45.970Z","avatar_url":"https://github.com/solidusio-contrib.png","language":"Ruby","funding_links":[],"categories":[],"sub_categories":[],"readme":"# solidus_gdpr\n\n[![CircleCI](https://circleci.com/gh/solidusio-contrib/solidus_gdpr.svg?style=svg)](https://circleci.com/gh/solidusio-contrib/solidus_gdpr)\n\nThis extension helps you respect the GDPR in your Solidus store.\n\n## Installation\n\nAdd `solidus_gdpr` to your Gemfile:\n\n```ruby\ngem 'solidus_gdpr'\n```\n\nBundle your dependencies and run the installation generator:\n\n```shell\n$ bundle\n$ bundle exec rails g solidus_gdpr:install\n```\n\n## Usage\n\nThe GDPR grants user several rights with respect to their data. solidus_gdpr helps you in two ways:\n\n1. it provides a centralized way to handle user requests under the GDPR (the \"User Rights\" section\n   in the Solidus backend), and\n2. it allows you to handle some of these requests automatically, with sane defaults and clean\n   extension points.\n\nLet's see how solidus_gdpr can help you in different scenarios!\n\n### Defining data segments\n\nsolidus_gdpr allows you to automate certain GDPR-related tasks through the concept of data segments.\nA data segment is any easily identifiable group of data about a user. By default, the extension\nships with two data segments:\n\n- `profile`: represents information about a user's profile (basically what's in the `spree_users`\n  table);\n- `orders`: represents information about a user's orders.\n\nHere's the simplest segment you can have:\n\n```ruby\n# app/data_segments/dummy_segment.rb\nclass DummySegment \u003c SolidusGdpr::DataSegments::Base\nend\n```\n\nOnce the segment has been defined, you need to add it to your configuration:\n\n```ruby\n# config/initializers/solidus_gdpr.rb\nSolidusGdpr.configure do |config|\n  config.segments[:reviews] = 'ReviewsSegment'\nend\n```\n\nAs you can see, the segment has a name (which will be used in logs as well as other places such as\ndata exports) and nothing else. Even though perfectly valid, this segment is not very useful right\nnow. Let's see how to define custom GDPR-related business logic for our segments!\n\n#### Data export\n\nThe GDPR grants users the right to data portability, which means you need to be able to provide\nusers with the data you have collected about them in a commonly used electronic format.\n\nsolidus_gdpr provides a `DataExporter` service that will automatically create a ZIP export of your\nuser's data. This export, by default, will contain the `profile.json` and `orders.json` files,\ncontaining information from the respective segments:\n\n```ruby\nSolidusGdpr::DataExporter.new(user).run # =\u003e 'tmp/data-exports/export-2932723756.zip'\n```\n\nIf you collect additional information about your users, all you have to do is define a segment that\nexposes an `#export` method. This method should return the data to be included in any data export\nrequests. Any object that responds to `#to_json` will do:\n\n```ruby\n# app/data_segments/reviews_segment.rb\nclass ReviewsSegment \u003c SolidusGdpr::DataSegments::Base\n  def export\n    user.reviews.find_each.map do |review|\n      {\n        subject: review.subject,\n        order_number: review.order.number,\n        content: review.content,\n        user_name: review.user_name,\n        created_at: review.created_at,\n      }\n    end\n  end\nend\n```\n\nWhen building the data export, solidus_gdpr will use the segment's name as the name of the JSON\nfile, so in this case the final data export would contain three files: `profile.json`, `orders.json`\nand `reviews.json`.\n\n#### Data erasure\n\nAnother request that can be handled automatically by solidus_gdpr is the right to erasure.\n\nThe functionality here is very similar to data exports: solidus_gdpr provides a `DataEraser` service\nwhose job it is to erase a user's data, which is done by calling the `#erase` method on all defined\ndata segments and returning the segments that were processed:\n\n```ruby\nSolidusGdpr::DataEraser.new(user).run # =\u003e ['profile', 'orders']\n```\n\nThe `profile` and `orders` data segments have default implementations of `#erase` which scramble\nthe user's data, but you can override these implementations by overriding the segments or even\ndefine the `#erase` method for your custom segments:\n\n```ruby\n# app/data_segments/reviews_segment.rb\nclass ReviewsSegment \u003c SolidusGdpr::DataSegments::Base\n  def erase\n    user.reviews.find_each do |review|\n      review.update!(user_name: 'Anonymous User')\n    end\n  end\nend\n```\n\nAll the `#erase` calls will be wrapped in a DB transaction, so if one call fails the entire erasure\nwill be rolled back.\n\n#### Data restriction\n\nUsers can also request that you retain their data, but stop any further processing. This can mean\nmany things, including but not limited to moving the data to cold storage, exclude the data from\nany statistical analysis etc.\n\nsolidus_gdpr provides a `DataRestrictor` service that will call the `#restrict_processing` method on\nall data segments. Because data processing can potentially be reverted, you also have a `#rollback`\nmethod that will call the `#resume_processing` method on all data segments.\n\nYou can use the service like this:\n\n```ruby\nrestrictor = SolidusGdpr::DataRestrictor.new(user)\n\nrestrictor.run # =\u003e ['profile', 'orders']\nrestrictor.rollback # =\u003e ['profile', 'orders']\n```\n\nBy default, `ProfileSegment` will set the `data_processable` attribute on the `Spree::User` record\nto, respectively, `false` and `true` when `#restrict_processing` and `#resume_processing` are called.\nNote that you most likely won't need to implement `#restrict_processing` and `#resume_processing` on\nall data segments: simply setting an attribute on the user record, and potentially notifying\nthird-parties, should be enough.\n\nThe extension also exposes the `Spree::User.data_processable` and `Spree::User.data_restricted`\nscopes for your convenience.\n\n### Serving requests automatically\n\nBy default, you are supposed to create GDPR requests manually from the admin panel as they come in\nby email or other customer support channels. However, you can allow your users to send requests\ndirectly to this area by creating `Spree::GdprRequest` records:\n\n```ruby\nrequest = Spree::GdprRequest.create!(\n  intent: 'data_export', # ['data_export', 'data_erasure', 'data_restriction', 'resume_processing']\n  user: current_spree_user,\n  notes: 'Any additional information here',\n)\n```\n\nThis could be done, for instance, in a controller attached to a self-serve form:\n\n```ruby\nclass GdprRequestsController \u003c ApplicationController\n  def create\n    request = Spree::GdprRequest.create!(gdpr_request_params.merge(user: current_spree_user))\n    request.serve # this will run the appropriate workflow and mark the request as served\n\n    redirect_to root_path, notice: 'Your request will be processed shortly.'\n  end\nend\n```\n\nNote that it is desirable to process these requests in the background, since some of them are\ncomputationally intensive.\n\nYou might even decide to simply create the request, but then serve it manually via the admin panel\nby clicking on \"Serve Request\".\n\n### Hooks\n\nWhen a request is created or served, the `after_create` and `after_serve` hooks are called.\n\nYou can use these hooks in two ways:\n\n- If your application uses Solidus \u003e= 3.2, you can use the `Spree::Bus` class.\n- If your application uses Solidus \u003c= 3.2 (and \u003e= 2.9), you can use the `Spree::Event` class, here is the [documentation](https://guides.solidus.io/developers/events/overview.html).\n\nIn both cases, the emitted events are: `gdpr_request_created` and `gdpr_request_served`.\n\n## Testing\n\nFirst bundle your dependencies, then run `rake`. `rake` will default to building the dummy app if it\ndoes not exist, then it will run specs, and [Rubocop](https://github.com/bbatsov/rubocop) static\ncode analysis. The dummy app can be regenerated by using `rake test_app`.\n\n```shell\n$ bundle\n$ bundle exec rake\n```\n\nWhen testing your application's integration with this extension, you may use its factories. Simply\nadd this `require` statement to your `spec_helper`:\n\n```ruby\nrequire 'solidus_gdpr/factories'\n```\n\nReleasing\n---------\n\nYour new extension version can be released using `gem-release` like this:\n\n```shell\nbundle exec gem bump -v VERSION --tag --push --remote upstream \u0026\u0026 gem release\n```\n\n## License\n\nCopyright (c) 2019 [Nebulab Srls](https://nebulab.it), released under the New BSD License\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsolidusio-contrib%2Fsolidus_gdpr","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fsolidusio-contrib%2Fsolidus_gdpr","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsolidusio-contrib%2Fsolidus_gdpr/lists"}