Merge pull request #1471 from biosistemika/master

Merge master into features/templates
This commit is contained in:
Luka Murn 2019-01-29 10:14:09 +01:00 committed by GitHub
commit 1f7bca485a
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
185 changed files with 1164 additions and 5464 deletions

3
.gitignore vendored
View file

@ -71,3 +71,6 @@ features/addons
spec/addons
!features/addons/.gitkeep
!spec/addons/.gitkeep
# RVM/rbenv ruby version for local development
.ruby-version

5
.overcommit.yml Normal file
View file

@ -0,0 +1,5 @@
PreCommit:
RuboCop:
enabled: true
on_warn: fail
problem_on_unmodified_line: ignore

View file

@ -350,6 +350,9 @@ Style/WhenThen:
Metrics/AbcSize:
Enabled: false
Metrics/BlockLength:
ExcludedMethods: ['describe', 'context']
Metrics/ClassLength:
Enabled: false

View file

@ -2,10 +2,12 @@ FROM ruby:2.4.5
MAINTAINER BioSistemika <info@biosistemika.com>
# additional dependecies
# libSSL-1.0 is required by wkhtmltopdf binary
RUN curl -sL https://deb.nodesource.com/setup_8.x | bash - && \
apt-get update -qq && \
apt-get install -y \
libjemalloc1 \
libssl1.0-dev \
nodejs \
postgresql-client \
default-jre-headless \

View file

@ -2,10 +2,12 @@ FROM ruby:2.4.5
MAINTAINER BioSistemika <info@biosistemika.com>
# additional dependecies
# libSSL-1.0 is required by wkhtmltopdf binary
RUN curl -sL https://deb.nodesource.com/setup_8.x | bash - && \
apt-get update -qq && \
apt-get install -y \
libjemalloc1 \
libssl1.0-dev \
nodejs \
groff-base \
awscli \

105
Gemfile
View file

@ -1,20 +1,22 @@
# frozen_string_literal: true
source 'http://rubygems.org'
ruby '2.4.5'
gem 'rails', '5.1.6'
gem 'webpacker', '~> 2.0'
gem 'figaro'
gem 'pg', '~> 0.18'
gem 'bootstrap-sass', '~> 3.3.7'
gem 'bootstrap_form'
gem 'devise', '~> 4.3.0'
gem 'devise_invitable'
gem 'simple_token_authentication', '~> 1.15.1' # Token authentication for Devise
gem 'bootstrap-sass', '~> 3.3.7'
gem 'sass-rails', '~> 5.0.6'
gem 'bootstrap_form'
gem 'yomu'
gem 'figaro'
gem 'pg', '~> 0.18'
gem 'rails', '5.1.6'
gem 'recaptcha', require: 'recaptcha/rails'
gem 'sanitize', '~> 4.4'
gem 'sass-rails', '~> 5.0.6'
gem 'simple_token_authentication', '~> 1.15.1' # Token authentication for Devise
gem 'webpacker', '~> 2.0'
gem 'yomu'
# Gems for OAuth2 subsystem
gem 'doorkeeper', '>= 4.6'
@ -36,97 +38,98 @@ gem 'bootstrap3-datetimepicker-rails', '~> 4.15.35'
gem 'bootstrap-select-rails', '~> 1.12.4'
gem 'uglifier', '>= 1.3.0'
# jQuery & plugins
gem 'autosize-rails' # jQuery autosize plugin
gem 'hammerjs-rails'
gem 'jquery-rails'
gem 'jquery-ui-rails'
gem 'jquery-scrollto-rails',
git: 'https://github.com/biosistemika/jquery-scrollto-rails'
gem 'hammerjs-rails'
gem 'jquery-ui-rails'
gem 'js_cookie_rails' # Simple JS API for cookies
gem 'spinjs-rails'
gem 'autosize-rails' # jQuery autosize plugin
gem 'underscore-rails'
gem 'turbolinks', '~> 5.1.1'
gem 'sdoc', '~> 1.0', group: :doc
gem 'bcrypt', '~> 3.1.10'
gem 'logging', '~> 2.0.0'
gem 'aspector' # Aspect-oriented programming for Rails
gem 'rgl' # Graph framework for project diagram calculations
gem 'nested_form_fields'
gem 'activerecord-import'
gem 'ajax-datatables-rails', '~> 0.3.1'
gem 'commit_param_routing' # Enables different submit actions in the same form to route to different actions in controller
gem 'i18n-js', '~> 3.0' # Localization in javascript files
gem 'roo', '~> 2.7.1' # Spreadsheet parser
gem 'wicked_pdf', '~> 1.1.0'
gem 'silencer' # Silence certain Rails logs
gem 'wkhtmltopdf-heroku'
gem 'faker' # Generate fake data
gem 'auto_strip_attributes', '~> 2.1' # Removes unnecessary whitespaces from ActiveRecord or ActiveModel attributes
gem 'aspector' # Aspect-oriented programming for Rails
gem 'auto_strip_attributes', '~> 2.1' # Removes unnecessary whitespaces AR
gem 'bcrypt', '~> 3.1.10'
gem 'commit_param_routing' # Enables different submit actions in the same form
gem 'deface', '~> 1.0'
gem 'nokogiri', '~> 1.8.1' # HTML/XML parser
gem 'sneaky-save', git: 'https://github.com/einzige/sneaky-save'
gem 'rails_autolink', '~> 1.1', '>= 1.1.6'
gem 'delayed_paperclip',
git: 'https://github.com/jrgifford/delayed_paperclip.git',
ref: 'fcf574c'
gem 'rubyzip'
gem 'faker' # Generate fake data
gem 'i18n-js', '~> 3.0' # Localization in javascript files
gem 'jbuilder' # JSON structures via a Builder-style DSL
gem 'activerecord-import'
gem 'logging', '~> 2.0.0'
gem 'nested_form_fields'
gem 'nokogiri', '~> 1.8.1' # HTML/XML parser
gem 'rails_autolink', '~> 1.1', '>= 1.1.6'
gem 'rgl' # Graph framework for project diagram calculations
gem 'roo', '~> 2.7.1' # Spreadsheet parser
gem 'rubyzip'
gem 'scenic', '~> 1.4'
gem 'sdoc', '~> 1.0', group: :doc
gem 'silencer' # Silence certain Rails logs
gem 'sneaky-save', git: 'https://github.com/einzige/sneaky-save'
gem 'turbolinks', '~> 5.1.1'
gem 'underscore-rails'
gem 'wicked_pdf', '~> 1.1.0'
gem 'wkhtmltopdf-heroku'
gem 'paperclip', '~> 5.3' # File attachment, image attachment library
gem 'aws-sdk', '~> 2'
gem 'paperclip', '~> 5.3' # File attachment, image attachment library
gem 'delayed_job_active_record'
gem 'devise-async',
git: 'https://github.com/mhfs/devise-async.git',
branch: 'devise-4.x'
git: 'https://github.com/mhfs/devise-async.git',
branch: 'devise-4.x'
gem 'discard', '~> 1.0'
gem 'ruby-graphviz', '~> 1.2' # Graphviz for rails
gem 'tinymce-rails', '~> 4.7.13' # Rich text editor - SEE BELOW
# Any time you update tinymce-rails Gem, also update the cache_suffix parameter in
# sitewide/tiny_mce.js - to prevent browsers from loading old, cached .js
# Any time you update tinymce-rails Gem, also update the cache_suffix parameter
# in sitewide/tiny_mce.js - to prevent browsers from loading old, cached .js
# TinyMCE files which might cause errors
gem 'base62' # Used for smart annotations
gem 'newrelic_rpm'
gem 'devise_security_extension',
git: 'https://github.com/phatworx/devise_security_extension.git',
ref: 'b2ee978'
gem 'newrelic_rpm'
# Permission helper Gem
gem 'canaid', git: 'https://github.com/biosistemika/canaid', branch: 'master'
group :development, :test do
gem 'listen', '~> 3.0'
gem 'awesome_print'
gem 'better_errors'
gem 'binding_of_caller'
gem 'bullet'
gem 'byebug'
gem 'factory_bot_rails'
gem 'listen', '~> 3.0'
gem 'overcommit'
gem 'pry'
gem 'pry-byebug'
gem 'pry-rails'
gem 'factory_bot_rails'
gem 'rails-controller-testing'
gem 'rspec-rails'
gem 'better_errors'
gem 'binding_of_caller'
gem 'awesome_print'
gem 'rubocop', '>= 0.59.0', require: false
gem 'scss_lint', require: false
gem 'starscope', require: false
gem 'bullet'
end
group :test do
gem 'shoulda-matchers'
gem 'cucumber-rails', '~> 1.5', require: false
gem 'database_cleaner'
gem 'capybara'
gem 'capybara-email'
gem 'poltergeist'
gem 'phantomjs', require: 'phantomjs/poltergeist'
gem 'simplecov', require: false
gem 'cucumber-rails', '~> 1.5', require: false
gem 'database_cleaner'
gem 'json_matchers'
gem 'phantomjs', require: 'phantomjs/poltergeist'
gem 'poltergeist'
gem 'shoulda-matchers'
gem 'simplecov', require: false
end
group :production do

View file

@ -156,6 +156,8 @@ GEM
mail
case_transform (0.2)
activesupport
childprocess (0.9.0)
ffi (~> 1.0, >= 1.0.11)
climate_control (0.2.0)
cliver (0.3.2)
coderay (1.1.2)
@ -241,6 +243,7 @@ GEM
concurrent-ruby (~> 1.0)
i18n-js (3.0.3)
i18n (~> 0.6, >= 0.6.6)
iniparse (1.4.4)
jaro_winkler (1.5.1)
jbuilder (2.7.0)
activesupport (>= 4.2.0)
@ -330,6 +333,9 @@ GEM
oauth2 (~> 1.1)
omniauth (~> 1.2)
orm_adapter (0.5.0)
overcommit (0.46.0)
childprocess (~> 0.6, >= 0.6.3)
iniparse (~> 1.4)
paperclip (5.3.0)
activemodel (>= 4.2.0)
activesupport (>= 4.2.0)
@ -590,6 +596,7 @@ DEPENDENCIES
nokogiri (~> 1.8.1)
omniauth
omniauth-linkedin-oauth2
overcommit
paperclip (~> 5.3)
pg (~> 0.18)
phantomjs
@ -637,4 +644,4 @@ RUBY VERSION
ruby 2.4.4p296
BUNDLED WITH
1.16.6
1.17.1

View file

@ -35,6 +35,7 @@
//= require underscore
//= require i18n.js
//= require i18n/translations
//= require users/settings/teams/invite_users_modal
//= require turbolinks

View file

@ -11,7 +11,7 @@
I18n setupSidebarTree */
//= require comments
(function() {
(function(global) {
var newProjectModal = null;
var newProjectModalForm = null;
var newProjectModalBody = null;
@ -203,7 +203,7 @@
}
// Initialize users editing modal remote loading.
function initUsersEditLink($el) {
global.initUsersEditLink = function($el) {
$el.find('.manage-users-link')
.on('ajax:before', function() {
var projectId = $(this).closest('.panel-default').attr('id');
@ -771,4 +771,4 @@
initProjectsViewModeSwitch();
initSorting();
loadCardsView();
}());
}(window));

View file

@ -115,8 +115,29 @@ function importProtocolFromFile(
$("#protocol_authors").val($(this).children("authors").text());
$("#import_protocol_description").val($(this).children("description").text());
}
$("#protocol_created_at").val($(this).children("created_at").text());
$("#protocol_updated_at").val($(this).children("updated_at").text());
$.ajax({
url: "/helpers/to_user_date_format.json",
type: "GET",
data: { "timestamp": $(this).children("created_at").text(),
"ts_format": "full" },
dataType: "json",
async: false,
success: function (data) {
$("#protocol_created_at").val(data.ts);
}
});
$.ajax({
url: "/helpers/to_user_date_format.json",
type: "GET",
data: { "timestamp": $(this).children("updated_at").text(),
"ts_format": "full" },
dataType: "json",
async: false,
success: function (data) {
$("#protocol_updated_at").val(data.ts);
}
});
});
// PREVIEW

View file

@ -1,6 +1,16 @@
(function() {
'use strict';
function reloadRecaptchaIfExists() {
if (typeof grecaptcha !== 'undefined') {
grecaptcha.reset();
}
}
window.recaptchaCallback = function recaptchaCallback(response) {
$('#recaptcha-invite-modal').val(response);
};
function initializeModal(modal) {
var modalDialog = modal.find('.modal-dialog');
var type = modal.attr('data-type');
@ -14,6 +24,9 @@
var teamSelectorDropdown = modal.find('[data-role=team-selector-dropdown]');
var teamSelectorDropdown2 = $();
var tagsInput = modal.find('[data-role=tags-input]');
var recaptchaInput = modal.find('#recaptcha-invite-modal');
var recaptchaErrorMsgDiv = modal.find('#recaptcha-error-msg');
var recaptchaErrorText = modal.find('#recaptcha-error-msg>span');
// Set max tags
tagsInput.tagsinput({
@ -85,7 +98,8 @@
// Click action
modal.find('[data-action=invite]').off('click').on('click', function() {
var data = {
emails: tagsInput.val()
emails: tagsInput.val(),
'g-recaptcha-response': recaptchaInput.val()
};
animateSpinner(modalDialog);
@ -130,16 +144,23 @@
// Add 'data-invited="true"' status to modal element
modal.attr('data-invited', 'true');
},
error: function() {
error: function(jqXHR) {
// ReCaptcha fails
if (jqXHR.status === 422) {
recaptchaErrorMsgDiv.removeClass('hidden');
recaptchaErrorText.text(jqXHR.responseJSON.recaptcha_error);
} else {
modal.modal('hide');
alert('Error inviting users.');
}
reloadRecaptchaIfExists();
animateSpinner(modalDialog, false);
modal.modal('hide');
alert('Error inviting users.');
}
});
});
}).on('shown.bs.modal', function() {
tagsInput.tagsinput('focus');
recaptchaErrorMsgDiv.addClass('hidden');
// Remove 'data-invited="true"' status
modal.removeAttr('data-invited');
}).on('hide.bs.modal', function() {
@ -150,6 +171,7 @@
inviteWithRoleBtn.attr('disabled', 'disabled');
teamSelectorDropdown2.addClass('disabled');
animateSpinner(modalDialog, false);
recaptchaErrorMsgDiv.addClass('hidden');
// Unbind event listeners
teamSelectorCheckbox.off('change');
@ -160,6 +182,8 @@
stepResultsDiv.html('');
stepResults.hide();
stepForm.show();
reloadRecaptchaIfExists();
recaptchaInput.val('');
});
}

View file

@ -783,7 +783,9 @@ ul.double-line > li {
}
.manage-users-link {
display: block;
padding-left: 15px;
margin-bottom: 10px;
}
}
@ -1403,6 +1405,10 @@ table.dataTable {
margin: 0;
}
}
.g-recaptcha {
margin-top: 20px;
}
}
// Image preview modal

