Skip to content

Commit

Permalink
feat(public account share): add public account share (#69)
Browse files Browse the repository at this point in the history
* feat(public account share): add public account share

* feat(public account share): fixup! add public account share

* feat(public account share): fixup! fixup! add public account share

* feat(public account share): fixup! fixup! fixup! add public account share

* feat(public account share): fixup! fixup! fixup! fixup! add public account share

* feat(public account share): fixup! fixup! fixup! fixup! fixup! add public account share

* feat(public account share): fixup! fixup! fixup! fixup! fixup! fixup! add public account share

* feat(public account share): fixup! fixup! fixup! fixup! fixup! fixup! fixup! add public account share

* feat(public account share): fixup! fixup! fixup! fixup! fixup! fixup! fixup! fixup! add public account share

* feat(public account share): fixup! fixup! fixup! fixup! fixup! fixup! fixup! fixup! fixup! add public account share

* feat(public account share): fixup! fixup! fixup! fixup! fixup! fixup! fixup! fixup! fixup! add public account share

* feat(public account share): fixup! fixup! fixup! fixup! fixup! fixup! fixup! fixup! fixup! add public account share

---------

Co-authored-by: VladislavSokov <[email protected]>
  • Loading branch information
VladislavSokov and VladislavSokov authored Sep 6, 2023
1 parent 153cea8 commit 51fbf37
Show file tree
Hide file tree
Showing 16 changed files with 156 additions and 45 deletions.
14 changes: 12 additions & 2 deletions app/controllers/account_shares_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

class AccountSharesController < ApplicationController
before_action :authenticate_user!
before_action :account_share, only: [:destroy]

def index; end

Expand All @@ -17,8 +18,9 @@ def create
end

def destroy
personal_account_share = AccountShare.find(ps.fetch(:id))
personal_account_share.destroy
return unless accessible?

account_share.destroy
respond_to do |format|
format.html { redirect_to account_shares_url, notice: 'Account share was successfully destroyed.' }
end
Expand All @@ -29,4 +31,12 @@ def destroy
def account_share_params
params.require(:account_share).permit(:name, :email)
end

memoize def account_share
AccountShare.find(params.fetch(:id))
end

def accessible?
current_user.id == account_share.user_id || current_user.email == account_share.email
end
end
18 changes: 18 additions & 0 deletions app/controllers/accounts_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,25 @@ def create

private

memoize def public_shared_accounts
Set.new(AccountShare.accepted.for_public.pluck(:account_id))
end

memoize def private_shared_accounts
Set.new(AccountShare.accepted.for(current_user).pluck(:account_id))
end

helper_method memoize def account
Account.visible_for(current_user).find(ps.fetch(:id))
end

# An account isn't considered publicly shared if it's privately shared with the user
# or it's the child account of the current user.

helper_method def public_share?(account)
return false if current_user.account_id == account.parent_id ||
private_shared_accounts.include?(account.id)

public_shared_accounts.include?(account.id)
end
end
4 changes: 4 additions & 0 deletions app/controllers/my_accounts_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,10 @@ def show; end
Account.shared_for(current_user)
end

helper_method memoize def public_shared_accounts
Account.shared_for_public
end

helper_method memoize def unaccepted_shares
AccountShare.unaccepted.for(current_user)
end
Expand Down
12 changes: 12 additions & 0 deletions app/controllers/public_account_shares_controller.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
# frozen_string_literal: true

class PublicAccountSharesController < ApplicationController
before_action :authenticate_user!

def new; end

def create
AccountShare.create!(user_id: current_user.id, account_id: account.id, accepted_at: Time.current)
redirect_to account_shares_path account
end
end
4 changes: 3 additions & 1 deletion app/models/account.rb
Original file line number Diff line number Diff line change
Expand Up @@ -19,10 +19,12 @@ class Account < ApplicationRecord
scope :visible_for, lambda { |current_user|
where(id: [current_user.account_id] +
current_user.account.child_ids +
shared_for(current_user).pluck(:id))
shared_for(current_user).pluck(:id) +
shared_for_public.pluck(:id))
}

scope :shared_for, ->(user) { where(id: AccountShare.accepted.for(user).pluck(:account_id)) }
scope :shared_for_public, -> { where(id: AccountShare.accepted.for_public.pluck(:account_id)) }

memoize def balance
income_transactions.sum(:amount) - outcome_transactions.sum(:amount)
Expand Down
5 changes: 5 additions & 0 deletions app/models/account_share.rb
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,11 @@ class AccountShare < ApplicationRecord
belongs_to :account

scope :for, ->(user) { where(email: user.email) }
scope :for_public, -> { where(email: nil) }
scope :accepted, -> { where.not(accepted_at: nil) }
scope :unaccepted, -> { where(accepted_at: nil) }

