diff --git a/.github/workflows/ci_cleaner.yml b/.github/workflows/ci_cleaner.yml
index 3b0c64d..7205f3f 100644
--- a/.github/workflows/ci_cleaner.yml
+++ b/.github/workflows/ci_cleaner.yml
@@ -19,14 +19,7 @@ jobs:
if: "github.ref != 'refs/heads/develop'"
env:
GITHUB_TOKEN: "${{ secrets.GITHUB_TOKEN }}"
- - uses: actions/checkout@v2.0.0
- with:
- fetch-depth: 1
- - uses: ruby/setup-ruby@v1
- with:
- bundler-cache: true
- - name: Run Rubocop
- run: bundle exec rubocop -P
+ - uses: OpenSourcePolitics/lint-action@master
tests:
name: Tests
runs-on: ubuntu-latest
@@ -51,86 +44,42 @@ jobs:
if: "github.ref != 'refs/heads/develop'"
env:
GITHUB_TOKEN: "${{ secrets.GITHUB_TOKEN }}"
- - uses: actions/checkout@v2.0.0
- with:
- fetch-depth: 1
- - uses: ruby/setup-ruby@v1
- with:
- bundler-cache: true
- - uses: actions/setup-node@v1
+ - uses: OpenSourcePolitics/rspec-action@master
with:
- node-version: ${{ env.NODE_VERSION }}
- - name: Get npm cache directory path
- id: npm-cache-dir-path
- run: echo "::set-output name=dir::$(npm get cache)-cleaner"
- - uses: actions/cache@v2
- id: npm-cache
- with:
- path: ${{ steps.npm-cache-dir-path.outputs.dir }}
- key: npm-${{ hashFiles('**/package-lock.json') }}
- restore-keys: |
- npm-
- - run: bundle exec rake test_app
- name: Create test app
- - run: mkdir -p ./spec/decidim_dummy_app/tmp/screenshots
- name: Create the screenshots folder
- - uses: nanasess/setup-chromedriver@v1.0.1
- - name: Run precompile if needed
- run: |
- if [[ -d "app/views" ]] || [[ -d "spec/mailers" ]] || [[ -d "spec/system" ]]; then
- cd "spec/decidim_dummy_app"
- bundle exec rails assets:precompile
- else
- echo "No need to precompile assets since system folder is empty"
- fi
- - run: bundle exec rspec
- name: RSpec
- - uses: codecov/codecov-action@v1
- - uses: actions/upload-artifact@v2
- if: always()
- with:
- name: screenshots
- path: ./spec/decidim_dummy_app/tmp/screenshots
- if-no-files-found: ignore
- release:
- if: "github.ref == 'refs/heads/master' || github.ref == 'refs/heads/main' || startsWith(github.ref, 'refs/heads/release' )"
- needs: [tests, lint]
+ command: "bundle exec rspec --exclude-pattern 'spec/system/**/*_spec.rb'"
+ system_tests:
+ name: System tests
runs-on: ubuntu-latest
+ timeout-minutes: 30
+ services:
+ postgres:
+ image: postgres:11
+ ports: ["5432:5432"]
+ options: >-
+ --health-cmd pg_isready
+ --health-interval 10s
+ --health-timeout 5s
+ --health-retries 5
+ env:
+ POSTGRES_PASSWORD: postgres
+ env:
+ DATABASE_USERNAME: postgres
+ DATABASE_PASSWORD: postgres
+ DATABASE_HOST: localhost
steps:
- - uses: actions/checkout@v2.0.0
- with:
- fetch-depth: 1
- - uses: ruby/setup-ruby@v1
+ - uses: rokroskar/workflow-run-cleanup-action@v0.3.0
+ if: "github.ref != 'refs/heads/develop'"
+ env:
+ GITHUB_TOKEN: "${{ secrets.GITHUB_TOKEN }}"
+ - uses: OpenSourcePolitics/rspec-action@master
with:
- bundler-cache: true
- - name: Setup git and gh
- run: |
- git config user.name "${GITHUB_ACTOR}"
- git config user.email "${GITHUB_ACTOR}@users.noreply.github.com"
- echo ${{ secrets.GITHUB_TOKEN }} | gh auth login --with-token
- - run: gem install parse_gemspec-cli
- name: Intall gem parser
- - run: echo "::set-output name=tag::$(parse-gemspec-cli *.gemspec | jq .'version')"
- name: Set tag version
- id: set_tag
- - name: Add tag and push
- run: |
- git tag
- git push --tags
- - name: Create release
- run: gh release create ${{ steps.set_tag.outputs.tag }} --generate-notes
+ command: "bundle exec rspec spec/system"
publish:
- needs: release
+ if: "github.ref == 'refs/heads/master' || github.ref == 'refs/heads/main' || startsWith(github.ref, 'refs/heads/release' )"
+ needs: [tests, system_tests, lint]
runs-on: ubuntu-latest
steps:
- - uses: actions/checkout@v1
- - name: Publish to RubyGems
- run: |
- mkdir -p $HOME/.gem
- touch $HOME/.gem/credentials
- chmod 0600 $HOME/.gem/credentials
- printf -- "---\n:rubygems_api_key: ${GEM_HOST_API_KEY}\n" > $HOME/.gem/credentials
- gem build *.gemspec
- gem push *.gem
- env:
- GEM_HOST_API_KEY: "${{secrets.RUBYGEMS_API_KEY}}"
\ No newline at end of file
+ - uses: OpenSourcePolitics/publish-gem-action@master
+ with:
+ github_token: ${{ secrets.GITHUB_TOKEN }}
+ rubygems_api_key: ${{ secrets.RUBYGEMS_API_KEY }}
\ No newline at end of file
diff --git a/Gemfile b/Gemfile
index 8db7554..9c063cd 100644
--- a/Gemfile
+++ b/Gemfile
@@ -4,7 +4,7 @@ source "https://rubygems.org"
ruby RUBY_VERSION
-gem "decidim"
+gem "decidim", "~> 0.27.0"
gem "decidim-cleaner", path: "."
gem "bootsnap", "~> 1.4"
@@ -12,7 +12,7 @@ gem "puma", ">= 4.3"
group :development, :test do
gem "byebug", "~> 11.0", platform: :mri
- gem "decidim-dev"
+ gem "decidim-dev", "~> 0.27.0"
gem "rubocop-faker"
end
diff --git a/Gemfile.lock b/Gemfile.lock
index 7ec2666..8c3b1cd 100644
--- a/Gemfile.lock
+++ b/Gemfile.lock
@@ -1,7 +1,7 @@
PATH
remote: .
specs:
- decidim-cleaner (3.1.0)
+ decidim-cleaner (3.1.1)
decidim-core (~> 0.27.0)
GEM
@@ -794,15 +794,16 @@ GEM
PLATFORMS
arm64-darwin-21
+ arm64-darwin-22
x86_64-darwin-21
x86_64-linux
DEPENDENCIES
bootsnap (~> 1.4)
byebug (~> 11.0)
- decidim
+ decidim (~> 0.27.0)
decidim-cleaner!
- decidim-dev
+ decidim-dev (~> 0.27.0)
faker (~> 2.14)
letter_opener_web (~> 2.0)
listen (~> 3.1)
diff --git a/README.md b/README.md
index 5520aff..b2a9f0a 100644
--- a/README.md
+++ b/README.md
@@ -66,7 +66,7 @@ You can then add to your 'config/sidekiq.yml' file:
## Available tasks
- [ ] **Delete inactive users**
- - Cron task that checks for user accounts where `last_sign_in_at` is superior to environment variable `CLEANER_USER_INACTIVITY_LIMIT`. If true, deletes inactive user from the database.
+ - Cron task that checks for user accounts where `current_sign_in_at` is superior to environment variable `CLEANER_USER_INACTIVITY_LIMIT`. If true, deletes inactive user from the database.
- [ ] **Delete old admin logs**
- Cron task that checks for admin logs where `created_at` is anterior to the time you configured in the back office. If true, deletes old admin logs from the database.
diff --git a/Rakefile b/Rakefile
index 9f1894c..759e8db 100644
--- a/Rakefile
+++ b/Rakefile
@@ -6,6 +6,9 @@ def install_module(path)
Dir.chdir(path) do
system("bundle exec rake decidim_cleaner:install:migrations")
system("bundle exec rake db:migrate")
+ system("npm install --save-dev @babel/plugin-proposal-private-methods")
+ system("npm install --save-dev @babel/plugin-proposal-private-property-in-object")
+ system("bundle exec rake assets:precompile")
end
end
diff --git a/app/jobs/decidim/cleaner/clean_inactive_users_job.rb b/app/jobs/decidim/cleaner/clean_inactive_users_job.rb
index 494ebf8..4c4135e 100644
--- a/app/jobs/decidim/cleaner/clean_inactive_users_job.rb
+++ b/app/jobs/decidim/cleaner/clean_inactive_users_job.rb
@@ -9,11 +9,11 @@ def perform
Decidim::Organization.find_each do |organization|
next unless organization.delete_inactive_users?
- send_warning(Decidim::User.where(organization: organization)
+ send_warning(Decidim::User.unscoped.where(organization: organization)
.not_deleted
.where.not(email: "")
- .where("last_sign_in_at < ?", email_inactive_before_date(organization)))
- delete_user_and_send_email(Decidim::User.where(organization: organization)
+ .where("current_sign_in_at < ?", email_inactive_before_date(organization)))
+ delete_user_and_send_email(Decidim::User.unscoped.where(organization: organization)
.not_deleted
.where.not(email: "")
.where("warning_date < ?", delete_inactive_before_date(organization)))
@@ -24,15 +24,20 @@ def send_warning(users)
users.find_each do |user|
next if user.warning_date.present?
- user.update!(warning_date: Time.zone.now) if InactiveUsersMailer.warning_inactive(user).deliver_now
- Rails.logger.info "Inactive warning sent to #{user.email}"
+ if InactiveUsersMailer.warning_inactive(user).deliver_now
+ user.warning_date = Time.zone.now
+ user.save(validate: false)
+ else
+ Rails.logger.info "Inactive warning sent to #{user.email}"
+ end
end
end
def delete_user_and_send_email(users)
users.find_each do |user|
- if user.last_sign_in_at > user.warning_date
- user.update!(warning_date: nil)
+ if user.current_sign_in_at > user.warning_date
+ user.warning_date = nil
+ user.save(validate: false)
Rails.logger.info "User with id #{user.id} has logged in again, warning date reset"
next
end
diff --git a/config/locales/fi.yml b/config/locales/fi.yml
new file mode 100644
index 0000000..4f81c2b
--- /dev/null
+++ b/config/locales/fi.yml
@@ -0,0 +1,40 @@
+---
+fi:
+ activemodel:
+ attributes:
+ organization:
+ delete_admin_logs: Ota käyttöön hallintatoimintojen lokien poistaminen
+ delete_admin_logs_after: Hallintatoimintojen lokien säilytysaika (päivää, oletusarvo 365)
+ delete_inactive_users: Ota käyttöön passiivisten käyttäjätilien poisto
+ delete_inactive_users_after: Passiivisten käyttäjätilien säilytysaika varoitusviestin lähetyksen jälkeen (päivää, oletusarvo 30)
+ delete_inactive_users_email_after: Käyttäjätilin poiston varoitusviestin lähetysaika käyttäjätilin ollessa passiivinen (päivää, oletusarvo 365)
+ decidim:
+ admin:
+ menu:
+ clean: Tietojen puhdistus
+ organization:
+ update:
+ error: Organisaation päivitys epäonnistui.
+ success: Organisaation päivitys onnistui.
+ cleaner:
+ admin:
+ organization_cleaner:
+ edit:
+ update: Päivitä
+ form:
+ admin_log_cleaner_title: Hallintatoimintojen lokitiedot
+ inactive_users_cleaner_title: Passiiviset käyttäjät
+ delete_reason: Käyttäjä poistettiin käyttäjätilin passiivisuuden takia
+ inactive_users_mailer:
+ warning_deletion:
+ body_1: Käyttäjätilisi on ollut passiivisena %{days} päivää palvelussa %{organization_name} .
+ body_2: Tämän takia käyttäjätilisi on nyt poistettu palvelusta.
+ greetings: Terveisin,
%{organization_name}
%{organization_url}
+ hello: Hei,
+ subject: Käyttäjätilisi on nyt poistettu
+ warning_inactive:
+ body_1: Käyttäjätilisi on ollut passiivisena %{days} päivää palvelussa %{organization_name}.
+ body_2: Mikäli et kirjaudu alustalle %{remaining_days} päivän aikana, käyttäjätilisi poistetaan.
+ greetings: Terveisin,
%{organization_name}
%{organization_url}
+ hello: Hei,
+ subject: Käyttäjätilisi on ollut passiivisena pitkään
diff --git a/lib/decidim/cleaner.rb b/lib/decidim/cleaner.rb
index 16470aa..f61c882 100644
--- a/lib/decidim/cleaner.rb
+++ b/lib/decidim/cleaner.rb
@@ -3,6 +3,7 @@
require "decidim/cleaner/admin"
require "decidim/cleaner/engine"
require "decidim/cleaner/admin_engine"
+require "decidim/cleaner/extends/commands/decidim/destroy_account"
module Decidim
# This namespace holds the logic of the `Cleaner` module.
diff --git a/lib/decidim/cleaner/engine.rb b/lib/decidim/cleaner/engine.rb
index aa8cc87..ecb02cb 100644
--- a/lib/decidim/cleaner/engine.rb
+++ b/lib/decidim/cleaner/engine.rb
@@ -8,6 +8,10 @@ module Cleaner
# This is the engine that runs on the public interface of cleaner.
class Engine < ::Rails::Engine
isolate_namespace Decidim::Cleaner
+
+ config.to_prepare do
+ Decidim::DestroyAccount.include(Decidim::Cleaner::Extends::DestroyAccount)
+ end
end
end
end
diff --git a/lib/decidim/cleaner/extends/commands/decidim/destroy_account.rb b/lib/decidim/cleaner/extends/commands/decidim/destroy_account.rb
new file mode 100644
index 0000000..24df182
--- /dev/null
+++ b/lib/decidim/cleaner/extends/commands/decidim/destroy_account.rb
@@ -0,0 +1,31 @@
+# frozen_string_literal: true
+
+module Decidim
+ module Cleaner
+ module Extends
+ # This command destroys the user's account.
+ module DestroyAccount
+ extend ActiveSupport::Concern
+
+ included do
+ private
+
+ # Invalidate all sessions after cleaning Decidim::User record to prevent Active Record error
+ def destroy_user_account!
+ @user.name = ""
+ @user.nickname = ""
+ @user.email = ""
+ @user.delete_reason = @form.delete_reason
+ @user.admin = false if @user.admin?
+ @user.deleted_at = Time.current
+ @user.skip_reconfirmation!
+ @user.avatar.purge
+ @user.save!
+
+ @user.invalidate_all_sessions!
+ end
+ end
+ end
+ end
+ end
+end
diff --git a/lib/decidim/cleaner/version.rb b/lib/decidim/cleaner/version.rb
index 0fa01d1..1cc3ad5 100644
--- a/lib/decidim/cleaner/version.rb
+++ b/lib/decidim/cleaner/version.rb
@@ -5,7 +5,7 @@ module Decidim
# This holds the decidim-meetings version.
module Cleaner
def self.version
- "3.1.0"
+ "3.1.1"
end
def self.compatible_decidim_version
diff --git a/spec/commands/decidim/destroy_account_spec.rb b/spec/commands/decidim/destroy_account_spec.rb
new file mode 100644
index 0000000..1212be9
--- /dev/null
+++ b/spec/commands/decidim/destroy_account_spec.rb
@@ -0,0 +1,108 @@
+# frozen_string_literal: true
+
+require "spec_helper"
+
+module Decidim
+ describe DestroyAccount do
+ let(:command) { described_class.new(user, form) }
+ let(:user) { create(:user, :confirmed) }
+ let!(:identity) { create(:identity, user: user) }
+ let(:valid) { true }
+ let(:data) do
+ {
+ delete_reason: "I want to delete my account"
+ }
+ end
+
+ let(:form) do
+ form = double(
+ delete_reason: data[:delete_reason],
+ valid?: valid
+ )
+
+ form
+ end
+
+ context "when invalid" do
+ let(:valid) { false }
+
+ it "broadcasts invalid" do
+ expect { command.call }.to broadcast(:invalid)
+ end
+ end
+
+ context "when valid" do
+ let(:valid) { true }
+
+ it "broadcasts ok" do
+ expect { command.call }.to broadcast(:ok)
+ end
+
+ it "changes the auth salt to invalidate all other sessions" do
+ old_salt = user.authenticatable_salt
+ command.call
+ expect(user.reload.authenticatable_salt).not_to eq(old_salt)
+ end
+
+ it "stores the deleted_at and delete_reason to the user" do
+ command.call
+ expect(user.reload.delete_reason).to eq(data[:delete_reason])
+ expect(user.reload.deleted_at).not_to be_nil
+ end
+
+ it "set name, nickname and email to blank string" do
+ command.call
+ expect(user.reload.name).to eq("")
+ expect(user.reload.nickname).to eq("")
+ expect(user.reload.email).to eq("")
+ end
+
+ it "destroys the current user avatar" do
+ command.call
+ expect(user.reload.avatar).not_to be_present
+ end
+
+ it "deletes user's identities" do
+ expect do
+ command.call
+ end.to change(Identity, :count).by(-1)
+ end
+
+ it "deletes user group memberships" do
+ user_group = create(:user_group)
+ create(:user_group_membership, user_group: user_group, user: user)
+
+ expect do
+ command.call
+ end.to change(UserGroupMembership, :count).by(-1)
+ end
+
+ it "deletes the follows" do
+ other_user = create(:user)
+ create(:follow, followable: user, user: other_user)
+ create(:follow, followable: other_user, user: user)
+
+ expect do
+ command.call
+ end.to change(Follow, :count).by(-2)
+ end
+
+ it "deletes participatory space private user" do
+ create(:participatory_space_private_user, user: user)
+
+ expect do
+ command.call
+ end.to change(ParticipatorySpacePrivateUser, :count).by(-1)
+ end
+
+ context "when user is admin" do
+ let(:user) { create(:user, :confirmed, :admin) }
+
+ it "removes admin role" do
+ command.call
+ expect(user.reload.admin).to be_falsey
+ end
+ end
+ end
+ end
+end
diff --git a/spec/jobs/decidim/cleaner/clean_inactive_users_job_spec.rb b/spec/jobs/decidim/cleaner/clean_inactive_users_job_spec.rb
index 3fe8aab..6b5d611 100644
--- a/spec/jobs/decidim/cleaner/clean_inactive_users_job_spec.rb
+++ b/spec/jobs/decidim/cleaner/clean_inactive_users_job_spec.rb
@@ -7,8 +7,8 @@
context "when the delay is specified" do
let!(:organization) { create(:organization, delete_inactive_users: true, delete_inactive_users_email_after: 25, delete_inactive_users_after: 5) }
- let!(:pending_user) { create(:user, organization: organization, last_sign_in_at: 27.days.ago) }
- let!(:inactive_user) { create(:user, organization: organization, last_sign_in_at: 35.days.ago, warning_date: 10.days.ago) }
+ let!(:pending_user) { create(:user, organization: organization, current_sign_in_at: 27.days.ago) }
+ let!(:inactive_user) { create(:user, organization: organization, current_sign_in_at: 35.days.ago, warning_date: 10.days.ago) }
let!(:user) { create(:user, organization: organization) }
it "enqueues job in queue 'cleaner'" do
@@ -32,8 +32,8 @@
end
context "when users have destroyed his/her account" do
- let!(:pending_user) { create(:user, :deleted, organization: organization, last_sign_in_at: 27.days.ago) }
- let!(:inactive_user) { create(:user, :deleted, organization: organization, last_sign_in_at: 35.days.ago, warning_date: 10.days.ago) }
+ let!(:pending_user) { create(:user, :deleted, organization: organization, current_sign_in_at: 27.days.ago) }
+ let!(:inactive_user) { create(:user, :deleted, organization: organization, current_sign_in_at: 35.days.ago, warning_date: 10.days.ago) }
it "doesn't send email" do
expect(Decidim::Cleaner::InactiveUsersMailer).not_to receive(:warning_inactive).with(pending_user).and_call_original
@@ -53,7 +53,7 @@
end
context "when user reconnect after warning" do
- let!(:inactive_user) { create(:user, organization: organization, last_sign_in_at: 7.days.ago, warning_date: 10.days.ago) }
+ let!(:inactive_user) { create(:user, organization: organization, current_sign_in_at: 7.days.ago, warning_date: 10.days.ago) }
it "doesn't send email" do
expect(Decidim::Cleaner::InactiveUsersMailer).not_to receive(:warning_deletion).with(inactive_user).and_call_original
diff --git a/spec/lib/decidim/cleaner/version_spec.rb b/spec/lib/decidim/cleaner/version_spec.rb
index adb2de7..5b32f57 100644
--- a/spec/lib/decidim/cleaner/version_spec.rb
+++ b/spec/lib/decidim/cleaner/version_spec.rb
@@ -7,7 +7,7 @@ module Decidim
subject { described_class }
it "has version" do
- expect(subject.version).to eq("3.1.0")
+ expect(subject.version).to eq("3.1.1")
end
it "has decidim version compatibility" do