View file

@ -36,6 +36,16 @@ class ApplicationController < ActionController::Base
Team.find_by_id(current_user.current_team_id)
end
def to_user_date_format
ts = I18n.l(Time.parse(params[:timestamp]),
format: params[:ts_format].to_sym)
respond_to do |format|
format.json do
render json: { ts: ts }, status: :ok
end
end
end
protected
def render_403(style = 'danger')

View file

@ -1,3 +1,5 @@
# frozen_string_literal: true
class ExperimentsController < ApplicationController
include SampleActions
include TeamsHelper
@ -237,49 +239,23 @@ class ExperimentsController < ApplicationController
# POST: move_experiment(id)
def move
project = Project.find_by_id(params[:experiment].try(:[], :project_id))
old_project = @experiment.project
# Try to move the experiment
success = true
if @experiment.moveable_projects(current_user).include?(project)
success = @experiment.move_to_project(project)
else
success = false
end
if success
Activity.create(
type_of: :move_experiment,
project: project,
experiment: @experiment,
user: current_user,
message: I18n.t(
'activities.move_experiment',
user: current_user.full_name,
experiment: @experiment.name,
project_new: project.name,
project_original: old_project.name
)
)
service = Experiments::MoveToProjectService
.call(experiment_id: @experiment.id,
project_id: move_experiment_param,
user_id: current_user.id)
if service.succeed?
flash[:success] = t('experiments.move.success_flash',
experiment: @experiment.name)
respond_to do |format|
format.json do
render json: { path: canvas_experiment_url(@experiment) }, status: :ok
end
end
path = canvas_experiment_url(@experiment)
status = :ok
else
respond_to do |format|
format.json do
render json: { message: t('experiments.move.error_flash',
experiment:
escape_input(@experiment.name)) },
status: :unprocessable_entity
end
end
message = t('experiments.move.error_flash',
experiment: escape_input(@experiment.name))
status = :unprocessable_entity
end
render json: { message: message, path: path }, status: status
end
def module_archive
@ -348,6 +324,10 @@ class ExperimentsController < ApplicationController
params.require(:experiment).permit(:name, :description, :archived)
end
def move_experiment_param
params.require(:experiment).require(:project_id)
end
def load_projects_tree
# Switch to correct team
current_team_switch(@experiment.project.team) unless @experiment.project.nil?

View file

@ -229,8 +229,7 @@ class TeamsController < ApplicationController
def export_projects
unless export_proj_requests_exceeded?
current_user.export_vars['num_of_export_all_last_24_hours'] += 1
current_user.save
current_user.increase_daily_exports_counter!
generate_export_projects_zip

View file

@ -5,6 +5,8 @@ module Users
prepend_before_action :check_captcha, only: [:update]
prepend_before_action :check_captcha_for_invite, only: [:invite_users]
before_action :check_invite_users_permission, only: :invite_users
before_action :update_sanitized_params, only: :update
@ -188,6 +190,15 @@ module Users
end
end
def check_captcha_for_invite
if Rails.configuration.x.enable_recaptcha
unless verify_recaptcha
render json: { recaptcha_error: t('invite_users.errors.recaptcha') },
status: :unprocessable_entity
end
end
end
def check_invite_users_permission
@user = current_user
@emails = params[:emails].map(&:downcase)

View file

@ -161,9 +161,9 @@ module ProtocolsIoHelper
timestamps = steps.map do |step|
step['modified_on'] if step['modified_on'].present?
end
Time.at(timestamps.max).utc.to_datetime
I18n.l(Time.at(timestamps.max), format: :full)
rescue StandardError
Time.at(0).utc.to_datetime
I18n.l(Time.at(0), format: :full)
end
# Checks so that null values are returned as zero length strings

View file

@ -98,12 +98,6 @@ class Experiment < ApplicationRecord
end
end
def modules_without_group
MyModule.where(experiment_id: id)
.where(my_module_group: nil)
.where(archived: false)
end
def active_module_groups
my_module_groups.joins(:my_modules)
.where('my_modules.archived = ?', false)
@ -227,125 +221,8 @@ class Experiment < ApplicationRecord
true
end
# This method generate the workflow image and saves it as
# experiment attachment
def generate_workflow_img
require 'graphviz'
graph = GraphViz.new(:G,
type: :digraph,
use: :neato)
graph[:size] = '4,4'
graph.node[color: Constants::COLOR_ALTO,
style: :filled,
fontcolor: Constants::COLOR_EMPEROR,
shape: 'circle',
fontname: 'Arial',
fontsize: '16.0']
graph.edge[color: Constants::COLOR_ALTO]
label = ''
subg = {}
# Draw orphan modules
if modules_without_group
modules_without_group.each do |my_module|
graph
.subgraph(rank: 'same')
.add_nodes("Orphan-#{my_module.id}",
label: label,
pos: "#{my_module.x / 10},-#{my_module.y / 10}!")
end
end
# Draw grouped modules
if my_module_groups.many?
my_module_groups.each_with_index do |group, gindex|
subgraph_name = "cluster-#{gindex}"
subg[subgraph_name] = graph.subgraph(rank: 'same')
group.ordered_modules.each_with_index do |my_module, index|
if my_module.outputs.any?
parent = subg[subgraph_name]
.add_nodes("#{subgraph_name}-#{index}",
label: label,
pos: "#{my_module.x / 10},-#{my_module.y / 10}!")
my_module.outputs.each_with_index do |output, i|
child_mod = MyModule.find_by_id(output.input_id)
child_node = subg[subgraph_name]
.add_nodes("#{subgraph_name}-O#{child_mod.id}-#{i}",
label: label,
pos: "#{child_mod.x / 10},-#{child_mod.y / 10}!")
subg[subgraph_name].add_edges(parent, child_node)
end
elsif my_module.inputs.any?
parent = subg[subgraph_name]
.add_nodes("#{subgraph_name}-#{index}",
label: label,
pos: "#{my_module.x / 10},-#{my_module.y / 10}!")
my_module.inputs.each_with_index do |input, i|
child_mod = MyModule.find_by_id(input.output_id)
child_node = subg[subgraph_name]
.add_nodes("#{subgraph_name}-I#{child_mod.id}-#{i}",
label: label,
pos: "#{child_mod.x / 10},-#{child_mod.y / 10}!")
subg[subgraph_name].add_edges(child_node, parent)
end
end
end
end
else
my_module_groups.each do |group|
group.ordered_modules.each_with_index do |my_module, index|
if my_module.outputs.any?
parent = graph.add_nodes("N-#{index}",
label: label,
pos: "#{my_module.x / 10},-#{ my_module.y / 10}!")
my_module.outputs.each_with_index do |output, i|
child_mod = MyModule.find_by_id(output.input_id)
child_node = graph
.add_nodes("N-O#{child_mod.id}-#{i}",
label: label,
pos: "#{child_mod.x / 10},-#{child_mod.y / 10}!")
graph.add_edges(parent, child_node)
end
elsif my_module.inputs.any?
parent = graph.add_nodes("N-#{index}",
label: label,
pos: "#{my_module.x / 10},-#{my_module.y / 10}!")
my_module.inputs.each_with_index do |input, i|
child_mod = MyModule.find_by_id(input.output_id)
child_node = graph
.add_nodes("N-I#{child_mod.id}-#{i}",
label: label,
pos: "#{child_mod.x / 10},-#{child_mod.y / 10}!")
graph.add_edges(child_node, parent)
end
end
end
end
end
file_location = Tempfile.open(['wimg', '.png'],
Rails.root.join('tmp'))
graph.output(png: file_location.path)
begin
file = File.open(file_location)
self.workflowimg = file
file.close
save
touch(:workflowimg_updated_at)
rescue => ex
logger.error ex.message
end
Experiments::GenerateWorkflowImageService.call(experiment_id: id)
end
# Clone this experiment to given project
@ -371,31 +248,13 @@ class Experiment < ApplicationRecord
end
# Copy modules without group
clone.my_modules << modules_without_group.map do |m|
clone.my_modules << my_modules.without_group.map do |m|
m.deep_clone_to_experiment(current_user, clone)
end
clone.save
clone
end
def move_to_project(project)
self.project = project
my_modules.each do |m|
new_tags = []
m.tags.each do |t|
new_tags << t.deep_clone_to_project(project)
end
m.my_module_tags.destroy_all
project.tags << new_tags
m.tags << new_tags
end
result = save
touch(:workflowimg_updated_at) if result
result
end
# Get projects where user is either owner or user in the same team
# as this experiment
def projects_with_role_above_user(current_user)

View file

@ -68,11 +68,13 @@ class MyModule < ApplicationRecord
scope :is_archived, ->(is_archived) { where('archived = ?', is_archived) }
scope :active, -> { where(archived: false) }
scope :overdue, -> { where('my_modules.due_date < ?', Time.current.utc) }
scope :without_group, -> { active.where(my_module_group: nil) }
scope :one_day_prior, (lambda do
where('my_modules.due_date > ? AND my_modules.due_date < ?',
Time.current.utc,
Time.current.utc + 1.day)
end)
scope :workflow_ordered, -> { order(workflow_order: :asc) }
# A module takes this much space in canvas (x, y) in database
WIDTH = 30

View file

@ -10,10 +10,6 @@ class MyModuleGroup < ApplicationRecord
optional: true
has_many :my_modules, inverse_of: :my_module_group, dependent: :nullify
def ordered_modules
my_modules.order(workflow_order: :asc)
end
def deep_clone_to_experiment(current_user, experiment)
clone = MyModuleGroup.new(
created_by: created_by,
@ -21,12 +17,12 @@ class MyModuleGroup < ApplicationRecord
)
# Get clones of modules from this group, save them as hash
cloned_modules = ordered_modules.each_with_object({}) do |m, hash|
hash[m.id] = m.deep_clone_to_experiment(current_user, experiment)
hash
cloned_modules = my_modules.workflow_ordered.each_with_object({}) do |m, h|
h[m.id] = m.deep_clone_to_experiment(current_user, experiment)
h
end
ordered_modules.each do |m|
my_modules.workflow_ordered.each do |m|
# Copy connections
m.inputs.each do |inp|
Connection.create(

View file

@ -1,3 +1,5 @@
# frozen_string_literal: true
class Tag < ApplicationRecord
include SearchableModel
@ -48,7 +50,10 @@ class Tag < ApplicationRecord
end
end
def deep_clone_to_project(project)
def clone_to_project_or_return_existing(project)
tag = Tag.find_by(project: project, name: name, color: color)
return tag if tag
Tag.create(
name: name,
color: color,

View file

@ -30,7 +30,7 @@ class TeamZipExport < ZipExport
zip_dir = FileUtils.mkdir_p(File.join(Rails.root, 'tmp/zip-ready')).first
zip_file = File.new(
File.join(zip_dir,
"projects_export_#{Time.now.strftime('%F_%H-%M-%S')}.zip"),
"projects_export_#{Time.now.strftime('%F_%H-%M-%S_UTC')}.zip"),
'w+'
)
fill_content(zip_input_dir, data, type, options)

View file

@ -56,7 +56,8 @@ class User < ApplicationRecord
default_variables(
export_vars: {
num_of_export_all_last_24_hours: 0
num_of_export_all_last_24_hours: 0,
last_export_timestamp: Date.today.to_time.to_i
}
)
@ -505,6 +506,16 @@ class User < ApplicationRecord
end
end
def increase_daily_exports_counter!
if Time.at(export_vars['last_export_timestamp'] || 0).to_date == Date.today
export_vars['num_of_export_all_last_24_hours'] += 1
else
export_vars['last_export_timestamp'] = Date.today.to_time.to_i
export_vars['num_of_export_all_last_24_hours'] = 1
end
save
end
protected
def confirmation_required?

View file

@ -56,7 +56,7 @@ class ZipExport < ApplicationRecord
).first
zip_dir = FileUtils.mkdir_p(File.join(Rails.root, 'tmp/zip-ready')).first
zip_file = File.new(
File.join(zip_dir, "export_#{Time.now.strftime('%F %H-%M-%S')}.zip"),
File.join(zip_dir, "export_#{Time.now.strftime('%F %H-%M-%S_UTC')}.zip"),
'w+'
)
fill_content(zip_input_dir, data, type, options)

View file

@ -0,0 +1,87 @@
# frozen_string_literal: true
module Experiments
class GenerateWorkflowImageService
extend Service
require 'graphviz'
attr_reader :errors
def initialize(experiment_id:)
@exp = Experiment.find experiment_id
@graph = GraphViz.new(:G, type: :digraph, use: :neato)
@graph[:size] = '4,4'
@graph.node[color: Constants::COLOR_ALTO,
style: :filled,
fontcolor: Constants::COLOR_EMPEROR,
shape: 'circle',
fontname: 'Arial',
fontsize: '16.0']
@graph.edge[color: Constants::COLOR_ALTO]
@errors = []
end
def call
draw_diagram
save_file
self
end
def succeed?
@errors.none?
end
private
def draw_diagram
# Draw orphan nodes
@exp.my_modules.without_group.each do |my_module|
@graph.subgraph(rank: 'same').add_nodes(
"Orphan-#{my_module.id}",
label: '',
pos: "#{my_module.x / 10},-#{my_module.y / 10}!"
)
end
# Draw grouped modules
subg = {}
@exp.my_module_groups.each_with_index do |group, gindex|
subgraph_id = "cluster-#{gindex}"
subg[subgraph_id] = @graph.subgraph(rank: 'same')
nodes = {}
group.my_modules.workflow_ordered.each_with_index do |my_module, index|
# draw nodes
node = subg[subgraph_id].add_nodes(
"#{subgraph_id}-#{index}",
label: '',
pos: "#{my_module.x / 10},-#{my_module.y / 10}!"
)
nodes[my_module.id] = node
end
# draw edges
group.my_modules.workflow_ordered.each do |m|
m.outputs.each do |output|
parent_node = nodes[m.id]
child_node = nodes[output.input_id]
subg[subgraph_id].add_edges(parent_node, child_node)
end
end
end
end
def save_file
file = Tempfile.open(%w(wimg .png), Rails.root.join('tmp'))
@graph.output(png: file.path)
@exp.workflowimg = file
file.close
@exp.save
@exp.touch(:workflowimg_updated_at)
rescue StandardError => ex
logger.error ex.message
end
end
end

View file