memoize def public?
email.nil? && name.nil? && token.nil?
end
end
5 changes: 4 additions & 1 deletion app/views/account_shares/_account_share.html.slim
Original file line number Diff line number Diff line change
Expand Up @@ -3,5 +3,8 @@ tr
td= account_share.email
td= account_share.created_at.to_formatted_s(:short)
td= account_share.accepted_at&.to_formatted_s(:short)
td= link_to 'link', accept_account_share_url(token: account_share.token)
- if account_share.public?
td= ''
- else
td= link_to 'link', accept_account_share_url(token: account_share.token)
td= link_to :delete, account_share_path(account, account_share), method: :delete, data: {confirm: 'Delete this share?'}
4 changes: 3 additions & 1 deletion app/views/account_shares/index.html.slim
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
h2.title
| Account shares
= link_to 'New share', new_account_share_path, class: 'button is-light'
.buttons.mt-4
= link_to 'New private share', new_account_share_path, class: 'button is-light mr-4'
= link_to 'New public share', new_account_public_account_share_path, class: 'button is-light'

.columns
.column
Expand Down
5 changes: 4 additions & 1 deletion app/views/accounts/_objective.html.slim
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,7 @@ tr
td= number_to_percentage(account.balance / objective.amount * 100, precision: 0)
td= ([objective.amount - account.balance, 0].max / account.automatic_topup_configs.sum(:amount).+(0.1)).round(2)
td= image_tag objective.image_url
td= link_to :delete, objective_path(objective), method: :delete, data: {confirm: 'Delete this objective?'}
- if public_share?(account)
td= ''
-else
td= link_to :delete, objective_path(objective), method: :delete, data: {confirm: 'Delete this objective?'}
5 changes: 4 additions & 1 deletion app/views/accounts/_transaction.html.slim
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,7 @@ tr
td= transaction.to_account.name
td= transaction.signed_amount(account)
td= transaction.description
td= link_to :delete, transaction_path(transaction), method: :delete, data: {confirm: 'Delete this transaction?'}
- if public_share?(account)
td= ''
-else
td= link_to :delete, transaction_path(transaction), method: :delete, data: {confirm: 'Delete this transaction?'}
41 changes: 24 additions & 17 deletions app/views/accounts/show.html.slim
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,11 @@
.column.is-three-quarters
h2.title
| Account details
= link_to 'Edit', edit_account_path(account), class: 'button is-light'
.column.is-flex.is-justify-content-flex-end
= link_to 'Account shares', account_shares_path(account), class: 'button is-light'
- unless public_share?(account)
= link_to 'Edit', edit_account_path(account), class: 'button is-light'
- unless public_share?(account)
.column.is-flex.is-justify-content-flex-end
= link_to 'Account shares', account_shares_path(account), class: 'button is-light'

.columns
.column
Expand All @@ -15,9 +17,10 @@
.card-content
.title.has-text-centered
| Balance: #{account.balance}
.card-footer
= link_to '+Add', new_account_topup_path(account), class: 'card-footer-item'
= link_to '-Spend', new_account_spend_path(account), class: 'card-footer-item'
- unless public_share?(account)
.card-footer
= link_to '+Add', new_account_topup_path(account), class: 'card-footer-item'
= link_to '-Spend', new_account_spend_path(account), class: 'card-footer-item'
.columns
.column
.card
Expand Down Expand Up @@ -53,8 +56,9 @@
th Image
th Actions
= render partial: 'objective', collection: account.objectives, account: account
.card-footer
= link_to '+Add', new_account_objective_path(account), class: 'card-footer-item'
- unless public_share?(account)
.card-footer
= link_to '+Add', new_account_objective_path(account), class: 'card-footer-item'

.columns
.column
Expand All @@ -73,12 +77,15 @@
tr
td= config.from_account.name
td= config.amount
td
= link_to 'edit', edit_account_account_automatic_topup_config_path(account, config)
| &nbsp;
= link_to 'delete', account_account_automatic_topup_config_path(account, config), method: :delete, data: { confirm: 'Are you sure?' }

.card-footer
= link_to '+ Add', new_account_account_automatic_topup_config_path(account), class: 'card-footer-item'
= line_chart account.accumulative_balance_data, xtitle: 'Date', ytitle: 'Accumulative Balance'

