-
-
Notifications
You must be signed in to change notification settings - Fork 4
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
8657162
commit 68c5cb2
Showing
14 changed files
with
328 additions
and
2 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,59 @@ | ||
module V0 | ||
class ExperimentsController < ApplicationController | ||
|
||
before_action :check_if_authorized!, only: [:create, :update, :destroy] | ||
|
||
def index | ||
raise_ransack_errors_as_bad_request do | ||
@q = Experiment.ransack(params[:q]) | ||
@q.sorts = 'id asc' if @q.sorts.empty? | ||
@experiments = @q.result(distinct: true) | ||
@experiments = paginate @experiments | ||
end | ||
end | ||
|
||
def show | ||
@experiment = Experiment.find(params[:id]) | ||
authorize @experiment | ||
end | ||
|
||
def create | ||
@experiment = Experiment.new(experiment_params) | ||
@experiment.owner ||= current_user | ||
authorize @experiment | ||
if @experiment.save | ||
render :show, status: :created | ||
else | ||
raise Smartcitizen::UnprocessableEntity.new @experiment.errors | ||
end | ||
end | ||
|
||
def update | ||
@experiment = Experiment.find(params[:id]) | ||
authorize @experiment | ||
if @experiment.update(experiment_params) | ||
render :show, status: :ok | ||
else | ||
raise Smartcitizen::UnprocessableEntity.new @experiment.errors | ||
end | ||
end | ||
|
||
def destroy | ||
@experiment = Experiment.find(params[:id]) | ||
authorize @experiment | ||
if @experiment.destroy! | ||
render json: {message: 'OK'}, status: :ok | ||
else | ||
raise Smartcitizen::UnprocessableEntity.new @experiment.errors | ||
end | ||
end | ||
|
||
private | ||
|
||
def experiment_params | ||
params.permit( | ||
:name, :description, :active, :is_test, :starts_at, :ends_at, device_ids: [] | ||
) | ||
end | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
class Experiment < ApplicationRecord | ||
belongs_to :owner, class_name: "User" | ||
has_and_belongs_to_many :devices | ||
|
||
validates_presence_of :name, :owner | ||
validates_inclusion_of :is_test, in: [true, false] | ||
|
||
def self.ransackable_attributes(auth_object = nil) | ||
["created_at", "description", "ends_at", "id", "is_test", "name", "owner_id", "starts_at", "status", "updated_at"] | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
class ExperimentPolicy < ApplicationPolicy | ||
def update? | ||
user.try(:is_admin?) || user == record.owner | ||
end | ||
|
||
def create? | ||
user | ||
end | ||
|
||
def destroy? | ||
update? | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -55,4 +55,6 @@ end | |
|
||
json.data device.formatted_data if local_assigns[:with_data] | ||
|
||
json.experiment_ids device.experiment_ids | ||
|
||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
json.(experiment, | ||
:id, :name, :description, :owner_id, :active, :is_test, :starts_at, :ends_at, :device_ids, :created_at, :updated_at | ||
) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
json.array! @experiments, partial: 'experiment', as: :experiment |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
json.partial! "experiment", experiment: @experiment |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
class CreateExperiments < ActiveRecord::Migration[6.1] | ||
def change | ||
create_table :experiments do |t| | ||
t.string :name, null: false | ||
t.string :description | ||
t.belongs_to :owner, index: true | ||
t.boolean :active, null: false, default: true | ||
t.boolean :is_test, null: false, default: false | ||
t.datetime :starts_at | ||
t.datetime :ends_at | ||
t.timestamps | ||
end | ||
add_foreign_key :experiments, :users, column: :owner_id | ||
|
||
create_table :devices_experiments, id: false do |t| | ||
t.belongs_to :device, index: true | ||
t.belongs_to :experiment, index: true | ||
end | ||
add_foreign_key :devices_experiments, :devices, column: :device_id | ||
add_foreign_key :devices_experiments, :experiments, column: :experiment_id | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
FactoryBot.define do | ||
factory :experiment do | ||
sequence("name") { |n| "experiment#{n}"} | ||
description { "my experiment" } | ||
association :owner, factory: :user | ||
active { true } | ||
is_test { false } | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,179 @@ | ||
require 'rails_helper' | ||
|
||
describe V0::ExperimentsController do | ||
|
||
let(:application) { create :application } | ||
|
||
let(:citizen_user) { create :user } | ||
let(:citizen_token) { create :access_token, application: application, resource_owner_id: citizen_user.id } | ||
|
||
let(:admin_user) { create :admin } | ||
let(:admin_token) { create :access_token, application: application, resource_owner_id: admin_user.id } | ||
|
||
let(:owner_user) { create :user } | ||
let(:owner_token) { create :access_token, application: application, resource_owner_id: owner_user.id } | ||
|
||
let(:experiment) { | ||
create(:experiment, name: "Existing experiment", owner: owner_user) | ||
} | ||
|
||
let(:device) { create(:device) } | ||
let(:valid_params) { | ||
{ | ||
name: "test experiment", | ||
description: "a test experiment", | ||
is_test: false, | ||
active: true, | ||
starts_at: "2024-01-01T00:00:00Z", | ||
ends_at: "2024-06-30T23:59:59Z", | ||
device_ids: [ device.id ] | ||
} | ||
} | ||
|
||
describe "GET /experiments" do | ||
it "lists all experiments" do | ||
first = create(:experiment, name: "first experiment") | ||
second = create(:experiment, name: "second experiment") | ||
j = api_get 'experiments' | ||
|
||
expect(j.length).to eq(2) | ||
expect(j[0]['name']).to eq('first experiment') | ||
expect(j[1]['name']).to eq('second experiment') | ||
expect(response.status).to eq(200) | ||
end | ||
end | ||
|
||
describe "POST /experiments" do | ||
context "When no user is logged in" do | ||
it "does not create an experiment" do | ||
before_count = Experiment.count | ||
api_post "experiments", valid_params | ||
|
||
expect(response.status).to eq(401) | ||
expect(Experiment.count).to eq(before_count) | ||
end | ||
end | ||
|
||
context "When a user is logged in" do | ||
it "creates an experiment" do | ||
before_count = Experiment.count | ||
api_post "experiments", valid_params.merge(access_token: citizen_token.token) | ||
|
||
expect(response.status).to eq(201) | ||
expect(Experiment.count).to eq(before_count + 1) | ||
created = Experiment.last | ||
expect(created.name).to eq(valid_params[:name]) | ||
expect(created.description).to eq(valid_params[:description]) | ||
expect(created.is_test).to eq(valid_params[:is_test]) | ||
expect(created.active).to eq(valid_params[:active]) | ||
expect(created.starts_at).to eq(Time.parse(valid_params[:starts_at])) | ||
expect(created.ends_at).to eq(Time.parse(valid_params[:ends_at])) | ||
expect(created.device_ids).to eq(valid_params[:device_ids]) | ||
end | ||
end | ||
end | ||
|
||
describe "GET /experiments/:id" do | ||
|
||
it "returns the experiment" do | ||
json = api_get "experiments/#{experiment.id}" | ||
|
||
expect(response.status).to eq(200) | ||
expect(json["name"]).to eq experiment.name | ||
end | ||
end | ||
|
||
describe "PUT /experiments/:id" do | ||
context "When no user is logged in" do | ||
it "does not update the experiment" do | ||
json = api_put "experiments/#{experiment.id}", valid_params | ||
|
||
updated = Experiment.find(experiment.id) | ||
expect(response.status).to eq(401) | ||
expect(updated).to eq(experiment) | ||
end | ||
end | ||
|
||
context "When the experiment owner is logged in" do | ||
it "updates the experiment" do | ||
json = api_put "experiments/#{experiment.id}", valid_params.merge(access_token: owner_token.token) | ||
|
||
updated = Experiment.find(experiment.id) | ||
expect(updated.name).to eq(valid_params[:name]) | ||
expect(updated.description).to eq(valid_params[:description]) | ||
expect(updated.is_test).to eq(valid_params[:is_test]) | ||
expect(updated.active).to eq(valid_params[:active]) | ||
expect(updated.starts_at).to eq(Time.parse(valid_params[:starts_at])) | ||
expect(updated.ends_at).to eq(Time.parse(valid_params[:ends_at])) | ||
expect(updated.device_ids).to eq(valid_params[:device_ids]) | ||
end | ||
end | ||
|
||
context "When a different user is logged in" do | ||
it "does not update the experiment" do | ||
json = api_put "experiments/#{experiment.id}", valid_params.merge(access_token: citizen_token.token) | ||
|
||
expect(response.status).to eq(403) | ||
updated = Experiment.find(experiment.id) | ||
expect(updated).to eq(experiment) | ||
end | ||
end | ||
|
||
context "When an admin is logged in" do | ||
it "updates the experiment" do | ||
json = api_put "experiments/#{experiment.id}", valid_params.merge(access_token: admin_token.token) | ||
|
||
updated = Experiment.find(experiment.id) | ||
expect(updated.name).to eq(valid_params[:name]) | ||
expect(updated.description).to eq(valid_params[:description]) | ||
expect(updated.is_test).to eq(valid_params[:is_test]) | ||
expect(updated.active).to eq(valid_params[:active]) | ||
expect(updated.starts_at).to eq(Time.parse(valid_params[:starts_at])) | ||
expect(updated.ends_at).to eq(Time.parse(valid_params[:ends_at])) | ||
expect(updated.device_ids).to eq(valid_params[:device_ids]) | ||
end | ||
end | ||
end | ||
|
||
describe "DELETE /experiments/:id" do | ||
context "When no user is logged in" do | ||
it "does not delete the experiment" do | ||
json = api_delete "experiments/#{experiment.id}" | ||
|
||
updated = Experiment.where(id: experiment.id).first | ||
expect(response.status).to eq(401) | ||
expect(updated).not_to be(nil) | ||
end | ||
end | ||
|
||
context "When the experiment owner is logged in" do | ||
it "deletes the experiment" do | ||
json = api_delete "experiments/#{experiment.id}", access_token: owner_token.token | ||
|
||
updated = Experiment.where(id: experiment.id).first | ||
expect(response.status).to eq(200) | ||
expect(updated).to be(nil) | ||
end | ||
end | ||
|
||
context "When a different user is logged in" do | ||
it "does not delete the experiment" do | ||
json = api_delete "experiments/#{experiment.id}", access_token: citizen_token.token | ||
|
||
updated = Experiment.where(id: experiment.id).first | ||
expect(response.status).to eq(403) | ||
expect(updated).not_to be(nil) | ||
end | ||
end | ||
|
||
context "When an admin is logged in" do | ||
it "deletes the experiment" do | ||
json = api_delete "experiments/#{experiment.id}", access_token: admin_token.token | ||
|
||
updated = Experiment.where(id: experiment.id).first | ||
expect(response.status).to eq(200) | ||
expect(updated).to be(nil) | ||
end | ||
end | ||
end | ||
end |