@ -0,0 +1,89 @@
# frozen_string_literal: true
module Experiments
class MoveToProjectService
extend Service
attr_reader :errors
def initialize(experiment_id:, project_id:, user_id:)
@exp = Experiment.find experiment_id
@project = Project.find project_id
@user = User.find user_id
@original_project = @exp&.project
@errors = {}
end
def call
return self unless valid?
ActiveRecord::Base.transaction do
@exp.project = @project
@exp.my_modules.each do |m|
new_tags = m.tags.map do |t|
t.clone_to_project_or_return_existing(@project)
end
m.my_module_tags.delete_all
m.tags = new_tags
end
raise ActiveRecord::Rollback unless @exp.save
end
@errors.merge!(@exp.errors.to_hash) unless @exp.valid?
track_activity if succeed?
self
end
def succeed?
@errors.none?
end
private
def valid?
unless @exp && @project && @user
@errors[:invalid_arguments] =
{ 'experiment': @exp,
'project': @project,
'user': @user }
.map do |key, value|
"Can't find #{key.capitalize}" if value.nil?
end.compact
return false
end
e = Experiment.find_by(name: @exp.name, project: @project)
if e
@errors[:project_with_exp] =
['Project already contains experiment with this name']
false
elsif !@exp.moveable_projects(@user).include?(@project)
@errors[:target_project_not_valid] =
['Experiment cannot be moved to this project']
false
else
true
end
end
def track_activity
Activity.create(
type_of: :move_experiment,
project: @project,
experiment: @exp,
user: @user,
message: I18n.t(
'activities.move_experiment',
user: @user,
experiment: @exp.name,
project_new: @project.name,
project_original: @original_project.name
)
)
end
end
end

7
app/services/service.rb Normal file
View file

@ -0,0 +1,7 @@
# frozen_string_literal: true
module Service
def call(*args)
new(*args).call
end
end

View file

@ -31,7 +31,7 @@
tooltipcontent: I18n.t('tooltips.text.experiment.move')
} %></li>
<% end %>
<% if can_manage_experiment?(experiment) %>
<% if can_archive_experiment?(experiment) %>
<li><%= link_to t('experiments.archive.label_title'),
archive_experiment_url(experiment),
type: 'button',

View file

@ -1,5 +1,5 @@
<div class="pull-right">
<span class="text-muted"><%= l comment.created_at, format: '%H:%M' %></span>
<span class="text-muted"><%= l comment.created_at, format: :time %></span>
<% if can_manage_comment_in_module?(comment.becomes(Comment)) %>
<div class="dropdown dropdown-comment">
<a href="#"

View file

@ -1,5 +1,5 @@
<div class="pull-right">
<span class="text-muted"><%= l comment.created_at, format: '%H:%M' %></span>
<span class="text-muted"><%= l comment.created_at, format: :time %></span>
<% if can_manage_comment_in_project?(comment) %>
<div class="dropdown dropdown-comment">
<a href="#"

View file

@ -53,16 +53,14 @@
<label><%= t('protocols.import_export.import_modal.created_at_label') %></label>
<% display_created_at=Time.at(not_null(@json_object['created_on']).to_i) %>
<%= f.text_field :created_at, :value => display_created_at.to_s,
<%= f.text_field :created_at, :value => I18n.l(display_created_at, format: :full),
readonly: true, class: "form-control" %>
</div>
<div class="col-xs-4">
<label><%= t('protocols.import_export.import_modal.updated_at_label') %></label>
<% display_last_modified=eval_last_modified(@json_object['steps']) %>
<%= f.text_field :last_modified, :value =>
display_last_modified.to_s,readonly: true, class:
"form-control" %>
<%= f.text_field :last_modified, :value => display_last_modified, readonly: true, class: "form-control" %>
</div>
</div>
</div>

View file

@ -13,7 +13,7 @@
<% experiment.my_module_groups.each do |my_module_group| %>
<% if my_module_group.my_modules.exists? then %>
<% my_module_group.ordered_modules.each do |my_module| %>
<% my_module_group.my_modules.workflow_ordered.each do |my_module| %>
<li>
<%= form.check_box "modules[#{my_module.id}]", label: my_module.name %>
</li>
@ -22,13 +22,10 @@
<% end %>
<!-- Tasks without groups -->
<% modules_without_group = experiment.modules_without_group %>
<% if modules_without_group.exists? %>
<% modules_without_group.each do |my_module| %>
<li>
<%= form.check_box "modules[#{my_module.id}]", label: my_module.name %>
</li>
<% end %>
<% experiment.my_modules.without_group.each do |my_module| %>
<li>
<%= form.check_box "modules[#{my_module.id}]", label: my_module.name %>
</li>
<% end %>
</ul>

View file

@ -19,7 +19,7 @@
<% experiment.my_module_groups.each do |my_module_group| %>
<% next unless my_module_group.my_modules.is_archived(false).exists? %>
<% my_module_group.ordered_modules.is_archived(false).each do |my_module| %>
<% my_module_group.my_modules.workflow_ordered.is_archived(false).each do |my_module| %>
<li>
<%= form.check_box "modules[#{my_module.id}]", label: my_module.name %>
</li>
@ -27,13 +27,10 @@
<% end %>
<!-- Tasks without groups -->
<% modules_without_group = experiment.modules_without_group %>
<% if modules_without_group.exists? %>
<% modules_without_group.each do |my_module| %>
<li>
<%= form.check_box "modules[#{my_module.id}]", label: my_module.name %>
</li>
<% end %>
<% experiment.my_modules.without_group.each do |my_module| %>
<li>
<%= form.check_box "modules[#{my_module.id}]", label: my_module.name %>
</li>
<% end %>
</ul>

View file

@ -99,6 +99,16 @@ invite_to_team = type.in?(%w(invite_to_team invite_to_team_with_role))
</div>
<% end %>
<% end %>
<% if ENV['ENABLE_RECAPTCHA'] %>
<div id="recaptcha-service" class="g-recaptcha"
data-callback="recaptchaCallback"
data-sitekey=<%= ENV['RECAPTCHA_SITE_KEY'] %>></div>
<script type="text/javascript" src="https://www.google.com/recaptcha/api.js?hl=en"></script>
<input type="hidden" id="recaptcha-invite-modal" value="">
<div class="form-group has-error hidden" id="recaptcha-error-msg" >
<span class="has-error help-block"></span>
</div>
<% end %>
</div>
<div class="results-container" data-role="step-results" data-clear="true">
</div>

View file

@ -1,6 +1,6 @@
<h5 class="text-center"><%= t("projects.index.users_tab") %></h5>
<hr>
<ul class="no-style content-users">
<ul class="no-style content-users" data-hook="project-users-tab-list">
<% if @users.size == 0 then %>
<li><em><%= t 'projects.index.no_users' %></em></li>
<% else %>

View file

@ -137,5 +137,4 @@
<%= render partial: 'users/settings/user_teams/destroy_user_team_modal.html.erb' %>
<%= stylesheet_link_tag 'datatables' %>
<%= javascript_include_tag 'users/settings/teams/show' %>
<%= javascript_include_tag 'users/settings/teams/invite_users_modal' %>
<span data-hook="team-bottom"></span>

View file

@ -19,15 +19,13 @@ default: &default
encoding: unicode
database: postgres
pool: 5
username: postgres
password: mysecretpassword
host: db
# For details on connection pooling, see rails configuration guide
# http://guides.rubyonrails.org/configuring.html#database-pooling
development:
<<: *default
database: scinote_development
url: <%= ENV['DATABASE_DEV_URL'] || 'postgresql://postgres:mysecretpassword@db/scinote_development' %>
# The specified database role being used to connect to postgres.
# To create additional roles in postgres see `$ createuser --help`.
@ -60,7 +58,7 @@ development:
# Do not set this db to the same as development or production.
test: &test
<<: *default
database: scinote_test
url: <%= ENV['DATABASE_TEST_URL'] || 'postgresql://postgres:mysecretpassword@db/scinote_test' %>
# As with config/secrets.yml, you never want to store sensitive information,
# like your database password, in your source code. If your source code is

View file

