Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature: Model for statistics #205

Merged
merged 20 commits into from
Jan 17, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 22 additions & 2 deletions app/controllers/items_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,8 @@ def create
@item.waitlist = Waitlist.new
@item.set_status_lent unless @item.holder.nil?

helpers.audit_create_item(@item)

create_create_response
end

Expand Down Expand Up @@ -70,6 +72,8 @@ def add_to_waitlist
@item = Item.find(params[:id])
@user = current_user

helpers.audit_add_to_waitlist(@item)

create_add_to_waitlist_response
end

Expand All @@ -78,6 +82,9 @@ def leave_waitlist
@user = current_user
@item.remove_from_waitlist(@user)
@item.save

helpers.audit_leave_waitlist(@item)

redirect_to item_url(@item)
end

Expand All @@ -89,9 +96,13 @@ def request_lend
@notification.save
@item.set_status_pending_lend_request
@item.save

helpers.audit_request_lend(@item)

redirect_to item_url(@item)
end

# (reduce complexity in future)
def accept_lend
@notification = LendRequestNotification.find_by(item: @item)
@item.set_status_pending_pickup
Expand All @@ -105,6 +116,9 @@ def accept_lend
@lendrequest = LendRequestNotification.find(@notification.actable_id)
@lendrequest.update(accepted: true)
@item.save

helpers.audit_accept_lend(@item)

LendingAcceptedNotification.create(item: @item, receiver: @notification.borrower, date: Time.zone.now,
active: false, unread: true)
redirect_to item_url(@item)
Expand Down Expand Up @@ -152,10 +166,12 @@ def request_return
@item = Item.find(params[:id])
@item.set_status_pending_return
@item.save
@user = current_user

helpers.audit_request_return(@item)

unless ReturnRequestNotification.find_by(item: @item)
@notification = ReturnRequestNotification.new(receiver: @item.owning_user, date: Time.zone.now,
item: @item, borrower: @user, active: true, unread: true)
item: @item, borrower: current_user, active: true, unread: true)
@notification.save
end
redirect_to item_url(@item)
Expand All @@ -171,6 +187,9 @@ def accept_return
@accepted_notif.save
@item.reset_status
@item.save

helpers.audit_accept_return(@item)

redirect_to item_url(@item)
end

Expand All @@ -184,6 +203,7 @@ def deny_return
date: Time.zone.now, active: false, unread: true)
@declined_notification.save
@item.destroy

redirect_to notifications_path
end

Expand Down
37 changes: 37 additions & 0 deletions app/helpers/audit_event_helper.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
module AuditEventHelper
def audit_create_item(item)
create_audit_event(item, :create_item)
end

def audit_request_lend(item)
create_audit_event(item, :request_lend)
end

def audit_accept_lend(item)
create_audit_event(item, :accept_lend)
end

def audit_request_return(item)
create_audit_event(item, :request_return)
end

def audit_accept_return(item)
create_audit_event(item, :accept_return)
end

def audit_add_to_waitlist(item)
create_audit_event(item, :add_to_waitlist)
end

def audit_leave_waitlist(item)
create_audit_event(item, :leave_waitlist)
end

private

def create_audit_event(item, event_type)
audit_event = AuditEvent.new(item: item, holder_id: item.holder,
triggering_user: current_user, event_type: event_type)
audit_event.save
end
end
4 changes: 4 additions & 0 deletions app/helpers/statistics_helper.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
module StatisticsHelper
# Module for generating and collecting statistics.
# Please let your helper function start with "statistics_"
end
10 changes: 10 additions & 0 deletions app/models/audit_event.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
class AuditEvent < ApplicationRecord
belongs_to :item
belongs_to :holder, class_name: 'User', optional: true
belongs_to :triggering_user, class_name: 'User'

enum :event_type,
{ create_item: 0, request_lend: 10, accept_lend: 11, request_return: 20, accept_return: 21, deny_return: 22,
add_to_waitlist: 30, leave_waitlist: 31 }
validates :event_type, presence: true, inclusion: { in: event_types.keys }
end
1 change: 1 addition & 0 deletions app/models/item.rb
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
class Item < ApplicationRecord
has_one_attached :image
has_one :waitlist, dependent: :destroy
has_many :audit_events, dependent: :destroy
antonykamp marked this conversation as resolved.
Show resolved Hide resolved
has_many :lend_request_notifications, dependent: :destroy
has_many :return_request_notifications, dependent: :destroy
has_many :return_accepted_notifications, dependent: :destroy
Expand Down
12 changes: 12 additions & 0 deletions db/migrate/20230103101636_create_audit_events.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
class CreateAuditEvents < ActiveRecord::Migration[7.0]
def change
create_table :audit_events do |t|
t.references :item, null: false, foreign_key: true
t.references :holder, null: true, foreign_key: { to_table: :users }
t.references :triggering_user, null: false, foreign_key: { to_table: :users }
t.integer :event_type

t.timestamps
end
end
end
15 changes: 15 additions & 0 deletions db/schema.rb

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