- if public_share?(account)
td ''
- else
td
= link_to 'edit', edit_account_account_automatic_topup_config_path(account, config)
| &nbsp;
= link_to 'delete', account_account_automatic_topup_config_path(account, config), method: :delete, data: { confirm: 'Are you sure?' }
- unless public_share?(account)
.card-footer
= link_to '+ Add', new_account_account_automatic_topup_config_path(account), class: 'card-footer-item'
- if account.accumulative_balance_data.present?
= line_chart account.accumulative_balance_data, xtitle: 'Date', ytitle: 'Accumulative Balance'
11 changes: 11 additions & 0 deletions app/views/my_accounts/show.html.slim
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,17 @@
footer.card-footer
= link_to '+ Add', new_account_topup_path(shared_account), class: 'card-footer-item'
= link_to '- Spend', new_account_spend_path(shared_account), class: 'card-footer-item'
br
- if public_shared_accounts.present?
| Public shared accounts
- public_shared_accounts.each do |shared_account|
.card.box
.card-content
.media
.media-content
p.title.is-6 Owner: #{shared_account.parent.email}
p.title.is-4= link_to shared_account.name, account_path(shared_account)
p.subtitle.is-6= shared_account.balance

- if unaccepted_shares.present?
h2.title
Expand Down
7 changes: 7 additions & 0 deletions app/views/public_account_shares/new.html.slim
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
.column
= link_to 'Back', account_shares_path, class: 'button is-light'
.column
p Create a new Public Account Share

= form_with(url: account_public_account_shares_path, method: :post) do |form|
= form.submit 'Create', class: 'button is-primary'
1 change: 1 addition & 0 deletions config/routes.rb
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
resource :spend, only: %i[new create]
resources :objectives, only: %i[new create]
resources :shares, only: %i[index new create destroy], controller: 'account_shares'
resources :public_account_shares, only: %i[new create]
end

resources :accept_account_shares, param: :token, only: %i[show update]
Expand Down
39 changes: 18 additions & 21 deletions spec/controllers/account_shares_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -3,34 +3,26 @@
require 'rails_helper'

RSpec.describe AccountSharesController, type: :controller do
describe '#index' do
let(:account) { create(:account, :parent) }
let(:user) { create(:user, account: account) }
let(:account) { create(:account, :parent) }
let(:user) { create(:user, account: account) }

subject(:index) { get :index, params: { account_id: account.id } }
before { sign_in user }

before { sign_in user }
describe '#index' do
subject(:index) { get :index, params: { account_id: account.id } }

it { is_expected.to have_http_status(:success) }
it { is_expected.to render_template(:index) }
end

describe '#new' do
let(:account) { create(:account, :parent) }
let(:user) { create(:user, account: account) }

subject(:new) { get :new, params: { account_id: account.id } }

before { sign_in user }

it { is_expected.to have_http_status(:success) }
it { is_expected.to render_template(:new) }
end

describe '#create' do
let(:account) { create(:account, :parent) }
let(:user) { create(:user, account: account) }

subject do
post :create, params: { account_share: {
name: FFaker::Name.first_name,
Expand All @@ -39,22 +31,27 @@
}, account_id: account.id }
end

before { sign_in user }

it { is_expected.to redirect_to(account_shares_path) }
it { is_expected.to have_http_status(302) }
it { expect { subject }.to change { AccountShare.where(user_id: user.id).count }.by(1) }
it { expect { subject }.to change { AccountShare.count }.by(1) }
end

describe '#destroy' do
let(:account) { create(:account, :parent) }
let(:user) { create(:user, account: account) }
let(:second_user) { create(:user) }
let!(:account_share) { create(:account_share, user: user, account: account, email: second_user.email) }
let!(:account_share) { create(:account_share, user: user, account: account, email: FFaker::Internet.email) }

subject { delete :destroy, params: { account_id: account.id, id: account_share } }
before { sign_in user }
it { expect { subject }.to change { AccountShare.count }.from(1).to(0) }

context 'when user have access to destroy the share' do
it { expect { subject }.to change { AccountShare.count }.by(-1) }
it { is_expected.to redirect_to(account_shares_path) }
end

context 'when user not to have access to destroy the share' do
let(:another_user) { create(:user) }
before { sign_in another_user }

it { expect { subject }.not_to(change { AccountShare.count }) }
end
end
end
26 changes: 26 additions & 0 deletions spec/controllers/public_account_shares_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
# frozen_string_literal: true

require 'rails_helper'

RSpec.describe PublicAccountSharesController, type: :controller do
let(:account) { create(:account, :parent) }
let(:user) { create(:user, account: account) }

before { sign_in user }

describe '#new' do
subject(:new) { get :new, params: { account_id: account.id } }

it { is_expected.to have_http_status(:success) }
it { is_expected.to render_template(:new) }
end

describe '#create' do
subject { post :create, params: { account_id: account.id } }

it { is_expected.to redirect_to(account_shares_path) }
it { is_expected.to have_http_status(302) }
it { expect { subject }.to change { AccountShare.where(user_id: user.id).count }.by(1) }
it { expect { subject }.to change { AccountShare.count }.by(1) }
end
end

0 comments on commit 51fbf37

Please sign in to comment.