@ -66,6 +66,8 @@ module Paperclip
# Checks file for spoofing
class MediaTypeSpoofDetector
def spoofed?
return false if ENV['DISABLE_SPOOF_CHECKING']
if has_name? && has_extension? && (media_type_mismatch? ||
mapping_override_mismatch?)
Paperclip.log("Content Type Spoof: Filename #{File.basename(@name)} "\
@ -121,8 +123,8 @@ module Paperclip
end
end
@type_from_file_command
rescue Cocaine::CommandLineError
''
rescue StandardError => e
puts e
end
# Determine file media type from it's content (file and mimetype command)

View file

@ -1831,6 +1831,8 @@ en:
invite_guest: "As Guests"
invite_user: "As Normal Users"
invite_admin: "As Administrators"
errors:
recaptcha: "reCAPTCHA verification failed, please try again"
results:
heading: "Invitation results:"
user_exists: "User is already a member of SciNote."

View file

@ -53,6 +53,12 @@ Rails.application.routes.draw do
get 'forbidden', to: 'application#forbidden', as: 'forbidden'
get 'not_found', to: 'application#not_found', as: 'not_found'
# JS backend helpers
get 'helpers/to_user_date_format',
to: 'application#to_user_date_format',
as: 'to_user_date_format',
defaults: { format: 'json' }
# Settings
resources :users, only: :index # needed for testing signup
# needed for testing edit passowrd

View file

@ -0,0 +1,195 @@
# frozen_string_literal: true
class ChangeIndicesFromIntToBigint < ActiveRecord::Migration[5.1]
def up
drop_view :datatables_teams
change_column :activities, :id, :bigint
change_column :assets, :id, :bigint
change_column :asset_text_data, :id, :bigint
change_column :checklist_items, :id, :bigint
change_column :checklists, :id, :bigint
change_column :comments, :id, :bigint
change_column :connections, :id, :bigint
change_column :custom_fields, :id, :bigint
change_column :delayed_jobs, :id, :bigint
change_column :experiments, :id, :bigint
change_column :my_module_groups, :id, :bigint
change_column :my_module_repository_rows, :id, :bigint
change_column :my_modules, :id, :bigint
change_column :my_module_tags, :id, :bigint
change_column :notifications, :id, :bigint
change_column :projects, :id, :bigint
change_column :protocol_keywords, :id, :bigint
change_column :protocol_protocol_keywords, :id, :bigint
change_column :protocols, :id, :bigint
change_column :report_elements, :id, :bigint
change_column :reports, :id, :bigint
change_column :repositories, :id, :bigint
change_column :repository_table_states, :id, :bigint
change_column :result_assets, :id, :bigint
change_column :results, :id, :bigint
change_column :result_tables, :id, :bigint
change_column :result_texts, :id, :bigint
change_column :sample_custom_fields, :id, :bigint
change_column :sample_groups, :id, :bigint
change_column :sample_my_modules, :id, :bigint
change_column :samples, :id, :bigint
change_column :samples_tables, :id, :bigint
change_column :sample_types, :id, :bigint
change_column :settings, :id, :bigint
change_column :step_assets, :id, :bigint
change_column :steps, :id, :bigint
change_column :step_tables, :id, :bigint
change_column :tables, :id, :bigint
change_column :tags, :id, :bigint
change_column :teams, :id, :bigint
change_column :temp_files, :id, :bigint
change_column :tiny_mce_assets, :id, :bigint
change_column :tokens, :id, :bigint
change_column :user_identities, :id, :bigint
change_column :user_my_modules, :id, :bigint
change_column :user_notifications, :id, :bigint
change_column :user_projects, :id, :bigint
change_column :users, :id, :bigint
change_column :user_teams, :id, :bigint
change_column :wopi_actions, :id, :bigint
change_column :wopi_apps, :id, :bigint
change_column :wopi_discoveries, :id, :bigint
change_column :zip_exports, :id, :bigint
change_column :activities, :user_id, :bigint
change_column :activities, :my_module_id, :bigint
change_column :activities, :project_id, :bigint
change_column :activities, :experiment_id, :bigint
change_column :assets, :created_by_id, :bigint
change_column :assets, :last_modified_by_id, :bigint
change_column :asset_text_data, :asset_id, :bigint
change_column :checklist_items, :checklist_id, :bigint
change_column :checklist_items, :last_modified_by_id, :bigint
change_column :checklist_items, :created_by_id, :bigint
change_column :checklists, :step_id, :bigint
change_column :checklists, :created_by_id, :bigint
change_column :checklists, :last_modified_by_id, :bigint
change_column :comments, :last_modified_by_id, :bigint
change_column :comments, :user_id, :bigint
change_column :connections, :output_id, :bigint
change_column :connections, :input_id, :bigint
change_column :custom_fields, :team_id, :bigint
change_column :custom_fields, :user_id, :bigint
change_column :custom_fields, :last_modified_by_id, :bigint
change_column :experiments, :created_by_id, :bigint
change_column :experiments, :restored_by_id, :bigint
change_column :experiments, :archived_by_id, :bigint
change_column :experiments, :last_modified_by_id, :bigint
change_column :my_module_groups, :experiment_id, :bigint
change_column :my_module_groups, :created_by_id, :bigint
change_column :my_module_repository_rows, :assigned_by_id, :bigint
change_column :my_modules, :last_modified_by_id, :bigint
change_column :my_modules, :created_by_id, :bigint
change_column :my_modules, :experiment_id, :bigint
change_column :my_modules, :my_module_group_id, :bigint
change_column :my_modules, :archived_by_id, :bigint
change_column :my_modules, :restored_by_id, :bigint
change_column :my_module_tags, :created_by_id, :bigint
change_column :notifications, :generator_user_id, :bigint
change_column :oauth_access_grants, :resource_owner_id, :bigint
change_column :oauth_access_tokens, :resource_owner_id, :bigint
change_column :projects, :team_id, :bigint
change_column :projects, :archived_by_id, :bigint
change_column :projects, :restored_by_id, :bigint
change_column :projects, :created_by_id, :bigint
change_column :projects, :last_modified_by_id, :bigint
change_column :protocol_keywords, :team_id, :bigint
change_column :protocol_protocol_keywords, :protocol_keyword_id, :bigint
change_column :protocol_protocol_keywords, :protocol_id, :bigint
change_column :protocols, :team_id, :bigint
change_column :protocols, :added_by_id, :bigint
change_column :protocols, :parent_id, :bigint
change_column :protocols, :restored_by_id, :bigint
change_column :protocols, :archived_by_id, :bigint
change_column :protocols, :my_module_id, :bigint
change_column :report_elements, :report_id, :bigint
change_column :report_elements, :experiment_id, :bigint
change_column :report_elements, :table_id, :bigint
change_column :report_elements, :asset_id, :bigint
change_column :report_elements, :checklist_id, :bigint
change_column :report_elements, :result_id, :bigint
change_column :report_elements, :step_id, :bigint
change_column :report_elements, :my_module_id, :bigint
change_column :report_elements, :project_id, :bigint
change_column :reports, :user_id, :bigint
change_column :reports, :last_modified_by_id, :bigint
change_column :reports, :project_id, :bigint
change_column :repositories, :created_by_id, :bigint
change_column :repository_columns, :created_by_id, :bigint
change_column :repository_date_values, :last_modified_by_id, :bigint
change_column :repository_date_values, :created_by_id, :bigint
change_column :repository_rows, :last_modified_by_id, :bigint
change_column :repository_rows, :created_by_id, :bigint
change_column :repository_text_values, :created_by_id, :bigint
change_column :repository_text_values, :last_modified_by_id, :bigint
change_column :result_assets, :result_id, :bigint
change_column :result_assets, :asset_id, :bigint
change_column :results, :archived_by_id, :bigint
change_column :results, :user_id, :bigint
change_column :results, :last_modified_by_id, :bigint
change_column :results, :restored_by_id, :bigint
change_column :results, :my_module_id, :bigint
change_column :result_tables, :result_id, :bigint
change_column :result_tables, :table_id, :bigint
change_column :result_texts, :result_id, :bigint
change_column :sample_custom_fields, :custom_field_id, :bigint
change_column :sample_custom_fields, :sample_id, :bigint
change_column :sample_groups, :team_id, :bigint
change_column :sample_groups, :last_modified_by_id, :bigint
change_column :sample_groups, :created_by_id, :bigint
change_column :sample_my_modules, :my_module_id, :bigint
change_column :sample_my_modules, :sample_id, :bigint
change_column :sample_my_modules, :assigned_by_id, :bigint
change_column :samples, :sample_group_id, :bigint
change_column :samples, :last_modified_by_id, :bigint
change_column :samples, :sample_type_id, :bigint
change_column :samples, :team_id, :bigint
change_column :samples, :user_id, :bigint
change_column :sample_types, :created_by_id, :bigint
change_column :sample_types, :team_id, :bigint
change_column :sample_types, :last_modified_by_id, :bigint
change_column :step_assets, :asset_id, :bigint
change_column :step_assets, :step_id, :bigint
change_column :steps, :last_modified_by_id, :bigint
change_column :steps, :user_id, :bigint
change_column :steps, :protocol_id, :bigint
change_column :step_tables, :step_id, :bigint
change_column :step_tables, :table_id, :bigint
change_column :tables, :created_by_id, :bigint
change_column :tables, :last_modified_by_id, :bigint
change_column :tags, :last_modified_by_id, :bigint
change_column :tags, :created_by_id, :bigint
change_column :tags, :project_id, :bigint
change_column :teams, :last_modified_by_id, :bigint
change_column :teams, :created_by_id, :bigint
change_column :tokens, :user_id, :bigint
change_column :user_my_modules, :my_module_id, :bigint
change_column :user_my_modules, :assigned_by_id, :bigint
change_column :user_my_modules, :user_id, :bigint
change_column :user_notifications, :user_id, :bigint
change_column :user_notifications, :notification_id, :bigint
change_column :user_projects, :assigned_by_id, :bigint
change_column :user_projects, :user_id, :bigint
change_column :user_projects, :project_id, :bigint
change_column :users, :current_team_id, :bigint
change_column :user_teams, :user_id, :bigint
change_column :user_teams, :team_id, :bigint
change_column :user_teams, :assigned_by_id, :bigint
change_column :wopi_actions, :wopi_app_id, :bigint
change_column :wopi_apps, :wopi_discovery_id, :bigint
change_column :zip_exports, :user_id, :bigint
create_view :datatables_teams
end
def down
# Bad, bad things can happen if we reverse this migration, so we'll
# simply skip it
end
end

View file

@ -10,22 +10,22 @@
#
# It's strongly recommended that you check this file into your version control system.
ActiveRecord::Schema.define(version: 20181212162649) do
ActiveRecord::Schema.define(version: 20190117155006) do
# These are extensions that must be enabled in order to support this database
enable_extension "plpgsql"
enable_extension "pg_trgm"
enable_extension "btree_gist"
create_table "activities", id: :serial, force: :cascade do |t|
t.integer "my_module_id"
t.integer "user_id"
create_table "activities", force: :cascade do |t|
t.bigint "my_module_id"
t.bigint "user_id"
t.integer "type_of", null: false
t.string "message", null: false
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.integer "project_id", null: false
t.integer "experiment_id"
t.bigint "project_id", null: false
t.bigint "experiment_id"
t.index ["created_at"], name: "index_activities_on_created_at"
t.index ["experiment_id"], name: "index_activities_on_experiment_id"
t.index ["my_module_id"], name: "index_activities_on_my_module_id"
@ -34,9 +34,9 @@ ActiveRecord::Schema.define(version: 20181212162649) do
t.index ["user_id"], name: "index_activities_on_user_id"
end
create_table "asset_text_data", id: :serial, force: :cascade do |t|
create_table "asset_text_data", force: :cascade do |t|
t.text "data", null: false
t.integer "asset_id", null: false
t.bigint "asset_id", null: false
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.tsvector "data_vector"
@ -44,15 +44,15 @@ ActiveRecord::Schema.define(version: 20181212162649) do
t.index ["data_vector"], name: "index_asset_text_data_on_data_vector", using: :gin
end
create_table "assets", id: :serial, force: :cascade do |t|
create_table "assets", force: :cascade do |t|
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.string "file_file_name"
t.string "file_content_type"
t.integer "file_file_size"
t.datetime "file_updated_at"
t.integer "created_by_id"
t.integer "last_modified_by_id"
t.bigint "created_by_id"
t.bigint "last_modified_by_id"
t.integer "estimated_size", default: 0, null: false
t.boolean "file_present", default: false, null: false
t.string "lock", limit: 1024
@ -67,14 +67,14 @@ ActiveRecord::Schema.define(version: 20181212162649) do
t.index ["team_id"], name: "index_assets_on_team_id"
end
create_table "checklist_items", id: :serial, force: :cascade do |t|
create_table "checklist_items", force: :cascade do |t|
t.string "text", null: false
t.boolean "checked", default: false, null: false
t.integer "checklist_id", null: false
t.bigint "checklist_id", null: false
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.integer "created_by_id"
t.integer "last_modified_by_id"
t.bigint "created_by_id"
t.bigint "last_modified_by_id"
t.integer "position"
t.index "trim_html_tags((text)::text) gin_trgm_ops", name: "index_checklist_items_on_text", using: :gin
t.index ["checklist_id"], name: "index_checklist_items_on_checklist_id"
@ -82,25 +82,25 @@ ActiveRecord::Schema.define(version: 20181212162649) do
t.index ["last_modified_by_id"], name: "index_checklist_items_on_last_modified_by_id"
end
create_table "checklists", id: :serial, force: :cascade do |t|
create_table "checklists", force: :cascade do |t|
t.string "name", null: false
t.integer "step_id", null: false
t.bigint "step_id", null: false
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.integer "created_by_id"
t.integer "last_modified_by_id"
t.bigint "created_by_id"
t.bigint "last_modified_by_id"
t.index "trim_html_tags((name)::text) gin_trgm_ops", name: "index_checklists_on_name", using: :gin
t.index ["created_by_id"], name: "index_checklists_on_created_by_id"
t.index ["last_modified_by_id"], name: "index_checklists_on_last_modified_by_id"
t.index ["step_id"], name: "index_checklists_on_step_id"
end
create_table "comments", id: :serial, force: :cascade do |t|
create_table "comments", force: :cascade do |t|
t.string "message", null: false
t.integer "user_id", null: false
t.bigint "user_id", null: false
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.integer "last_modified_by_id"
t.bigint "last_modified_by_id"
t.string "type"
t.integer "associated_id"
t.index "trim_html_tags((message)::text) gin_trgm_ops", name: "index_comments_on_message", using: :gin
@ -111,26 +111,26 @@ ActiveRecord::Schema.define(version: 20181212162649) do
t.index ["user_id"], name: "index_comments_on_user_id"
end
create_table "connections", id: :serial, force: :cascade do |t|
t.integer "input_id", null: false
t.integer "output_id", null: false
create_table "connections", force: :cascade do |t|
t.bigint "input_id", null: false
t.bigint "output_id", null: false
t.index ["input_id"], name: "index_connections_on_input_id"
t.index ["output_id"], name: "index_connections_on_output_id"
end
create_table "custom_fields", id: :serial, force: :cascade do |t|
create_table "custom_fields", force: :cascade do |t|
t.string "name", null: false
t.integer "user_id", null: false
t.integer "team_id", null: false
t.bigint "user_id", null: false
t.bigint "team_id", null: false
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.integer "last_modified_by_id"
t.bigint "last_modified_by_id"
t.index ["last_modified_by_id"], name: "index_custom_fields_on_last_modified_by_id"
t.index ["team_id"], name: "index_custom_fields_on_team_id"
t.index ["user_id"], name: "index_custom_fields_on_user_id"
end
create_table "delayed_jobs", id: :serial, force: :cascade do |t|
create_table "delayed_jobs", force: :cascade do |t|
t.integer "priority", default: 0, null: false
t.integer "attempts", default: 0, null: false
t.text "handler", null: false
@ -146,16 +146,16 @@ ActiveRecord::Schema.define(version: 20181212162649) do
t.index ["queue"], name: "delayed_jobs_queue"
end
create_table "experiments", id: :serial, force: :cascade do |t|
create_table "experiments", force: :cascade do |t|
t.string "name", null: false
t.text "description"
t.integer "project_id", null: false
t.integer "created_by_id", null: false
t.integer "last_modified_by_id", null: false
t.bigint "created_by_id", null: false
t.bigint "last_modified_by_id", null: false
t.boolean "archived", default: false, null: false
t.integer "archived_by_id"
t.bigint "archived_by_id"
t.datetime "archived_on"
t.integer "restored_by_id"
t.bigint "restored_by_id"
t.datetime "restored_on"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
@ -171,53 +171,53 @@ ActiveRecord::Schema.define(version: 20181212162649) do
t.index ["restored_by_id"], name: "index_experiments_on_restored_by_id"
end
create_table "my_module_groups", id: :serial, force: :cascade do |t|
create_table "my_module_groups", force: :cascade do |t|
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.integer "created_by_id"
t.integer "experiment_id", default: 0, null: false
t.bigint "created_by_id"
t.bigint "experiment_id", default: 0, null: false
t.index ["created_by_id"], name: "index_my_module_groups_on_created_by_id"
t.index ["experiment_id"], name: "index_my_module_groups_on_experiment_id"
end
create_table "my_module_repository_rows", id: :serial, force: :cascade do |t|
create_table "my_module_repository_rows", force: :cascade do |t|
t.bigint "repository_row_id", null: false
t.integer "my_module_id"
t.integer "assigned_by_id", null: false
t.bigint "assigned_by_id", null: false
t.datetime "created_at"
t.datetime "updated_at"
t.index ["my_module_id", "repository_row_id"], name: "index_my_module_ids_repository_row_ids"
t.index ["repository_row_id"], name: "index_my_module_repository_rows_on_repository_row_id"
end
create_table "my_module_tags", id: :serial, force: :cascade do |t|
create_table "my_module_tags", force: :cascade do |t|
t.integer "my_module_id"
t.integer "tag_id"
t.integer "created_by_id"
t.bigint "created_by_id"
t.index ["created_by_id"], name: "index_my_module_tags_on_created_by_id"
t.index ["my_module_id"], name: "index_my_module_tags_on_my_module_id"
t.index ["tag_id"], name: "index_my_module_tags_on_tag_id"
end
create_table "my_modules", id: :serial, force: :cascade do |t|
create_table "my_modules", force: :cascade do |t|
t.string "name", null: false
t.datetime "due_date"
t.string "description"
t.integer "x", default: 0, null: false
t.integer "y", default: 0, null: false
t.integer "my_module_group_id"
t.bigint "my_module_group_id"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.boolean "archived", default: false, null: false
t.datetime "archived_on"
t.integer "created_by_id"
t.integer "last_modified_by_id"
t.integer "archived_by_id"
t.integer "restored_by_id"
t.bigint "created_by_id"
t.bigint "last_modified_by_id"
t.bigint "archived_by_id"
t.bigint "restored_by_id"
t.datetime "restored_on"
t.integer "nr_of_assigned_samples", default: 0
t.integer "workflow_order", default: -1, null: false
t.integer "experiment_id", default: 0, null: false
t.bigint "experiment_id", default: 0, null: false
t.integer "state", limit: 2, default: 0
t.datetime "completed_on"
t.index "trim_html_tags((description)::text) gin_trgm_ops", name: "index_my_modules_on_description", using: :gin
@ -230,18 +230,18 @@ ActiveRecord::Schema.define(version: 20181212162649) do
t.index ["restored_by_id"], name: "index_my_modules_on_restored_by_id"
end
create_table "notifications", id: :serial, force: :cascade do |t|
create_table "notifications", force: :cascade do |t|
t.string "title"
t.string "message"
t.integer "type_of", null: false
t.integer "generator_user_id"
t.bigint "generator_user_id"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.index ["created_at"], name: "index_notifications_on_created_at"
end
create_table "oauth_access_grants", force: :cascade do |t|
t.integer "resource_owner_id", null: false
t.bigint "resource_owner_id", null: false
t.bigint "application_id", null: false
t.string "token", null: false
t.integer "expires_in", null: false
@ -254,7 +254,7 @@ ActiveRecord::Schema.define(version: 20181212162649) do
end
create_table "oauth_access_tokens", force: :cascade do |t|
t.integer "resource_owner_id"
t.bigint "resource_owner_id"
t.bigint "application_id"
t.text "token", null: false
t.string "refresh_token"
@ -281,19 +281,19 @@ ActiveRecord::Schema.define(version: 20181212162649) do
t.index ["uid"], name: "index_oauth_applications_on_uid", unique: true
end
create_table "projects", id: :serial, force: :cascade do |t|
create_table "projects", force: :cascade do |t|
t.string "name", null: false
t.integer "visibility", default: 0, null: false
t.datetime "due_date"
t.integer "team_id", null: false
t.bigint "team_id", null: false
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.boolean "archived", default: false, null: false
t.datetime "archived_on"
t.integer "created_by_id"
t.integer "last_modified_by_id"
t.integer "archived_by_id"
t.integer "restored_by_id"
t.bigint "created_by_id"
t.bigint "last_modified_by_id"
t.bigint "archived_by_id"
t.bigint "restored_by_id"
t.datetime "restored_on"
t.string "experiments_order"
t.index "trim_html_tags((name)::text) gin_trgm_ops", name: "index_projects_on_name", using: :gin
@ -304,36 +304,36 @@ ActiveRecord::Schema.define(version: 20181212162649) do
t.index ["team_id"], name: "index_projects_on_team_id"
end
create_table "protocol_keywords", id: :serial, force: :cascade do |t|
create_table "protocol_keywords", force: :cascade do |t|
t.string "name"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.integer "nr_of_protocols", default: 0
t.integer "team_id", null: false
t.bigint "team_id", null: false
t.index "trim_html_tags((name)::text) gin_trgm_ops", name: "index_protocol_keywords_on_name", using: :gin
t.index ["team_id"], name: "index_protocol_keywords_on_team_id"
end
create_table "protocol_protocol_keywords", id: :serial, force: :cascade do |t|
t.integer "protocol_id", null: false
t.integer "protocol_keyword_id", null: false
create_table "protocol_protocol_keywords", force: :cascade do |t|
t.bigint "protocol_id", null: false
t.bigint "protocol_keyword_id", null: false
t.index ["protocol_id"], name: "index_protocol_protocol_keywords_on_protocol_id"
t.index ["protocol_keyword_id"], name: "index_protocol_protocol_keywords_on_protocol_keyword_id"
end
create_table "protocols", id: :serial, force: :cascade do |t|
create_table "protocols", force: :cascade do |t|
t.string "name"
t.text "authors"
t.text "description"
t.integer "added_by_id"
t.integer "my_module_id"
t.integer "team_id", null: false
t.bigint "added_by_id"
t.bigint "my_module_id"
t.bigint "team_id", null: false
t.integer "protocol_type", default: 0, null: false
t.integer "parent_id"
t.bigint "parent_id"
t.datetime "parent_updated_at"
t.integer "archived_by_id"
t.bigint "archived_by_id"
t.datetime "archived_on"
t.integer "restored_by_id"
t.bigint "restored_by_id"
t.datetime "restored_on"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
@ -351,22 +351,22 @@ ActiveRecord::Schema.define(version: 20181212162649) do
t.index ["team_id"], name: "index_protocols_on_team_id"
end
create_table "report_elements", id: :serial, force: :cascade do |t|
create_table "report_elements", force: :cascade do |t|
t.integer "position", null: false
t.integer "type_of", null: false
t.integer "sort_order", default: 0
t.integer "report_id"
t.bigint "report_id"
t.integer "parent_id"
t.integer "project_id"
t.integer "my_module_id"
t.integer "step_id"
t.integer "result_id"
t.integer "checklist_id"
t.integer "asset_id"
t.integer "table_id"
t.bigint "project_id"
t.bigint "my_module_id"
t.bigint "step_id"
t.bigint "result_id"
t.bigint "checklist_id"
t.bigint "asset_id"
t.bigint "table_id"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.integer "experiment_id"
t.bigint "experiment_id"
t.integer "repository_id"
t.index ["asset_id"], name: "index_report_elements_on_asset_id"
t.index ["checklist_id"], name: "index_report_elements_on_checklist_id"
@ -381,14 +381,14 @@ ActiveRecord::Schema.define(version: 20181212162649) do
t.index ["table_id"], name: "index_report_elements_on_table_id"
end
create_table "reports", id: :serial, force: :cascade do |t|
create_table "reports", force: :cascade do |t|
t.string "name", null: false
t.string "description"
t.integer "project_id", null: false
t.integer "user_id", null: false
t.bigint "project_id", null: false
t.bigint "user_id", null: false
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.integer "last_modified_by_id"
t.bigint "last_modified_by_id"
t.bigint "team_id"
t.index "trim_html_tags((description)::text) gin_trgm_ops", name: "index_reports_on_description", using: :gin
t.index "trim_html_tags((name)::text) gin_trgm_ops", name: "index_reports_on_name", using: :gin
@ -398,9 +398,9 @@ ActiveRecord::Schema.define(version: 20181212162649) do
t.index ["user_id"], name: "index_reports_on_user_id"
end
create_table "repositories", id: :serial, force: :cascade do |t|
create_table "repositories", force: :cascade do |t|
t.integer "team_id"
t.integer "created_by_id", null: false
t.bigint "created_by_id", null: false
t.string "name"
t.datetime "created_at"
t.datetime "updated_at"
@ -434,7 +434,7 @@ ActiveRecord::Schema.define(version: 20181212162649) do
create_table "repository_columns", force: :cascade do |t|
t.integer "repository_id"
t.integer "created_by_id", null: false
t.bigint "created_by_id", null: false
t.string "name"
t.integer "data_type", null: false
t.datetime "created_at"
@ -446,8 +446,8 @@ ActiveRecord::Schema.define(version: 20181212162649) do
t.datetime "data"
t.datetime "created_at"
t.datetime "updated_at"
t.integer "created_by_id", null: false
t.integer "last_modified_by_id", null: false
t.bigint "created_by_id", null: false
t.bigint "last_modified_by_id", null: false
end
create_table "repository_list_items", force: :cascade do |t|
@ -478,8 +478,8 @@ ActiveRecord::Schema.define(version: 20181212162649) do
create_table "repository_rows", force: :cascade do |t|
t.integer "repository_id"
t.integer "created_by_id", null: false
t.integer "last_modified_by_id", null: false
t.bigint "created_by_id", null: false
t.bigint "last_modified_by_id", null: false
t.string "name"
t.datetime "created_at"
t.datetime "updated_at"
@ -487,7 +487,7 @@ ActiveRecord::Schema.define(version: 20181212162649) do
t.index ["repository_id"], name: "index_repository_rows_on_repository_id"
end
create_table "repository_table_states", id: :serial, force: :cascade do |t|
create_table "repository_table_states", force: :cascade do |t|
t.jsonb "state", null: false
t.integer "user_id", null: false
t.integer "repository_id", null: false
@ -501,41 +501,41 @@ ActiveRecord::Schema.define(version: 20181212162649) do
t.string "data"
t.datetime "created_at"
t.datetime "updated_at"
t.integer "created_by_id", null: false
t.integer "last_modified_by_id", null: false
t.bigint "created_by_id", null: false
t.bigint "last_modified_by_id", null: false
t.index "trim_html_tags((data)::text) gin_trgm_ops", name: "index_repository_text_values_on_data", using: :gin
end
create_table "result_assets", id: :serial, force: :cascade do |t|
t.integer "result_id", null: false
t.integer "asset_id", null: false
create_table "result_assets", force: :cascade do |t|
t.bigint "result_id", null: false
t.bigint "asset_id", null: false
t.index ["result_id", "asset_id"], name: "index_result_assets_on_result_id_and_asset_id"
end
create_table "result_tables", id: :serial, force: :cascade do |t|
t.integer "result_id", null: false
t.integer "table_id", null: false
create_table "result_tables", force: :cascade do |t|
t.bigint "result_id", null: false
t.bigint "table_id", null: false
t.index ["result_id", "table_id"], name: "index_result_tables_on_result_id_and_table_id"
end
create_table "result_texts", id: :serial, force: :cascade do |t|
create_table "result_texts", force: :cascade do |t|
t.string "text", null: false
t.integer "result_id", null: false
t.bigint "result_id", null: false
t.index "trim_html_tags((text)::text) gin_trgm_ops", name: "index_result_texts_on_text", using: :gin
t.index ["result_id"], name: "index_result_texts_on_result_id"
end
create_table "results", id: :serial, force: :cascade do |t|
create_table "results", force: :cascade do |t|
t.string "name"
t.integer "my_module_id", null: false
t.integer "user_id", null: false
t.bigint "my_module_id", null: false
t.bigint "user_id", null: false
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.boolean "archived", default: false, null: false
t.datetime "archived_on"
t.integer "last_modified_by_id"
t.integer "archived_by_id"
t.integer "restored_by_id"
t.bigint "last_modified_by_id"
t.bigint "archived_by_id"
t.bigint "restored_by_id"
t.datetime "restored_on"
t.index "trim_html_tags((name)::text) gin_trgm_ops", name: "index_results_on_name", using: :gin
t.index ["archived_by_id"], name: "index_results_on_archived_by_id"
@ -546,10 +546,10 @@ ActiveRecord::Schema.define(version: 20181212162649) do
t.index ["user_id"], name: "index_results_on_user_id"
end
create_table "sample_custom_fields", id: :serial, force: :cascade do |t|
create_table "sample_custom_fields", force: :cascade do |t|
t.string "value", null: false
t.integer "custom_field_id", null: false
t.integer "sample_id"
t.bigint "custom_field_id", null: false
t.bigint "sample_id"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.index "trim_html_tags((value)::text) gin_trgm_ops", name: "index_sample_custom_fields_on_value", using: :gin
@ -557,52 +557,52 @@ ActiveRecord::Schema.define(version: 20181212162649) do
t.index ["sample_id"], name: "index_sample_custom_fields_on_sample_id"
end
create_table "sample_groups", id: :serial, force: :cascade do |t|
create_table "sample_groups", force: :cascade do |t|
t.string "name", null: false
t.string "color", default: "#ff0000", null: false
t.integer "team_id", null: false
t.bigint "team_id", null: false
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.integer "created_by_id"
t.integer "last_modified_by_id"
t.bigint "created_by_id"
t.bigint "last_modified_by_id"
t.index "trim_html_tags((name)::text) gin_trgm_ops", name: "index_sample_groups_on_name", using: :gin
t.index ["created_by_id"], name: "index_sample_groups_on_created_by_id"
t.index ["last_modified_by_id"], name: "index_sample_groups_on_last_modified_by_id"
t.index ["team_id"], name: "index_sample_groups_on_team_id"
end
create_table "sample_my_modules", id: :serial, force: :cascade do |t|
t.integer "sample_id", null: false
t.integer "my_module_id", null: false
t.integer "assigned_by_id"
create_table "sample_my_modules", force: :cascade do |t|
t.bigint "sample_id", null: false
t.bigint "my_module_id", null: false
t.bigint "assigned_by_id"
t.datetime "assigned_on"
t.index ["assigned_by_id"], name: "index_sample_my_modules_on_assigned_by_id"
t.index ["my_module_id"], name: "index_sample_my_modules_on_my_module_id"
t.index ["sample_id", "my_module_id"], name: "index_sample_my_modules_on_sample_id_and_my_module_id"
end
create_table "sample_types", id: :serial, force: :cascade do |t|
create_table "sample_types", force: :cascade do |t|
t.string "name", null: false
t.integer "team_id", null: false
t.bigint "team_id", null: false
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.integer "created_by_id"
t.integer "last_modified_by_id"
t.bigint "created_by_id"
t.bigint "last_modified_by_id"
t.index "trim_html_tags((name)::text) gin_trgm_ops", name: "index_sample_types_on_name", using: :gin
t.index ["created_by_id"], name: "index_sample_types_on_created_by_id"
t.index ["last_modified_by_id"], name: "index_sample_types_on_last_modified_by_id"
t.index ["team_id"], name: "index_sample_types_on_team_id"
end
create_table "samples", id: :serial, force: :cascade do |t|
create_table "samples", force: :cascade do |t|
t.string "name", null: false
t.integer "user_id", null: false
t.integer "team_id", null: false
t.bigint "user_id", null: false
t.bigint "team_id", null: false
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.integer "sample_group_id"
t.integer "sample_type_id"
t.integer "last_modified_by_id"
t.bigint "sample_group_id"
t.bigint "sample_type_id"
t.bigint "last_modified_by_id"
t.integer "nr_of_modules_assigned_to", default: 0
t.index "trim_html_tags((name)::text) gin_trgm_ops", name: "index_samples_on_name", using: :gin
t.index ["last_modified_by_id"], name: "index_samples_on_last_modified_by_id"
@ -612,7 +612,7 @@ ActiveRecord::Schema.define(version: 20181212162649) do
t.index ["user_id"], name: "index_samples_on_user_id"
end
create_table "samples_tables", id: :serial, force: :cascade do |t|
create_table "samples_tables", force: :cascade do |t|
t.jsonb "status", default: {"time"=>0, "order"=>[[2, "desc"]], "start"=>0, "length"=>10, "search"=>{"regex"=>false, "smart"=>true, "search"=>"", "caseInsensitive"=>true}, "columns"=>[{"search"=>{"regex"=>false, "smart"=>true, "search"=>"", "caseInsensitive"=>true}, "visible"=>true}, {"search"=>{"regex"=>false, "smart"=>true, "search"=>"", "caseInsensitive"=>true}, "visible"=>true}, {"search"=>{"regex"=>false, "smart"=>true, "search"=>"", "caseInsensitive"=>true}, "visible"=>true}, {"search"=>{"regex"=>false, "smart"=>true, "search"=>"", "caseInsensitive"=>true}, "visible"=>true}, {"search"=>{"regex"=>false, "smart"=>true, "search"=>"", "caseInsensitive"=>true}, "visible"=>true}, {"search"=>{"regex"=>false, "smart"=>true, "search"=>"", "caseInsensitive"=>true}, "visible"=>true}, {"search"=>{"regex"=>false, "smart"=>true, "search"=>"", "caseInsensitive"=>true}, "visible"=>true}], "assigned"=>"all", "ColReorder"=>[0, 1, 2, 3, 4, 5, 6]}, null: false
t.integer "user_id", null: false
t.integer "team_id", null: false
@ -622,35 +622,35 @@ ActiveRecord::Schema.define(version: 20181212162649) do
t.index ["user_id"], name: "index_samples_tables_on_user_id"
end
create_table "settings", id: :serial, force: :cascade do |t|
create_table "settings", force: :cascade do |t|
t.text "type", null: false
t.jsonb "values", default: {}, null: false
t.index ["type"], name: "index_settings_on_type", unique: true
end
create_table "step_assets", id: :serial, force: :cascade do |t|
t.integer "step_id", null: false
t.integer "asset_id", null: false
create_table "step_assets", force: :cascade do |t|
t.bigint "step_id", null: false
t.bigint "asset_id", null: false
t.index ["step_id", "asset_id"], name: "index_step_assets_on_step_id_and_asset_id"
end
create_table "step_tables", id: :serial, force: :cascade do |t|
t.integer "step_id", null: false
t.integer "table_id", null: false
create_table "step_tables", force: :cascade do |t|
t.bigint "step_id", null: false
t.bigint "table_id", null: false
t.index ["step_id", "table_id"], name: "index_step_tables_on_step_id_and_table_id", unique: true
end
create_table "steps", id: :serial, force: :cascade do |t|
create_table "steps", force: :cascade do |t|
t.string "name"
t.string "description"
t.integer "position", null: false
t.boolean "completed", null: false
t.datetime "completed_on"
t.integer "user_id", null: false
t.bigint "user_id", null: false
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.integer "last_modified_by_id"
t.integer "protocol_id", null: false
t.bigint "last_modified_by_id"
t.bigint "protocol_id", null: false
t.index "trim_html_tags((description)::text) gin_trgm_ops", name: "index_steps_on_description", using: :gin
t.index "trim_html_tags((name)::text) gin_trgm_ops", name: "index_steps_on_name", using: :gin
t.index ["created_at"], name: "index_steps_on_created_at"
@ -660,12 +660,12 @@ ActiveRecord::Schema.define(version: 20181212162649) do
t.index ["user_id"], name: "index_steps_on_user_id"
end
create_table "tables", id: :serial, force: :cascade do |t|
create_table "tables", force: :cascade do |t|
t.binary "contents", null: false
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.integer "created_by_id"
t.integer "last_modified_by_id"
t.bigint "created_by_id"
t.bigint "last_modified_by_id"
t.tsvector "data_vector"
t.string "name", default: ""
t.integer "team_id"
@ -677,26 +677,26 @@ ActiveRecord::Schema.define(version: 20181212162649) do
t.index ["team_id"], name: "index_tables_on_team_id"
end
create_table "tags", id: :serial, force: :cascade do |t|
create_table "tags", force: :cascade do |t|
t.string "name", null: false
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.string "color", default: "#ff0000", null: false
t.integer "project_id", null: false
t.integer "created_by_id"
t.integer "last_modified_by_id"
t.bigint "project_id", null: false
t.bigint "created_by_id"
t.bigint "last_modified_by_id"
t.index "trim_html_tags((name)::text) gin_trgm_ops", name: "index_tags_on_name", using: :gin
t.index ["created_by_id"], name: "index_tags_on_created_by_id"
t.index ["last_modified_by_id"], name: "index_tags_on_last_modified_by_id"
t.index ["project_id"], name: "index_tags_on_project_id"
end
create_table "teams", id: :serial, force: :cascade do |t|
create_table "teams", force: :cascade do |t|
t.string "name", null: false
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.integer "created_by_id"
t.integer "last_modified_by_id"
t.bigint "created_by_id"
t.bigint "last_modified_by_id"
t.string "description"
t.bigint "space_taken", default: 1048576, null: false
t.index ["created_by_id"], name: "index_teams_on_created_by_id"
@ -704,7 +704,7 @@ ActiveRecord::Schema.define(version: 20181212162649) do
t.index ["name"], name: "index_teams_on_name"
end
create_table "temp_files", id: :serial, force: :cascade do |t|
create_table "temp_files", force: :cascade do |t|
t.string "session_id", null: false
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
@ -714,7 +714,7 @@ ActiveRecord::Schema.define(version: 20181212162649) do
t.datetime "file_updated_at"
end
create_table "tiny_mce_assets", id: :serial, force: :cascade do |t|
create_table "tiny_mce_assets", force: :cascade do |t|
t.string "image_file_name"
t.string "image_content_type"
t.integer "image_file_size"
@ -730,13 +730,13 @@ ActiveRecord::Schema.define(version: 20181212162649) do
t.index ["team_id"], name: "index_tiny_mce_assets_on_team_id"
end
create_table "tokens", id: :serial, force: :cascade do |t|
create_table "tokens", force: :cascade do |t|
t.string "token", null: false
t.integer "ttl", null: false
t.integer "user_id", null: false
t.bigint "user_id", null: false
end
create_table "user_identities", id: :serial, force: :cascade do |t|
create_table "user_identities", force: :cascade do |t|
t.integer "user_id"
t.string "provider", null: false
t.string "uid", null: false
@ -747,20 +747,20 @@ ActiveRecord::Schema.define(version: 20181212162649) do
t.index ["user_id"], name: "index_user_identities_on_user_id"
end
create_table "user_my_modules", id: :serial, force: :cascade do |t|
t.integer "user_id", null: false
t.integer "my_module_id", null: false
create_table "user_my_modules", force: :cascade do |t|
t.bigint "user_id", null: false
t.bigint "my_module_id", null: false
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.integer "assigned_by_id"
t.bigint "assigned_by_id"
t.index ["assigned_by_id"], name: "index_user_my_modules_on_assigned_by_id"
t.index ["my_module_id"], name: "index_user_my_modules_on_my_module_id"
t.index ["user_id"], name: "index_user_my_modules_on_user_id"
end
create_table "user_notifications", id: :serial, force: :cascade do |t|
t.integer "user_id"
t.integer "notification_id"
create_table "user_notifications", force: :cascade do |t|
t.bigint "user_id"
t.bigint "notification_id"
t.boolean "checked", default: false
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
@ -769,31 +769,31 @@ ActiveRecord::Schema.define(version: 20181212162649) do
t.index ["user_id"], name: "index_user_notifications_on_user_id"
end
create_table "user_projects", id: :serial, force: :cascade do |t|
create_table "user_projects", force: :cascade do |t|
t.integer "role"
t.integer "user_id", null: false
t.integer "project_id", null: false
t.bigint "user_id", null: false
t.bigint "project_id", null: false
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.integer "assigned_by_id"
t.bigint "assigned_by_id"
t.index ["assigned_by_id"], name: "index_user_projects_on_assigned_by_id"
t.index ["project_id"], name: "index_user_projects_on_project_id"
t.index ["user_id"], name: "index_user_projects_on_user_id"
end
create_table "user_teams", id: :serial, force: :cascade do |t|
create_table "user_teams", force: :cascade do |t|
t.integer "role", default: 1, null: false
t.integer "user_id", null: false
t.integer "team_id", null: false
t.bigint "user_id", null: false
t.bigint "team_id", null: false
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.integer "assigned_by_id"
t.bigint "assigned_by_id"
t.index ["assigned_by_id"], name: "index_user_teams_on_assigned_by_id"
t.index ["team_id"], name: "index_user_teams_on_team_id"
t.index ["user_id"], name: "index_user_teams_on_user_id"
end
create_table "users", id: :serial, force: :cascade do |t|
create_table "users", force: :cascade do |t|
t.string "full_name", null: false
t.string "initials", null: false
t.string "email", default: "", null: false
@ -824,7 +824,7 @@ ActiveRecord::Schema.define(version: 20181212162649) do
t.string "invited_by_type"
t.integer "invited_by_id"
t.integer "invitations_count", default: 0
t.integer "current_team_id"
t.bigint "current_team_id"
t.string "authentication_token", limit: 30
t.jsonb "settings", default: {}, null: false
t.jsonb "variables", default: {}, null: false
@ -849,21 +849,21 @@ ActiveRecord::Schema.define(version: 20181212162649) do
t.index ["viewable_type", "viewable_id"], name: "index_view_states_on_viewable_type_and_viewable_id"
end
create_table "wopi_actions", id: :serial, force: :cascade do |t|
create_table "wopi_actions", force: :cascade do |t|
t.string "action", null: false
t.string "extension", null: false
t.string "urlsrc", null: false
t.integer "wopi_app_id", null: false
t.bigint "wopi_app_id", null: false
t.index ["extension", "action"], name: "index_wopi_actions_on_extension_and_action"
end
create_table "wopi_apps", id: :serial, force: :cascade do |t|
create_table "wopi_apps", force: :cascade do |t|
t.string "name", null: false
t.string "icon", null: false
t.integer "wopi_discovery_id", null: false
t.bigint "wopi_discovery_id", null: false
end
create_table "wopi_discoveries", id: :serial, force: :cascade do |t|
create_table "wopi_discoveries", force: :cascade do |t|
t.integer "expires", null: false
t.string "proof_key_mod", null: false
t.string "proof_key_exp", null: false
@ -871,8 +871,8 @@ ActiveRecord::Schema.define(version: 20181212162649) do
t.string "proof_key_old_exp", null: false
end
create_table "zip_exports", id: :serial, force: :cascade do |t|
t.integer "user_id"
create_table "zip_exports", force: :cascade do |t|
t.bigint "user_id"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.string "zip_file_file_name"

View file

@ -23,19 +23,12 @@ Feature: Team settings
Then I click "Save" button
And I should see "BioSistemika Process Company" on "#team-name" element
@javascript
Scenario: Successfully adds team description
Given I'm on "BioSistemika Process" team settings page
Then I click on ".description-label" element
And I fill in "I was on Triglav one summer." in "team_description" textarea field
Then I click "Save" button
And I should see "I was on Triglav one summer." on ".description-label" element
@javascript
Scenario: Successfully changes team description
Given I'm on "BioSistemika Process" team settings page
Then I click on ".description-label" element
And I change "Lorem ipsum dolor sit amet, consectetuer adipiscing eli." with "I was on Triglav one summer." in "team_description" textarea field
Then I should not see "I was on Triglav one summer." on ".description-label" element
And I fill in "I was on Triglav one summer." in "team_description" textarea field
Then I click "Save" button
And I should see "I was on Triglav one summer." on ".description-label" element

View file

@ -128,6 +128,11 @@ Then(/^I change "([^"]*)" with "([^"]*)" in "([^"]*)" textarea field$/) do |old_
textarea.set(new_text)
end
Then(/^I should not see "([^"]*)" on "([^"]*)" element$/) do |text, element|
wait_for_ajax
expect(find(element)).not_to have_content(text)
end
Then(/^I should see "([^"]*)" on "([^"]*)" element$/) do |text, element|
wait_for_ajax
expect(find(element)).to have_content(text)

View file

@ -149,33 +149,6 @@ class AddonGenerator < Rails::Generators::NamedBase
end
end
def create_test
# test/fixtures
create_file("addons/#{@addon_name}/test/fixtures/#{@folders_path}/.keep")
# test/integrations
create_file("addons/#{@addon_name}/test/integrations/.keep")
# test/models
create_file("addons/#{@addon_name}/test/models/#{@folders_path}/.keep")
# test/engine_test
create_file(
"addons/#{@addon_name}/test/" \
"#{@folders_path}/#{@addon_name}_test.rb"
) do
"require 'test_helper'\n\n" \
"class #{name}::Test < ActiveSupport::TestCase\n" \
" test 'truth' do\n" \
" assert_kind_of Module, #{name}\n" \
" end\n" \
"end\n"
end
# test/test_helper.rb
copy_file('test_helper.rb', "addons/#{@addon_name}/test/test_helper.rb")
end
def create_root
copy_file('.gitignore', "addons/#{@addon_name}/.gitignore")
copy_file('Gemfile', "addons/#{@addon_name}/Gemfile")

View file

@ -1,24 +0,0 @@
# Configure Rails Environment
ENV['RAILS_ENV'] = 'test'
require File.expand_path('../..//config/environment.rb', __FILE__)
ActiveRecord::Migrator.migrations_paths = [
File.expand_path('../..//db/migrate', __FILE__)
]
require 'rails/test_help'
# Filter out Minitest backtrace while allowing backtrace from other libraries
# to be shown.
Minitest.backtrace_filter = Minitest::BacktraceFilter.new
# Load support files
Dir["#{File.dirname(__FILE__)}/support/**/*.rb"].each { |f| require f }
# Load fixtures from the engine
if ActiveSupport::TestCase.respond_to?(:fixture_path=)
ActiveSupport::TestCase.fixture_path =
File.expand_path('../fixtures', __FILE__)
ActiveSupport::TestCase.file_fixture_path =
ActiveSupport::TestCase.fixture_path + 'files'
ActiveSupport::TestCase.fixtures :all
end

View file

@ -1,3 +1,5 @@
# frozen_string_literal: true
namespace :exportable_items do
desc 'Removes exportable zip files'
task cleanup: :environment do
@ -6,23 +8,4 @@ namespace :exportable_items do
puts "All exportable zip files older than " \
"'#{num.days.ago}' have been removed"
end
desc 'Resets export project counter to 0'
task reset_export_projects_counter: :environment do
User.find_each do |user|
User.transaction do
begin
user.export_vars['num_of_export_all_last_24_hours'] = 0
user.save
rescue ActiveRecord::ActiveRecordError,
ArgumentError,
ActiveRecord::RecordNotSaved => e
puts "Error resetting users num_of_export_all_last_24_hours " \
"variable to 0, transaction reverted: #{e}"
end
end
end
puts 'Export project counter successfully ' \
'reset on all users'
end
end

10
pull_request_template.md Normal file
View file

@ -0,0 +1,10 @@
Jira ticket: [SCI-xxxx](https://biosistemika.atlassian.net/browse/SCI-xxxx)
###What was done
_In a sentence or two describe what was done, focus on the tech aspect_
####ToDo:
_(Optional) If you have discovered an oppurtunity for refactor or another task that was not part of the jira issue, please write it here_
###Note:
_(Optional) Note any other remarks, problems you were facing during the development, suggestion etc_

View file

@ -54,11 +54,15 @@ describe ProjectsController, type: :controller do
end
end
# rubocop:disable Security/Eval
# rubocop:disable Style/EvalWithLocation
(1..PROJECTS_CNT).each do |i|
let!("user_projects_#{i}") do
create :user_project, project: eval("project_#{i}"), user: user
create :user_project, :owner, project: eval("project_#{i}"), user: user
end
end
# rubocop:enable Security/Eval
# rubocop:enable Style/EvalWithLocation
describe '#index' do
context 'in JSON format' do

View file

@ -1,26 +1,19 @@
# frozen_string_literal: true
FactoryBot.define do
factory :experiment do
name { Faker::Name.unique.name }
description 'Lorem ipsum dolor sit amet, consectetuer adipiscing elit.'
end
factory :experiment_one, class: Experiment do
name 'My Experiment One'
description 'Lorem ipsum dolor sit amet, consectetuer adipiscing elit.'
association :project, factory: :project
association :created_by, factory: :user, email: Faker::Internet.email
association :last_modified_by,
factory: :user,
email: Faker::Internet.email
end
factory :experiment_two, class: Experiment do
name Faker::Name.name
description 'Lorem ipsum dolor sit amet, consectetuer adipiscing elit.'
association :project, factory: :project
association :created_by, factory: :user, email: Faker::Internet.email
association :last_modified_by,
factory: :user,
email: Faker::Internet.email
factory :experiment, class: Experiment do
transient do
user { create :user }
end
sequence(:name) { |n| "Experiment-#{n}" }
description { Faker::Lorem.sentence }
created_by { user }
last_modified_by { user }
project { create :project, created_by: user }
factory :experiment_with_tasks do
after(:create) do |e|
create_list :my_module, 3, :with_tag, experiment: e
end
end
end
end

View file

@ -1,5 +1,7 @@
# frozen_string_literal: true
FactoryBot.define do
factory :my_module_group do
experiment { Experiment.first || create(:experiment_two) }
experiment
end
end

View file

@ -1,10 +1,15 @@
# frozen_string_literal: true
FactoryBot.define do
factory :my_module do
name 'My first module'
x 0
y 0
workflow_order 0
experiment { Experiment.first || create(:experiment_one) }
my_module_group { MyModuleGroup.first || create(:my_module_group) }
sequence(:name) { |n| "Task-#{n}" }
x { Faker::Number.between(1, 100) }
y { Faker::Number.between(1, 100) }
workflow_order { MyModule.where(experiment_id: experiment.id).count + 1 }
experiment
my_module_group { create :my_module_group, experiment: experiment }
trait :with_tag do
tags { create_list :tag, 3, project: experiment.project }
end
end
end

View file

@ -1,10 +1,12 @@
# frozen_string_literal: true
FactoryBot.define do
factory :project do
created_by { User.first || association(:project_user) }
team { Team.first || association(:project_team) }
archived false
name 'My project'
visibility 'hidden'
sequence(:name) { |n| "My project-#{n}" }
association :created_by, factory: :user
team { create :team, created_by: created_by }
archived { false }
visibility { 'hidden' }
end
factory :project_user, class: User do
@ -14,11 +16,4 @@ FactoryBot.define do
password 'asdf1243'
password_confirmation 'asdf1243'
end
factory :project_team, class: Team do
created_by { User.first || association(:project_user) }
name 'My team'
description 'Lorem ipsum dolor sit amet, consectetuer adipiscing eli.'
space_taken 1048576
end
end

9
spec/factories/tags.rb Normal file
View file

@ -0,0 +1,9 @@
# frozen_string_literal: true
FactoryBot.define do
factory :tag do
sequence(:name) { |n| "My tag-#{n}" }
project
color { Faker::Color.hex_color }
end
end

View file

@ -1,8 +1,13 @@
# frozen_string_literal: true
FactoryBot.define do
factory :team do
created_by { User.first || create(:user) }
name 'My team'
description 'Lorem ipsum dolor sit amet, consectetuer adipiscing eli.'
space_taken 1048576
association :created_by, factory: :user
sequence(:name) { |n| "My team-#{n}" }
description { Faker::Lorem.sentence }
space_taken { 1048576 }
trait :with_members do
users { create_list :user, 3 }
end
end
end

View file

@ -1,5 +0,0 @@
FactoryBot.define do
factory :user_project do
role 'owner'
end
end

View file

@ -0,0 +1,21 @@
# frozen_string_literal: true
FactoryBot.define do
factory :user_project do
user
project
assigned_by { user }
trait :owner do
role { UserProject.roles[:owner] }
end
trait :normal_user do
role { UserProject.roles[:normal_user] }
end
trait :technician do
role { UserProject.roles[:technician] }
end
trait :viewer do
role { UserProject.roles[:viewer] }
end
end
end

View file

@ -1,8 +1,10 @@
# frozen_string_literal: true
FactoryBot.define do
factory :user do
full_name 'admin'
initials 'AD'
email Faker::Internet.unique.email
sequence(:email) { |n| "user-#{n}@example.com" }
password 'asdf1243'
password_confirmation 'asdf1243'
current_sign_in_at DateTime.now

View file

@ -1,3 +1,5 @@
# frozen_string_literal: true
require 'rails_helper'
describe Experiment, type: :model do

View file

@ -1,3 +1,5 @@
# frozen_string_literal: true
require 'rails_helper'
describe Project, type: :model do
@ -39,22 +41,30 @@ describe Project, type: :model do
it { should have_many :report_elements }
end
describe 'Should be a valid object' do
let(:user) { create :user }
let(:team) { create :team, created_by: user }
it { should validate_presence_of :visibility }
it { should validate_presence_of :team }
it do
should validate_length_of(:name).is_at_least(Constants::NAME_MIN_LENGTH)
.is_at_most(Constants::NAME_MAX_LENGTH)
describe 'Validations' do
describe '#visibility' do
it { should validate_presence_of :visibility }
end
it 'should have a unique name scoped to team' do
create :project, created_by: user, last_modified_by: user, team: team
project_two = build :project, created_by: user,
last_modified_by: user,
team: team
expect(project_two).to_not be_valid
describe '#team' do
it { should validate_presence_of :team }
end
describe '#name' do
it 'should be at least 2 long and max 255 long' do
should validate_length_of(:name)
.is_at_least(Constants::NAME_MIN_LENGTH)
.is_at_most(Constants::NAME_MAX_LENGTH)
end
it 'should be uniq per project and team' do
first_project = create :project
second_project = build :project,
name: first_project.name,
team: first_project.team
expect(second_project).to_not be_valid
end
end
end
end

View file

@ -1,3 +1,5 @@
# frozen_string_literal: true
require 'rails_helper'
describe Tag, type: :model do
@ -23,15 +25,46 @@ describe Tag, type: :model do
it { should have_many :my_modules }
end
describe 'Should be a valid object' do
it { should validate_presence_of :name }
it { should validate_presence_of :color }
it { should validate_presence_of :project }
it do
should validate_length_of(:name).is_at_most(Constants::NAME_MAX_LENGTH)
describe 'Validations' do
describe '#name' do
it { should validate_presence_of :name }
it do
should validate_length_of(:name)
.is_at_most(Constants::NAME_MAX_LENGTH)
end
end
it do
should validate_length_of(:color).is_at_most(Constants::COLOR_MAX_LENGTH)
describe '#color' do
it { should validate_presence_of :color }
it do
should validate_length_of(:color)
.is_at_most(Constants::COLOR_MAX_LENGTH)
end
end
describe '#projects' do
it { should validate_presence_of :project }
end
end
describe '.clone_to_project_or_return_existing' do
let(:project) { create :project }
let(:tag) { create :tag }
context 'when tag does not exits' do
it 'does create new tag for project' do
expect do
tag.clone_to_project_or_return_existing(project)
end.to(change { Tag.where(project_id: project.id).count })
end
end
context 'when tag already exists' do
it 'return existing tag for project' do
Tag.create(name: tag.name, color: tag.color, project: project)
expect do
tag.clone_to_project_or_return_existing(project)
end.to_not(change { Tag.where(project_id: project.id).count })
end
end
end
end

View file

@ -187,7 +187,9 @@ describe User, type: :model do
describe '#last_activities' do
let!(:user) { create :user }
let!(:project) { create :project }
let!(:user_projects) { create :user_project, project: project, user: user }
let!(:user_projects) do
create :user_project, :viewer, project: project, user: user
end
let!(:activity_one) { create :activity, user: user, project: project }
let!(:activity_two) { create :activity, user: user, project: project }
@ -198,4 +200,62 @@ describe User, type: :model do
expect(activities).to include activity_two
end
end
describe '#increase_daily_exports_counter!' do
let(:user) { create :user }
context 'when last_export_timestamp is set' do
it 'increases counter by 1' do
expect { user.increase_daily_exports_counter! }
.to change {
user.reload.export_vars['num_of_export_all_last_24_hours']
}.from(0).to(1)
end
it 'sets last_export_timestamp on today' do
user.export_vars['last_export_timestamp'] = Date.yesterday.to_time.to_i
user.save
expect { user.increase_daily_exports_counter! }
.to change {
user.reload.export_vars['last_export_timestamp']
}.to(Date.today.to_time.to_i)
end
it 'sets new counter for today' do
user.export_vars = {
'num_of_export_all_last_24_hours': 3,
'last_export_timestamp': Date.yesterday.to_time.to_i
}
user.save
expect { user.increase_daily_exports_counter! }
.to change {
user.reload.export_vars['num_of_export_all_last_24_hours']
}.from(3).to(1)
end
end
context 'when last_export_timestamp not exists (existing users)' do
it 'sets last_export_timestamp on today' do
user.export_vars.delete('last_export_timestamp')
user.save
expect { user.increase_daily_exports_counter! }
.to change {
user.reload.export_vars['last_export_timestamp']
}.from(nil).to(Date.today.to_time.to_i)
end
it 'starts count reports with 1' do
user.export_vars.delete('last_export_timestamp')
user.export_vars['num_of_export_all_last_24_hours'] = 2
user.save
expect { user.increase_daily_exports_counter! }
.to change {
user.reload.export_vars['num_of_export_all_last_24_hours']
}.from(2).to(1)
end
end
end
end

View file

@ -4,9 +4,9 @@ require 'rails_helper'
RSpec.describe 'Api::V1::UsersController', type: :request do
before :all do
@user1 = create(:user, email: Faker::Internet.unique.email)
@user2 = create(:user, email: Faker::Internet.unique.email)
@user3 = create(:user, email: Faker::Internet.unique.email)
@user1 = create(:user)
@user2 = create(:user)
@user3 = create(:user)
@team1 = create(:team, created_by: @user1)
@team2 = create(:team, created_by: @user2)
@team3 = create(:team, created_by: @user3)
@ -40,7 +40,7 @@ RSpec.describe 'Api::V1::UsersController', type: :request do
it 'When invalid request, non existing user' do
hash_body = nil
get api_v1_user_path(id: 123), headers: @valid_headers
get api_v1_user_path(id: -1), headers: @valid_headers
expect(response).to have_http_status(403)
expect { hash_body = json }.not_to raise_exception
expect(hash_body['errors'][0]).to include('status': 403)

View file

@ -0,0 +1,22 @@
# frozen_string_literal: true
require 'rails_helper'
describe Experiments::GenerateWorkflowImageService do
let(:experiment) { create :experiment_with_tasks }
let(:params) { { experiment_id: experiment.id } }
context 'when succeed' do
it 'succeed? returns true' do
expect(described_class.call(params).succeed?).to be_truthy
end
it 'worklfow image of experiment is updated' do
old_filename = experiment.workflowimg_file_name
described_class.call(params)
experiment.reload
expect(experiment.workflowimg_file_name).not_to be == old_filename
end
end
end

View file

@ -0,0 +1,98 @@
# frozen_string_literal: true
require 'rails_helper'
describe Experiments::MoveToProjectService do
let(:team) { create :team, :with_members }
let(:project) do
create :project, team: team, user_projects: []
end
let(:new_project) do
create :project, team: team, user_projects: [user_project2]
end
let(:experiment) do
create :experiment_with_tasks, name: 'MyExp', project: project
end
let(:user) { create :user }
let(:user_project2) { create :user_project, :normal_user, user: user }
let(:service_call) do
Experiments::MoveToProjectService.call(experiment_id: experiment.id,
project_id: new_project.id,
user_id: user.id)
end
context 'when call with valid params' do
it 'unnasigns experiment from project' do
service_call
expect(project.experiments.pluck(:id)).to_not include(experiment.id)
end
it 'assigns experiment to new_project' do
service_call
expect(new_project.experiments.pluck(:id)).to include(experiment.id)
end
it 'copies tags to new project' do
expect { service_call }.to(change { new_project.tags.count })
end
it 'leaves tags on an old project' do
experiment # explicit call to create tags
expect { service_call }.not_to(change { project.tags.count })
end
it 'sets new project tags to modules' do
service_call
new_tags = experiment.my_modules.map { |m| m.tags.map { |t| t } }.flatten
tags_project_id = new_tags.map(&:project_id).uniq.first
expect(tags_project_id).to be == new_project.id
end
it 'adds Activity record' do
expect { service_call }.to(change { Activity.all.count })
end
end
context 'when call with invalid params' do
it 'returns an error when can\'t find user and project' do
allow(Project).to receive(:find).and_return(nil)
allow(User).to receive(:find).and_return(nil)
expect(service_call.errors).to have_key(:invalid_arguments)
end
it 'returns an error on validate' do
FactoryBot.create :experiment, project: new_project, name: 'MyExp'
expect(service_call.succeed?).to be_falsey
end
it 'returns an error on saving' do
expect_any_instance_of(Experiments::MoveToProjectService)
.to receive(:valid?)
.and_return(true)
FactoryBot.create :experiment, project: new_project, name: 'MyExp'
expect(service_call.succeed?).to be_falsey
end
it 'rollbacks cloned tags after unsucessful save' do
expect_any_instance_of(Experiments::MoveToProjectService)
.to receive(:valid?)
.and_return(true)
FactoryBot.create :experiment, project: new_project, name: 'MyExp'
experiment
expect { service_call }.not_to(change { Tag.count })
end
it 'returns error if teams is not the same' do
t = create :team, :with_members
project.update(team: t)
expect(service_call.errors).to have_key(:target_project_not_valid)
end
end
end

View file

View file

@ -1,5 +0,0 @@
require 'test_helper'
class ActivitiesControllerTest < ActionController::TestCase
end

View file

@ -1,7 +0,0 @@
require 'test_helper'
class CustomFieldsControllerTest < ActionController::TestCase
# test "the truth" do
# assert true
# end
end

View file

@ -1,7 +0,0 @@
require 'test_helper'
class MyModulesControllerTest < ActionController::TestCase
# test "the truth" do
# assert true
# end
end

View file

@ -1,7 +0,0 @@
require 'test_helper'
class ProjectActivitiesControllerTest < ActionController::TestCase
# test "the truth" do
# assert true
# end
end

View file

@ -1,7 +0,0 @@
require 'test_helper'
class ProjectsControllerTest < ActionController::TestCase
# test "the truth" do
# assert true
# end
end

View file

@ -1,7 +0,0 @@
require 'test_helper'
class ResultAssetsControllerTest < ActionController::TestCase
# test "the truth" do
# assert true
# end
end

View file

@ -1,7 +0,0 @@
require 'test_helper'
class ResultCommentsControllerTest < ActionController::TestCase
# test "the truth" do
# assert true
# end
end

View file

@ -1,7 +0,0 @@
require 'test_helper'
class ResultTablesControllerTest < ActionController::TestCase
# test "the truth" do
# assert true
# end
end

View file

@ -1,7 +0,0 @@
require 'test_helper'
class ResultTextsControllerTest < ActionController::TestCase
# test "the truth" do
# assert true
# end
end

View file

@ -1,7 +0,0 @@
require 'test_helper'
class SampleGroupsControllerTest < ActionController::TestCase
# test "the truth" do
# assert true
# end
end

View file

@ -1,7 +0,0 @@
require 'test_helper'
class SampleTypesControllerTest < ActionController::TestCase
# test "the truth" do
# assert true
# end
end

View file

@ -1,7 +0,0 @@
require 'test_helper'
class SamplesControllerTest < ActionController::TestCase
# test "the truth" do
# assert true
# end
end

View file

@ -1,7 +0,0 @@
require 'test_helper'
class SearchControllerTest < ActionController::TestCase
# test "the truth" do
# assert true
# end
end

View file

@ -1,7 +0,0 @@
require 'test_helper'
class StepCommentsControllerTest < ActionController::TestCase
# test "the truth" do
# assert true
# end
end

View file

@ -1,7 +0,0 @@
require 'test_helper'
class StepsControllerTest < ActionController::TestCase
# test "the truth" do
# assert true
# end
end

View file

@ -1,7 +0,0 @@
require 'test_helper'
class TeamsControllerTest < ActionController::TestCase
# test "the truth" do
# assert true
# end
end

View file

@ -1,7 +0,0 @@
require 'test_helper'
class UserMyModulesControllerTest < ActionController::TestCase
# test "the truth" do
# assert true
# end
end

0
test/fixtures/.keep vendored
View file

View file

@ -1,95 +0,0 @@
one:
project: interfaces
my_module: qpcr
user: steve
type_of: assignment
message: User Steve assigned module lalala to user Jlaw.
created_at: 2015-11-01 10:01:01
two:
project: interfaces
my_module: qpcr
user: steve
type_of: result
message: User Steve added result to step 2 of module qPCR.
created_at: 2015-11-01 10:02:01
three:
project: interfaces
my_module: qpcr
user: steve
type_of: result
message: User Steve added result to step 3 of module qPCR.
created_at: 2015-11-01 10:03:01
four:
project: interfaces
my_module: rna_test
user: steve
type_of: assignment
message: User Steve assigned module lalala to user Jlaw.
created_at: 2015-11-01 10:04:01
five:
project: interfaces
my_module: rna_test
user: steve
type_of: result
message: User Steve added result to step 2 of module RNA test.
created_at: 2015-11-01 10:05:01
six:
project: interfaces
my_module: rna_test
user: steve
type_of: result
message: User Steve added result to step 3 of module RNA test.
created_at: 2015-11-01 10:06:01
seven:
project: interfaces
my_module: sample_prep
user: steve
type_of: assignment
message: User Steve assigned module lalala to user Jlaw.
created_at: 2015-11-01 10:07:01
eight:
project: interfaces
my_module: sample_prep
user: steve
type_of: result
message: User Steve added result to step 2 of module Sample preparation.
created_at: 2015-11-01 10:08:01
nine:
project: interfaces
my_module: sample_prep
user: steve
type_of: result
message: User Steve added result to step 3 of module Sample preparation.
created_at: 2015-11-01 10:09:01
ten:
project: interfaces
my_module: list_of_samples
user: steve
type_of: assignment
message: User Steve assigned module lalala to user Jlaw.
created_at: 2015-11-01 10:10:01
eleven:
project: interfaces
my_module: list_of_samples
user: steve
type_of: result
message: User Steve added result to step 2 of module List of samples.
created_at: 2015-11-01 10:11:01
twelve:
project: interfaces
my_module: list_of_samples
user: steve
type_of: result
message: User Steve added result to step 3 of module List of samples.
created_at: 2015-11-01 10:12:01

View file

@ -1,15 +0,0 @@
one:
asset: one
data: This is text content of asset file #1.
two:
asset: two
data: This is text content of asset file #2.
invalid_asset_id:
asset_id: 12321321
data: This is text content of invalid asset.
invalid_asset_value:
asset: nil
data: This is text content of nil asset.

View file

@ -1,48 +0,0 @@
one:
file_file_name: file1.pdf
file_content_type: application/pdf
file_file_size: 15
estimated_size: <%= (15 * Constants::ASSET_ESTIMATED_SIZE_FACTOR).to_i %>
created_by: steve
last_modified_by: steve
two:
file_file_name: file2.zip
file_content_type: application/zip
file_file_size: 32
estimated_size: <%= (32 * Constants::ASSET_ESTIMATED_SIZE_FACTOR).to_i %>
created_by: mark
last_modified_by: mark
three:
file_file_name: file3.jpg
file_content_type: image/jpg
file_file_size: 64
estimated_size: <%= (64 * Constants::ASSET_ESTIMATED_SIZE_FACTOR).to_i %>
created_by: mark
last_modified_by: jlaw
four:
file_file_name: file4.png
file_content_type: image/png
file_file_size: 128
estimated_size: <%= (128 * Constants::ASSET_ESTIMATED_SIZE_FACTOR).to_i %>
created_by: steve
last_modified_by: jlaw
test:
file_file_name: file7.png
file_content_type: image/png
file_file_size: 578
estimated_size: <%= (578 * Constants::ASSET_ESTIMATED_SIZE_FACTOR).to_i %>
created_by: steve
last_modified_by: jlaw
test_result:
file_file_name: file8.png
file_content_type: image/png
file_file_size: 631
estimated_size: <%= (631 * Constants::ASSET_ESTIMATED_SIZE_FACTOR).to_i %>
created_by: steve
last_modified_by: steve

View file

@ -1,56 +0,0 @@
one:
text: "Checklist Item 1"
checked: true
checklist: one
created_by: steve
last_modified_by: steve
two:
text: "Checklist Item 2"
checked: false
checklist: one
created_by: mark
last_modified_by: mark
three:
text: "Checklist Item 3"
checked: false
checklist: one
created_by: steve
last_modified_by: mark
four:
text: "Checklist Item 4"
checked: true
checklist: two
created_by: jlaw
last_modified_by: jlaw
five:
text: "Checklist Item 5"
checked: false
checklist: two
created_by: steve
last_modified_by: nora
six:
text: "Checklist Item 6"
checked: true
checklist: two
created_by: mark
last_modified_by: mark
seven:
text: "Checklist Item 7"
checked: false
checklist: three
created_by: mark
last_modified_by: steve
eight:
text: "Checklist Item 8"
checked: false
checklist: three
created_by: nora
last_modified_by: steve

View file

@ -1,17 +0,0 @@
one:
name: "Checklist 1"
step: step1
created_by: steve
last_modified_by: steve
two:
name: "Checklist 2"
step: step2
created_by: steve
last_modified_by: jlaw
three:
name: "Checklist 3"
step: step3
created_by: nora
last_modified_by: jlaw

View file

@ -1,89 +0,0 @@
one:
message: "Good job, JLaw, very comprehensive results!"
user: steve
two:
message: "This doesn't look so good, please repeat the experiment."
user: steve
three:
message: "Consider it done!"
user: nora
four:
message: "I still have to write abstract."
user: mark
five:
message: "Ok, I will do it tomorrow."
user: mark
six:
message: "Ok"
user: jlaw
seven:
message: "Nah, I don't feel like it."
user: jlaw
eight:
message: "I don't have time now, maybe tomorrow."
user: jlaw
nine:
message: "This is project comment."
user: mark
ten:
message: "This is module comment."
user: mark
eleven:
message: "This is module comment 2."
user: nora
twelve:
message: "This is project comment 2."
user: nora
thirteen:
message: "Random comment 1"
user: john
fourteen:
message: "Random comment 2"
user: john
fifteen:
message: "Random comment 3"
user: john
sixteen:
message: "Congrats!"
user: jlaw
seventeen:
message: "Congrats, aswell!"
user: nora
test:
message: "This is test message"
user: nora
<% 25.times do |n| %>
test_step_comment_<%= n %>:
message: "This is test message #<%= n %>"
user: steve
created_at: "2015-11-06 11:<%= n.to_s.rjust(2, '0') %>:00"
<% end %>
<% 25.times do |n| %>
test_result_comment_<%= n %>:
message: "This is test message #<%= n %>"
user: steve
created_at: "2015-11-06 11:<%= n.to_s.rjust(2, '0') %>:00"
<% end %>
unassociated:
message: This message is not associated with any entity
user: nora

View file

@ -1,19 +0,0 @@
one:
from: list_of_samples
to: sample_prep
two:
from: sample_prep
to: qpcr
three:
from: qpcr
to: quantification
four:
from: list_of_samples
to: rna_test
five:
from: rna_test
to: quantification

View file

@ -1,14 +0,0 @@
volume:
name: "Volume"
user: steve
team: biosistemika
location:
name: "Location"
user: jlaw
team: biosistemika
description:
name: "Description"
user: nora
team: nib

View file

@ -1,8 +0,0 @@
philadelphia:
name: PHILADELPHIA
description: experiment
project: interfaces
created_at: 2012-05-09 16:23:33
created_by: steve
last_modified_by: steve
updated_at: 2012-05-09 16:23:33

View file

@ -1,7 +0,0 @@
one:
team: biosistemika
message: This is a test log numero uno
two:
team: biosistemika
message: This is a test log numero due

View file

@ -1,23 +0,0 @@
one:
my_module: list_of_samples
comment: thirteen
two:
my_module: sample_prep
comment: fourteen
three:
my_module: sample_prep
comment: fifteen
four:
my_module: qpcr
comment: sixteen
five:
my_module: quantification
comment: seventeen
test:
my_module: qpcr
comment: eleven

View file

@ -1,14 +0,0 @@
wf1:
name: Workflow 1
experiment: philadelphia
created_by: mark
ge:
name: Gene Expression
experiment: philadelphia
created_by: steve
wf2:
name: Workflow 2
experiment: philadelphia
created_by: jlaw

View file

@ -1,140 +0,0 @@
list_of_samples:
name: List of samples
due_date: 2015-11-10 12:00:00
description: Listing samples...
x: 0
y: 0
workflow_order: 0
experiment: philadelphia
my_module_group: ge
tags: urgent, nice
created_by: steve
last_modified_by: steve
archived: false
archived_by:
restored_by:
archived_on:
restored_on:
sample_prep:
name: Sample preparation
due_date: 12-04-2015 12:45:00
description: nil
x: 1
y: 0
workflow_order: 2
experiment: philadelphia
my_module_group: ge
created_by: mark
last_modified_by: mark
archived: false
archived_by: steve
restored_by: steve
archived_on: 2012-09-10 16:23:35
restored_on: 2012-10-05 06:03:33
qpcr:
name: qPCR
due_date: 12-04-2015 15:10:00
description: nil
x: 2
y: 0
workflow_order: 3
experiment: philadelphia
my_module_group: ge
tags: nice
created_by: jlaw
last_modified_by: jlaw
archived: false
archived_by:
restored_by:
archived_on:
restored_on:
quantification:
name: Quantification
due_date: "04-13-2015 09:45:00"
description: nil
x: 3
y: 0
workflow_order: 4
experiment: philadelphia
my_module_group: ge
tags: todo
created_by: mark
last_modified_by: mark
archived: false
archived_by:
restored_by:
archived_on:
restored_on:
rna_test:
name: RNA quality test
due_date: 12-04-2015 16:15:00
description: nil
x: 1
y: 1
workflow_order: 1
experiment: philadelphia
my_module_group: ge
tags: urgent, todo
created_by: steve
last_modified_by: steve
archived: false
archived_by: mark
restored_by: mark
archived_on: 2012-02-09 16:23:35
restored_on: 2012-12-09 12:33:48
custom:
name: Unknown module
due_date:
description: Hodor hodor hodor.
x: 0
y: 0
workflow_order: -1
experiment: philadelphia
my_module_group: wf1
created_by: steve
last_modified_by: steve
archived: false
archived_by:
restored_by:
archived_on:
restored_on:
no_group:
name: No group module
due_date:
description: Module without group
x: 0
y: 3
workflow_order: -1
experiment: philadelphia
my_module_group: wf2
created_by: nora
last_modified_by: nora
archived: false
archived_by:
restored_by:
archived_on:
restored_on:
archived:
name: Archived module
due_date:
description: Module in archive
x: 0
y: 0
workflow_order: -1
experiment: philadelphia
my_module_group:
created_by: steve
last_modified_by: steve
archived: true
archived_by: jlaw
restored_by:
archived_on: 2015-11-16 10:25:34
restored_on:

View file

@ -1,9 +0,0 @@
one:
title: 'Notification one'
message: 'Message for notification one'
type_of: 1
two:
title: 'Notification two'
message: 'Message for notification two'
type_of: 1

View file

@ -1,15 +0,0 @@
one:
project: interfaces
comment: seven
two:
project: interfaces
comment: eight
three:
project: interfaces
comment: nine
test:
project: interfaces
comment: six

View file

@ -1,175 +0,0 @@
interfaces:
name: INTERFACES
visibility: 1
due_date: 2015-11-02 15:30:22
team: biosistemika
archived: false
archived_on:
created_at: 2015-11-01 11:37:26
created_by: steve
last_modified_by: steve
archived_by:
restored_by:
restored_on:
eurostars:
name: EUROSTARS
visibility: 1
due_date: 2015-11-02 15:30:22
team: biosistemika
archived: false
archived_on:
created_at: 2015-11-01 12:53:07
created_by: steve
last_modified_by: steve
archived_by:
restored_by:
restored_on:
krop:
name: KROP 2012
visibility: 1
due_date: 2012-05-07 13:30:25
team: biosistemika
archived: true
archived_on: 2012-05-09 16:23:33
created_by: mark
last_modified_by: mark
archived_by: mark
restored_by:
restored_on:
phd:
name: PhD Thesis
visibility: 0
due_date:
team: nib
archived: false
archived_on:
created_by: mark
last_modified_by: steve
archived_by:
restored_by:
restored_on:
decathlon:
name: DECATHLON
visibility: 1
due_date:
team: phylos
archived: false
archived_on:
created_by: jlaw
last_modified_by: jlaw
archived_by:
restored_by:
restored_on:
valor:
name: VALOR 2010
visibility: 1
due_date: 2010-11-13 14:11:23
team: nib
archived: false
archived_on: 2012-05-09 16:33:33
created_by: nora
last_modified_by: nora
archived_by: mark
restored_by: mark
restored_on: 2014-09-15 11:43:22
secret:
name: My Secret Life
visibility: 0
due_date: 2030-06-04 13:00:00
team: nib
archived: false
archived_on:
created_by: mark
last_modified_by: steve
archived_by:
restored_by:
restored_on:
a_project:
name: A Project
visibility: 1
due_date: 2018-12-02 15:30:22
team: biosistemika
archived: false
archived_on:
created_at: 2015-11-01 14:28:15
created_by: steve
last_modified_by: steve
archived_by:
restored_by:
restored_on:
z_project:
name: Z Project
visibility: 1
due_date: 2018-12-02 15:30:22
team: biosistemika
archived: false
archived_on:
created_at: 2015-11-01 16:15:37
created_by: steve
last_modified_by: steve
archived_by:
restored_by:
restored_on:
a_archived_project:
name: A Archived Project
visibility: 1
due_date: 2018-12-02 15:30:22
team: biosistemika
archived: true
archived_on: 2015-11-05 08:14:56
created_at: 2015-11-01 14:28:15
created_by: steve
last_modified_by: steve
archived_by:
restored_by:
restored_on:
z_archived_project:
name: Z Archived Project
visibility: 1
due_date: 2018-12-02 15:30:22
team: biosistemika
archived: true
archived_on: 2015-11-05 08:12:56
created_at: 2015-11-01 16:15:37
created_by: steve
last_modified_by: steve
archived_by:
restored_by:
restored_on:
test1:
name: Project 1
visibility: 1
due_date: <%= DateTime.now %>
team: biosistemika
archived: false
created_by: steve
test2:
name: Project 2
visibility: 0
team: biosistemika
archived: true
archived_on: <%= DateTime.now %>
test3:
name: Project 3
visibility: 1
team: nib
archived: false
dummy:
name: Dummy project
visibility: 1
team: nib
archived: false

Some files were not shown because too many files have changed in this diff Show more