9 changes: 9 additions & 0 deletions spec/factories/audit_events.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
FactoryBot.define do
factory :audit_event do
item { nil }
owner { nil }
holder { nil }
triggering_user { nil }
event_type { 1 }
end
end
30 changes: 30 additions & 0 deletions spec/features/items/show.html.erb_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,13 @@
expect(page).to have_button("Waiting for lend approval", disabled: true)
end

it "creates audit event when requesting for lending" do
sign_in user
visit item_path(item)
find(:button, "Lend").click
expect(AuditEvent.where(item_id: item.id, event_type: "request_lend", triggering_user: user).count).to be(1)
end

it "has return button when item is lent by borrower" do
sign_in borrower
visit item_path(item_lent)
Expand All @@ -83,6 +90,14 @@
expect(page).to have_button("Waiting for return approval", disabled: true)
end

it "creates audit event when requesting for returning" do
sign_in borrower
visit item_path(item_lent)
find(:button, "Return").click
expect(AuditEvent.where(item_id: item_lent.id, event_type: "request_return",
triggering_user: borrower).count).to be(1)
end

it "has enter waitlist button when not on list and item not available" do
sign_in user
visit item_path(item_lent)
Expand Down Expand Up @@ -114,6 +129,13 @@
expect(Item.find(item_lent.id).waitlist.users).to include(user)
end

it "creates audit event when entering for waitlist" do
sign_in user
visit item_path(item_lent)
find(:button, "Enter Waitlist").click
expect(AuditEvent.where(item_id: item_lent.id, event_type: "add_to_waitlist", triggering_user: user).count).to be(1)
end

it "removes user from waitlist when clicking remove from waitlist button" do
sign_in user
item_lent.waitlist.add_user(user)
Expand All @@ -122,6 +144,14 @@
expect(Item.find(item_lent.id).waitlist.users).not_to include(user)
end

it "creates audit event when leaving waitlist" do
sign_in user
item_lent.waitlist.add_user(user)
visit item_path(item_lent)
find(:button, "Leave Waitlist").click
expect(AuditEvent.where(item_id: item_lent.id, event_type: "leave_waitlist", triggering_user: user).count).to be(1)
end

it "creates added to waitlist notification when adding user to waitlist" do
sign_in user
visit item_path(item_lent)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,14 @@
expect(ReturnRequestNotification.exists?(@notification.id)).to be false
end

it "creates an audit when completing the lending process by clicking on 'Accept'" do
visit notifications_path

click_button('Accept')
expect(AuditEvent.where(item: @notification.item.id, event_type: "accept_return",
triggering_user: user).count).to be(1)
end

it "deletes the notification upon clicking on 'Decline'" do
visit notifications_path(id: @notification.id)
expect(ReturnRequestNotification.exists?(@notification.id)).to be true
Expand Down Expand Up @@ -55,5 +63,6 @@
expect(@declined_notification.nil?).to be false
expect(ReturnDeclinedNotification.exists?(id: @declined_notification.actable_id,
item_name: @notification.item.name)).to be true

end
end
2 changes: 2 additions & 0 deletions spec/features/request/accept_lend_request_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
visit item_path(item)
click_button('Lend')
expect(item.reload.lend_status).to eq('pending_lend_request')
expect(AuditEvent.where(item: item, event_type: "request_lend").count).to be(1)
end

it "if owner accepts lend request, the item lend status changes to pending_pickup" do
Expand Down Expand Up @@ -44,6 +45,7 @@
click_button('Confirm pickup')
puts item.reload.lend_status
expect(item.reload.lend_status).to eq('lent')
expect(AuditEvent.where(item: item, event_type: "accept_lend").count).to be(1)
end

end
36 changes: 36 additions & 0 deletions spec/models/audit_event_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
require 'rails_helper'

RSpec.describe AuditEvent, type: :model do

before do
@user = create(:user)
@item = create(:item)
end

it "is valid with all required attributes" do
audit_event = described_class.new(item: @item, holder: @user, triggering_user: @user,
event_type: "create_item")
expect(audit_event).to be_valid
end

it "is not valid without item" do
audit_event = described_class.new(holder: @user, triggering_user: @user, event_type: "create_item")
expect(audit_event).not_to be_valid
end

it "is valid without holder" do
audit_event = described_class.new(item: @item, triggering_user: @user, event_type: "create_item")
expect(audit_event).to be_valid
end

it "is not valid without triggering_user" do
audit_event = described_class.new(item: @item, holder: @user, event_type: "create_item")
expect(audit_event).not_to be_valid
end

it "is not valid without event_type" do
audit_event = described_class.new(item: @item, holder: @user, triggering_user: @user)
expect(audit_event).not_to be_valid
end

end
8 changes: 8 additions & 0 deletions spec/requests/items_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@

RSpec.describe "/items", type: :request do

let(:user) { create(:user) }

# This should return the minimal set of attributes required to create a valid
# Item. As you add validations to Item, be sure to
# adjust the attributes here as well.
Expand Down Expand Up @@ -73,6 +75,12 @@
post items_url, params: { item: valid_request_attributes }
expect(response).to redirect_to(item_url(Item.last))
end

it "creates an audit event" do
sign_in user
post items_url, params: { item: valid_request_attributes }
expect(AuditEvent.where(event_type: "create_item").count).to be(1)
end
end

context "with invalid parameters" do
Expand Down